Skip to main content

Multi-Exit WireGuard VPN with Policy Routing

Multi-Exit WireGuard VPN with Policy Routing

This guide explains how to build a WireGuard setup where a central VPN server can route traffic through different exit gateways depending on which client profile connects.

The idea is simple:

  • Clients connect to one WireGuard server
  • The server decides where traffic exits
  • Different clients can exit through different gateways

This allows profile-based switching without requiring complex routing logic on the client.


Architecture

The topology looks like this:

Client Device

WireGuard Server (public IP)
      ↓ policy routing
Gateway Node (remote network)
      ↓ NAT
Local Internet

Example addressing used in this guide:

WireGuard network   10.44.0.0/24

Server              10.44.0.1
Gateway node        10.44.0.9
Special client      10.44.0.21

Step 1 - Install the WireGuard Server

On a Linux server with a public IP:

apt update
apt install wireguard

Enable packet forwarding:

sysctl -w net.ipv4.ip_forward=1

Persist the setting:

Create:

/etc/sysctl.d/99-wireguard.conf

Contents:

net.ipv4.ip_forward=1

Apply:

sysctl --system

Step 2 - Create the Server Configuration

Example server configuration:

/etc/wireguard/wg0.conf
[Interface]
Address = 10.44.0.1/24
ListenPort = 51820
PrivateKey = <server_private_key>

Enable the interface:

systemctl enable wg-quick@wg0
systemctl start wg-quick@wg0

Step 3 - Add a Gateway Node

A remote machine connects to the server and acts as an exit gateway.

Add this peer on the server:

[Peer]
PublicKey = <gateway_public_key>
AllowedIPs = 10.44.0.9/32, 0.0.0.0/1, 128.0.0.0/1

The split prefixes allow the server to route internet traffic through the gateway without affecting the server’s own routes.


Step 4 - Configure the Gateway Node

On the gateway machine:

Install WireGuard:

apt install wireguard

Create:

/etc/wireguard/wg0.conf
[Interface]
Address = 10.44.0.9/24
PrivateKey = <gateway_private_key>

[Peer]
PublicKey = <server_public_key>
Endpoint = <server_ip>:51820
AllowedIPs = 10.44.0.0/24
PersistentKeepalive = 25

Start the tunnel:

systemctl enable wg-quick@wg0
systemctl start wg-quick@wg0

Step 5 - Enable Gateway Forwarding

Enable forwarding:

sysctl -w net.ipv4.ip_forward=1

Add NAT rules (assuming the internet interface is eth0):

iptables -t nat -A POSTROUTING -s 10.44.0.0/24 -o eth0 -j MASQUERADE
iptables -A FORWARD -i wg0 -o eth0 -j ACCEPT
iptables -A FORWARD -i eth0 -o wg0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

Step 6 - Create a Client Profile

Example client configuration:

[Interface]
Address = 10.44.0.21/24
PrivateKey = <client_private_key>
DNS = 1.1.1.1

[Peer]
PublicKey = <server_public_key>
Endpoint = <server_ip>:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25

Add the peer to the server:

[Peer]
PublicKey = <client_public_key>
AllowedIPs = 10.44.0.21/32

Step 7 - Configure Policy Routing on the Server

Create a routing table.

Edit:

/etc/iproute2/rt_tables

Add:

100 exitgw

Add the route:

ip route add default via 10.44.0.9 dev wg0 table exitgw

Add the rule:

ip rule add from 10.44.0.21 lookup exitgw

Now all traffic from that client is routed through the gateway.


Step 8 - Test the Setup

From the client:

curl -4 ifconfig.me

The returned IP should match the gateway’s internet connection.

Traceroute should show the path through the server and gateway:

1 10.44.0.1
2 10.44.0.9
3 gateway router

Step 9 - Make Routing Persistent

Create a routing script on the server:

/usr/local/sbin/wg-exit-routing.sh
#!/bin/sh

ip route replace default via 10.44.0.9 dev wg0 table exitgw
ip rule add from 10.44.0.21 lookup exitgw 2>/dev/null || true

Make it executable:

chmod +x /usr/local/sbin/wg-exit-routing.sh

Attach it to the WireGuard interface:

PostUp = /usr/local/sbin/wg-exit-routing.sh
PostDown = ip rule del from 10.44.0.21 lookup exitgw

Step 10 - Persist Firewall Rules

Install persistent firewall support:

apt install iptables-persistent

Save rules:

iptables-save > /etc/iptables/rules.v4

Extending the Design

Multiple gateways can be added easily:

Gateway A → exit location A
Gateway B → exit location B
Gateway C → exit location C

Each gateway receives its own routing table and client profile.


Advantages

This architecture provides:

  • centralized routing control
  • multiple exit locations
  • simple client configuration
  • efficient WireGuard tunnels
  • minimal client-side complexity

Clients connect only to the server; the server decides where traffic exits.


Final Notes

WireGuard’s cryptokey routing model combined with Linux policy routing makes it possible to build flexible multi-exit VPN systems with minimal overhead.

A small Linux machine can serve as a reliable gateway node, allowing the architecture to scale easily as additional exit locations are added.

← Back to blog