The idea
Many tools should never be open to the whole internet: databases, Docker dashboards, monitoring pages, admin consoles. Bind them to 127.0.0.1 on the server, and use SSH to forward a port from your computer to that private address. All traffic runs through your encrypted SSH connection, and the service stays invisible to scanners.
This needs nothing extra on the server beyond SSH access, because TCP forwarding is allowed by default.
sudo ss -lntp | grep -E "127.0.0.1:(3000|3001|5432|3306)"Forward a local port to a service
The -L option binds a port on your computer and forwards it to an address as the server sees it. This example forwards local port 8080 to port 3000 on the server's own loopback interface. While the command runs, open http://localhost:8080 in your browser. Press Control-C to close the tunnel.
ssh -L 8080:127.0.0.1:3000 deploy@YOUR_SERVERssh -N -L 8080:127.0.0.1:3000 deploy@YOUR_SERVERUse it with a database tool
A database client on your computer can connect to the forwarded port as if the database were local. Use a local port different from your own database, if you run one, to avoid a clash. Connect to 127.0.0.1 and that port.
ssh -N -L 15432:127.0.0.1:5432 deploy@YOUR_SERVER
# in another terminal:
psql -h 127.0.0.1 -p 15432 -U appuser appdbssh -N -L 13306:127.0.0.1:3306 deploy@YOUR_SERVER
mysql -h 127.0.0.1 -P 13306 -u appuser -p appdbKeep it in your SSH config
Put the settings in ~/.ssh/config so you only type a short name. You can list several forwards for one host. The ExitOnForwardFailure option makes SSH stop with an error instead of silently running without the tunnel if a port is already in use.
Host myserver-tools
HostName YOUR_SERVER
User deploy
LocalForward 8080 127.0.0.1:3000
LocalForward 15432 127.0.0.1:5432
ExitOnForwardFailure yes
ServerAliveInterval 30ssh -N myserver-toolsRun it in the background
The -f option sends SSH to the background after authentication. Combine it with -N so it does not start a shell. Find and stop the tunnel afterwards with the process list. For a tunnel that must stay up and reconnect, use autossh or a systemd service, but for occasional use a foreground command is simpler and clearer.
ssh -f -N -L 8080:127.0.0.1:3000 deploy@YOUR_SERVER
pgrep -af "ssh -f -N"
# stop it when finished:
pkill -f "ssh -f -N -L 8080"Reach a service on a third machine
You can forward through the server to another private machine, such as a database on a private network, by naming that machine's address instead of 127.0.0.1. Use a jump host with -J when you must log in to a private server through a public one.
ssh -N -L 15432:10.0.0.5:5432 deploy@YOUR_SERVER
ssh -J deploy@YOUR_SERVER [email protected]Use the server as a SOCKS proxy
A dynamic forward with -D turns the SSH connection into a SOCKS proxy that sends your browser traffic through the server. It is handy for testing a site from the server's location or using a private admin page by name. Point your browser or application at the SOCKS5 address 127.0.0.1:1080.
ssh -N -D 1080 deploy@YOUR_SERVER
curl --socks5-hostname 127.0.0.1:1080 https://ifconfig.meSecurity notes
Forwards bind to your own computer's loopback address by default, so other people on your network cannot use them. Do not add a bind address of 0.0.0.0 unless you want to share the tunnel. A tunnel gives you the same network access as the server, so do not forward ports to untrusted hosts. If a tunnel will not open, check that the service listens on the server, that the local port is free and that the SSH server allows forwarding.
ss -ltn | grep 8080sudo sshd -T | grep -i allowtcpforwardingOfficial documentation
These upstream references provide more detail on the commands and workflows in this guide.