SSH tunnels in Ubuntu
There are two types of SSH tunnels:
- Reverse tunnel = remote port forwarding:
ssh -R [int:]dport:uhost:uport server.
- Forward tunnel = local port forward:
ssh -L [int:]dport:uhost:uport server.
int:dport: listening/downstream interface:port that will be occupied (at remote or local), needed to be available.
uhost:uport: The (upstream) host:port that will be used to forward requests.
-NT flags are used with these commands.
-N: do not execute command, do port forwarding only.
-T: do not allocate pseudo-terminal.
How to remember and interpret these commands:
- Rule 1: group them by
- Rule 2: For
-Remote, a remote (server's) port is opened, for
-Local, a local port is opened, for listening. The specified port must be available.
- Rule 3: because
interface value is optional. The port that comes with it must be the port to be occupied. Based on this rule, we know that
dportis the port to be occupied for request listening.
- Rule 4: the rest is the destination for request forwarding. When opening port at remote server,
uhost:uportis relative to local, and vice versa.
From sshd_config reference:
Specifies whether remote hosts are allowed to connect to ports forwarded for the client. By default, sshd(8) binds remote port forwardings to the loopback address. This prevents other remote hosts from connecting to forwarded ports. GatewayPorts can be used to specify that sshd should allow remote port forwardings to bind to non-loopback addresses, thus allowing other hosts to connect. The argument may be ''no'' to force remote port forwardings to be available to the local host only, ''yes'' to force remote port forwardings to bind to the wildcard address, or ''clientspecified'' to allow the client to select the address to which the forwarding is bound. The default is ''no''.
In sshd_config, there are 3 values of GatewayPorts config
"no": always force to loopback interface.
"yes": always force to wildcard interface.
"clientspecified": up to client, i.e., the
intoption in the previous section of this post.
To allow the access from other host, such as from a different machine or from a docker container host, you must change the default GatewayPorts option in
/etc/ssh/sshd_config and restart the sshd server with
systemctl restart sshd.
To start the tunnel in background
autossh -o "ServerAliveInterval 30" -o "ServerAliveCountMax 100" -R \*:2222:localhost:22 -fNT transang.me
To start the tunnel when startup, refer to this post.
autossh: same command interface as
ssh, except that
autosshautomatically restarts the
sshcommand if terminated.
autosshneeds to manually be installed (
sudo apt install autossh). This command can be replaced with
o "ServerAliveInterval 30": for every 30 seconds, send a ping package to the server in order to prevent the ssh connection from being terminated due to inactivity.
-o "ServerAliveCountMax 100": the number of server alive messages sent when the server does not respond, before terminating the connection.
-R: reverse tunnel
localhost: the firewalled, this can be
localhostor replaced with IP address of any machine in the same LAN network of the client PC (i.e. the PC where this command is executed)
transang.me: the center machine (the server machine), which should be public and must be reachable from the client machine. This machine is later used to connect to the
localhost( firewalled) machine specified above.
-C: compress data
-q: quiet mode, no warning
-N: open SSH connection with no command to be executed
-f: run background
-T: do not allocate a TTY-terminal save a tiny amount of memory.
(Optional) SSH to forwarded server
By default, the ssh server disallows forwarding, which means you cannot ssh to the forwarded server by ssh(ing) directly to the forwarded port from another client machine.
To explicitly allow it, edit
/etc/ssh/sshd_config, append following content
Match User root GatewayPorts yes AllowTcpForwarding yes
sudo systemctl restart sshd.
Also, remember to open the forwarding port with, for example, port 2222, with
ufw allow 2222/tcp && ufw reload.
To ssh to the forwarded machine by directly ssh(ing) to from another client machine:
ssh firstname.lastname@example.org -p 2222 -l username_at_server.