SSH tunneling (also called port forwarding) allows you to access services running on a remote machine as if they were running locally. It is widely used for Jupyter Notebook, TensorBoard, databases, and internal web services on clusters.
What problem does SSH tunneling solve?#
Assume:
- A remote server runs a Jupyter Notebook on port
8888. - The server is not directly accessible from your local browser.
- Opening firewall ports is not allowed or not safe.
SSH tunneling lets you forward a local port to a remote port through an encrypted SSH connection.
From your browser point of view:
localhost:8888 <==SSH TUNNEL==> remote_server:8888No public exposure of the remote server is needed.
Local port forwarding (-L)#
The most common form of SSH tunneling is local port forwarding:
ssh -L LOCAL_PORT:REMOTE_HOST:REMOTE_PORT user@remote_serverExample:
ssh -L 8888:localhost:8888 user@remote_serverMeaning:
- SSH listens on
localhost:8888on your local machine. - Any connection to
localhost:8888is forwarded tolocalhost:8888onremote_server. REMOTE_HOSTis resolved on the remote side.
Tunnel-only connection (-N)#
By default, SSH opens a shell session after establishing the tunnel. If you only want to create the tunnel without opening a shell, use the -N option:
ssh -N -L 8888:localhost:8888 user@remote_server-N means:
- Do not run a remote command.
- Do not open a shell
- Keep the connection open for tunneling only.
-N is required if you also use -f to run SSH in the background.
Jump hosts and bastion nodes (-J)#
Many clusters require connecting through a login or bastion node.
Network layout:
local_machine <==SSH==> bastion_node <==SSH==> remote_serverYou can use the -J option to specify a jump host:
ssh -J user@bastion_node -L 8888:localhost:8888 user@remote_serverImportant notes:
localhostin-Lrefers to the final target (remote_server), not the jump host.- You can chain multiple jump hosts by separating them with commas:
-J user@host1,user@host2.
