WireGuard Peer Unreachable — Tunnel Debugging
Fix a WireGuard tunnel where peers can't reach each other. Covers handshake failure, AllowedIPs + routing, UDP firewalling, IP forwarding, and NAT/masquerade for site-to-site setups.
`wg show` answers 80% of WireGuard questions in one call.
wg show && echo '---' && ip -brief addr show wg0 && echo '---' && ip -brief link show wg0
Each side must list the OTHER side's public key. A swapped-key config silently produces zero handshakes forever.
# On peer A: wg show wg0 peers grep -E 'PublicKey|Endpoint|AllowedIPs' /etc/wireguard/wg0.conf # On peer B: wg show wg0 peers grep -E 'PublicKey|Endpoint|AllowedIPs' /etc/wireguard/wg0.conf # Derive A's public key to compare: wg pubkey < /etc/wireguard/privatekey
WireGuard is UDP-only; many firewalls silently drop UDP.
# Listen port: grep -i listenport /etc/wireguard/wg0.conf || echo 51820 # From the OTHER peer, probe UDP: nc -u -v -w 3 <peer-endpoint> <port> < /dev/null # On the receiving side, confirm the kernel is actually bound: ss -lunp | grep -E ':(51820|<your-port>)' # Quick tcpdump on the expected interface: tcpdump -n -i any udp port 51820 -c 10
On the receiving side, a packet with source-IP not in AllowedIPs is dropped. On the sending side, AllowedIPs acts as the destination route.
# Per-peer AllowedIPs table: wg show wg0 allowed-ips # Kernel routes to the tunnel: ip route show | grep wg0
If WireGuard is a gateway to a LAN / the internet, the kernel must forward and NAT packets.
sysctl net.ipv4.ip_forward net.ipv6.conf.all.forwarding # iptables/nftables: iptables -t nat -S POSTROUTING | grep MASQUERADE # or: nft list table inet nat 2>/dev/null | grep -i masquerade
Once handshake succeeds and routing is right, verify real traffic flows.
# From peer A to peer B's tunnel IP: ping -c 3 -W 2 <peer-B-tunnel-ip> # From peer A to an endpoint behind peer B: curl -sS --max-time 5 http://<endpoint-behind-B>/ # Watch both sides of the tunnel simultaneously: watch -n 1 'wg show wg0 transfer'
A mismatched PresharedKey, corrupted private key, or reused IP on the tunnel subnet can leave tunnels stuck forever. Fresh keys is the nuclear option.
# Generate new keys: umask 077 wg genkey | tee /etc/wireguard/new.key | wg pubkey > /etc/wireguard/new.pub # Replace PrivateKey in wg0.conf, update the OTHER peer's [Peer] PublicKey to match new.pub, restart: systemctl restart wg-quick@wg0