When exposing a local server located behind a residential CGNAT (Carrier-Grade NAT) to the public internet using a cloud VPS as a front-end gateway, standard DNAT/MASQUERADE setups rewrite incoming packets with the WireGuard gateway's internal IP. This destroys client IP visibility, making rate-limiting, geo-blocking, and security auditing impossible. Here is how to configure policy-based routing and iptables PREROUTING to preserve the original client IP all the way to your backend application.
1. Cloud VPS Gateway Configuration
On the cloud VPS, forward external ports directly through the WireGuard interface (wg0) without applying SNAT/MASQUERADE to the incoming packets:
# Enable IP forwarding
sysctl -w net.ipv4.ip_forward=1
# Forward HTTP port 80 to WireGuard client (10.200.200.2)
iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 10.200.200.2:80
iptables -A FORWARD -p tcp -d 10.200.200.2 --dport 80 -j ACCEPT
2. Home Server Policy Routing (The Secret to Preserving IPs)
Because the incoming packet preserves the public client IP, the home server's reply would normally route through its default residential gateway rather than returning via the WireGuard tunnel (causing asymmetric routing drop). Resolve this using Linux policy routing:
# 1. Create a custom routing table
echo "200 custom_vpn" >> /etc/iproute2/rt_tables
# 2. Route responses to traffic arriving on wg0 back through wg0
ip rule add from 10.200.200.2 table custom_vpn
ip route add default via 10.200.200.1 dev wg0 table custom_vpn
Now your backend web application logs the true public client IP address for every visitor!