SSH tunnel command generator
Nobody remembers whether they want -L, -R or -D. I’ve looked it up roughly a hundred times. So: pick the direction, drop in your ports and hosts, and you get the one-line ssh command plus a matching ~/.ssh/config block to copy. Every piece gets explained, because the local-versus-remote thing trips up everyone, and honestly it should. It all runs in your browser.
What this SSH tunnel generator does
SSH isn’t just a shell. It’ll also shove network ports through its encrypted pipe, which means you can reach stuff that’s private or stuck behind a firewall. There are three forwarding modes: -L, -R and -D. People mix them up constantly. The syntax looks almost identical, but the direction is flipped, and that’s exactly where the confusion lives. This generator just asks what you’re reaching and from where. Then it gives you the right command, plus a ~/.ssh/config entry so you can stop retyping the thing.
Local, remote and dynamic forwarding
| Mode | What it does | Example |
|---|---|---|
-L Local | Pulls a remote service onto a local port. You hit localhost, you land on the server side. | ssh -L 8080:localhost:80 user@server |
-R Remote | Pushes a local service out to a remote port, so the server (or whoever’s on it) can reach back into your machine. | ssh -R 9000:localhost:3000 user@server |
-D Dynamic | Spins up a local SOCKS proxy that shoves any traffic through the SSH server. | ssh -D 1080 user@server |
Here’s the mnemonic that finally stuck for me. -L brings a remote thing to you, you’re the one listening. -R sends a local thing out, the remote listens instead. And -D just turns the whole SSH server into a proxy you can point traffic at. The -N flag tells SSH to skip the shell, because you only want the tunnel, not a prompt. -f shoves it into the background.
Reading the -L syntax
Take 8080:localhost:80. It means: listen on local port 8080, then forward to localhost:80 as the SSH server sees it. That italicized bit is the whole thing, really. The localhost in there is the server’s localhost, not yours. This is the part that bites people, me included, the first dozen times. Say you’ve got a database only the server can touch. You’d write -L 5432:db.internal:5432, where the server resolves db.internal, and then you point your client at localhost:5432.
Saving tunnels in ssh config
Retyping a long tunnel command is how you end up with a typo at 2am. So the generator also hands you a ~/.ssh/config block, using whichever of LocalForward, RemoteForward or DynamicForward fits. Save it once. After that the tunnel is just ssh mytunnel. The config also tucks away the user, the port, the identity file, the keepalive, all of it in one place, so your commands stay short and everyone on the team is running the same thing.
Privacy and how this tool runs
JavaScript builds the command and the config block right in your browser. The hostnames and key paths you type never leave the page, and nothing gets logged anywhere. Which matters a bit more here than usual, since tunnel configs tend to describe your internal network.
Frequently asked questions
What is the difference between ssh -L and -R?
-L (local) listens on your machine and forwards to something the server can reach, so you get at a remote service through localhost. -R (remote) flips it: the server listens, then forwards back to something your machine can reach, so the server side can poke at one of your local services. The bit I actually memorized: -L pulls in, -R pushes out.
How do I create a SOCKS proxy with SSH?
Dynamic forwarding does it: ssh -D 1080 -N user@server. That gives you a SOCKS5 proxy on local port 1080, and everything you send through it tunnels out via the server. Point your browser or app at socks5://localhost:1080. Handy on sketchy coffee-shop wifi.
Why does my -L tunnel connect to the wrong host?
In -L localport:host:hostport, that host gets resolved by the SSH server, not by you. So if you typed localhost, you just asked for the server itself. Want a different internal box? Put the name or IP the server can see, like -L 5432:db.internal:5432. I’ve lost a couple of hours to exactly this mistake.
What do -N and -f do?
-N says don’t run a remote command, which is what you want for a tunnel, so no shell prompt shows up. -f drops SSH into the background once it’s authenticated. Stick them together and -fN is the old reliable for a background tunnel.
How do I keep an SSH tunnel from dropping?
Add keepalives: -o ServerAliveInterval=60 makes SSH fire a probe every 60 seconds, so it actually notices when the link goes dead. That stops idle drops. It won’t reconnect on its own, though. For that, wrap the tunnel in autossh, or run it as a systemd service with Restart=always.
How do I tunnel through a bastion or jump host?
Reach for -J user@bastion (that’s ProxyJump). One command hops through the bastion to the real host: ssh -J user@bastion -L 8080:localhost:80 user@target. And in your ssh config it’s the same idea, just spelled out as ProxyJump user@bastion.
Sources & further reading
- man7.org: ssh(1) man page (port forwarding)
- RFC 4254: SSH Connection Protocol (channels & forwarding)
- OpenSSH: official manuals
Related tools and resources
A few more builders and references from the same toolkit, if you’re in the mood to keep tinkering.













