sslh: One Port, Many Protocols — Because You Only Get 443

2026-07-04

You're at an airport, a hotel, or a corporate office. Outbound 443 works; nothing else does. You want SSH home. You could stand up nginx stream with ssl_preread, or HAProxy in TCP mode, or Caddy layer4 — but that's a lot of framework for a demux. sslh is the ~2000-line C daemon designed for exactly this: listen on one port, peek at the first bytes of every incoming connection, and forward each to a different backend based on the protocol it detected.

Point sslh at 443, tuck sshd, nginx, and OpenVPN behind it on loopback, and everyone's happy:

# /etc/sslh/sslh.cfg
listen: ( { host: "0.0.0.0"; port: "443"; } );

protocols:
(
    { name: "ssh";     host: "127.0.0.1"; port: "22";   service: "ssh"; },
    { name: "openvpn"; host: "127.0.0.1"; port: "1194"; },
    { name: "tls";     host: "127.0.0.1"; port: "8443";
      sni_hostnames: [ "www.example.com", "git.example.com" ]; },
    { name: "http";    host: "127.0.0.1"; port: "8080"; },
    { name: "anyprot"; host: "127.0.0.1"; port: "8080"; }  # fallback
);

ssh -p 443 [email protected] works. https://example.com works. Both hit the same TCP port. sslh identifies protocols by fingerprinting the opening bytes:

The killer feature: sslh never decrypts anything. It peeks the plaintext prelude, forwards, and gets out of the way. Your certificates stay on the backend, HTTP/2 and mTLS keep working end-to-end, and there's no TLS material on the demux box to steal.

Why not just nginx stream + ssl_preread? You can. But nginx forks workers, brings HTTP vocabulary you don't need, and eats real RAM at idle. sslh runs happily in ~500KB. On a Turris router, a $3/month VPS, or a hardened jump box, that's the difference between "runs" and "swaps".

Two binaries ship in the same package: sslh-fork (fork-per-connection, dead simple, great for a handful of long-lived sessions) and sslh-ev (libev event loop, scales to thousands of concurrent connections). Pick by load, not by fashion.

Three tricks worth knowing:

Install is apt install sslh or brew install sslh. Move whatever currently owns 443 to 127.0.0.1:8443, drop sslh in front, and you've quietly upgraded a single-port host into a full-service demux — without inviting a reverse proxy to the party.

Key Takeaway: When you only have one port to spare, sslh sniffs each connection's opening bytes and routes SSH, HTTPS (with SNI), OpenVPN, and more to different backends — no TLS termination, no framework, ~500KB of resident memory.

All newsletters