Building a near-undoxxable home server with VPN + Cloudflare Tunnel
I recently set up an old laptop as a home server:

This setup works surprisingly good – the laptop already comes with a great uninterruptible power supply (the battery!), there's plenty of compute and RAM, and symmetric fiber-to-the-home means more than enough network bandwidth. The biggest advantage, of course, is security and autonomy – physically owning hardware entirely avoids trusting somebody else's computer to do everything.
A big problem, though, occurs if I want to use this laptop to host a public website. Naively using my home internet would expose my public IPv4 address. If I want more than a few trusted people to use these services, this will be a privacy disaster:
- Anybody on the globe can dox my home location with pretty high accuracy
- My ISP would know that I'm hosting a public website, which they might frown upon
- Every host I talk to on the internet – every website, every P2P peer – now instantly knows I am the same guy as whoever hosts a certain website
- Anyone who wants to get at any valuable secrets on your server (e.g. crypto hot wallets, secret data hoards) now knows exactly who to execute a wrench attack on:

You end up with a privacy – and even security – picture a lot worse than just using an off-the-shelf hosting provider, and it's not clear this is better for "user autonomy" than just buying a server.
The simplest solution to this problem would be to just rent an ordinary server and set up a reverse proxy to my laptop:

But I wanted a solution that
- didn't involve maintaining a separate server
- greatly improves privacy versus buying a regular server – "doxxing" should be even harder than normally hosted websites
The solution, at a glance
It turns out that Cloudflare offers a completely free reverse-proxy service, called Cloudflare Tunnel. You can use an ngrok-like tool called cloudflared
on any internet-connected computer (even one without a public IP address; it only makes outgoing connections) to expose locally running HTTP services through any public domain connected through the Cloudflare CDN.
Cloudflare Tunnel completely eliminates the need to maintain a separate server, on top of giving you the nice caching and anti-DDoS features of Cloudflare for free. A second step – running the Internet connection of the laptop through a trusted VPN – gives us the second point of greatly improving privacy:

Other than the slight delay added by the VPN service, this doesn't measurably reduce performance. Using this exact setup with a WireGuard tunnel from Mullvad to a location on the other side of an ocean, I could still easily saturate a 500 Mbps FTTH link.
Assuming that the VPN service is trustworthy, it's not hard to see why we now have a virtually "undoxxable" website:
- Website users only see Cloudflare's IP addresses, which can't be linked to anybody
- Even Cloudflare only sees the VPN's IP address, so even if they're evil (and they might be!), or your Cloudflare account gets hacked, you're not doxxed
How anonymous is this? On one hand, it's certainly more than enough to defeat even a determined online doxxer. On the other hand, it's not as anonymous a setup as something like using a Tor onion service and is certainly not going to defeat three-letter agencies and such – I do depend on trusting the VPN, and in any case large-scale traffic snooping can correlate traffic patterns to link the website with my home internet connection.
But I would guess that it's the about as anonymous as any hardcore "anonymous hosting" provider. For instance, the setup is likely to be resilient to DMCA/copyright takedowns:
- We know that Cloudflare legally serves famous shadow libraries like Anna's Archive, since it's generally considered an "ISP" not responsible for any copyright violations by its customers.
- Thus, Cloudflare normally forward copyright complaints to the upstream hosting provider.
- But in our case, Cloudflare itself would not even know who to forward the complaint to, as the actual host is behind a public VPN!
Avoiding some footguns
Merely following the above picture when the website is hosted and running isn't sufficient for achieving high anonymity; you still have to avoid leaking your real IP or identity in any other way linkable to the website.
This means anonymizing all web traffic and web accounts that can be linked to ownership of the website:
- Registering the domain
- Registering and operating the Cloudflare account
- Registering and operating the email address connected to the Cloudflare account
- All network traffic originating from the server, not just
cloudflared
In practice, I've found that the easiest way of achieving this is through three simple rules:
- Use Tor Browser when operating on anything website-related – domain registrar (njal.la is a great anonymous registry), VPN account, Cloudflare account, email account (ProtonMail accepts registrations over Tor)... I also test the website through Tor too; nothing in my non-Tor browsing activity should give a hint I'm behind the website.
- Pay for everything with Monero. If the merchant only accepts other crypto, use Trocador to swap from Monero. This way, nothing can be tied back to your identity via a credit card, blockchain analysis, etc.
- Serve the website from a VM/container that only has access to the Internet via a VPN run on the host.
The last point requires a bit of explanation. Basically, the idea is to set up the VPN on the laptop, then create a virtual machine or container (I chose to use a LXC container), on its own virtual LAN, with no Internet access at all, then use iptables rules to give that LAN Internet access only through the virtual network interface created by the VPN. In my case, this meant iptables rules as follows:
# prevent forwarding by default
iptables -t filter -P FORWARD DROP
# forward traffic between "lxcbr0" (the virtual LAN connecting to the container) and "wg0-mullvad" (the virtual interface created by Mullvad)
iptables -t filter -A FORWARD -i lxcbr0 -o wg0-mullvad -j ACCEPT
iptables -t filter -A FORWARD -i wg0-mullvad -o lxcbr0 -m state --state RELATED,ESTABLISHED -j ACCEPT
# clamp MTU for TCP packets; fixes issues with the VPN tunnel having a smaller MTU than default
iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
We then set up the entire website-hosting stack – cloudflared, nginx, etc – on the VM, not the host. The final picture looks something like this:

This way, it's very hard to accidentally have some website-related process leak the real IP address to a third-party service, since from within the VM, nothing should even be able to deduce the real IP address. Any sort of VPN malfunction on the host would also simply lead to the VM becoming unreachable rather than a leak.
Next steps
This basic setup works great for a single website, but eventually not everything will easily fit the paradigm of a single web-server daemon tunneled through cloudflared
and a VPN. More specifically, I ran into two things that turned out to be rather challenging:
- Third-party object storage: S3-style object storage, like Backblaze B2 or Cloudflare R2, is very convenient for things like offsite backups, storing/hosting large files, etc, but of course directly using a mainstream object storage bucket paid for with my credit card greatly reduces anonymity (the object storage provider can now link my identity with my website).
- High-security applications that can't trust Cloudflare: Cloudflare terminates all TLS connections, so it sees all the data in flight. This means I wouldn't be very comfortable with, say, remote-accessing a personal file server with security camera footage, personal files, etc through Cloudflare. A naive reverse-proxy approach (at the TCP level, not TLS) would work, but I would like to still use a VPN and not let the reverse proxy know my IP – after all, there aren't really any reputable server providers accepting anonymous customers.
I eventually found elegant fixes for both challenges – leveraging rclone
encryption for anonymous object storage and crafting a high-performance reverse proxy that can run behind a VPN – but a full walkthrough deserves its own blogpost.