Skip to content

Multiple IPs to LAN Hosts

If you have multiple static IPs on one tunnel and want each one to reach a different machine on your LAN, you have two options:

Option A: DNAT + SNAT (simpler, but hides the original destination)

Section titled “Option A: DNAT + SNAT (simpler, but hides the original destination)”

The WireGuard host acts as a NAT gateway. It rewrites the destination IP to the LAN host, and rewrites the source of replies back to the static IP.

Terminal window
# Forward 134.49.198.17 → LAN host 192.168.1.101
iptables -t nat -A PREROUTING -i getrealip -d 134.49.198.17 -j DNAT --to-destination 192.168.1.101
iptables -t nat -A POSTROUTING -s 192.168.1.101 -o getrealip -j SNAT --to-source 134.49.198.17
# Forward 134.49.198.18 → LAN host 192.168.1.102
iptables -t nat -A PREROUTING -i getrealip -d 134.49.198.18 -j DNAT --to-destination 192.168.1.102
iptables -t nat -A POSTROUTING -s 192.168.1.102 -o getrealip -j SNAT --to-source 134.49.198.18

Pros: The LAN hosts don’t need any special configuration. They see traffic from the WireGuard host’s LAN IP, reply normally, and the WireGuard host handles the rest.

Cons: The LAN hosts can’t see the real source IP of incoming connections (it’s been SNAT’d). Logs show the WireGuard host’s IP, not the remote client.

Option B: Direct routing (preserves source IP, LAN host must route back)

Section titled “Option B: Direct routing (preserves source IP, LAN host must route back)”

With direct routing, there’s no NAT at all. The LAN host sees the real remote client IP in its logs and connection info. The tradeoff: both the WireGuard host and the LAN host need routing configuration.

The key requirement is that the LAN host must own the static IP so it can process packets destined for that IP and generate replies with the correct source. We use a dummy interface for this — it exists purely to hold the address without affecting any real network interface.

On the WireGuard host (192.168.1.59):

Terminal window
# Enable IP forwarding
sysctl -w net.ipv4.ip_forward=1
# Route packets destined for the static IP to the LAN host
ip route add 134.49.198.17 via 192.168.1.101 dev eth0
# Route packets sourced from the static IP back into the tunnel
ip rule add from 134.49.198.17 table 198 priority 100
ip route add default dev getrealip table 198

The WireGuard host receives a packet on getrealip destined for 134.49.198.17, sees the host route, and forwards it to 192.168.1.101 on the LAN. When the reply comes back from the LAN host with source 134.49.198.17, the source-based rule catches it and routes it back into the tunnel.

On the LAN host (192.168.1.101):

Terminal window
# Load the dummy module and create a dummy interface to hold the static IP
modprobe dummy
ip link add dummy0 type dummy
ip link set dummy0 up
# Own the static IP on dummy0 so the kernel accepts packets for it
ip addr add 134.49.198.17/32 dev dummy0
# Route replies (sourced from the static IP) back via the WireGuard host
ip rule add from 134.49.198.17 table 198 priority 100
ip route add default via 192.168.1.59 table 198

The LAN host receives the packet (it owns the IP on dummy0), processes it, generates a reply with source 134.49.198.17. The policy rule routes that reply to the WireGuard host, which sends it back through the tunnel.

Summary:

Machine Config
WireGuard host ip_forward=1, host route to LAN host, source-based rule back to getrealip
LAN host Static IP on dummy0, source-based rule back to WireGuard host

Pros: LAN host sees real source IPs. No NAT anywhere. Clean for running mail servers, game servers, etc.

Cons: Every LAN host needs routing configuration. More complex. Both machines need coordinated setup.

  • SNAT (Option A): Use when you don’t care about seeing real client IPs on the LAN host, or when you can’t configure routing on the LAN host (e.g., it’s an appliance). Simplest setup.
  • Direct routing (Option B): Use when you need real client IPs visible on the LAN host (mail servers checking connecting IP, game servers with anti-cheat, web servers logging real IPs). More setup, but no information loss.

For every additional IP, the return path must be explicitly defined. The OS won’t automatically route replies back through the tunnel just because the inbound packet arrived there — you must tell it, either with:

  • ip rule from <static-ip> table <wg-table> (Linux)
  • reply-to or route-to in pf rules scoped to each IP (BSD)
  • Per-IP mangle marks and routing tables (MikroTik / OpenWrt)

Without this, replies for additional IPs will leak out the default gateway with the wrong source IP, and the connection will break.