WireGuard — The Modern VPN Protocol

WireGuard is the modern VPN protocol that’s replaced OpenVPN at most new deployments. It’s faster, simpler, in the Linux kernel, and the entire codebase is small enough to audit (~4000 lines of C vs OpenVPN’s ~600,000 lines of code). Tailscale and Cloudflare WARP are built on it.

Why WireGuard wins

  • Speed — typically 2-3x faster than OpenVPN, lower CPU usage
  • Simplicity — one config file per peer, no PKI to manage
  • In-kernel — no userspace overhead
  • Modern crypto only — no algorithm negotiation, no downgrade attacks
  • Connectionless — works well with mobile devices roaming between networks
  • Auditable — small enough that security researchers actually read it

The mental model: peers, not client/server

WireGuard treats every endpoint as a “peer.” There’s no inherent client or server distinction — it’s a mesh of peers that have each other’s public keys and know how to reach each other.

In practice, you usually have one peer with a public IP that “listens” (the server) and others that initiate connections to it (the clients). But the protocol itself doesn’t care.

Cryptography (no choices, no downgrades)

  • Key exchange: Curve25519
  • Symmetric encryption: ChaCha20
  • Authentication: Poly1305
  • Hashing: BLAKE2s

You don’t pick. WireGuard uses these. If a flaw is found, the entire protocol gets a new version.

Generate keys

wg genkey | tee privatekey | wg pubkey > publickey
cat privatekey   # secret — protect like an SSH key
cat publickey    # share with the other peer

Server config (/etc/wireguard/wg0.conf)

[Interface]
PrivateKey = SERVER_PRIVATE_KEY
Address = 10.10.0.1/24
ListenPort = 51820

# allow forwarding + NAT for clients
PostUp = iptables -A FORWARD -i %i -j ACCEPT
PostUp = iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT
PostDown = iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

[Peer]
# laptop
PublicKey = LAPTOP_PUBLIC_KEY
AllowedIPs = 10.10.0.2/32

[Peer]
# phone
PublicKey = PHONE_PUBLIC_KEY
AllowedIPs = 10.10.0.3/32

Client config

[Interface]
PrivateKey = LAPTOP_PRIVATE_KEY
Address = 10.10.0.2/24
DNS = 1.1.1.1

[Peer]
PublicKey = SERVER_PUBLIC_KEY
Endpoint = vpn.example.com:51820
AllowedIPs = 0.0.0.0/0   # route ALL traffic through VPN
PersistentKeepalive = 25

Bring it up

# Start
sudo wg-quick up wg0

# Status
sudo wg show

# Auto-start on boot
sudo systemctl enable wg-quick@wg0

# Stop
sudo wg-quick down wg0

The AllowedIPs field is also routing

This is the most-confused WireGuard concept. AllowedIPs serves two purposes:

  1. From this peer: only accept packets from these source IPs
  2. To this peer: route traffic for these destination IPs to this peer

So AllowedIPs = 0.0.0.0/0 on a client means “send all my traffic to this peer.” On a server, it means “this client can send packets from any IP” — which you probably don’t want.

Mobile clients

Official WireGuard apps for iOS and Android. Scan a QR code generated from your config and you’re connected. Roaming between Wi-Fi and cellular is handled cleanly because WireGuard has no concept of session state to break.

# Generate a QR code from a config (server side)
qrencode -t ansiutf8 < phone.conf

WireGuard-based services

  • Tailscale — managed mesh VPN built on WireGuard. No config files, just install and log in. Excellent for remote teams.
  • Cloudflare WARP — consumer Cloudflare service that uses WireGuard under the hood.
  • NetMaker — open-source self-hosted alternative to Tailscale.

Common mistakes

  • Forgetting to enable IP forwarding: sysctl -w net.ipv4.ip_forward=1
  • Wrong AllowedIPs (sends traffic to wrong peer or doesn’t route at all)
  • Forgetting to open UDP 51820 in firewall
  • Public key in PrivateKey field (don’t paste the wrong one)
  • Not setting PersistentKeepalive on clients behind NAT (NAT entry expires)

What to learn next

SSH tunnels — local, remote, dynamic forwarding. SSH as a poor-man’s VPN. Up next.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *