Introduction
Set up a production-ready WireGuard VPN server on a cloud VPS with automatic key management, split tunneling, and monitoring. This comprehensive guide covers everything from design through implementation, testing, and deployment.
Set up a production-ready WireGuard VPN server on a cloud VPS with automatic key management, split tunneling, and monitoring.
Set up a production-ready WireGuard VPN server on a cloud VPS with automatic key management, split tunneling, and monitoring. This comprehensive guide covers everything from design through implementation, testing, and deployment.
WireGuard advantages: state-of-the-art cryptography (Curve25519, ChaCha20-Poly1305, BLAKE2s), only ~4000 lines of code (vs OpenVPN's 100,000+ — much smaller attack surface), faster handshake (unlike OpenVPN's SSL negotiation), faster performance (3–5× throughput vs OpenVPN in benchmarks). Integrated into Linux kernel since 5.6 (March 2020) — no module needed on modern kernels. Connect/disconnect in milliseconds (OpenVPN takes 5–10s). WireGuard is the recommended modern VPN protocol.
10 components required for this project.
| # | Component | Purpose | Qty |
|---|---|---|---|
| 1 | Ubuntu 22.04 VPS (DigitalOcean/Linode/Vultr) | VPN server host | x1 |
| 2 | Domain name (for DNS) | Dynamic DNS for VPN endpoint | x1 |
| 3 | WireGuard kernel module | High-performance VPN kernel integration | x1 |
| 4 | wireguard-tools package | Key generation and configuration | x1 |
| 5 | UFW firewall | Server firewall management | x1 |
| 6 | Fail2Ban | Brute force protection | x1 |
| 7 | Python 3 + QRcode library | Mobile client QR code generation | x1 |
| 8 | Prometheus + Grafana | VPN usage monitoring | x1 |
| 9 | Certbot | Let's Encrypt TLS certificate | x1 |
| 10 | Nginx (reverse proxy) | Management web interface | x1 |
Follow these 5 steps carefully.
WireGuard advantages: state-of-the-art cryptography (Curve25519, ChaCha20-Poly1305, BLAKE2s), only ~4000 lines of code (vs OpenVPN's 100,000+ — much smaller attack surface), faster handshake (unlike OpenVPN's SSL negotiation), faster performance (3–5× throughput vs OpenVPN in benchmarks). Integrated into Linux kernel since 5.6 (March 2020) — no module needed on modern kernels. Connect/disconnect in milliseconds (OpenVPN takes 5–10s). WireGuard is the recommended modern VPN protocol.
Generate server keys: wg genkey | tee server_private.key | wg pubkey > server_public.key. Create /etc/wireguard/wg0.conf: [Interface] with Address (VPN subnet, e.g., 10.0.0.1/24), ListenPort 51820, PrivateKey from server_private.key, and PostUp/PreDown rules for NAT (iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o eth0 -j MASQUERADE). Enable IP forwarding: sysctl -w net.ipv4.ip_forward=1 (add to /etc/sysctl.conf for persistence).
For each client: generate client_private.key and client_public.key. Add [Peer] to server config: PublicKey=client public key, AllowedIPs=10.0.0.2/32 (one IP per client). Client config file: [Interface] Address=10.0.0.2/32, DNS=10.0.0.1 (optionally, server-side Pi-hole), PrivateKey=client private key. [Peer] PublicKey=server public key, Endpoint=your_server_ip:51820, AllowedIPs=0.0.0.0/0 (full tunnel) or 192.168.x.0/24 (split tunnel for home network only). Generate QR code for mobile: qrencode -t PNG -o client.png < client.conf.
Full tunnel: AllowedIPs=0.0.0.0/0, ::/0 — all traffic through VPN. Split tunnel: AllowedIPs=192.168.50.0/24, 10.0.0.0/24 — only specific subnets through VPN, internet traffic goes direct. Split tunneling reduces VPN server bandwidth usage and improves performance for non-VPN-critical traffic. Use split tunnel for remote access to home network resources. Use full tunnel for privacy/security when on untrusted public WiFi.
SSH hardening: disable password auth (only SSH keys), change default port (e.g., 2222), enable fail2ban. UFW firewall: allow SSH port, allow 51820/UDP (WireGuard), deny everything else. Regular security updates: unattended-upgrades package. Monitor connections: wg show displays active peers, their IP, and last handshake time. Log all connections to syslog. Rate limiting: WireGuard has no built-in rate limiting — protect with network-level rules for DoS resistance.
Core code for wireguard_setup.sh:
#!/bin/bash # WireGuard Server Quick Setup Script # Run as root on Ubuntu 22.04 apt update && apt install -y wireguard qrencode # Generate server keys umask 077 wg genkey | tee /etc/wireguard/server_private.key | wg pubkey > /etc/wireguard/server_public.key SERVER_PRIVATE=$(cat /etc/wireguard/server_private.key) SERVER_PUBLIC=$(cat /etc/wireguard/server_public.key) SERVER_IP=$(curl -s ifconfig.me) # Server config cat > /etc/wireguard/wg0.conf << EOF [Interface] Address = 10.8.0.1/24 ListenPort = 51820 PrivateKey = $SERVER_PRIVATE PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE PreDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE EOF # Enable and start sysctl -w net.ipv4.ip_forward=1 echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf systemctl enable wg-quick@wg0 systemctl start wg-quick@wg0 echo "Server public key: $SERVER_PUBLIC" echo "Server IP: $SERVER_IP:51820" # Generate first client config add_client() { CLIENT_PRIVATE=$(wg genkey) CLIENT_PUBLIC=$(echo $CLIENT_PRIVATE | wg pubkey) CLIENT_IP="10.8.0.2" echo "[Peer]" >> /etc/wireguard/wg0.conf echo "PublicKey = $CLIENT_PUBLIC" >> /etc/wireguard/wg0.conf echo "AllowedIPs = $CLIENT_IP/32" >> /etc/wireguard/wg0.conf # Client config cat > client1.conf << CONF [Interface] PrivateKey = $CLIENT_PRIVATE Address = $CLIENT_IP/24 DNS = 1.1.1.1 [Peer] PublicKey = $SERVER_PUBLIC Endpoint = $SERVER_IP:51820 AllowedIPs = 0.0.0.0/0 PersistentKeepalive = 25 CONF qrencode -t ansiutf8 < client1.conf echo "Client config saved to client1.conf" } add_client
Test WireGuard VPN Server by verifying each subsystem individually before full integration.
Verify power voltages, check ground connections, use serial monitor for debug.
An interactive simulator will be available here — simulate circuits and run code in-browser without hardware.