How I Secured My VPS with Tailscale and Cloudflare

Running a VPS with public services like a website can quickly become risky if ports are left wide open. I recently hardened my Ubuntu VPS using a combination of Tailscale, Cloudflare, and a strict UFW firewall for my private coding environment setup. This setup follows a true zero-trust model, ie nothing is trusted by default.


Initial Situation

My VPS had Nginx serving a website and SSH enabled. A quick check revealed the issue:

sudo ss -tulnp

Ports 22 (SSH), 80, and 443 were listening on 0.0.0.0, meaning they were potentially accessible to anyone scanning the public IP.


Step 1: Configure a Strict Firewall with UFW

I installed UFW and applied a default-deny policy for maximum security:

sudo apt install ufw -y
sudo ufw default deny incoming
sudo ufw default allow outgoing


Key changes made:

  • Restricted SSH (port 22) to accept connections only from the Tailscale network range.
  • Removed all broad “Anywhere” rules for web ports 80 and 443.
  • Added precise allow rules for only Cloudflare’s official IP ranges (both IPv4 and IPv6). This allows legitimate traffic coming through Cloudflare while blocking everything else.
  • Allowed full access through the Tailscale interface for safe administration:
sudo ufw allow in on tailscale0

After applying the rules, I checked the final configuration:

sudo ufw status verbose


Step 2: Enable Tailscale SSH

In the Tailscale admin console, I enabled Tailscale SSH. This lets me connect securely using the VPS’s Tailscale IP instead of exposing the public SSH port.


Step 3: Verification

To confirm everything was working correctly:

  • I performed external port scans using nmap from a machine outside my Tailscale network.
  • Direct access to the VPS public IP (on ports 22, 80, or 443) was blocked or filtered.
  • The website continued to load normally when accessed through the Cloudflare-proxied domain.
Continue reading “How I Secured My VPS with Tailscale and Cloudflare”