TLS ingress protocol router

One public address, many services behind it — the ingress peeks at the hostname inside the TLS handshake and sends each connection to the right backend.

The idea

Dozens of services share a single IP and port 443. When a client connects, how does the front door know whether it wants the API, the store, or the docs site?

The client announces the hostname it's after in the very first TLS message, the ClientHello, in a field called SNI (Server Name Indication). The ingress reads SNI, looks it up in a routing table, picks the matching certificate, terminates TLS (decrypts), and forwards the plaintext request to that backend.

Pick a host and press play to watch the connection get routed.

How it works

SNI travels in the ClientHello in the clear (it has to — the server needs it before a shared key exists), so the router can read it without decrypting anything. It matches the name against routes, selects that route's certificate, completes the handshake, decrypts, and proxies plaintext to the backend.

def on_connection(conn):
    hello = read_client_hello(conn)        # first TLS record, unencrypted
    host  = hello.sni                       # e.g. "api.shop.example"

    route = routes.match(host)              # exact, then wildcard *.shop.example
    if route is None:
        conn.close(alert="unrecognized_name")   # no cert, no backend
        return

    tls = terminate(conn, route.certificate)     # finish handshake, decrypt
    backend = connect(route.upstream)
    pipe(tls, backend)                            # forward plaintext both ways

Cost

StepCost
SNI route lookupO(1) exact / O(labels) wildcard
TLS termination1 handshake (CPU: asymmetric crypto)
ProxyingO(bytes) streamed

The trade-off: terminating TLS lets you route on hostname and path and centralise certificates, but the ingress now sees plaintext and owns the private keys — it is a high-value target and a single point of failure.

Watch out for

Worked example

An ingress fronts three services on one IP. A browser opens store.shop.example: its ClientHello carries sni = store.shop.example. The router matches the store route, presents the store's certificate, finishes the handshake, and pipes the decrypted HTTP to the store pods. Moments later a bot connects to unknown.other.example; no route matches, so the ingress sends an unrecognized_name alert and closes — no backend is ever touched.

Check yourself

How can the router pick the right backend before decrypting anything?