Proxy SSH server over WebSocket and Cloudflare

What’s the point of doing this?

Well you might end up in a place that only allows HTTP/HTTPS traffic which is pretty common in schools, universities, dorms, etc.

Once when I stayed in a dorm I noticed that most non-whitelisted ports and IP ranges were throttled.

Ok so let’s begin…

Requirements:

To build WebSocat run:

cargo build --release --features=ssl

Yes it is indeed written in Rust and requires Cargo build tool and package manager.

Note: This has to be done on both server and also the client.

Server-side setup

Create a Cron job to start WebSocat tcp -> ws proxy on boot.
Add this entry by running crontab -e.

@reboot ~/.cargo/bin/websocat --binary ws-l:127.0.0.1:8022 tcp:127.0.0.1:22

Time to configure our beloved Nginx proxy.
Add this to /etc/nginx/nginx.conf.

server {
    listen 80;
    server_name ws.doner.kernal.eu cf.ws.doner.kernal.eu;
    location / {
        proxy_pass http://127.0.0.1:8022;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
    }
}

In this example I’m also adding a DNS record to proxy it through Cloudflare servers in case of IP address blacklist.

DNS records should look something like this.

DNS management panel — Cloudflare

Client-side setup

Edit ~/.ssh/config file accordingly.

host doner.kernal.eu
    HostName doner.kernal.eu
    IdentityFile ~/.ssh/id_ed25519_passless

host ws.doner.kernal.eu
    HostName ws.doner.kernal.eu
    ProxyCommand websocat --binary ws://ws.doner.kernal.eu
    IdentityFile ~/.ssh/id_ed25519_passless

host cf.ws.doner.kernal.eu
    HostName cf.ws.doner.kernal.eu
    ProxyCommand websocat --binary ws://cf.ws.doner.kernal.eu
    IdentityFile ~/.ssh/id_ed25519_passless

Done, everything works as expected

$ ssh cf.ws.doner.kernal.eu
Last login: Fri Aug 21 05:51:38 2020 from 127.0.0.1
[stnby@doner ~]$ exit
logout
Connection to cf.ws.doner.kernal.eu closed.