SSH-over-HTTPS for fame & profit

In the past, I’ve discussed using SSH to circumvent restricted networks with censoring transparent proxies, but that relied on the restricted network allowing free SSH access on port 22 (what we call in the industry – the single network requirement for getting work done).

Unfortunately, there are restricted networks that don’t even allow that – all you get is the transparent censoring HTTP proxy (which has recently became the case with the free Wi-Fi on the Israeil Railways trains).

But fortunately for us, there is still one protocol which they can’t block, they can’t proxy and they can’t man-in-the-middle  – or else they’d break the internet even for people who only read news, search google and watch YouTube – that is HTTPS.

In this article I’ll cover running SSH-over-HTTPS using ProxyTunnel and Apache. The main consideration is that the target web server is also running some other websites that we can’t interrupt. The main content is based on this article by Mark S. Kolich, but since it only covers using plain HTTP and in addition to some simple changes in the example configurations I also wanted to cover getting an SSL certificate, here’s my version of the tutorial:


  • A web server running Apache – this is the standard setup for some server serving some sites with some wordpress and maybe a few other things, and is what I have on my personal server. My system is using a funky home-brewed dynamic virtual hosting system and its important to note that the following setup doesn’t touch that and doesn’t interfere with it, so likely – whatever setup you use – it’ll not interfere with yours.
  • A DNS name that you control and is free to be (ab)used – this doesn’t have to be a “domain”, it can be a sub-domain that you can CNAME or something.
  • ProxyTunnel on your local machine

DNS Setup

Because we don’t want to interfere with whatever web hosting is going on on our chosen web server, we are going to make use of the “name based” virtual hosting capability of Apache, using the SNI TLS extension. In order to make use of that we’d need a DNS name that we can point at our server that will not be used to host anything else.

In the below example I’m using, which works for me because all sub-domains under point to the same server (unless otherwise assigned).

Web Server Setup

The first thing we need to do is to get a valid SSL certificate. This is easy to do using EFF’s Certbot and Let’s Encrypt free CA. The certbot command line tool is available by default on all major modern Linux operating systems. You can follow the above site’s instructions, but often we’ll need a simple apt install python-certbot-apache (or yum install, as the case may be).

Once we have Certbot and its Apache plugin installed, we can use it to setup our Apache with a certificate. We start by creating a plain HTTP (not TLS) virtual host setup for our chosen DNS name. To do this, create a new file in your Apache configuration directory – the exact location depends on your operating system, on Debian based servers it will be /etc/apache2/sites-available while on Red Hat based server it will be /etc/httpd/conf.d. The file should be named something that will be loaded after the standard virtual hosts configuration that hold your current web sites – because Apache loads files in the lexicographical order, we’d just create the file as zzz-ssh-proxy.conf and lets set up a simple website that serves files from the default directory:

<VirtualHost *:80>
DocumentRoot /var/www/html
ServerAdmin your@email.tld
LogLevel info
## the following log directory is for Debian, RHEL uses should use /var/log/httpd
ErrorLog /var/log/apache2/ssh-proxy_error_log
CustomLog /var/log/apache2/ssh-proxy_access_log combined

On Debian based system we’d need to also run a2ensite zzz-ssh-proxy.conf before we continue. Now lets restart the Apache web server. This is not the setup we’d use for the actual proxy, its just a scaffolding to complete the automatic SSL certificate registration.

Next we’d need to run Certbot to get an SSL certificate. I’m running it like this:

sudo certbot run --apache -d

After agreeing to the terms of use and providing a notification email, Certbot should create a new certificate and a new configuration file named zzz-ssh-proxy-le-ssl.conf with an SSL setup. At which point if you restart Apache you should be able to access your server from your web browser over HTTPS and get the default welcome page.

At this point we can delete the non-SSL file (if you want, I’m keeping it for debugging) and lets edit the new configuration file that Certbot created for us, to enable the proxying features. Open the new zzz-ssh-proxy-le-ssl.conf file, and add the following instructions above the LogLevel line:

## Only ever allow incoming HTTP CONNECT requests.
## Explicitly deny other request types like GET, POST, etc.
## This tells Apache to return a 403 Forbidden if this virtual
## host receives anything other than an HTTP CONNECT.
RewriteEngine On
RewriteRule ^/(.*)$ - [F,L]

## Setup proxying between youwebserver:8443 and yoursshserver:22
ProxyRequests On
ProxyBadHeader Ignore
ProxyVia Full
## IMPORTANT: The AllowCONNECT directive specifies a list
## of port numbers to which the proxy CONNECT method may
## connect.  For security, only allow CONNECT requests
## bound for port 22.
AllowCONNECT 22 443

## IMPORTANT: By default, deny everyone.  If you don't do this
## others will be able to connect to port 22 on any host.
<Proxy *>
Order deny,allow
Deny from all

## Now, only allow CONNECT requests bound for
Order allow,deny
Allow from all

Finally restart Apache to take in the new configuration. At this point, if you try to access your server over HTTPS again, using your browser, you should get a 403 Forbidden error.

ProxyTunnel setup

Finally we come to the local machine to set up the connection to the proxy. We need to install ProxyTunnel to set up the tunnel for SSH, but there’s a fly in the ointment – ProxyTunnel is an old project (some people would call “stable” 😉 ) that had its last official release – version 1.9 – in 2008. This was before SSL was finally and completely deprecated and before TLS became the one and only protocol to use for HTTPS. As a result, the default ProxyTunnel installation works only over SSLv3 and will not work with a modern Apache installation that only has TLS enabled. This shouldn’t be a problem if you are using a recent Debian based operating system (such as Ubuntu) as they carry a patched ProxyTunnel version that supports all valid OpenSSL protocols. If this is not the case with your system, check if you can get a correctly patched version (there are various patches floating around that solve the problem in different ways).

Once you have a correctly patched ProxyTunnel installed, you’d need to edit your ~/.ssh/config to set up your proxied connection (its possible to run this using just command line options, but that is tedious and annoying to use). Add this to your ~/.ssh/config file (creating it if needed)

Host yoursshserver
   Hostname yoursshserver
   ProtocolKeepAlives 30
   ProxyCommand /usr/bin/proxytunnel -E -p yoursshserver:443 -d %h:%p

Note to use the new DNS name for the Host “address”, that we’ve setup at the start of the tutorial, and not the original host name – you should still be able to use the original host name of your server to SSH normally to it, without proxying, and you’d use ssh user@yoursshserver with the new address to run SSH over the HTTPS tunnel.

For the technical details about how this works, please review Mark Kolich’s article above.

Now lets tie everything with HTTP over SSH over HTTP over TLS proxy

To tie back to the original article, now that you have your proxy setup, you can start the SSH connection with the -D 1080 option and set up the proxy as in the original article to break through the restricted network censorship!

One Response to “SSH-over-HTTPS for fame & profit”

  1. Nelson:

    I like this post very much. it is possible you create a tutorial using a VPS ( virtual private server ) in Linux like Centos or Debian or Ubuntu ? because I want to create a connection like this using my android and the app HTTP INJECTOR which I can modify http header and use a proxy with ssh.

    I will wait your answer.

Leave a Reply