WireGuard has become my go-to VPN solution for connecting remote machines. It’s fast, simple, and the configuration is refreshingly minimal compared to OpenVPN or IPSec.

Why WireGuard?

After years of wrestling with OpenVPN configs, WireGuard feels like a breath of fresh air:

  • Performance: Runs in kernel space, significantly less overhead
  • Simplicity: A single config file per interface
  • Modern cryptography: ChaCha20, Curve25519, BLAKE2s — no cipher negotiation headaches
  • Small codebase: ~4,000 lines of code vs. OpenVPN’s ~100,000+

Installation

On Debian 12 (Bookworm), WireGuard is available directly:

apt update && apt install -y wireguard

Verify the module is loaded:

modprobe wireguard
lsmod | grep wireguard

Key Generation

Each peer needs a private/public key pair:

wg genkey | tee /etc/wireguard/private.key | wg pubkey > /etc/wireguard/public.key
chmod 600 /etc/wireguard/private.key

Server Configuration

Create /etc/wireguard/wg0.conf:

[Interface]
PrivateKey = <server-private-key>
Address = 10.0.0.1/24
ListenPort = 51820
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

[Peer]
PublicKey = <client-public-key>
AllowedIPs = 10.0.0.2/32

Start it up:

wg-quick up wg0
systemctl enable wg-quick@wg0

Verifying the Tunnel

wg show wg0

You should see the peer listed with a recent handshake timestamp. If latest handshake shows “never”, check firewall rules and ensure UDP port 51820 is open.

Tips

  1. PersistentKeepalive: Set to 25 on the client side if behind NAT, this keeps the tunnel alive
  2. DNS: If routing all traffic through the tunnel, don’t forget to set DNS = 1.1.1.1 on the client
  3. MTU: Default is usually fine, but if you see packet fragmentation issues, try setting MTU = 1380

WireGuard is one of those tools that just works once configured correctly. The hardest part is usually getting the firewall rules right.