SSH tunnels in Ubuntu

TLDR;

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.

Where:

  • 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.

Usually, -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 int:dport and uhost:uport.
  • 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 dport is 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:uport is relative to local, and vice versa.

Examples

Reserve tunnel with ssh -R \*:2222:firewalled:2200 server

GatewayPorts config

From sshd_config reference:

GatewayPorts
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

  • (default) "no": always force to loopback interface.
  • "yes": always force to wildcard interface.
  • "clientspecified": up to client, i.e., the int option 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.

Command explanation:

  • autossh: same command interface as ssh, except that autossh automatically restarts the ssh command if terminated. autossh needs to manually be installed (sudo apt install autossh). This command can be replaced with ssh.
  • 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 localhost or 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

Restart sshd via 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 my_username_at_firewalled@transang.me -p 2222 -l username_at_server.