Ingress controller migration
The Platon PaaS is replacing ingress-nginx with HAProxy Ingress as the cluster ingress controller. Ingress-nginx reaches end-of-life in March 2026.
The cut-over will happen Thursday, 26th February 2026 at 12.00. During the cut-over, the Platon team will rewrite all Ingress resources in the cluster to work with HAProxy. Your running services will continue to work.
If you use the default HTTP_PORT variable and do not define your own Ingress resources, no action is needed -- the kubernetes-deploy tooling will be updated by the Platon team.
If your deploy manifests include custom Ingress resources (i.e. you define them in your deployment.yaml), they will still contain the old nginx ingressClassName and annotations after the cut-over. Your next deploy will fail, because a cluster admission policy will reject Ingress resources that use ingressClassName: nginx or nginx.ingress.kubernetes.io/* annotations.
If you deploy custom Ingress resources, you must update them in your deploy manifests before your next deployment.
How to update your deploy code
- Inspect your running Ingress to see what the Platon team changed:
kubectl -n <namespace> get ingress <name> -o yaml - Update your deploy code to match what is currently running in the cluster:
- Change
ingressClassNamefromnginxtohaproxy - Replace nginx annotations that have HAProxy equivalents
- Remove nginx annotations that are no longer needed
- The annotation
kubernetes.io/tls-acme: "true"is unchanged -- cert-manager continues to work as before
- Change
Annotation mapping
Common annotations with HAProxy equivalents
Replace the nginx annotation with the corresponding HAProxy annotation:
| nginx annotation | HAProxy equivalent |
|---|---|
nginx.ingress.kubernetes.io/whitelist-source-range | haproxy.org/allow-list |
nginx.ingress.kubernetes.io/proxy-connect-timeout | haproxy.org/timeout-server |
nginx.ingress.kubernetes.io/proxy-read-timeout | haproxy.org/timeout-server |
nginx.ingress.kubernetes.io/proxy-send-timeout | haproxy.org/timeout-server |
nginx.ingress.kubernetes.io/auth-type | haproxy.org/auth-type |
nginx.ingress.kubernetes.io/auth-realm | haproxy.org/auth-realm |
nginx.ingress.kubernetes.io/auth-secret | haproxy.org/auth-secret * |
* The annotation names map directly, but the secret format is different. See Basic auth below.
Note that the three nginx timeout annotations (proxy-connect-timeout, proxy-read-timeout, proxy-send-timeout) all map to a single HAProxy annotation (timeout-server). Use the largest value of the three if they differ.
Annotations to remove
These nginx annotations have no HAProxy equivalent and should be removed from your deploy code:
| nginx annotation | Reason |
|---|---|
nginx.ingress.kubernetes.io/proxy-body-size | HAProxy has no client body size limit |
nginx.ingress.kubernetes.io/ssl-redirect | HAProxy redirects to HTTPS by default (so did nginx so this was never needed) |
nginx.ingress.kubernetes.io/proxy-request-buffering | HAProxy doesn't buffer requests by default |
nginx.ingress.kubernetes.io/proxy-buffer-size | HAProxy default (16k) should be sufficient for most workloads |
nginx.ingress.kubernetes.io/proxy-next-upstream | Not supported by HAProxy |
nginx.ingress.kubernetes.io/proxy-next-upstream-timeout | Not supported by HAProxy |
Special cases
Some nginx features require extra work beyond a simple annotation swap. The Platon team will handle these during the cut-over so your running services continue to work, but you will need to adapt your deploy code as described below.
Basic auth
If your Ingress uses nginx basic auth annotations:
nginx.ingress.kubernetes.io/auth-type: basic
nginx.ingress.kubernetes.io/auth-secret: basic-auth
nginx.ingress.kubernetes.io/auth-realm: "Authentication Required"
The HAProxy equivalents are:
haproxy.org/auth-type: basic-auth
haproxy.org/auth-secret: basic-auth-haproxy
haproxy.org/auth-realm: "Authentication Required"
Note that the credential secret needs a different format than the one used by nginx. The HAProxy secret must contain one key per user, where each value is a password hashed with crypt(). Create a new secret like this:
kubectl -n <namespace> create secret generic basic-auth-haproxy \
--from-literal=<username>=$(openssl passwd -5)
This uses SHA-256 hashing (-5). You will be prompted to enter the password.
See the HAProxy auth-secret documentation for more details.
Sticky session cookies
If your Ingress uses nginx annotations for cookie-based session affinity:
nginx.ingress.kubernetes.io/affinity: "cookie"
nginx.ingress.kubernetes.io/session-cookie-name: "my-route"
nginx.ingress.kubernetes.io/session-cookie-max-age: "28800"
nginx.ingress.kubernetes.io/session-cookie-secure: "true"
nginx.ingress.kubernetes.io/session-cookie-samesite: "Lax"
HAProxy Ingress has a haproxy.org/cookie-persistence annotation for basic sticky sessions, but it does not support setting cookie flags like secure and SameSite. To get full control over cookie parameters, a HAProxy Backend custom resource is needed.
The Platon team will create the appropriate Backend resources in affected namespaces during the cut-over and attach them to your Ingress using the haproxy.org/cr-backend annotation. Remove all nginx.ingress.kubernetes.io/affinity and nginx.ingress.kubernetes.io/session-cookie-* annotations from your deploy code. Do not include the Backend resource in your deploy code as it is managed by the Platon team as of now. Allowing developers to deploy Backend resources is under evaluation.
After the cut-over, inspect your namespace to see the resources that were created:
kubectl -n <namespace> get backend
kubectl -n <namespace> get backend <name> -o yaml
kubectl -n <namespace> get ingress <name> -o yaml
If you need to change sticky session parameters (cookie name, max-age, etc.), contact the Platon team.
Path rewrites and redirects
If your Ingress uses nginx annotations for path rewriting or root redirects:
nginx.ingress.kubernetes.io/app-root: "/dashboard"
nginx.ingress.kubernetes.io/rewrite-target: "/$1"
nginx.ingress.kubernetes.io/use-regex: "true"
These all map to the HAProxy haproxy.org/path-rewrite annotation, but the syntax differs from nginx:
app-root: Usepath-rewriteto rewrite/to the desired path.rewrite-target: Usepath-rewritewith a regex and replacement pair, e.g.haproxy.org/path-rewrite: (.*) /new-prefix\1.use-regex: Can be removed.pathType: ImplementationSpecific: In nginx-ingress this was used together withuse-regexto enable regex path matching. This should be changed topathType: Prefix(orpathType: Exact) sinceImplementationSpecifichas different behavior in HAProxy Ingress.
Since the rewrite syntax is not a 1:1 mapping, inspect your running Ingress after the cut-over and adapt your deploy code to match. Contact the Platon team if you need help translating complex rewrite rules.
Custom error pages / maintenance backends
If your Ingress uses custom-http-errors and default-backend annotations to show a maintenance page when backends are unavailable:
nginx.ingress.kubernetes.io/custom-http-errors: "503"
nginx.ingress.kubernetes.io/default-backend: maintenance-page-backend
There is no equivalent in HAProxy Ingress. The Platon team will work with affected projects to find an alternative solution.
Allowed HAProxy annotations
Certain annotations have caused bugs where the HAProxy ingress controller gets stuck with an invalid configuration. We therefore use a conservative allowlist for now.
haproxy.org/allow-list
haproxy.org/auth-realm
haproxy.org/auth-secret
haproxy.org/auth-type
haproxy.org/cr-backend
haproxy.org/path-rewrite
haproxy.org/timeout-server
If you need an annotation not listed here, contact the Platon team. We will test it and add it to the allowlist if it works as expected.
Need help?
If your Ingress uses nginx annotations not listed above, or if you run into issues, contact the Platon team.