Skip to content

VPN & Tunneling Footguns

  1. MTU mismatch causing silent packet drops. Large packets work fine on the LAN but fail through the VPN tunnel. SSH works (small packets), but SCP stalls, web pages half-load, or database queries timeout. The tunnel adds headers that push packets over the path MTU, and PMTUD is often broken. Fix: Set the tunnel interface MTU to account for encapsulation overhead. WireGuard: MTU = 1420. OpenVPN: mssfix 1400 or tun-mtu 1420. Test with ping -s 1400 -M do through the tunnel and adjust.

    Debug clue: If SSH works but SCP stalls, web pages half-load, or large database queries timeout through a VPN, suspect MTU. Small packets (SSH keystrokes) fit; large packets get silently dropped when PMTUD is broken. The ping -s <size> -M do test reveals the exact breakpoint.

  2. DNS leaks bypassing the VPN. You configure a full-tunnel VPN but DNS queries still go to your ISP or local resolver, revealing every domain you access. You think you are protected, but your browsing activity is fully visible. Fix: Set DNS in the VPN client config (DNS = 10.0.0.1 for WireGuard, push "dhcp-option DNS" for OpenVPN). Verify with dig +short whoami.akamai.net — the response should be your VPN server's IP, not your ISP's.

  3. Split-brain routing (routing VPN traffic through the VPN). You set AllowedIPs = 0.0.0.0/0 for a full tunnel but the VPN endpoint's own packets also match, creating a routing loop. The tunnel connects for a moment then dies as the encapsulated packets try to route through themselves. Fix: Use wg-quick which handles this automatically. If managing routes manually, add a specific host route for the VPN endpoint via the physical gateway before setting the default route through the tunnel.

  4. Missing PersistentKeepalive behind NAT. Your WireGuard client is behind a home router (NAT). The VPN works initially, but after a few minutes of idle time, the NAT mapping expires and the server can no longer reach the client. Incoming connections fail until the client sends traffic. Fix: Add PersistentKeepalive = 25 to the peer configuration on the NAT'd side. This sends an empty packet every 25 seconds to keep the NAT mapping alive.

  5. Running OpenVPN over TCP (TCP-over-TCP meltdown). You choose TCP mode because UDP is blocked by a firewall. Now TCP retransmissions in the outer tunnel conflict with TCP retransmissions in the inner connection, causing exponential backoff cascades. Performance degrades badly under any packet loss. Fix: Use UDP whenever possible. If UDP is blocked, use OpenVPN over TCP as a last resort and be aware of the performance tradeoff. Consider WireGuard (UDP-only but often passes through firewalls on common ports).

    Under the hood: TCP-over-TCP meltdown was first described by Olaf Titz in 2001. The inner and outer TCP layers both maintain retransmission timers. When a packet is lost, both layers retransmit independently, causing exponential backoff cascades. Under even 1-2% packet loss, throughput can collapse to near zero. This is a fundamental protocol interaction, not a bug in OpenVPN.

  6. Using pre-shared keys instead of public key infrastructure for IPSec at scale. You configure IPSec between 20 sites using the same pre-shared key. When one site is compromised, the attacker has the PSK for every tunnel. Rotating the key requires touching every device. Fix: Use certificate-based authentication for IPSec at scale. Each peer gets its own certificate signed by a common CA. Revoking one compromised peer does not affect others. PSK is acceptable for two-site setups.

  7. Forgetting to enable IP forwarding on the VPN server. The VPN tunnel is up and clients can ping the server's tunnel IP, but they cannot reach anything beyond the server. Traffic arrives at the server but is not forwarded to the destination network. Fix: Enable IP forwarding: sysctl net.ipv4.ip_forward=1. Add iptables MASQUERADE or SNAT rules for the outbound interface. Make both changes persistent (/etc/sysctl.d/ and iptables-save or firewalld rules).

  8. Exposing the VPN management interface to the internet. OpenVPN's management interface or WireGuard's configuration endpoint is accessible from the public internet. An attacker can disconnect clients, extract config, or pivot into the network. Fix: Bind management interfaces to localhost only. Use firewall rules to restrict access to VPN ports to expected source IPs where possible. For WireGuard, the kernel interface is silent to unauthenticated packets, but iptables rules are still good defense-in-depth.

  9. Not monitoring VPN tunnel health. The VPN tunnel goes down at 3 AM. Nobody notices until morning when developers cannot access staging. Six hours of lost productivity because there was no monitoring. Fix: Monitor tunnel state (interface up/down), handshake recency (WireGuard: latest handshake age), and traffic counters. Alert when the last handshake exceeds 5 minutes or when the interface goes down. Use wg show output for monitoring scripts.

  10. Leaving WireGuard private keys with wrong file permissions. The private key file is world-readable. Any local user can read it and impersonate the VPN peer, or decrypt captured tunnel traffic. Fix: chmod 600 /etc/wireguard/privatekey and chmod 600 /etc/wireguard/wg0.conf (the config file also contains the private key). Verify with ls -la /etc/wireguard/. wg-quick warns about this but does not enforce it.

    Remember: The WireGuard private key is the single most sensitive item in your VPN setup. Treat it like a root password. A compromised private key lets an attacker impersonate the peer and decrypt all captured tunnel traffic. Generate keys inside a subshell with restrictive umask: (umask 077 && wg genkey > privatekey).