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
- PersistentKeepalive: Set to
25on the client side if behind NAT, this keeps the tunnel alive - DNS: If routing all traffic through the tunnel, don’t forget to set
DNS = 1.1.1.1on the client - 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.