WireGuard: Not Connecting — Fix
The Problem
Your WireGuard tunnel won’t establish a connection. Symptoms include: no handshake between peers, the wg show command shows 0 bytes transferred, clients can’t reach the server, or the tunnel connects but internet access stops working.
The Cause
WireGuard connection failures are almost always caused by one of five things: firewall blocking UDP traffic, incorrect endpoint configuration, key mismatches between peers, NAT/port forwarding issues, or AllowedIPs misconfiguration.
The Fix
Method 1: Verify Port Is Open
WireGuard uses UDP (default port 51820). Check your firewall allows it:
# Check if WireGuard is listening
sudo ss -ulnp | grep 51820
# If using UFW
sudo ufw allow 51820/udp
# If using iptables
sudo iptables -A INPUT -p udp --dport 51820 -j ACCEPT
Cloud VPS users: Also check the provider’s firewall panel (Hetzner Cloud Firewall, AWS Security Groups, DigitalOcean Firewall). These block traffic before it reaches your server’s iptables.
Test UDP connectivity from the client:
# On the server, start a temporary listener
nc -u -l 51820
# On the client, send a test packet
echo "test" | nc -u <server-ip> 51820
Method 2: Fix Handshake Failures
Run sudo wg show on both sides:
sudo wg show
If latest handshake is missing or shows (none), the peers aren’t communicating.
Check keys: Each peer’s PublicKey in one config must match the other peer’s PrivateKey-derived public key:
# On server: verify the client's public key matches
wg pubkey < client-private.key
# Output must match [Peer] PublicKey in server's wg0.conf
# On client: verify the server's public key matches
wg pubkey < server-private.key
# Output must match [Peer] PublicKey in client's wg0.conf
Common mistake: Swapping public and private keys. Each side uses its own private key in [Interface] and the other side’s public key in [Peer].
Method 3: Fix Endpoint Configuration
The client’s [Peer] section needs the server’s public IP and port:
[Peer]
PublicKey = <server-public-key>
Endpoint = <server-public-ip>:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
Behind NAT: If either side is behind NAT, add PersistentKeepalive = 25 to maintain the NAT mapping. Without this, the connection drops after the NAT timeout (usually 30-120 seconds).
Dynamic IP: If your server’s IP changes, use a DDNS hostname as the endpoint. WireGuard resolves the hostname once at startup — use a cron job to restart WireGuard if the IP changes, or use a tool like wireguard-vanity-address with dynamic DNS.
Method 4: Fix AllowedIPs
AllowedIPs controls both routing and cryptokey routing (which packets are accepted from which peer). Misconfiguration here is the most common cause of “connected but can’t reach anything.”
Full tunnel (all traffic through VPN):
# Client config
[Peer]
AllowedIPs = 0.0.0.0/0, ::/0
Split tunnel (only VPN subnet):
# Client config
[Peer]
AllowedIPs = 10.0.0.0/24
Server-side: Each peer’s AllowedIPs must include that peer’s VPN IP:
# Server config — for a client with VPN IP 10.0.0.2
[Peer]
AllowedIPs = 10.0.0.2/32
Method 5: Enable IP Forwarding and NAT
If the tunnel connects but clients can’t reach the internet through it, the server isn’t forwarding packets:
# Enable IP forwarding (temporary)
sudo sysctl -w net.ipv4.ip_forward=1
# Enable IP forwarding (permanent)
echo "net.ipv4.ip_forward = 1" | sudo tee -a /etc/sysctl.d/99-wireguard.conf
sudo sysctl -p /etc/sysctl.d/99-wireguard.conf
Add NAT rules in your WireGuard server config:
[Interface]
Address = 10.0.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
Replace eth0 with your server’s actual network interface (check with ip route | grep default).
Method 6: Fix Docker-Specific Issues
If running WireGuard in Docker (e.g., linuxserver/wireguard):
# The container needs NET_ADMIN and SYS_MODULE capabilities
cap_add:
- NET_ADMIN
- SYS_MODULE
# And host networking or proper port mapping
ports:
- 51820:51820/udp
# Sysctl must be set
sysctls:
- net.ipv4.conf.all.src_valid_mark=1
Check that the kernel module is loaded on the host:
sudo modprobe wireguard
lsmod | grep wireguard
If wireguard module isn’t available, install it:
# Ubuntu/Debian
sudo apt install wireguard-tools
# CentOS/RHEL
sudo dnf install wireguard-tools
Prevention
- Test after every config change — run
sudo wg showon both sides to verify the handshake succeeds. - Use
PersistentKeepalive = 25on any peer behind NAT. - Always pin your WireGuard Docker image version — kernel module compatibility matters.
- Document your IP addressing scheme — track which peer gets which IP in
AllowedIPs. - Back up your keys — losing a private key means regenerating keys for all peers that used the corresponding public key.
Related
Get self-hosting tips in your inbox
Get the Docker Compose configs, hardware picks, and setup shortcuts we don't put in articles. Weekly. No spam.
Comments