I have an intermittent issue where one of my machines on a specifc network seems to be operational locally on network but not accessible over netbird some of the time. I could not tell if the problem was due to the network the problematic machine was on or due to netbird.

So to debug this I:

  1. Setup a grafana node agent to report journald logs to https://grafana.com/

  2. Setup to docker to log to journald

  3. Wrote ssh-via-cloudflare-tunnel docker-compose stack to tunnel ssh over websocat to internet over cloudflared. Set docker compose to restart-on-failure.

Today netbird had some downtime (tailscale had theirs just a few days before that). I was able to log into grafana, look up the temporary hostname cloudflare assigned to me and ssh in using

ssh -o ProxyCommand="websocat -E --binary - -v %h" -o ServerAliveInterval=10 wss://library-won-nt-gauge.trycloudflare.com

Architecture

graph TD;
    A[ssh client] <-->|Invoke websocat over ProxyCommand| B[websocat client-mode]
    B <-->|WebSocket to Stdio| D(Cloudflare)
    D <-->|HTTPS to WebSocket| E[cloudflared Server]
    E <-->|Reverse proxy over HTTPS| F[websocat server-mode]
    F <-->|Stdio to SSH| G[sshd server]

    style A fill:#f9f,stroke:#333,stroke-width:2px
    style B fill:#dfd,stroke:#333,stroke-width:2px
    style D fill:#bbf,stroke:#333,stroke-width:2px
    style E fill:#ddf,stroke:#333,stroke-width:2px
    style F fill:#dfd,stroke:#333,stroke-width:2px
    style G fill:#f9f,stroke:#333,stroke-width:2px

Conclusion

This turned out trivial to do. However it took me over 5 years of pondering, discovering ssh ProxyCommand, cloudflared, websocat and deciding to combine them to conveniently expose ssh over web.

I think it’s pretty cool how Cloudflare allows one expose geographically distributed tunnels without requiring any signups. I wish their UX simpler so it was equally easy to expose tunnels with fixed dns. Cloudflare actually has something similar as an official ssh feature, but it requires more hoop jumping.

websocat is amazing. I use websockets a lot more now that I have a robust way to utilize them without writing any code.

Why Would I Want To Do This?

  • As a fallback to tailscale/netbird that uses a completely different network topology as in this case
  • To temporarily grant ssh to some machine without requiring end-users to install a vpn
  • To bypass restrictive gsm/wifi networks that block access to ssh
  • As an alternative to port-knocking to obscure ssh (eg hide ssh behind http basic-auth)

How would you improve this?

Checkout ssh-via-cloudflare-tunnel on github.