The Problem

SSHing into machines behind NAT is a pain. Either you’re stuck with clunky VPNs, or you resort to hacks like port knocking and reverse tunnels that break every time your IP changes. Nobody wants to babysit OpenVPN configs or deal with junk like dynamic DNS.

What This Does

mssh is a Go tool that sets up a “rendezvous” server (internal/server/server.go) on a public host. Machines behind NAT run the agent (internal/agent/agent.go), which keeps a persistent connection back to that server. When you want to SSH in, you use either the built-in client or run mssh proxy as a ProxyCommand in your ssh config.

Setup is dead simple: drop the binary with install/install.sh, run the server, and launch the agent. The agent auto-reconnects if the session dies—no fiddling required. Config is handled in internal/config/config.go, and you get per-node overrides in ~/.mssh/config.yaml. The project avoids overengineering: no database, no TLS in-app (just proxy it), and you can use your own SSH keys. CI is minimal (just .github/workflows/release.yml).

Real-World Use

Let’s say you’ve got a production database server on a remote VPC, and you need SSH access from time to time. You deploy the rendezvous server on a VPS, run mssh agent prod-db-1 --server rendezvous.example.com:8443 on the NAT’d host, and then add this to your ~/.ssh/config:

Now, you just run ssh prod-db-1. No VPN, no port forwarding, no “call me when your IP changes.” The agent keeps your host reachable, and you use your SSH keys as usual.

The Bottom Line

mssh is what you reach for when you want SSH behind NAT without the headaches of VPNs or reverse tunnels. It’s minimal, easy to set up, and doesn’t try to be your PKI or firewall. The downside? No built-in TLS or access controls—so use a proxy and don’t be dumb about security. Great for small teams and personal projects; probably not enough for big enterprise setups.