Files
loadbalancer/docs/adr/0001-traefik-tcp-tls-passthrough.md
T
2026-06-30 10:53:01 +02:00

2.8 KiB

ADR-0001: Traefik TCP TLS passthrough load balancer

Date: 2026-06-30

Status: Accepted

Context

The load balancer must run as a Docker container and forward TCP TLS traffic to backend services reachable by local IP address and port. Backend services already expose their own SSL certificates, so the load balancer must not terminate TLS or store backend private keys. Runtime configuration must be kept in a host-based volume.

Decision

Use Traefik Proxy in Docker with the file provider and TCP TLS passthrough routing. Static and dynamic configuration live under the host ./config directory and are mounted read-only at /etc/traefik.

Traefik uses host networking so it can reach backends bound to host loopback addresses such as 127.0.0.1:8443. The container is granted only NET_BIND_SERVICE so Traefik can bind host ports 80 and 443.

Traefik routes incoming TLS connections with HostSNI(...) to the configured TCP load-balancer services. HTTP routes on port 80 use Host(...) and forward the full request to the selected backend because SNI exists only in TLS handshakes and backend nginx instances are responsible for redirects and ACME challenge handling.

Consequences

TLS certificates, private keys, and certificate renewal remain the responsibility of each backend. Traefik can route TLS traffic based on the TLS SNI value but cannot inspect HTTP headers or paths because TLS is passed through unchanged.

Backend health checks are configured per site. TCP health checks verify backend port reachability; HTTP health checks call / with the configured hostname. Configuration changes in config/dynamic/ are watched by Traefik and can be applied without recreating the container.

Alternatives considered

TLS termination at Traefik was rejected because the requested backend-owned certificate model would require moving certificates or keys to Traefik.

The Docker provider was not selected because the backends are addressed directly by IP and port rather than discovered from Docker labels.

Security impact

The container does not mount the Docker socket, does not run privileged, drops Linux capabilities except NET_BIND_SERVICE, uses no-new-privileges, and mounts configuration read-only. No private keys or credentials are required in this repository. Host networking exposes Traefik directly on the host network namespace, so host firewall rules should restrict non-public ports such as the ping entrypoint.

Operational impact

Operators update backend IP addresses and ports in per-site files under config/dynamic/. Traefik listens directly on host 80/tcp and 443/tcp; the ping entrypoint is used by the healthcheck.

Rollback

Revert the commit that introduced the Traefik configuration and restore any previous load-balancer service. If deployed, stop the Compose stack with docker compose down.