Networking

WireGuard NAT / MASQUERADE (PostUp & PostDown Rules)

3 min read

For clients to reach anything beyond the WireGuard server (the internet, or the server’s LAN), the server must forward and masquerade their traffic. WireGuard runs these as PostUp/PostDown commands in the server’s [Interface].

iptables (most common)

Replace eth0 with the server’s outbound interface (ip route show default):

PostUp   = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

%i is the WireGuard interface (wg0). The FORWARD rule permits forwarding; MASQUERADE rewrites the source IP to the server’s so replies come back.

With IPv6 too

PostUp   = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; ip6tables -A FORWARD -i %i -j ACCEPT; ip6tables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; ip6tables -D FORWARD -i %i -j ACCEPT; ip6tables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

nftables variant (modern distros)

PostUp   = nft add table inet wg; nft add chain inet wg post '{ type nat hook postrouting priority 100 ; }'; nft add rule inet wg post oifname "eth0" masquerade; nft add chain inet wg fwd '{ type filter hook forward priority 0 ; }'; nft add rule inet wg fwd iifname "%i" accept
PostDown = nft delete table inet wg

The PostDown simply drops the whole inet wg table, cleaning up every rule at once.

Don’t forget IP forwarding

NAT does nothing without forwarding enabled — see the IP-forwarding recipe (net.ipv4.ip_forward = 1).

Verify

sudo iptables -t nat -L POSTROUTING -n -v    # see the MASQUERADE rule + packet counts
# from a client:
curl ifconfig.me                              # should show the server's IP (full tunnel)

Wrong interface = no traffic. The single most common mistake is leaving eth0 when the WAN NIC is ens3, enp1s0, etc. Check with ip route show default and use that name in the rules.

Open the full version (with copy buttons) ↗

← All recipes