SSH Tunnels, TCP Port 443 and Socat

In my private cloud setup, I use SSH tunnels a lot to create a redundant path from the Internet to services I host at home for times when my DSL line is down. It doesn’t happen a lot, but it does happen. The method is also ideal for hosting services at home in case the ISP does not assign a public IP address to the link. Have a look here and here for the details. When I recently wanted to add two new tunnels for port 80 and 443, which I did not forward so far, I was a bit baffled that this didn’t work out of the box.

It turned out that ssh seems to flatly refuse to reverse proxy ports such as 80 and 443 if one is not root on both sides of the connection. On second thought, that makes sense, because those are privileged ports that require root permissions. That’s a bit of a show-stopper, of course, if one wants to run a web server on the standard ports. On the other hand, I’m also not keen to use root rights on the remote server for the account that is used to receive the reverse tunnel. But fortunately, there is a fix: Socket Cat, or socat for short. Have a look here and here for the details.

This nifty tool can forward streams of bytes between different parts of the Linux kernel. And for this particular case it can be used to forward packets between two different TCP ports on the same machine. In other words, instead of creating a reverse TCP tunnel from port 443 of my web server at home to port 443 on the remote proxy server, I tunnel the local port 443 to a higher non-priviledged port such as 4444 on the remote machine. With socat running as root, TCP packets are then tunneled between remote port 443 to remote port 4444, and from there via ssh tunneling to port 443 on the server at home. And here’s how this looks like in practice:

On the server at home:

nohup ssh -o ConnectTimeout=10 \
      -o ServerAliveInterval=60 \
      -o ServerAliveCountMax=2 \
      -o ExitOnForwardFailure=yes \
      -R 8888:locahost:80 \
      -R 4444:localhost:443 \
      user@destination &

And on the remote machine, I start socat via /etc/crontab at boot time to create the necessary redirections:

@reboot root socat TCP-LISTEN:443,fork TCP:localhost:4444 
@reboot root socat TCP-LISTEN:80,fork TCP:localhost:8888

This way, I can now tunnel ports 80 and 443 from the remote proxy server to my web server at home without having to give the user account required for the tunneling root rights. Very nice!