There’s heaps on this on the internet and a good book. Here is my usage, which is useful for IoT connections.
Remote Server Access
I want to connect remotely to a web server on machine.com. But it’s behind a firewall which refuses incoming connections and/or has no public IP address.:
# machine.com>
ssh -N -R 8080:localhost:80 ssh-user@your.public.server
-N: using no shell/command…
-R : listen on the remote machine…
8080: at remote port 8080…
localhost:80: and forward connection that back here…
ec2-user@your.public.server: do this by sshing to this remote machine
Finally, there’s a configuration setting on public.com required. See details here.
And now, from Admin’s computer, we can connect to public.com:8080 which is really connecting to machine.com:80, its webserver. From the public.com machine, we can see it’s listening on :8080 to forward to machine.com:80
public.com>ss -t -l -n State Recv-Q Send-Q Local Address:Port Peer Address:Port LISTEN 0 128 0.0.0.0:8080 0.0.0.0:*
Unmanned Tunnel
Extending this concept, we can create a ssh tunnel from the remote machine.com to a public server:
# machine.com: ssh -N -R 2345:localhost:22 ec2-user@public.com
And then from an admin machine connect to sshd on machine.com by:
# admin machine ssh -p 2222 ec2-user@machine.com # and we get: machine.com>
Keep Alive and AutoSSH
We’ve got a remote machine without a public ip. It’s headless. We can run a process automatically to ‘phone home’. Use autossh, available via apt, to nicely monitor the connection:
/usr/bin/autossh -N -R 2020:localhost:22 user@public.com -o ForwardX11=no -o ExitOnForwardFailure=yes -o StrictHostKeyChecking=no -o ServerAliveInterval=20
Those options are for reliability. Check the man page. Then run it on boot as a systemd service as suggested here:
[Unit]
Description=Auto Reverse SSH
After=systemd-networkd-wait-online.service
# Try to restart forever!
StartLimitIntervalSec=0
[Service]
Type=simple
Restart=always
RestartSec=60 # Wait a bit before restart
[Service]
ExecStart=/usr/bin/autossh -N -R 0:localhost:22 user@public.com -o ForwardX11=no -o ExitOnForwardFailure=yes -o StrictHostKeyChecking=no -o ServerAliveInterval=20
[Install]
WantedBy=multi-user.target
Multiple Connections
Right, so we’ve got a tunnel from our remote (maybe IoT) machine to a publicly accessible, but secure, server. We can use ‘0’ as the remote port (0:localhost:22) to let it choose one. If we have a few remote computers, how do we know what is what? Use github.com/brettbeeson/tunnel/ to interrogate the clients periodically.
Forward a Connection from Remote Server to Public Server
So, we’ve ssh’d onto a remote machine. On that remote machine’s network is a device (“device.local”) with a web server we need to access.
First let’s find available web servers on the local network:
nmap -q --open -oG a -p 80 10.1.1.* && cat a
We can forward one IP or host to our public machine. Have to config sshd on the remote machine too (see details here.) Then:
ssh -N -R 8080:device.local:80 user@public.com
Just kill when finished add -f
to fork to background. Now we can access device’s web server from outside. (Don’t forgot about security considerations as it’s now a ‘public’ site.) Port 8080 needs to be unfirewalled on public.com.
One thought on “SSH Port Forwarding”