A Practical Guide to SSH Tunnels: Local and Remote Port Forwarding
labs.iximiuz.com
labs.iximiuz.com
So, if you use SSH tunneling to forward a port from localhost to a remote, then Docker unwittingly pushes to a remote. This is super useful "off the grid" with robotics/embedded applications where you don't want to bother with a registry and a good Internet connection.
Example, docker pussh: https://github.com/psviderski/unregistry
i set it up a few years ago for my homelab
```/etc/docker/daemon.json
{
"insecure-registries": ["10.100.0.0/24", "registry.yourmom.example.com:5000"]
}
```[1] https://docs.docker.com/reference/cli/dockerd/#insecure-regi...
Pretty cool thing, I ship plenty of services to my tiny $5/mo vps with it without having to pay for a docker registry.
[0] https://kamal-deploy.org/docs/configuration/docker-registry/...
[1] https://github.com/basecamp/kamal/blob/eee0083b38661c3707c6b...
"~C" will drop you into the SSH command line, allowing you to, among other things, effect port forwarding
-L8080:localhost:443
Learning that "~C" exists, and what you can do with it, has supercharged my use of SSH tunnels, which were already awesome on their own.But for some reason this has been disabled by default in more recent ssh configurations... to ensure its available
-o EnableEscapeCommandline=yes
or, in your ~/.ssh/config EnableEscapeCommandline yes
(edit: formatting)Also EnableEscapeCommandline fortunately only affects `~C` - the all-important `~.` to kill a hung SSH session still works with it disabled.
That was a nightmare to triage back in the late 90s when I did it. Thankfully Ctrl-Q (I think it’s Q) “resumes”, so, easy fix if you know what you’ve done.
- software flow control user
Goes over similar content as TFA, in perhaps a little more depth. Indispensable sysadmin knowledge.
ssh -J user1@bastion1,user2@bastion2 targetuser@targethost
Edit: Jumphosting was introduced in OpenSSH 7.3 2016-08-01.Support was added to OpenSSH about a decade ago? Even on a low moving Linux distro like Debian/LTS everyone should have support by now.
Are you using SSH key auth or password authenticating three times when you do this?
The final target is a pre-elliptic curve OpenSSH server, so legacy is enabled. I could probably have removed that for clarity.
C:\Users\me\>ssh -J me@bhost1,me@bhost2 -o KexAlgorithms=diffie-hellman-group14-sha1 -o HostKeyAlgorithms=ssh-rsa -o MACs=hmac-sha1 oracle@target
Enter passphrase for key 'C:\Users\me/.ssh/id_ed25519':
me@host1's password:
Enter passphrase for key 'C:\Users\me/.ssh/id_ed25519':
me@host2's password:
oracle@target's password:
Last login: Wed Jun 24 13:29:55 2026 from bhost2
That client is Microsoft's port of OpenSSH.Because the jump mechanism works via use of TCP forwarding, each host authn step is talking "directly" to your client. Importantly, this means it still works without requiring "agent forwarding" for the connection you are making.
It is also nice that it works recursively, so I can logically structure my rules so that the one for my regular targets say to use bastion1, then the rule for bastion1 says to go via bastion 2, etc.
I find this easier to reason about and maintain rather than juggling a bunch of these multi-step rules.
Match host="MyHost" exec "! grep Home ~/.wifi-loc-control/.current"
ProxyJump home-jumphost.mydomain.tldAnd this allows me to have zero open ports on my home internet. I do a reverse tunnel to my VPS from my home server (in a FreeBSD jail), and that port is what my laptop client jumps through.
The socks proxy support can also deal with bad web filtering and privacy issues on public wifi networks (though nowadays if you're ssh'ing to a cloud IP, you'll get lots of "bot" restrictions).
I need VPN to get into some internal resources via SSH, but there are lots of external/public/AWS resources I also need to access, and the full VPN adds too much overhead and fragility for those.
Using the available split VPN, I can point a browser instance at a localhost SOCKS proxy port to relay over SSH + VPN for other web resources I need to access internally.
Unfortunately, Firefox proxy config rules are sort of backwards for my needs. I want to say "only use proxy for these 3 domains" whereas it wants to use the proxy by default and only allow me to bypass specific domains.
- Use Multi-Account Containers plugin, where you define which domain should be opened in which container.
- Use Container Proxy to configure which socks proxy to use for different containers.
Pair that with ssh tunnel that you use as socks proxy and you have nive tunneling solution for browser.
Here's my ad-hoc proxy. Use it for only these domains (while everything else goes direct).
After I complete my special tunneling task, I'm going to flip it back to "no proxy" and resume normal life.
I just love SOCKS proxy in SSH tunnels: at some point I had a dedicated server (on a fixed IP) with countless machines (usually headless Pis dropped at a family member's place and/or SME office) automatically setting up, 24/7, reverse tunnels to that dedicated server.
Then I could, from anywhere, both access their LANs (to fix stuff) and have a browser, running locally, pretending to be in this or that country.
Basically because I had all those reverse tunnels always there, I could always decide how to use them (just SSH in or SOCKS in etc.).
Hak5 - SSH Forwarding: Local vs Remote with examples, Hak5 1113 part1 https://www.youtube.com/watch?v=g_Row8zEJZc
I then use nginx to proxy it.
Because its a unit file, sshd reconnects if my ISP's IP changes. Does so within 30s. Also hides my ISP IP in case I have to turn it off.
And no data is effectively on the VPS. Its just a mostly empty machine.
It's amazing how lightweight this method actually is. I have managed to connect hundreds of devices using a single EC2 nano instance.
Let me know if anything is confusing, I'll answer it here.
[0] https://paskozdilar.github.io/blog/entries/zero_code_ssh_jum...
Particularly, you can use name patterns to apply the same rule broadly, assuming you have some systematic naming scheme for your eventual target devices.
But, you're saying all these remote devices individually connect "back" to the central host to keep a tunnel open?
Honestly, I've never had this problem at large scale. When I did have it, I used one of these methods rather than SSH TCP tunneling tricks:
1. I'm in control of the firewall/NAT router itself, deployed OpenWRT, and setup the port-forwarding rules there (i.e. iptables address rewriting).
2. I really need to punch through uncooperative NAT, so I setup OpenVPN with that remote device initiating the persistent tunnel.
What we had was many devices behind such corporate networks. Instead of requesting exposed ports for each device, or setting up OpenVPN (never done it so I'm not sure how much the red tape would it be), I requested only outbound access to our bastion server's SSH. Since SSH is pretty standard, admins usually allow it fairly quickly.
There were also a few cases where non-HTTPS connections were also banned, so we set up an HTTPS proxy that tunneled the SSH reverse forwarding... But that's probably not needed in most cases.
Some pages have a nice up-front synopsis of flags, others put them in a wall of text. Browsing the former can supplant Google, /\b-x while paging is helpful for the latter.
Can’t I just open up a harness and prompt “Teach me how to do X?”
If you have a private server with a public IP, you don't need localtunnel etc.. you can just use ssh tunnels to expose your home network services over public IP.
Why is that?
SSH is yet another example of an ancient technology that is still in wide use today.
Ancient technology? If it was telnet or FTP... But SSH is much younger than, let's say, IPv4, which is _maybe_ ancient technology still in wide use today.I know this is a solid "cool story bro" moment, but whatever hah
Also annoys me we "invented" ssh:// url format after the tools were baked so it's a somewhat odd bonding into the model.