Sequel to RDP on WARP to WARP.

You’ll probably need to connect a domain to Cloudflare (i.e. use its nameservers) for this one.

TLDR

Install cloudflared and secure any web app behind Zero Trust.

You can also SSH in the browser without needing passwords or keys (unless you sudo, of course).

Motivation

My pretty-cheap Racknerd server (I found on LowEndBox deals) runs some Docker stuff.

Out of a (perhaps irrational) fear of exposing my box’s IP address, I was keen on never announcing it anywhere. So I had this setup:

  • Tell Docker to only bind to some port on 127.0.0.1. (Otherwise, the port becomes available to the outside world.)
  • Reverse-proxy the port to a subdomain using nginx
  • Proxy that subdomain through Cloudflare

But this still gives the outside world access to my services, so I had to use each app’s built-in logins. Plus, there is the slightly tedious task of manually adding DNS records and pasting Cloudflare’s origin certificate around.

Setup

Tunnel

From the Cloudflare docs: Set up a tunnel through the dashboard

Then, under Access > Tunnel, I added a new tunnel. The UI will prompt you to install cloudflared on the server; just copy-paste and run it.

Here, you can connect an “public hostname” and/or a “private network”.

A private network means cloudflared will route an IP range through Cloudflare; the end user can connect by installing cloudflared or WARP. This involves messing with split tunnels and potentially colliding with something else on my local network, so I skipped this.

A public hostname means something that runs on, say, http://localhost:80, and you access it through https://web.example.com.

Although there is support for paths (such that you can have two things running under a subdomain), my Docker apps tended to want / and changing that would be a little bit tedious, so I used the default /*.

App

Then, we can add the tunnel as an app under Access > Applications.

Add an app and choose “self-hosted” as the application type. The subdomain will be the one you just entered on Tunnel.

For the “add policies” page, you can name the policy whatever, since this policy only applies to the current app.

Then, you’ll want to set up CORS if you need to. (I did not.)

Under Cookie Settings, it’s probably a good idea to enable “HTTP Only”, “Enable Binding Cookie”, and Strict “Same Site Attribute”, unless you meet the exceptions outlined here.

For “cookie path attribute”, I turned it off since I wasn’t using any paths.

Then, you can see “Broswer rendering”. What is that, you ask? It is how you can have nice things such as…

SSH in your browser!

Yes, Cloudflare can render SSH or VNC in the browser for you. No need to install anything to that effect.

To do this:

  • In Tunnels, add a service of type SSH and URL localhost:22 (or whichever port you changed it to be).
  • In Applications, add an app. On the final step, enable “Broswer rendering”.

If all goes well, then you can now visit the app, and login with your SSH credentials.

What about password-less?

Ah yes, I promised you this.

But first, if you want to use the browser-based terminal (meaning no network setup like private IPs), your email name (the part before the @) must match your SSH username.

So you either create a new user, or here’s a handy guide to change your username and group name. (Remember to save everything and pkill -u old_username).

After you make sure the usernames match, here’s how to configure the short-lived certificates Cloudflare talks about:

  • Head over to Access > Service Auth > SSH.
  • Choose your SSH app, and choose “Generate certificate”.
  • Save that public key somewhere on the server, say at /etc/ssh/ca.pub.
  • In /etc/ssh/sshd_config, uncomment (or add) this line: PubkeyAuthentication yes
  • Add the public key as a User CA, like this: TrustedUserCAKeys /etc/ssh/ca.pub
  • Restart your SSH server.

And then you are done.

The “wow it just works” moment was quite satisfying. I had already logged into GitHub on my phone, so when I typed in the SSH app’s URL, I was just in. Simple as that.

A note on networking

For apps in Docker, there is “some kind of NAT” going on. Since Docker uses 172.16.0.0/12 by default, you can safely whitelist that.

(You should have already added 127.0.0.1 when binding Docker ports, such that only the server itself can access the container.)

I haven’t tested apps outside Docker (just SSH for now), since I don’t have a static IP (I use WARP, loll), and I don’t want to install cloudflared on my laptop.

But SSH does tell me my logins are from ::1, so I guess whitelisting localhost works.

You want more

Maybe I will do private networks someday, like how I did Cloudflare Access.

But that won’t be today.