Your VPS has an admin panel, a database and SSH. A VPN lets your laptop and phone reach them privately and encrypted — with WireGuard and Zerotier, the two tools every shipper should know.
← / → to navigate · EN/VI switch below · the operator's view — mental model first, a few small examples
The moment you deploy, your machine has a public IP — visible to every scanner, crawler and script on the internet.
Your VPS has an address like 203.0.113.10. Anyone who knows it — and bots know everything — can try every port on it.
Every service you start on a port is reachable from anywhere: Grafana on :3000, your admin on :8080, Postgres on :5432, SSH on :22.
Bots constantly scan the internet for known admin panels and default credentials. An exposed Grafana gets found within hours, not days.
Your website can stay public. But admin tools, databases and SSH should be reachable from your devices — and only your devices.
No tunnel yet — every service answers anyone who asks.
Same boxes, same ports — but now every one of them also answers the credential-stuffing bots. That is the problem this whole deck solves.
The best attack surface is the one that doesn't exist — keep your admin tools off the public internet entirely.
One idea, two jobs: an encrypted pipe and a private network. Get this and WireGuard vs Zerotier becomes easy.
Everything you send through the tunnel becomes unreadable gibberish to anyone on the wire — your ISP, the café Wi-Fi, anyone sniffing. Encryption = nobody can read your traffic.
Your devices get internal addresses (like 10.0.0.2) and can reach each other — and your VPS — as if you were all plugged into one LAN at home.
A VPN network is an 'overlay': a private network laid over the public internet. The internet carries the tunnel; the tunnel carries you.
HTTPS protects one browser tab talking to one site. A VPN protects every app on your whole device — and adds the private network on top.
Laptop + phone → the tunnel → private net → VPS admin. The internet only ever sees an encrypted blob.
From inside the tunnel, the VPS is just a neighbour on your LAN — addressed by its private IP, no public admin ports at all.
On a shared network — café, airport, hotel — traffic is easy to capture. Encrypted, the capture is useless: ciphertext, no keys, no reading. Your admin login and data can't be sniffed in transit.
Your laptop at the café and your VPS live on different networks — no route between them. The overlay gives both an address in the same private network, so 'reach 10.0.0.1' just works, from anywhere, over any connection.
Ranges like 10.0.0.0/20 don't route on the public internet — they only exist inside your overlay. Your home router does the exact same thing with 192.168.x.x.
On the VPS you run the tunnel's server (WireGuard or Zerotier). It takes 10.0.0.1, and every device in the tunnel can address it directly — no DNS, no public ports for admin.
Café Wi-Fi, 4G, hotel, office — doesn't matter. Inside the tunnel you're on the same private network, so the admin panel is just 'http://10.0.0.1:3000'.
The operator's move: put your product on the public internet, and everything you manage behind the tunnel.
Grafana, your app's admin, the dashboard where you make things happen. One exposed login form is a magnet for credential stuffing.
Postgres or Mongo on :5432/:27017 should never answer strangers. If they did, they'd answer bots — and bots already have SQL ready to go.
:22 is the most scanned port on earth. Behind the tunnel your shell is reachable from your laptop — not from a botnet.
Your website, public API, docs, checkout — the things your users need. Public is fine (and good) for them. The rule is about tools, not products.
The internet sees one door. Your devices hold the key.
Same VPS, same services — now reachable only from inside the tunnel. The scanner keeps knocking; nothing admin answers.
The website, the public API, the docs, the checkout. Users need them, and HTTPS already protects the data in transit. Exposure here is the point.
Grafana, the admin panel, the database, SSH, backup endpoints. Nothing here has a legitimate stranger. If you can't name who should reach it, keep it behind the tunnel.
If a stranger could open it, it's not an admin panel — it's an invitation.
The modern default for a self-hosted tunnel: tiny, fast, and simple enough to hold in your head.
Designed in 2013, released in 2016. Newer than OpenVPN, built on modern crypto (ChaCha20-Poly1305), and it lives in the Linux kernel — so it's fast.
The whole protocol is a few thousand lines of auditable code. No hundreds-of-pages config to fear — a small INI file per device, that's it.
Every device has a private key (its secret) and a public key (its name). The server only opens the door for public keys you have told it to trust.
The server runs on your VPS. That's the trade: full control, zero service — you generate the keys, write the config, and keep them safe.
On the VPS: wg genkey gives the server's private key, and the matching public key. Each device gets its own pair the same way.
The server takes an interface on a private subnet — say 10.0.0.1/20 — listens on a port (51820), and lists each trusted client under a [Peer] section.
Each [Peer] holds the client's public key and its AllowedIPs — the one private address it may use, e.g. 10.0.0.2/32. New laptop? Add a [Peer].
The client's config points at the server's public IP (Endpoint = 203.0.113.10:51820), carries the server's public key, and claims its own private address.
Load the config in the client app. Instantly your laptop is 10.0.0.2 on the private net — and 10.0.0.1 (the VPS) is reachable by its internal address.
[Interface]
# the VPS: server end of the tunnel
Address = 10.0.0.1/20
ListenPort = 51820
PrivateKey = <server-private-key>
[Peer]
# Alice's laptop — the only client we trust
PublicKey = <alice-public-key>
AllowedIPs = 10.0.0.2/32
Two sections: [Interface] is the server itself; [Peer] is one trusted client. More clients = more [Peer] blocks.
[Interface]
# Alice's laptop, inside the tunnel
Address = 10.0.0.2/20
PrivateKey = <alice-private-key>
[Peer]
# the VPS — the server end
PublicKey = <server-public-key>
Endpoint = 203.0.113.10:51820
AllowedIPs = 10.0.0.0/20
The client's [Peer] is the server. Endpoint = the VPS's public IP; AllowedIPs = 'everything in the private net goes through the tunnel'.
On the server, one command tells you every peer and whether it's actually alive.
A few thousand lines of code, audited by many eyes. Fewer lines, fewer holes — and the config is small enough to read end to end.
Modern crypto in the Linux kernel. You genuinely won't feel the difference — it's just free performance.
Every device = generate a key pair, paste the public key into a [Peer], hand the private config to that device. Private keys never travel in the open.
Ten devices, three networks, a phone that keeps reconnecting — that's when the bookkeeping of keys and configs starts to feel like a job.
The same private-network idea, with the coordination outsourced to the cloud.
You create a Zerotier network in the cloud and get a 16-digit ID, like 914b7c2a5d6e8f30. That ID is the whole 'server' — there is no server of yours.
Every device runs the Zerotier client and joins with that ID. Inside the network, every device can reach every other by its internal Zerotier address.
Zerotier's cloud acts as the address book: it knows who's in the network and introduces members to each other. After the intro, traffic goes device-to-device.
Members reach out to the cloud and to each other outbound — NAT traversal handles the awkward cases, with cloud relay as the fallback. Nothing inbound, ever.
The network ID comes from the Zerotier admin console. That's the entire setup on this machine.
After the cloud introduces two members, their traffic flows peer-to-peer, encrypted. The cloud sees who's talking to whom — but not what they say.
Behind home routers and 4G, devices usually still manage to punch direct paths to each other. When they can't, Zerotier's relay carries the traffic — slightly slower, still private.
Your members' identities live in Zerotier's cloud, managed from a web console. Convenient — and one more trust to weigh in the decision.
The console lets you allow/deny specific members, or whole subnets. Kick a laptop = flip one switch in the browser.
Same destination — a private, encrypted network. Two very different ways to run it.
The same private network, two operating models.
| WireGuard | Zerotier | |
|---|---|---|
| Who coordinates | You — the server on your VPS | Zerotier's cloud |
| Runs on | your VPS, kernel module | client apps + their cloud |
| Config effort | a small INI per device, keys to manage | one join command per device |
| Ports to open | one (e.g. 51820/udp) on the VPS | none — outbound only |
| Removing a device | delete its [Peer] block | one switch in the web console |
| Good fit | one VPS + your machines, full control | many devices, fast setup, no ports |
You self-host and manage the keys. Maximum control and simplicity — the server is a small program on your VPS, and every trust decision is yours.
Managed cloud coordination, less config. You trade a bit of control and one external dependency for near-zero setup and a console to manage members.
The older, extremely common workhorse — you'll meet it in companies and older tutorials. Same job, more config, more moving parts. For a new VPS in 2026, start with WireGuard or Zerotier.
WireGuard and Zerotier both ship client apps for macOS, Linux, iOS and Android. On your phone it's literally: open the app, load the config (or join the ID), toggle it on.
One VPS + your laptop and phone? WireGuard — it's small, fast, and fully yours. A dozen devices, no ports allowed, or you just want it done today? Zerotier.
The VPN is the secure back door to your infrastructure — the internet gets your product, and your tools stay behind the tunnel.
Website public, admin private: pick WireGuard or Zerotier, put the tunnel on your VPS, and never open an admin port to the world again.