You choose your own ingress controller on Syself Autopilot, and you can run more than one. An ingress controller combines two components: a **reverse proxy** (nginx, Traefik, or Envoy) that receives each request and forwards it to the correct backend, and a **controller** that watches your `Ingress` and Gateway objects and rewrites the proxy's configuration to match. Different teams require different proxies for their features, their custom resources, and their resource footprint, so the platform leaves the choice to you and installs none by default. The Hetzner cloud-controller-manager (CCM) still creates the load balancer in front, as it does for any Service. Every controller is an implementation of the same `Ingress` API, so they install and route the same way; this page installs Traefik, and Envoy, HAProxy, or Contour follow the same pattern. ## Why you choose the controller An ingress controller is an application choice rather than infrastructure. A controller included in the platform by default would be one more component you could not replace, pinned to a version and a feature set chosen for you. The platform therefore stops at the load balancer, and the controller remains yours to choose, upgrade, and configure. You are never required to migrate off a default you did not want. ## Install Traefik Install the chart and add the Hetzner load balancer annotations to its Service, so the CCM places the load balancer in your region: ```console $ helm repo add traefik https://traefik.github.io/charts $ helm repo update ``` ```yaml title="traefik-values.yaml" service: type: LoadBalancer annotations: load-balancer.hetzner.cloud/location: fsn1 load-balancer.hetzner.cloud/type: lb11 ``` ```console $ helm install traefik traefik/traefik --namespace traefik --create-namespace -f traefik-values.yaml ``` Wait for the Service to receive an external IP, which indicates that the load balancer is provisioned: ```console $ kubectl get svc -n traefik traefik ``` Route an application to it with an `Ingress` whose `ingressClassName` matches the controller (`traefik`), as you would for any controller. ## The default IngressClass Each controller registers an `IngressClass`. An `Ingress` with no `ingressClassName` is handled by whichever class is marked default, and if two controllers each mark themselves default, routing becomes ambiguous. Set `ingressClassName` on every `Ingress`, and designate at most one default. ## Run more than one controller Running more than one controller is a supported configuration, not a workaround. Each controller has its own `type: LoadBalancer` Service, so each has its own Hetzner load balancer and its own public IP. This is the purpose of the design: one load balancer is one IP, and a single load balancer has its own throughput and connection limit. To separate tenants onto their own IPs, keep a legacy application on nginx while new applications move to Traefik, or carry more traffic than one load balancer can handle, add another controller and another load balancer. Keep the `IngressClass` names distinct and set `ingressClassName` explicitly, so an `Ingress` never reaches the wrong controller. ## PROXY protocol per controller To pass the real client IP through, enable PROXY protocol on the controller's load balancer Service and configure the controller to read it. The Service annotation is the same for every controller. The controller-side configuration is not, and both ends must agree or connections fail. Traefik reads PROXY protocol when you enable it on the entryPoint that the load balancer Service targets; other controllers provide an equivalent setting (a ConfigMap key or entry-point flag), and both ends must agree. See [Preserve the client source IP](/docs/hetzner/apalla/network/load-balancing/preserve-client-source-ip) for the Service-side annotation and the full setup. ## Picking a controller Choose based on features rather than defaults. Compare the routing custom resources each controller adds, whether it supports the [Gateway API](/docs/hetzner/apalla/network/expose/gateway-api), its middleware and rate-limiting options, and its memory footprint. All of them sit behind the same Hetzner load balancer, so the load balancer side of the setup does not change with the controller. ## Next - [Configure a Hetzner load balancer](/docs/hetzner/apalla/network/load-balancing/configure-a-load-balancer) to set the load balancer's type, algorithm, and health checks for whichever controller you pick.