Skip to main content
Gå til innhold

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.

caution

If you deploy custom Ingress resources, you must update them in your deploy manifests before your next deployment.

How to update your deploy code

  1. Inspect your running Ingress to see what the Platon team changed:
    kubectl -n <namespace> get ingress <name> -o yaml
  2. Update your deploy code to match what is currently running in the cluster:
    • Change ingressClassName from nginx to haproxy
    • 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

Annotation mapping

Common annotations with HAProxy equivalents

Replace the nginx annotation with the corresponding HAProxy annotation:

nginx annotationHAProxy equivalent
nginx.ingress.kubernetes.io/whitelist-source-rangehaproxy.org/allow-list
nginx.ingress.kubernetes.io/proxy-connect-timeouthaproxy.org/timeout-server
nginx.ingress.kubernetes.io/proxy-read-timeouthaproxy.org/timeout-server
nginx.ingress.kubernetes.io/proxy-send-timeouthaproxy.org/timeout-server
nginx.ingress.kubernetes.io/auth-typehaproxy.org/auth-type
nginx.ingress.kubernetes.io/auth-realmhaproxy.org/auth-realm
nginx.ingress.kubernetes.io/auth-secrethaproxy.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 annotationReason
nginx.ingress.kubernetes.io/proxy-body-sizeHAProxy has no client body size limit
nginx.ingress.kubernetes.io/ssl-redirectHAProxy redirects to HTTPS by default (so did nginx so this was never needed)
nginx.ingress.kubernetes.io/proxy-request-bufferingHAProxy doesn't buffer requests by default
nginx.ingress.kubernetes.io/proxy-buffer-sizeHAProxy default (16k) should be sufficient for most workloads
nginx.ingress.kubernetes.io/proxy-next-upstreamNot supported by HAProxy
nginx.ingress.kubernetes.io/proxy-next-upstream-timeoutNot 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: Use path-rewrite to rewrite / to the desired path.
  • rewrite-target: Use path-rewrite with 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 with use-regex to enable regex path matching. This should be changed to pathType: Prefix (or pathType: Exact) since ImplementationSpecific has 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.