Disclaimer

This is not a tutorial, just brief description of a working configuration. You should be at least vaguely familiar with wireguard before attempting to do something like this. That being said, I am a networking novice, so please do not blindly copy and paste these configs.

Setup

flowchart LR subgraph Internet S[S\nCentral Server] end subgraph Clients C1(C1)---S C2(C2)---S C3(C3)---S end S---G subgraph LAN NAT G[G\nGateway] --- r1([LAN resource 1]) G --- r2([LAN resource 2]) G --- r3([LAN resource ...]) end
I wish to access the resources of a local network remotely. For this, I have $\geq 3$ peers: a central server $S$ publicly accessible, a gateway Server $G$ behind NAT (in the local network), and multiple clients $C_1, C_2, …$. All clients $C_i$ and $G$ connect to $S$.

IP Name
192.168.10.0/24 The private network for the VPN
192.168.10.1 The public server S
192.168.10.2 The Gateway device G
192.168.10.3-n The other clients C
100.100.20.0/24 G’s local network (This has to be different to the network above)

Routing

By setting AllowedIPs = 0.0.0.0/0, ::0/0 for $G$ on $S$, all traffic will by default be routed through $G$. But this also means, that all of $S$’s traffic will be routed through $G$, making $S$ inaccessible from outside $G$. To avoid this, we configure a separate routing table.

IP forwarding

For this to work, S and G need ip forwarding to be enabled.

echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
echo "net.ipv6.conf.all.forwarding=1" >> /etc/sysctl.conf
sysctl -w net.ipv4.ip_forward=1
sysctl -w net.ipv6.conf.all.forwarding=1

Or alternatively, use the PreUp command specified below

Configuration

The configuration files below should be put into /etc/wireguard/wg0.conf and the connection can be automatically started by systemctl enable --now wg-quick@wg0.service.

Gateway config

[Interface]
Address = 192.168.10.3/32
PrivateKey = <...>

# IP forwarding (see section above)
PreUp = sysctl -w net.ipv4.ip_forward=1

# IP masquerading
PreUp = iptables -t mangle -I PREROUTING -i wg0 -j MARK --set-mark 0x30
PreUp = iptables -t nat -I POSTROUTING ! -o wg0 -m mark --mark 0x30 -j MASQUERADE
PostDown = iptables -t mangle -D PREROUTING -i wg0 -j MARK --set-mark 0x30
PostDown = iptables -t nat -D POSTROUTING ! -o wg0 -m mark --mark 0x30 -j MASQUERADE

# Server S
[Peer]
PublicKey = <...>
Endpoint = domain.of.server.s.example.com:51820
AllowedIPs = 192.168.10.0/24
PersistentKeepalive = 20

Server config

[Interface]
Address = 192.168.10.1/24
ListenPort = 51820
PrivateKey = <...>

# Do not pass the server's traffic through G, only other wg0 traffic
Table = 123
PreUp = ip rule add iif wg0 table 123 priority 456
PostDown = ip rule del iif wg0 table 123 priority 456
PreUp = ip -6 rule add iif wg0 table 123 priority 456
PostDown = ip -6 rule del iif wg0 table 123 priority 456

# Gateway
[Peer]
PublicKey = <...>
AllowedIPs = 0.0.0.0/0, ::0/0

# Client C_1
[Peer]
PublicKey = <...>
AllowedIPs = 192.168.10.3/32

# Client C_2
[Peer]
PublicKey = <...>
AllowedIPs = 192.168.10.4/32

...

Client C_1 config

[Interface]
PrivateKey = <...>
Address = 192.168.10.3/32

[Peer]
PublicKey = <...>
Endpoint = domain.of.server.s.example.com:51820
AllowedIPs = 0.0.0.0/0, ::0/0
PersistentKeepalive = 20