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:
- WebSocat — Netcat, curl and socat for WebSockets.
- Nginx — High Performance Load Balancer, Web Server, & Reverse Proxy.
- OpenSSH — SSH Server / Client. Duhhh…
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.
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.