Wireguard - How to only tunnel some of the traffic

You can use iptables.
Replace eth0 with the network interface that connects to the internet and 10.6.0.1/24 with your client subnet.

Insert this somewhere in your Wireguard config below [INTERFACE]

# Drop all outgoing packets from the client subnet
PreUp = iptables -I FORWARD -s 10.6.0.1/24 -o eth0 -j DROP
## Add your exceptions here

For example:

[Interface]
PrivateKey = ...
Address = 10.6.0.1/24
MTU = 1420
ListenPort = 51820

## Before interface wg0 is up
# Drop all outgoing packets from the client subnet
PreUp = iptables -I FORWARD -s 10.6.0.1/24 -o eth0 -j DROP
# Allow clients to connect to the local network 192.168.0.1/24
PreUp = iptables -I FORWARD -s 10.6.0.1/24 -d 192.168.0.1/24 -j ACCEPT
# Allow clients to connect to tcp port 80 (usually http) on 10.10.0.5
PreUp = iptables -I FORWARD -s 10.6.0.1/24 -d 10.10.0.5 -p tcp --dport 80 -j ACCEPT

## After interface wg0 is down
PostDown = iptables -D FORWARD -s 10.6.0.1/24 -o eth0 -j DROP
PostDown = iptables -D FORWARD -s 10.6.0.1/24 -d 192.168.0.1/24 -j ACCEPT
PostDown = iptables -D FORWARD -s 10.6.0.1/24 -d 10.10.0.5 -p tcp --dport 80 -j ACCEPT

[Peer]
...

For a seamless experience on the client's side you also have to configure the AllowedIPs in the client's config. Otherwise the clients will try to use the VPN to access the internet and those requests will just time out.

Following the example above, the client's config could look like this:

[Interface]
PrivateKey = ...
Address = 10.6.0.2/24
DNS = 10.6.0.1

[Peer]
PublicKey = ...
AllowedIPs = 192.168.0.1/24, 10.10.0.5
Endpoint = ...
PresharedKey = ...

Documentation:

  • Wireguard config
  • iptables