Reach your home server without opening ports - WireGuard vs Tailscale
Three ways in: port forward + DDNS, plain WireGuard, Tailscale or Headscale. A minimal Ubuntu 24.04 config, the trade-offs, and what still needs hardening behind a VPN.
- A port exposed to the internet is scanned and attacked within hours, not days
- WireGuard stays silent to packets without a valid key, so scanners see nothing - but it still needs one UDP port on the router
- Tailscale gets through NAT with no open port at all, in exchange for a third party in the control plane (Headscale removes it)
- A public web service should not run from the home box; put a VPS reverse proxy or a tunnel in front
Getting into the machine at home from outside is two half-problems. The “name” half is that your home IP keeps changing; DDNS solves that (companion article). The “access” half is how a packet from outside reaches your box at all without turning it into a target for every bot on the internet. This article is about the second half, comparing three routes: the classic port forward, self-managed WireGuard, and Tailscale.
Every command was tested on Ubuntu 24.04.
Why an open port gets hit immediately
Nobody is targeting your house. Bots simply sweep the whole IPv4 space all day. Palo Alto Networks’ Unit 42 put 320 honeypots on public clouds (2021): 80% were compromised within 24 hours and every one of them within a week. SSH was the most attacked service, and some services were hit within 30 seconds of going live. A home connection is no different: forward port 22 or 3389 and your logs fill up overnight.
Port forward + DDNS therefore “works”, but you own the security of every service you expose: patched on time, no weak passwords, no admin panel you forgot to disable. One slip and the whole house is in.
WireGuard in one paragraph
WireGuard is a kernel-level VPN stripped down to the essentials. Each side has a Curve25519 key pair (think SSH keys) and knows the other side’s public key in advance. It runs over UDP, does a one-round-trip handshake (Noise_IK) and encrypts with ChaCha20-Poly1305. The security detail that matters here: if an incoming packet fails the key check, the server does not answer at all. No banner, no error, no memory allocated. A scanner sees that port as if nothing were listening, unlike SSH or HTTPS, which greet everyone who knocks.
UDP 51820 with WireGuard listening is in a different league from TCP 22 with sshd listening: without the key you don’t even get a reply.
Minimal WireGuard: server + one peer
This route still needs one UDP port forwarded from the router to the home server (and DDNS so the laptop knows the home IP).
On the home server:
sudo apt install wireguard
umask 077
wg genkey | tee server.key | wg pubkey > server.pub
Do the same on the laptop (giving laptop.key / laptop.pub) and exchange only the .pub files. A .key file never leaves the machine that made it.
Server: /etc/wireguard/wg0.conf
[Interface]
Address = 10.8.0.1/24
ListenPort = 51820
PrivateKey = <contents of server.key>
[Peer]
# laptop
PublicKey = <contents of laptop.pub>
AllowedIPs = 10.8.0.2/32
Laptop: wg0.conf
[Interface]
Address = 10.8.0.2/24
PrivateKey = <contents of laptop.key>
[Peer]
PublicKey = <contents of server.pub>
Endpoint = home.example.net:51820
AllowedIPs = 10.8.0.0/24
PersistentKeepalive = 25
Bring it up on both sides:
sudo wg-quick up wg0
sudo systemctl enable wg-quick@wg0 # start at boot
sudo wg # last handshake and byte counters
From the laptop, ssh dev@10.8.0.1 getting in means you are done.
The trap: AllowedIPs is not just “who may come in”; it is also the routing table (cryptokey routing). The server uses a /32 per peer; the laptop uses the VPN’s /24. Set 0.0.0.0/0 and all of the laptop’s traffic goes via home, which is not what you want here. PersistentKeepalive = 25 is needed when the laptop sits behind NAT; otherwise the NAT forgets the return path after a quiet spell.
What Tailscale adds
Tailscale uses the same WireGuard in the data plane but takes away two chores: key distribution and NAT.
- Coordination server acts as a “drop box for public keys”. Every device logs in with an identity (Google, GitHub, Microsoft and so on), generates its keys locally, uploads only the public key and downloads the public keys of the other devices in the network. No swapping
.pubfiles by hand. - NAT traversal with STUN/ICE punches a direct path between two devices behind different NATs, with no port opened on the router. If that fails (hard NAT, UDP blocked) traffic goes through a DERP relay, which forwards already-encrypted packets it cannot read.
- MagicDNS names every device automatically:
ssh home-nasinstead of an IP. - ACLs are a central policy of who may talk to whom on which port, enforced on every device as packets are decrypted.
- Tailscale SSH (
tailscale set --ssh) uses your tailnet identity instead of SSH keys and can force a fresh MFA sign-in with check mode.
On Ubuntu, run Tailscale’s install script, then sudo tailscale up prints a login link. Every device signed in to the same account can talk straight away.
Tailscale’s trade-offs
- A third party in the control plane. Tailscale cannot read your traffic, but it knows how many devices you have, their names and public IPs, and it decides whose public key is handed to whom. If your identity-provider account is compromised, that person is on every device.
- An external dependency. Control plane down means new devices cannot join (devices already connected keep talking, since the data plane is peer-to-peer).
- The free tier has edges. At the time of writing the pricing page lists Personal as free for 6 users with unlimited devices. This has changed before; check the current pricing page.
- Some advanced features (fine-grained ACL options, audit logs) sit in paid plans; verify against the current docs.
Headscale: your own control plane
Headscale is an open-source reimplementation of Tailscale’s control server. You keep the stock Tailscale clients and point them at your server (tailscale up --login-server https://hs.example.net), getting key distribution, NAT traversal and MagicDNS with no company in the middle.
From the project README: it is deliberately scoped to a single tailnet for self-hosters and small open-source organisations, not large companies. You also need one public server running Headscale (a small VPS is enough) that you maintain yourself. If you keep using Tailscale’s DERP servers, relayed traffic still passes through them when a direct path fails; closing that last gap means running your own DERP too.
Decision table
| Situation | Pick | Why |
|---|---|---|
| Home lab, one user, 2-5 devices | Tailscale free, or plain WireGuard | Tailscale is a 5-minute install with no open port; WireGuard if you want zero dependencies and have only 1-2 peers |
| Small team, several people, several homes | Tailscale (ACLs + SSH) or Headscale | Central identity revokes access instantly when someone leaves; Headscale when policy forbids a third party |
| One public web service for the general public | VPS + reverse proxy, or a tunnel to the home box | The thing being attacked is the VPS, not your home network; the home box dials out to the VPS over WireGuard/Tailscale with no inbound port |
The home box should never take traffic from strangers directly. If you need a public site, let the thing that gets shot at be a $5 VPS, not the NAS with the family photos.
What still needs hardening behind a VPN
A VPN shrinks who can “knock on the door” from the whole internet to devices holding a key. It does not make the door any stronger.
- Updates.
unattended-upgradesis still required. One device on the network catching malware puts every other device in range. - Local firewall. With
ufw, allow services only from the VPN interface, e.g.sudo ufw allow in on wg0 to any port 22(Tailscale’s interface istailscale0), and don’t expose 22 to the LAN unless you need to. - SSH still means keys. Passwords off, root off, as in the SSH hardening article. A VPN is not an excuse to turn passwords back on.
- Treat keys like passwords. Laptop lost = remove the peer from
wg0.confor delete the device in the admin console, immediately. - Unauthenticated LAN services (printers, IoT, admin panels) are visible to every device on the VPN. Keep ACLs or
AllowedIPsas narrow as possible.
Sources
FAQ
Can Tailscale read my traffic?
No. Traffic is WireGuard-encrypted end to end and private keys never leave the device. The coordination server sees public keys, IPs and policy; DERP relays forward already-encrypted packets they cannot decrypt.
Does plain WireGuard need a port forward?
Yes, one UDP port (for example 51820) forwarded to the server. But WireGuard never replies to a packet that fails the key check, so a scanner sees the port as closed. If you want no open port at all, use Tailscale.
How many people can use Tailscale for free?
At the time of writing (Oct 2026) the pricing page lists the free Personal plan at 6 users with unlimited devices. This number has changed several times; check the current pricing page before you plan around it.
Commands and settings were tested on sample systems. Try them on a test machine before production.