Why WireGuard over OpenVPN or commercial VPNs
WireGuard has a codebase roughly 100 times smaller than OpenVPN. Fewer lines of code means a smaller attack surface, faster security audits, and measurably lower overhead. Benchmarks consistently show WireGuard delivering 2 to 4 times the throughput of OpenVPN at lower latency.
Compared to commercial VPN services, running your own on a Raspberry Pi means your traffic goes directly to your home network rather than through a third-party server. You control the keys, the logs (or complete absence of them), and every endpoint.
Requirements
Before starting, make sure you have:
- Raspberry Pi 3B+, 4, or 5 running Raspberry Pi OS 64-bit (Lite recommended)
- Static local IP for your Pi - see our static IP guide first
- Port forwarding access on your router - you will open UDP port 51820
- A public hostname - if your ISP gives you a dynamic IP, set up DuckDNS first
Some ISPs, particularly mobile broadband providers, use carrier-grade NAT. If your router WAN IP starts with 100.64.x.x, you are behind CGNAT and cannot receive inbound connections. Use a Cloudflare Tunnel or a VPS relay as an alternative.
Step 1: Install WireGuard
WireGuard is included in the Linux kernel since version 5.6. On Raspberry Pi OS Bullseye or Bookworm, the kernel module is already present. Install the userspace tools:
sudo apt update
sudo apt install wireguard -y
Verify the module loads cleanly:
sudo modprobe wireguard
lsmod | grep wireguard
Step 2: Generate server keys
WireGuard uses public-key cryptography. Each endpoint needs its own key pair. Generate the server keys and set secure permissions:
wg genkey | sudo tee /etc/wireguard/server_private.key | wg pubkey | sudo tee /etc/wireguard/server_public.key
sudo chmod 600 /etc/wireguard/server_private.key
Note both values. You will need the server public key when configuring clients.
Step 3: Configure the WireGuard interface
Create the server configuration file:
sudo nano /etc/wireguard/wg0.conf
Add the following, replacing SERVER_PRIVATE_KEY with the content of server_private.key:
[Interface]
Address = 10.8.0.1/24
ListenPort = 51820
PrivateKey = SERVER_PRIVATE_KEY
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
Save with Ctrl+X, Y, Enter. Lock down the config file permissions:
sudo chmod 600 /etc/wireguard/wg0.conf
Enable IP forwarding so VPN clients can reach your LAN devices:
echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
Step 4: Add client devices
For each device you want to connect, generate a client key pair on the Pi:
wg genkey | tee client1_private.key | wg pubkey > client1_public.key
Add the client as a peer in wg0.conf:
[Peer]
PublicKey = CLIENT1_PUBLIC_KEY
AllowedIPs = 10.8.0.2/32
Create a client configuration to import into the WireGuard app:
[Interface]
PrivateKey = CLIENT1_PRIVATE_KEY
Address = 10.8.0.2/32
DNS = 1.1.1.1
[Peer]
PublicKey = SERVER_PUBLIC_KEY
Endpoint = your-ddns-hostname.duckdns.org:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
Use AllowedIPs = 192.168.1.0/24 instead of 0.0.0.0/0 for split tunneling, where only home network traffic routes through the VPN.
Step 5: Start WireGuard and enable on boot
Start the interface and enable automatic startup:
sudo systemctl enable wg-quick@wg0
sudo systemctl start wg-quick@wg0
sudo wg show
The wg show output should display your server public key and listening port.
Step 6: Port forwarding on your router
Log into your router admin panel and create a UDP port forwarding rule pointing external UDP port 51820 to your Pi's static LAN IP on port 51820. The exact menu location varies by router model but is usually found under Advanced, NAT, or Firewall settings.
Testing the connection
Install the WireGuard app on your phone from the App Store or Google Play. Import the client configuration file or scan a QR code generated with:
qrencode -t ansiutf8 < client1.conf
Turn off Wi-Fi on your phone so it uses mobile data, then toggle the VPN tunnel on. Try accessing a device on your home LAN by its local IP address. On the Pi, run sudo wg show to confirm the latest handshake.
Troubleshooting common issues
No handshake after connecting: Verify UDP port 51820 is correctly forwarded in your router. Test with an external port checker tool.
Connected but cannot reach LAN devices: Confirm IP forwarding is active: cat /proc/sys/net/ipv4/ip_forward should return 1. Verify the PostUp iptables rules are present in wg0.conf.
DNS not resolving: Set the DNS in your client config to your Pi's LAN IP if you run Pi-hole, or use 1.1.1.1 as a fallback.
Marcus has run WireGuard on Raspberry Pi since it was merged into the Linux kernel in 2020. He tests every network guide on a Pi 4 and Pi 5 before publishing.