Pass TLS through at Layer 4
TLS passthrough terminates the TLS connection inside your pod instead of at the ingress controller. The load balancer and the cluster move the raw encrypted bytes and never decrypt them, so your application performs the TLS handshake itself. Use this when the pod must hold the private key, when you need mutual TLS all the way to the application, or when the protocol is not HTTP.
This works because the load balancer runs at Layer 4. A Layer 7 (HTTP) load balancer or ingress reads the request and can route by hostname or path, which means it must decrypt TLS first. A Layer 4 (TCP) load balancer moves bytes and never inspects them, so the encrypted connection reaches your pod untouched.
When to terminate in the app instead of the edge#
Terminating at the ingress is the common choice: the controller holds one certificate and every application behind it speaks plain HTTP. Pass through instead when:
- the application must see the client certificate for mutual TLS,
- a compliance rule says the key never leaves the workload,
- or the protocol is raw TCP or something other than HTTP, so an HTTP ingress cannot route it.
The simplest passthrough: a TCP Service#
For a single application, a type: LoadBalancer Service on the TLS port moves the connection directly to the pod, and the pod terminates TLS:
apiVersion: v1
kind: Service
metadata:
name: my-app-tls
annotations:
load-balancer.hetzner.cloud/location: fsn1
spec:
type: LoadBalancer
selector:
app: my-app
ports:
- name: https
port: 443
targetPort: 8443
The pod listens on 8443 with its own certificate and performs the handshake. Nothing in the path decrypts the traffic.
Route several hosts by SNI#
One TCP Service sends everything on the port to a single application. To place several TLS applications behind one load balancer and still terminate in each pod, you need a component that reads the SNI (Server Name Indication, the hostname the client sends in the clear at the start of the TLS handshake) and forwards it without decrypting.
Enable the controller flag --enable-ssl-passthrough, then annotate an Ingress with nginx.ingress.kubernetes.io/ssl-passthrough: "true". The controller reads the SNI and forwards the still-encrypted connection to the backend Service. This carries a cost: passthrough routing runs outside the controller's normal path and adds latency, so use it only for the hosts that need it.
Run an L4 proxy such as HAProxy or Envoy in front of your applications, matching on SNI and forwarding by host. You gain full control over the routing at the cost of one more component to run and keep available.
Keep the client address#
At Layer 4 the load balancer still replaces the source address. To provide the pod with the real client IP alongside the passed-through TLS, enable PROXY protocol and have the application read the PROXY header before the TLS bytes. For the full picture of what the pod sees and the trade-offs, read Preserve the client source IP .
The trade-off#
Passthrough moves certificate handling, renewal, and TLS tuning into every application that uses it, and you lose the edge features an ingress provides: a single place for certificates, HTTP routing, and header rewriting. Terminate at the edge unless a genuine requirement (mutual TLS to the application, key custody, or a non-HTTP protocol) forces the key into the pod.
Load balance to bare-metal nodes
How Hetzner Robot bare-metal servers join a load balancer as IP targets, and where they differ from Cloud nodes.
Egress gateway for a stable source IP
Route outbound traffic from chosen pods through one node so an IP-allowlisted third party always sees the same source address.