Public access and administrative access are two different problems, and they deserve two different solutions. In the previous post we covered how to remove the VM’s public inbound surface entirely with a Cloudflare Tunnel. That solves how visitors reach your website. It says nothing about how you reach the VM itself to run commands, check logs, or restart a container. For that, opening port 22 to the world and hoping your key never leaks is still the default — and it’s still a bad one. Tailscale replaces that with a private network you and the VM are both quietly members of.
Why Not Just Use SSH Directly
-
Port 22 open to the internet is a permanent target for credential-stuffing and brute-force bots
-
Every laptop, coffee-shop network, and IP change means updating firewall allow-lists
-
A leaked or misconfigured key is reachable from anywhere on the planet, not just from you
-
You end up maintaining two separate security postures: one for public traffic, one for admin access
How Tailscale Works
Tailscale builds a private mesh network (a «tailnet») on top of WireGuard. Every device you enroll — your laptop, the VM, anything else — gets its own stable private IP inside that mesh and can reach the others directly, encrypted, without any of them needing a public IP or an open inbound port. Authentication happens once, through your identity provider, not per-connection. From the VM’s perspective, SSH never has to listen on the public internet at all; it only has to be reachable from other tailnet members.
Step-by-Step Setup
-
Install Tailscale on the VM:
curl -fsSL https://tailscale.com/install.sh | sh -
Bring it up and authenticate:
tailscale up, then approve the device in the Tailscale admin console -
Install Tailscale on your laptop the same way, and sign in with the same account
-
Close port 22 on the VM’s public firewall entirely — it’s no longer needed there
-
SSH using the VM’s tailnet name instead of its public IP:
ssh user@vm-hostname -
Optional but worth it: enable Tailscale SSH (
tailscale up --ssh) to let Tailscale itself manage SSH access and identity-based authorization, instead of distributing key pairs
Public Traffic vs. Admin Access
| Cloudflare Tunnel | Tailscale |
|---|---|
| For visitors: the public website | For you: administrative access |
| Anyone on the internet can connect | Only enrolled tailnet devices can connect |
| Routes to a public-facing service (HTTP/HTTPS) | Routes to private services (SSH, internal dashboards) |
| No identity check beyond what the app itself does | Every connection is tied to an authenticated device/identity |
Put together, the two posts cover the whole picture: Cloudflare Tunnel handles the traffic that’s supposed to be public, and Tailscale handles the traffic that very much isn’t. Neither one requires a single open inbound port on the VM, which means the entire firewall can stay closed by default — the safest configuration a server can be in.