SSH Local Port Forwarding
Introduction
OpenSSH can forward a port on your client machine to a port on the remote host with the -L
option. Sometimes this is also called ssh tunneling. With this you can access services that are normally restricted to the machine it's running on (localhost). In this post, I'll share a couple of cases where I have used SSH port forwarding.
Syntax
The syntax for the argument of the -L
option is
-L [bind_address:]port:host:hostport
The bind_address
parameter is optional. Since it is not used in this article, argument examples can simply be read as port:host:hostport
. All of the examples below use localhost
as the host, which refers to the remote itself that we are sshing into. It can be replaced with a different host so that it looks to the host the remote machine is connecting to it (think of it like a proxy), but the examples below are mainly to show how you can access local services on a server with SSH.
In the examples, I typically set the port
the same as the hostport
. You can choose to make them different if the remote port a service is running on is not configurable and you don't like the port number, or if the port is not available on your local machine, because another service is listening on it for example.
I use the -N
flag in all of my examples below. The -N
tells ssh not to execute any remote command. It can be omitted if you want to use the connection to run interactive commands.
Examples
VNC
To use VNC, the remote needs to run a VNC server, and the client needs a VNC client. For Xorg environments, x11vnc and TigerVNC provide VNC server implementations. For wlroots-based Wayland compositors, wayvnc provides a VNC server for those. Regardless of the remote's display server protocol, TigerVNC provides the vncviewer
command for connecting to a VNC server.
On the remote:
# If the remote runs an xorg server
# -locahost is the same as "-allow 127.0.0.1" and "-listen localhost",
# which only allows localhost to connect to the server.
# -nopw disables the warning message which can be ignored
# if the SSH server and network is hardened.
x11vnc -localhost -nopw -display :0 -loop
# If the remote runs a wlroots based compositor
wayvnc -grR --max-fps=60 -L warning
On the client:
ssh -N -L 5900:localhost:5900 remote
vncviewer localhost
SPICE
SPICE servers are usually used for viewing virtual machines (but VNC can be used too). With local forwarding, you can run the virtual machine on a remote host, and connect to it remotely. Because we are using SPICE, we can also redirect USB devices remotely (when I first tested this, this felt like black magic).
On the remote virt-manager, make sure the graphics type is "SPICE", the listen type is "Address", and that the port is explicitly set. If the port is not explicitly set, and the port is already in use (the default port is 5900, the same as VNC's default port), virt-manager will automatically use the next available port. After applying the settings, start the virtual machine either with the virt-manager interface, or with libvirt with the following command:
sudo virsh start myvirtualmachine
On the client:
# Change 5902 to whatever port you want to use
ssh -N -L 5902:localhost:5902 remote
remote-viewer spice://localhost:5902
The remote-viewer
command is provided by the virt-viewer
package.
Jupyter
Running jupyter on a server will allow you to use the resources of the server and save some battery on your laptop. If you use CUDA for libraries like Pytorch, but your laptop doesn't have an Nvidia GPU, you can port forward Jupyter on a server with an Nvidia GPU.
On the remote:
jupyter notebook --no-browser
# Or specify a custom port with --port
#jupyter notebook --no-browser --port=8080
Jupyter will print out a link to connect to the Jupyter server. On the client:
ssh -N -L 8888:localhost:8888 remote
After running the port forwarding command, open the Jupyter link and you should see the Jupyter file browser.
Ollama
Similar to the Jupyter example, instead of running Ollama on a local laptop, you can run Ollama on a server, which will save some battery. If your server is stronger than your laptop, it'll also enable you to run bigger models and get faster responses.
Start Ollama on the remote server. On the client:
ssh -N -L 11434:localhost:11434 remote
Test the connection with
curl http://localhost:11434/api/generate -d '{
"model": "llama3.2",
"prompt": "Why is the sky blue?",
"stream": false
}'
With this, you can run local apps that use Ollama's REST API like Continue. This can also work with Open WebUI, but just keep it installed on the same machine as Ollama, and forward Open WebUI's port instead.
Forward multiple ports
The -L
flag can be specified multiple times to forward more than one port. The following example local forwards both port 5900 and 8888:
ssh -L 5900:localhost:5900 -L 8888:localhost:8888 remote
Shortening the command with SSH config file
The ssh config file ~/.ssh/config
can be used to alias a long ssh command to a host name. The LocalForward
keyword is the ssh config equivalent of the -L
option in the ssh
CLI.
Host mytunnel
User myuser
Hostname 192.168.1.42
LocalForward 5900 localhost:5900
Now invoking ssh mytunnel
will be as if you ran ssh -L 5900:localhost:5900 [email protected]
.
The next example local forwards two ports and prevents remote commands:
Host mytunnel
User myuser
Hostname 192.168.1.42
LocalForward 5900 localhost:5900
LocalForward 8888 localhost:8888
# Does the same as -N
SessionType none
If you want to connect to the same server, but have one host for normal ssh and the other for only local forwarding, you can split up the config like the following:
Host myserver mytunnel
User myuser
Hostname 192.168.1.42
Host myserver
# Put any other options here.
# Otherwise this host entry can be omitted
Host mytunnel
LocalForward 5900 localhost:5900
LocalForward 8888 localhost:8888
SessionType none