Wireguard Client - Exit node CGNAT with VPS

Hello everyone,

Unfortunately my previous simple set-up with one wireguard client and one wireguard server will no longer be possible as the local company provided a 5G router instad of fixing the normal line.

Considering that I can’t afford to leak my real IP address I’ve excluded the option of usingTailscale as seems that might leak it in case of high memory usage.

I’ve worked out a set-up with a VPS set-up that involves using 2 wireguard client that with keepalive reach the server with public IP. The set-up works if I use the configuration file for the home router in a windows machine therefore I assume that the configuration works properly.
When i transfer the wireguard file (that is working on windows) on my GL-MT3000 (firmware 4.8.1) from my phone I can ping the router and the VPS but the web surfing is not working.

I’ve tried to follow this guide without success.
I’m convinced that it should be a matter of firewall but after 2 days of attempts I don’t know what else I can do so I would really appreciate your support.

This is the wireguard configuration file I’ve executed on my Windows machine and glinet (port 443 is because I travel in airports where sometomes other ports are blocked)

[Interface]
Address = 10.10.0.2/32
PrivateKey = <PRIVATE_KEY_GLINET>
MTU = 1420

[Peer]
AllowedIPs = 10.10.0.0/24
Endpoint = <PUBLIC_IP>:443
PersistentKeepalive = 15
PublicKey = <PUBLIC_KEY_SERVER>

this is the VPS configuration

[Interface]
Address = 10.10.0.1/24
ListenPort = 443
MTU = 1280
PrivateKey = xxx

Table = off

PostUp = ip route add 10.10.0.0/24 dev wg0 2>/dev/null || true
PostUp = ip rule add priority 100 from 10.10.0.1/32 lookup main
PostUp = ip rule add priority 150 to 10.10.0.0/24 lookup main
PostUp = ip rule add priority 200 from 10.10.0.0/24 lookup 200
PostUp = ip route add default dev wg0 table 200
PostUp = iptables -t nat -A POSTROUTING -s 10.10.0.0/24 -o wg0 -j MASQUERADE
PostUp = iptables -A FORWARD -i wg0 -o wg0 -j ACCEPT

PostDown = ip route del 10.10.0.0/24 dev wg0 2>/dev/null
PostDown = ip rule del priority 100 2>/dev/null
PostDown = ip rule del priority 150 2>/dev/null
PostDown = ip rule del priority 200 2>/dev/null
PostDown = ip route del default dev wg0 table 200 2>/dev/null
PostDown = iptables -D FORWARD -i wg0 -o wg0 -j ACCEPT
PostDown = iptables -t nat -D POSTROUTING -s 10.10.0.0/24 -o wg0 -j MASQUERADE

--- PEERS ---

1. HOME MT3000 (Exit Node)

[Peer]
PublicKey = xxx
AllowedIPs = 10.10.0.2/32, 0.0.0.0/0

2. TRAVELING MT3000 (Work PC Gateway)

[Peer]
PublicKey = xxx
AllowedIPs = 10.10.0.3/32

3. PHONE

[Peer]
PublicKey = xxx
AllowedIPs = 10.10.0.4/32

4. IPAD

[Peer]
PublicKey = xxx
AllowedIPs = 10.10.0.5/32

5. PERSONAL PC

[Peer]
PublicKey = xxx
AllowedIPs = 10.10.0.6/32

I’m doing about the same thing, except I only use one remote entry, as it is my travel router which all my devices connect to, and route to my exit node . My remote router, that is connected to a 5G router behind a NAT, is a GL iNet router running OpenWrt 24.10, my travel router is running Debian Trixie, and my VPS is running Ubuntu 24.04. Here is how the Ubuntu system is configured. The big difference is you only want to run MASQUERADE on the output router.

[Interface]
Address = 10.0.0.1/24
ListenPort = 51820
PrivateKey = REPLACE_VPS_PRIVATE_KEY
SaveConfig = false
Table = 200

PostUp   = sysctl -w net.ipv4.ip_forward=1
PostUp   = iptables -I INPUT -p udp --dport 51820 -j ACCEPT
PostUp   = iptables -I FORWARD -i wg0 -j ACCEPT
PostUp   = iptables -I FORWARD -o wg0 -j ACCEPT
PostUp   = iptables -t mangle -I FORWARD -i wg0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
PostUp   = iptables -t mangle -I FORWARD -o wg0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
PostUp   = ip rule add iif wg0 table 200 priority 200

PreDown  = iptables -D INPUT -p udp --dport 51820 -j ACCEPT
PreDown  = iptables -D FORWARD -i wg0 -j ACCEPT
PreDown  = iptables -D FORWARD -o wg0 -j ACCEPT
PreDown  = iptables -t mangle -D FORWARD -i wg0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
PreDown  = iptables -t mangle -D FORWARD -o wg0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
PreDown  = ip rule del iif wg0 table 200 priority 200

[Peer]
# Home/Exit Router — AllowedIPs MUST be 0.0.0.0/0 so VPS can forward all traffic to it
PublicKey = REPLACE_HOME_ROUTER_PUBLIC_KEY
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25

[Peer]
# Travel Router
PublicKey = REPLACE_TRAVEL_ROUTER_PUBLIC_KEY
AllowedIPs = 10.0.0.3/32

--
# As a 1 time operation, you need to create the new route table:
echo "200     wg_exit" >> /etc/iproute2/rt_tables


I used this as my guide: https://www.procustodibus.com/blog/2022/06/multi-hop-wireguard/#internet-gateway-as-a-spoke

Hi @eric,

thank you for the detailed VPS config and the very helpful guide.

I'm still struggling to get the GL-iNet side working as the exit node. Could you share how you configured the GL-MT3000 (or whichever GL-iNet device you used)?

Specifically:

  • Did you need to change any firewall zone settings (e.g. allow forwarding from the WireGuard zone to WAN)?
  • Did you add a MASQUERADE rule on the router itself, and if so, how — via LuCI, SSH/iptables, or editing /etc/firewall.user?
  • What WireGuard interface name does GL-iNet assign in your setup (wg0, wgclient, etc.)?

For context: on Windows with Internet card sharing it works perfectly, but on the GL-iNet the WireGuard tunnel connects fine (ping to VPS works) yet internet traffic from other peers doesn't route through.

Thanks!

For my VPN servers, I use generic OpenWrt on my GL iNet routers, as I feel that GL 4.x firmware too bloated for this purpose. I do all my work with either the OpenWrt command: uci or by editing the files directly with vi.

Here is a generic version of the entry in my OpenWrt /etc/config/network file:

config interface 'wg0'
    option proto 'wireguard'
    option private_key 'REPLACE_HOME_ROUTER_PRIVATE_KEY'
   list addresses '10.0.0.2/32'

config wireguard_wg0
    option public_key 'REPLACE_VPS_PUBLIC_KEY'
    option description 'vps_hub'
    option endpoint_host 'hub.example.com'
    option endpoint_port '51820'
    option persistent_keepalive '25'
    list allowed_ips '0.0.0.0/0'
    option route_allowed_ips '0'

I also added this in my rc.local file:

ip route add 10.0.0.0/24 dev wg0

To set the MASQUERADE and fix the MTU, I added wg0 to my /etc/config/firewall:

config zone
    option name 'vpn'
    option input 'ACCEPT'
    option output 'ACCEPT'
    option forward 'ACCEPT'
    option masq '1'
    option mtu_fix '1'
    list network 'openvpn1'
    list network 'wg0'
    list network 'wg3'

I am running 3 different VPN packages and 2 different Wireguard links on my GL iNet exit node, so my settings are much more complex, and it took time to work it all out. I pulled out the parts I think you need to get you going down the right path, but there is not a whole lot more help I can give you on this, as I’m on travel.