Routing, DNS, and privacy
Understand forwarding, NAT, and egress
Follow a packet across a VPN gateway and know why forwarding and address translation may be required for Internet access.
A VPN endpoint that moves traffic between interfaces is acting as a gateway. Packets arrive on wg0 and need to leave through eth0.
By default, Linux refuses to do that. It behaves as a host, not a router. Packets addressed to someone else get dropped. So the first step is to allow IP forwarding:
sudo sysctl -w net.ipv4.ip_forward=1
echo 'net.ipv4.ip_forward=1' | sudo tee /etc/sysctl.d/99-wireguard.conf
The first command applies the setting now. The second makes it survive reboots. You can confirm it with sysctl net.ipv4.ip_forward, which should print = 1.
Forwarding alone is not enough for Internet access. Think about the packet the client sends. Its source address is 10.14.0.2, a private address. The web server replies to 10.14.0.2, and the first Internet router that sees that reply drops it. There is no return path.
So for Internet egress, the gateway replaces the client’s source address with its own public address. This is source NAT, and on Linux we usually do it with masquerading:
sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
Every packet leaving through eth0 now carries the server’s address. Replies come back to the gateway, which maps them to the right VPN client using its connection-tracking table. Neither end notices the rewriting.
Let’s verify the whole chain from the client:
curl https://ifconfig.me
# 203.0.113.10 ← the gateway's public address, not yours
If you see the gateway’s address, forwarding and NAT both work. If the command hangs, one of them is missing.
Private-network access is a different story. If the office network knows a route back to 10.14.0.0/24, no address rewriting is needed. Real routes carry traffic in both directions. I prefer routing whenever both sides can learn the return path. Destination logs keep the real client addresses, and you carry no NAT state that can fill up or expire in the middle of a connection.
Now the classic failure. The handshake works, pinging the gateway’s 10.14.0.1 works, and nothing beyond it responds. That pattern almost always means forwarding is off or the masquerade rule vanished. iptables rules do not survive reboots unless you persist them, so a server that worked yesterday can break overnight.
Check both before touching anything else:
sysctl net.ipv4.ip_forward
# net.ipv4.ip_forward = 1
sudo iptables -t nat -L POSTROUTING -n
# MASQUERADE all -- 0.0.0.0/0 0.0.0.0/0
A 0 on the first line or an empty chain on the second tells you exactly what to fix.
Lesson completed