Announcing HAProxy Kubernetes Ingress Controller 3.2

We’re excited to announce the simultaneous releases of HAProxy Kubernetes Ingress Controller 3.2 and HAProxy Enterprise Kubernetes Ingress Controller 3.2! All new features described here apply to both products.

These releases introduce user-defined annotations, a new frontend CRD, and other minor improvements, and we’ll cover these in detail below. Visit our documentation to view the full release notes.

If you have questions about how to replace Ingress NGINX or how to migrate from Ingress to Gateway API, you can skip to the FAQs.

Version compatibility with HAProxy 

HAProxy Kubernetes Ingress Controller 3.2 is built with HAProxy 3.2.

New to HAProxy Kubernetes Ingress Controller?

HAProxy Kubernetes Ingress Controller is a free, open-source product providing high-performance Kubernetes-native application routing for the Ingress API. It supports HTTP/S and TCP (via CRD), and is built on HAProxy’s legendary performance, flexibility, and reliability. Additionally, it provides a low-risk migration path to Gateway API via the HAProxy Unified Gateway (beta). 

HAProxy Enterprise Kubernetes Ingress Controller provides secure, high-performance Kubernetes-native application routing for the Ingress API. It combines the flexibility of the open-source HAProxy Kubernetes Ingress Controller with an integrated web application firewall (WAF) and world-class support.

What’s new?

Feature

Benefit

Impact

User-defined annotations

Add new annotations independent of release pipeline and make use of more HAProxy features

Rapid feature adoption and modernization; simple support for Ingress NGINX annotations

Frontend CRD

Flexibly configure HAProxy frontend sections, validate changes to K8s resources

Simplified configuration and added flexibility

These enhancements make the community and enterprise products even more flexible, and enable simpler migration from existing Ingress NGINX deployments (EOL in March 2026) to HAProxy Kubernetes Ingress Controller. For an immediate, step-by-step technical transition plan from Ingress NGINX to HAProxy Kubernetes Ingress Controller, see our Ingress NGINX migration assistant.

Ready to upgrade?

When you're ready to start the upgrade process, view the upgrade instructions for your product:

User-defined annotations

User-defined annotations are annotations with full validation that users can create for the frontend and backend sections of the HAProxy configuration that the ingress controller generates. These annotations are CRD driven, and allow you to limit their scope to certain resources. They're powerful, unlocking all previously unavailable HAProxy options through custom templates. They also bundle in safety through validation rules you define. 

User-defined annotations are especially useful when migrating to HAProxy Kubernetes Ingress Controller. If any annotation is missing, you can easily recreate it without tethering yourself to our release schedule.

HAProxy offers an extensive number of powerful load balancing options, all detailed within our Configuration Manual. The best and most reliable way to expose them is through secure deployment methods like user-defined annotations that still fully expose HAProxy's standard settings. 

How do user-defined annotations compare to CRDs?

Both annotations and CRDs have validation and can represent almost everything HAProxy offers. However, CRDs don't offer the same level of granularity that custom annotations do.

User-defined annotations vs. regular annotations

Security

The most important difference between user-defined annotations and regular annotations involves security. With user-defined annotations, there's a clear separation between internal teams that define them and those that consume them. 

When an administrator defines an annotation through a custom resource, they can define and limit its usage. This can be achieved by limiting annotations on certain HAProxy sections, namespaces, Services, or Ingress, as needed. If a specific service or group needs a little more configuration freedom, administrators can create a team-specific custom annotation.

Developers and teams 

Teams receive a complete list of available annotations from their admin or admin group. If they need additional annotations, team members can send new requests to their admin(s).

Validation

User-defined annotations have validation. You'll use Common Expression Language (CEL) to write these rules, which can be lenient or strict, simple or complex. Stricter rules help minimize the risk of misconfigurations.

Delivery speed

While the number of supported annotations has steadily grown alongside this project, no two deployments are identical. Company A needs different customization than Company B. While this project's goal is to consider every use case and setup, covering all scenarios with limited resources and time isn't possible. 

Luckily, user-defined annotations reduce the need for new annotations to be accepted, developed, and released. You can simply create a new annotation, deploy it, and start using it immediately.

Monitoring

We all read logs — right? When a user configures a user-defined annotation, validation runs and any error messages will display in the log. That user will quickly see if annotations aren't accepted due to various reasons. User-defined annotations offer added advantages too. Even if validation fails, the user-defined annotations will still appear in your configuration, but as a comment in the frontend or backend, alongside the error messages, which are also displayed as comments, helping explain what went wrong.

How can I distinguish user-defined annotations from 'regular' ones?

The official HAProxy annotations can have ingress.kubernetes.io, haproxy.org, and haproxy.com prefixes. User-defined annotations can have any prefix you define. For example, a well-known corporation at example.com can use an example.com prefix. Let's now tackle how to define the structure.

How to enable user-defined annotations?

The HAProxy Kubernetes Ingress Controller must be started with the following command line argument: --custom-validation-rules=<namespace>/<crd-name>.

If you’re using helm to manage HAProxy Kubernetes Ingress Controller, you may be using a custom values file (using -f <values file>). In this case, ensure you have the following path covered:

controller:
extraArgs:
- --custom-validation-rules=haproxy-controller/example-validationrules

User-defined annotation examples

We'll begin defining our annotations by including a prefix we want to use:

apiVersion: ingress.v3.haproxy.org/v3
kind: ValidationRules
metadata:
name: example-validationrules
namespace: haproxy-controller
spec:
prefix: "example.com" # ‘company’ or any prefix for custom annotations
validation_rules: # list of user defined annotations
...

This prefix indicates that the annotations HAProxy Kubernetes Ingress Controller will process are user-defined:

prefix: "example.com"
validation_rules:
timeout-server:
template: "timeout server {{.}}"
type: duration
rule: "value > duration('42s') && value <= duration('42m')"

We use standard Golang templating for the templates parameter, so any complex templating can be used. We write our rules in Common Expression Language (CEL). Once this is applied, a log confirmation message will appear:

ValidationRules haproxy-controller/example-validationrules accepted and set [example.com]

How to use user-defined annotations

Within Service, Ingress, or ConfigMap, we'll simply add our annotation metadata:

kind: Service
apiVersion: v1
metadata:
name: http-echo
annotations:
backend.example.com/timeout-server: "60s"

After applying the annotation(s), we'll see the following in our configuration file:

backend default_svc_http-echo_http
...
###_config-snippet_### BEGIN
### example.com/timeout-server ###
timeout server 60s
###_config-snippet_### END
...

Working with more complex annotations

The user-defined annotations feature also enables you to create more complex annotations. The json type is highly useful in this scenario:

http-request-set-header-X-Request-ID:
# http-request set-header X-Request-ID %[unique-id] if { hdr(Host) -i example.com }
section: backend
template: "http-request set-header X-Request-ID %[unique-id] if { hdr({{.hdr}}) -i {{.domain}} }"
type: json
rule: "'hdr' in value && 'domain' in value && ((value.hdr == 'host' && value.domain.matches('^([a-zA-Z0-9-]+\\\\.)+[a-zA-Z]{2,}$')) || (value.hdr == 'ip' && value.domain.matches('^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$')))"

Since rules and templates can be sophisticated, HAProxy Kubernetes Ingress Controller now supports multi-line annotations. If your template consists of a multi-line string, HAProxy Kubernetes Ingress Controller will create multiple lines in the configuration using the same annotation:

timeouts:
section: backend
template: |
timeout server {{.server}}
timeout server-fin {{.server_fin}}
timeout tarpit {{.tarpit}}
type: json
rule: |
'server' in value && value.server.matches('^[0-9]+[smh]?$') &&
'server_fin' in value && value.server_fin.matches('^[0-9]+[smh]?$') &&
'tarpit' in value && value.tarpit.matches('^[0-9]+[smh]?$')

Predefined variables

While using templates, the following variables are also available:

BACKEND, NAMESPACE, INGRESS, SERVICE, POD_NAME, POD_NAMESPACE, and POD_IP

template: |
# ==============================================
# custom annotation for {{.BACKEND}}
# namespace {{.NAMESPACE}}, ingress {{.INGRESS}}, service {{.SERVICE}}
# POD_NAME {{.POD_NAME}}, POD_NAMESPACE {{.POD_NAMESPACE}}, POD_IP {{.POD_IP}}
# ==============================================
timeout server {{.server}}
timeout client {{.client}}
# ==============================================

Options for defining rules

timeout-server: # name of annotation
section: all # can be all, frontend, backend (default)
namespaces: # we can limit namespace usage
- haproxy-controller
resources: # limit usage to Service, Frontend or Backend names
- <name>
ingresses: # limit usage to specific ingresses
- <name>
order_priority: 100 # order of custom annotations in config. higher has more priority
template: "timeout server {{.}}" # template we can use (golang templates)
type: duration # expected data type for conversion (duration;int;uint;bool;string;float;json;)
rule: "value > duration('42s') && value <= duration('42m')" # CEL expression

User-defined frontend annotations

Since Kubernetes lacks a Frontend object, you can instead define frontend annotations in your HAProxy Kubernetes Ingress Controller ConfigMap. This exists as an annotation of ConfigMap — not as a key-value pair.

apiVersion: v1
kind: ConfigMap
metadata:
name: haproxy-kubernetes-ingress
namespace: haproxy-controller
annotations:
frontend.<prefix>/<custom-annotation-name>: <value>

User-defined backend annotations

Users can also define backend annotations in three ways: via ConfigMap, Service, or Ingress. These annotations come with some caveats: 

  • Annotations made with ConfigMap will be applied to each supported backend. 

  • Annotations made with Service will be applied only on the specified service.

  • Annotations made with Ingress will be applied on services used in Ingress.

Note

Use Ingress annotations with caution. While these offer greater control, Ingress annotations are disabled by default due to potential configuration conflicts. This can happen when pointing multiple Ingress annotations simultaneously to the same Service

While this is supported in Kubernetes and HAProxy, using different values for one Service can trigger inconsistencies if you aren't careful. We don't recommend enabling backend Ingress annotations for this reason. If you're an advanced user wanting to experiment with the feature, you can enable it using the --enable-custom-annotations-on-ingress flag.

What happens when you try to use the same annotation in multiple places? 

  • Service annotations have the highest priority. 

  • If Service annotations don't exist, Ingress annotations will be applied next. 

  • If neither Service nor Ingress annotations exist, ConfigMap annotations will be applied next.

To dive even deeper into user annotations, check out our user annotations documentation.

Frontend Custom Resources

Similar to backend CRDs, you can now use Custom Resources to further configure the essential frontend sections that should always exist within your HAProxy configuration — such as HTTP, HTTPS, and STATS. We make this distinction since TCP frontend sections are created and managed solely through their own TCP CRDs, by comparison.

It's important to note that frontend CRDs should only be available to administrators, since they impact all traffic in the controller.

To start using them, you'll need to specify which resource is connected to a specific frontend. There are three new values you can use for frontend Custom Resources:

  • cr-frontend-http

    • Configures the HTTP frontend in your HAProxy configuration

  • cr-frontend-https

    • Configures the HTTPS frontend in your HAProxy configuration

  • cr-frontend-stats

    • Configures the STATS frontend in your HAProxy configuration

You can configure these specific frontend CRDs within Ingress Controller's ConfigMap:

apiVersion: v1
kind: ConfigMap
metadata:
name: haproxy-kubernetes-ingress
namespace: haproxy-controller
data:
cr-frontend-http: default/test-http
cr-frontend-https: default/test-https
cr-frontend-stats: default/test-stats

All available options contained within the frontend section of HAProxy can be configured using frontend CRDs. But what happens with any predefined values? All CRD values are merged with values that already exist. For example, CRD values will come first for binds, http-request rules, and for all lists in general. Afterwards, HAProxy Kubernetes Ingress Controller will append its own values on top of everything else.

apiVersion: ingress.v3.haproxy.org/v3
kind: Frontend
metadata:
name: test-http
spec:
name: test-http
accept_invalid_http_request: enabled
binds:
test:
address: 127.0.0.1
port: 9080
name: test-http
compression:
algo-req: identity
acl_list:
- acl_name: images_url
criterion: path
value: -i -m beg /images/

Minor improvements

HAProxy Kubernetes Ingress Controller 3.2 and HAProxy Enterprise Kubernetes Ingress Controller 3.2 add the following enhancements:

  • Backend names are now more readable than before

    • Each backend previously consisted of a namespace title, service name, and port number (or name) in the <namespace>_<service>_<port> format. The new format is <namespace>_svc_<service>_<port>. This enables more finely-grained statistical analysis, since it's now easier to separate namespace title and service name. 

  • The admin port is now the only way of fetching pprof and Prometheus data. This helps protect sensitive stats data.

  • A new generate-certificates-signer annotation will automatically generate TLS certificates signed by a provided CA secret for incoming connections. This uses the generate-certificates and ca-sign-file HAProxy bind options.

  • We've added a new --disable-ingress-status-update flag. When set, the controller will skip updating the loadBalancer status field in managed Ingress resources.

  • HAProxy Kubernetes Ingress Controller has moved from OpenSSL to the AWS-LC for added security, faster SSL/TLS cryptography, and higher throughput with low latency.

Deprecations

There are several planned feature deprecations for the next version of HAProxy Kubernetes Ingress Controller (version 3.4). 

First, we're removing support for CRDs in the ingress.v1.haproxy.org group. Those are CRDs for backends, defaults, globals, and TCPs. However, all of these have had ingress.v3.haproxy.org alternatives already available since HAProxy Kubernetes Ingress Controller 3.0.

  • With the available binary released on GitHub, we can use --input-file and --output-file to convert your resources from v1 to v3. You can use a simple Terminal command to begin converting:
    ./haproxy-ingress-controller --input-file=global-full-v1.yaml --output-file=global-full-v3.yaml

To better unify functionality across multiple products (especially HAProxy Unified Gateway), most of the annotations we currently use will also be deprecated in favor of using Custom Resources. To ensure continuity and provide a simple migration from annotations to CRDs, we'll release a tool that converts the output of annotations into CRDs. We'll make this available to community and enterprise users in 2026.

Contributions

HAProxy Kubernetes Ingress Controller's development thrives on community feedback and feature input. We’d like to thank the code contributors who helped make this version possible!

Contributor

Area

Hélène Durand

FEATURE, BUG, BUILD, DOC, OPTIM, TEST

Ivan Matmati

BUG, FEATURE, TEST, DOC

Dario Tranchitella

BUG

Dinko Korunić

FEATURE

Philipp Hossner

BUG, FEATURE

SF97

BUG, BUILD

Fabiano Parente

FEATURE

Saba Orkoshneli

CLEANUP

Vladyslav Riabyk

FEATURE

Zlatko Bratkovic

BUG, FEATURE, TEST, BUILD, CLEANUP, DOC, OPTIM, REORG

FAQs and what’s next

Can I replace Ingress NGINX with HAProxy Kubernetes Ingress Controller?

Ingress NGINX is officially reaching end of life in March 2026, after which planned releases, bug fixes, security updates, and feature development will stop. We're here to help teams replace Ingress NGINX and ensure continuity.

HAProxy Kubernetes Ingress Controller is the easiest, most immediate, and most direct production-ready replacement for teams facing a tight migration deadline. While not a 100% drop-in replacement, a robust annotation system — including the new user-defined annotations and our Ingress NGINX Migration Assistant — make it simple to achieve equivalent functionality for a stress-free switchover. HAProxy Kubernetes Ingress Controller also offers superior speed, stability, and advanced features to level up your existing Ingress setup.

To learn more about migration, we encourage you to watch our on-demand webinar and contact us with any questions.

Can I migrate from Ingress to Gateway API?

For teams considering migrating from Ingress to Gateway API, the new Kubernetes-native standard for traffic management, HAProxy makes it simple. 

  1. First, HAProxy Kubernetes Ingress Controller users will be able to migrate easily to the new HAProxy Unified Gateway, maintaining their existing Ingress rules (feature coming in 2026). 

  2. Second, HAProxy Unified Gateway users will be able to gradually migrate from Ingress to Gateway API within the same product for consistent management.

HAProxy Unified Gateway is a free, open-source product providing unified, high-performance, Kubernetes-native application routing for both Gateway API and Ingress. HAProxy Unified Gateway provides flexible protocol support, role-based access control, and a low-risk, gradual migration path for organizations moving from Ingress to Gateway API. Combined with HAProxy’s legendary performance and reliability, these key features support the needs of modern applications and evolving organizations.

Can I manage all my traffic with HAProxy – in Kubernetes and other environments too?

HAProxy One — the world's fastest application delivery and security platform — provides universal traffic management with a data plane and control plane that are completely infra-agnostic. For Kubernetes users it currently enables intelligent external load balancing, multi-cluster routing, direct-to-pod load balancing, and the groundbreaking universal mesh. In 2026, we're adding built-in support for both Gateway API and Ingress via HAProxy Fusion Control Plane. These enhancements will enable HAProxy One to provide comprehensive Kubernetes routing and load balancing as part of its universal traffic management. 

Development for HAProxy Enterprise Kubernetes Ingress Controller will continue, with version 3.4 planned for 2026. Existing users can keep using HAProxy Enterprise Kubernetes Ingress Controller, or upgrade to HAProxy One for universal traffic management, intelligent multi-layered security, and a centralized control plane that works across all environments. 

To learn more, check out our Kubernetes solution.

Conclusion 

HAProxy Kubernetes Ingress Controller 3.2 and HAProxy Enterprise Kubernetes Ingress Controller 3.2 are even more powerful, while simplifying migration from alternatives such as Ingress NGINX. User-defined annotations and frontend CRDs enable faster feature adoption and modernization, and more flexible configuration. We hope you enjoy using these new features!

To learn more about HAProxy Kubernetes Ingress Controller, follow our blog and browse our documentation. To take HAProxy Enterprise Kubernetes Ingress Controller for a test drive, contact us.

If you want to explore additional Kubernetes capabilities in HAProxy — such as external load balancing and multi-cluster routing — check out our on-demand webinar.

Subscribe to our blog. Get the latest release updates, tutorials, and deep-dives from HAProxy experts.