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
- 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
firstname.lastname@example.org 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 users are probably used to tools like
WinSCP to handle their
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
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
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.
Nmapneeds Administrator rights in order to be installed and used, but
ncatdoesn’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.
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.