The corporate or university network only allows ports 80 and 443 out. SSH on 22 is blocked. Getting back to your home server means VPN or a web terminal, both annoying. sslh lets your server accept both HTTPS and SSH on 443. The firewall sees 443. SSH is hidden inside it.
How It Works
sslh sits in front of port 443. When a connection arrives, it reads the first packet, identifies the protocol, and forwards to the right backend.
| |
From the SSH client’s perspective, it connected to 443 and got SSH. From nginx’s perspective, it’s still listening on its own port. sslh sits between them.
Supported protocols: SSH, TLS/HTTPS, HTTP, OpenVPN, SOCKS5, tinc, XMPP, and custom regex patterns.
Installation
| |
Quick Start: Command Line
Test it first before setting up a service:
| |
Before running this, move nginx off 443 to 8443 (sslh now owns 443):
| |
Config File
For production, use a config file at /etc/sslh.cfg:
| |
Enable and start:
| |
Client Connection
SSH to port 443:
| |
After that, ssh myserver works without -p 443. HTTPS needs no changes β browsers connect to https://yourserver.com as usual.
Docker Compose
If you run services in Docker, sslh fits naturally as a container in front of nginx:
| |
Neither nginx nor sshd need to expose ports externally. sslh multiplexes everything.
Adding OpenVPN
If OpenVPN is also blocked, sslh handles that too:
| |
Set your OpenVPN client’s remote to yourserver.com 443. sslh identifies the OpenVPN handshake and forwards to 1194.
sslh vs Other Approaches
| Approach | Pros | Cons |
|---|---|---|
| sslh | Lightweight, multi-protocol, transparent to clients | Needs root, backend loses real client IP (needs transparent mode) |
| reverse_ssh | Target machine doesn’t need a public IP | Requires a relay server |
| HAProxy | More powerful, PROXY protocol support | More complex config |
| Nginx stream | Simple, native TLS SNI routing | Can’t demux SSH from TLS |
If the goal is “SSH through a firewall,” sslh is the most direct solution. If the target machine has no public IP at all, reverse_ssh is a different approach worth knowing.
Things to Know
Backend loses real client IP: By default sslh NATs connections, so backend services see 127.0.0.1 instead of the real client IP. If you need real IPs for fail2ban or access logs, enable transparent proxy mode β it requires extra iptables rules.
Move nginx off 443 first: sslh needs to own 443. Whatever was listening there before needs to move to another port.
CVE history: sslh has had a few CVEs over the years. Keep it updated; not a reason to avoid it.
Summary
Multiple services, one port. sslh routes by inspecting the first packet. The most common setup is SSH on 443, getting through firewalls that only allow HTTPS. Once configured, SSH clients just change port from 22 to 443 β everything else stays the same.
