Connect two remote places

📷Modestas Urbonas

ssh is a very versatile tool that many of us depend on for everyday tasks. Other than the basic connection to a remote host and multiplexing the terminal with tmux or screen, it is also used

  • together with rsync
  • to execute remote commands in scripts
  • for port forwarding
  • for an adhoc VPN of sorts

That’s a lot of functionality. Yet in some places the connection is restricted behind an HTTP proxy that won’t let ssh do its magic. Fortunately, it’s still possible to configure ssh for these cases and here we’ll be covering such a scenario. HTTP proxies usually only allow connections to specific ports such as 80 and 443, although they allow arbitrary TCP streams with the CONNECT method.

Linux, MacOS and Windows with WSL

We will be using netcat-openbsd, as it’s called in Ubuntu and Debian. Apparently there are two implemenations of netcat and we want the one that supports the -x “connect to proxy” parameter. Here is how ~/.ssh/config would look like:

Host otherside
    HostName example.com
    User torvalds
    Port 443
    IdentityFile ~/.ssh/id_ed25519
    ProxyCommand nc -X connect -x 10.20.30.40:8080 %h %p
    LocalForward 9999 127.0.0.1:5050

We are connecting to torvalds@example.com over an HTTP proxy at 10.20.30.40:8080 . netcat also supports SOCKS proxies and authentication if you need them, but you’ll have to man nc for more information on these topics. As a bonus, we forward the local port 9999 to port 5050 on the remote server.

The tricky part is that the ssh server has to listen to port 443, which is normally used by HTTPS. Don’t worry about that, we’ll fix it later.

Windows native

Windows users are probably used to tools like PuTTY and WinSCP to handle their ssh and sftp connections. These programs do support proxy connections, forwarding ports and the like. One thing to keep in mind is that PuTTY uses it’s own file format for ssh key files, however it’s possible to import an existing openssh key into it. We will not be covering their configuration here though. One limitation of them is that they cannot be used with Visual Studio Code for remote development over ssh and you don’t get the handy rsync either.

Windows come with their own version of OpenSSH which can be enabled as an optional feature. Its configuration files can be found in C:\Users\username\.ssh. We also need to install Nmap, which comes with its own netcat-like program, called ncat.

C:\Users\username\.ssh\config:

Host otherside
    HostName example.com
    User torvalds
    Port 443
    IdentityFile C:\Users\torvalds\.ssh\id_ed25519
    ProxyCommand C:\Program Files (x86)\Nmap\ncat.exe --proxy 10.20.30.40:8080 %h %p
    LocalForward 9999 127.0.0.1:5050

It works the same as described in the previous section.

Some gotchas…

  • Nmap needs Administrator rights in order to be installed and used, but ncat doesn’t. If you are unable to install Nmap, then I suggest that you install it on a computer where you do have Administrator rights, then copy ncat.exe, all DLLs and ca-bundle.crt. These are all the files you need.
  • Do not use an old, so-called portable version linked by ncat’s site.
  • nmap 7.93 has a bug, use 7.92 or a later version instead.

DNAT the incoming connection on the server

As we mentioned before, the ssh client has to connect to port 443 in order to pass through an HTTP proxy. The port may be already in use by a web server. We can work around this requirement by using a DNAT rule on the server.

sysctl net.ipv4.conf.$dev.forwarding=1
iptables -t nat -A PREROUTING -p tcp -i $dev --src $proxy_ip --dport 443 -j DNAT --to-destination $my_ip:$ssh_port

$proxy_ip is the outgoing IP of the HTTP proxy e.g. the address duckduckgo.com gives you when you search for “my ip”. $my_ip is the server’s IP and $ssh_port the port ssh is normally listening to.

Note that both port 443 and $ssh_port must be open in the firewall rules or at least accept connections coming from $proxy_ip.

Final remarks

You may want to encrypt the connection with TLS. This mainly serves to obfuscate the headers sent by ssh and make it look more like a common HTTPS connection. This will not be covered here; for more information, have a look at the program’s guide.

That’s it. Have fun.