A load balancer in front of your web servers is configured to "terminate TLS". Which parts of the path from the browser to the application are encrypted after that, and which are not?
answer
- one connection ends, another begins
- who holds the private key
- the backend hop is a separate decision
- app judges the scheme from its own socket
- redirect loop, http:// links, dropped Secure cookies
basics
~20 sTerminating TLS means the load balancer holds the certificate's private key and completes the HTTPS handshake itself, so the browser-to-load-balancer hop is encrypted and the load-balancer-to-application hop is plain HTTP unless you separately encrypt it.
solid answer
~40 sTLS protects one connection between two endpoints, and the endpoint that owns the private key and finishes the handshake is the one that terminates it. When the load balancer terminates, the browser's encrypted connection ends there: the balancer decrypts the request, and what reaches the application is a second, separate connection that is plain HTTP by default. That is exactly why the balancer can now route on path or Host, add headers, compress, or cache — it can read the request. The cost is that the application no longer knows on its own that the client used HTTPS, and its socket peer is the balancer, not the client, so it sees the balancer's IP. Whether the second hop stays plaintext or gets re-encrypted is a separate decision, not something termination settles for you.
code
bash · 2 linesopenssl s_client -connect www.example.com:443 -servername www.example.com </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer
curl -sS -o /dev/null -w '%{http_code}\n' http://app-server.internal:8080/healthgo deeper
Be able to say plainly that the encrypted connection ends at the load balancer and a second, separate connection continues to the app, and that the certificate and its private key live wherever the handshake is completed.
Explain the mechanics that follow: the proxy can read and rewrite HTTP only because it decrypted, the backend judges the scheme from its own plaintext socket, and forwarded headers are how the lost facts are restored.
Show you have debugged the consequences in production — the redirect loop, the dropped Secure cookie, per-IP limits that count only proxy addresses — and that you know a forwarded header is only safe when the trusted-proxy boundary is configured.
Frame the edge as a deliberate decryption point: one tier that can read every request and impersonate the site. Be ready to argue where key custody belongs and who is allowed shell access there.
## What "terminating" means TLS secures a *connection* between two endpoints. One of those endpoints proves who it is by presenting a certificate and demonstrating that it holds the matching private key; from then on both ends share symmetric keys and everything above the record layer — the HTTP request line, the headers, the body — is ciphertext to anyone in between. "Terminating TLS" simply names which box is that endpoint. If the load balancer holds the private key for `www.example.com` and completes the handshake, the client's TLS session ends at the load balancer. Nothing about the client's request travels further in encrypted form unless the load balancer deliberately encrypts it again on a *new* connection. ## The two hops Once a proxy terminates, there are always at least two independent connections, and it is worth drawing them: ``` browser --- TLS (encrypted) ---> load balancer --- HTTP (plaintext) ---> app server hop 1: client's session hop 2: a separate connection key + cert live here ^ opened by the balancer ``` Hop 1 and hop 2 are unrelated protocols-wise. Hop 1 can be TLS 1.3 with HTTP/2; hop 2 can be cleartext HTTP/1.1. The balancer is a full participant in both: a server on hop 1, a client on hop 2. ## What the proxy gains Because it decrypts, the proxy can read HTTP. That unlocks essentially everything people buy a reverse proxy for: routing by path, Host or header; sticky sessions from a cookie; inserting the forwarded headers that tell the backend who the client was; response compression; caching; a web application firewall; per-request retries to a different backend; and translating HTTP/2 or HTTP/3 on the client side into HTTP/1.1 on the backend side. None of that is possible against ciphertext. ## What the application loses The application's view narrows to hop 2, and two facts disappear from it: - **The client's IP address.** The TCP peer of the application is the load balancer, so the remote address it reads is the balancer's. Every client looks like it comes from a handful of proxy addresses, which quietly breaks per-IP rate limiting, geo logic and audit logs. - **The fact that the request was HTTPS.** Frameworks derive "is this request secure?" from their own socket. On hop 2 that socket is plaintext, so the framework says "no". That second one produces the single most common symptom in this whole area. The application is configured to redirect insecure requests to `https://`. A browser asks for `https://www.example.com/`, the balancer decrypts it and forwards plain HTTP, the app decides the request is insecure and answers a redirect to `https://www.example.com/`, and the browser comes back over HTTPS again — forever. The same cause makes the app emit `http://` absolute URLs in password-reset links and refuse to set cookies marked `Secure`. The fix is not to stop terminating; it is to tell the application what the proxy knows. The proxy states the original scheme and client address in forwarded request headers, and the application is configured to trust those headers *only* when the request arrived from the proxy — otherwise any client can claim to be anyone from anywhere. ## Where the key lives, and why that matters Terminating at the edge concentrates the private key in one tier. That is usually an advantage: renewal and rotation happen in one place, the key can sit in dedicated hardware or a managed key service, and the set of machines that can impersonate your site is small and auditable. The flip side is equally real — that tier is a decryption point. Anyone with shell access or a core dump on the balancer sees plaintext requests, including whatever secrets are in the headers. Whether that is acceptable is a design question, not a default. ## How to check what is actually happening From outside, open a TLS connection and look at whose certificate comes back and what protocol was negotiated — if the certificate is the load balancer's wildcard rather than the origin's, something is terminating in front of you. From inside, request the app directly on its own port: if it answers plain HTTP on 8080, hop 2 is unencrypted. And log the forwarded scheme header alongside the framework's own notion of the scheme; when they disagree, you have found your redirect loop.
- If the load balancer terminates TLS, how can the application still find out that the client used HTTPS?The proxy states it in a forwarded request header describing the original scheme, and the application is configured to trust that header only for connections arriving from the proxy's addresses. Trusting it unconditionally is worse than not having it: any client could then assert that its plaintext request was secure and slip past a scheme check.
- Does terminating at the load balancer mean the backend hop must be plaintext?No. Terminating only settles where the client's session ends. The proxy may open a fresh TLS connection to the backend — commonly called re-encryption or bridging — while still reading and routing the request in between. Plaintext on the second hop is a common default, not a consequence.
- Why does the application see the same handful of source addresses for every request once a proxy terminates in front of it?Because the application's TCP peer is the proxy. The client's connection stopped at the proxy, and the proxy opened its own connection from its own address, usually reusing a small pool of them. The client's real address survives only if the proxy passes it on explicitly.
saying these in an interview costs you the question
- Thinks the client's TLS session continues to the backend
- Believes the backend hop is automatically encrypted too
- Says the app can read the client IP from the socket regardless
- Assumes HTTPS in the browser proves end-to-end encryption
- Blames an expired certificate for an https redirect loop