WireGuard Split Tunneling Guide
What Is Split Tunneling?
Split tunneling routes only specific traffic through your VPN while the rest uses your normal internet connection. In a full tunnel, all traffic flows through the VPN — this adds latency, uses your VPN server’s bandwidth for everything, and breaks local network access. Split tunneling gives you the best of both worlds: private access to your self-hosted services without slowing down Netflix, video calls, or local network printers.
Prerequisites
- A working WireGuard setup with at least one peer connected
- Basic understanding of networking concepts (IP addresses, subnets, CIDR notation)
Full Tunnel vs Split Tunnel
| Aspect | Full Tunnel | Split Tunnel |
|---|---|---|
AllowedIPs | 0.0.0.0/0, ::/0 | Specific subnets only |
| All internet traffic | Through VPN | Normal ISP connection |
| Self-hosted services | Through VPN | Through VPN |
| Speed impact | Higher latency on everything | No impact on normal browsing |
| Privacy | All traffic encrypted | Only VPN-bound traffic encrypted |
| Local network access | Broken (unless excluded) | Works normally |
| Bandwidth usage | VPN server handles all traffic | VPN server only handles targeted traffic |
Basic Split Tunnel Setup
The key is the AllowedIPs setting in the client’s [Peer] section. Instead of 0.0.0.0/0 (send everything), list only the subnets you want routed through the VPN.
Route Only VPN Subnet
The simplest split tunnel — access only devices on the WireGuard network:
# Client config (wg0.conf)
[Interface]
PrivateKey = <client-private-key>
Address = 10.0.0.2/32
DNS = 10.0.0.1 # Optional: use VPN server's DNS
[Peer]
PublicKey = <server-public-key>
Endpoint = vpn.yourdomain.com:51820
AllowedIPs = 10.0.0.0/24
PersistentKeepalive = 25
This routes traffic to 10.0.0.x through WireGuard. Everything else — web browsing, streaming, gaming — goes through your normal connection.
Route VPN + Home LAN
Access both WireGuard peers and your home network (e.g., 192.168.1.0/24):
[Peer]
PublicKey = <server-public-key>
Endpoint = vpn.yourdomain.com:51820
AllowedIPs = 10.0.0.0/24, 192.168.1.0/24
PersistentKeepalive = 25
Server-side requirement: Your WireGuard server must be able to route to the home LAN. If the server IS on the home LAN, enable IP forwarding:
sudo sysctl -w net.ipv4.ip_forward=1
And add routing rules in the server’s WireGuard config:
[Interface]
Address = 10.0.0.1/24
ListenPort = 51820
PrivateKey = <server-private-key>
PostUp = iptables -A FORWARD -i wg0 -o eth0 -j ACCEPT; iptables -A FORWARD -i eth0 -o wg0 -m state --state RELATED,ESTABLISHED -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -o eth0 -j ACCEPT; iptables -D FORWARD -i eth0 -o wg0 -m state --state RELATED,ESTABLISHED -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
Route Multiple Service Subnets
If your self-hosted services use different Docker networks or subnets:
[Peer]
PublicKey = <server-public-key>
Endpoint = vpn.yourdomain.com:51820
AllowedIPs = 10.0.0.0/24, 172.18.0.0/16, 192.168.1.0/24
PersistentKeepalive = 25
| Subnet | Purpose |
|---|---|
10.0.0.0/24 | WireGuard peer network |
172.18.0.0/16 | Docker bridge network (your containers) |
192.168.1.0/24 | Home LAN |
DNS Split Tunneling
By default, a split tunnel doesn’t route DNS through the VPN. This means you can reach services by IP but not by hostname. To fix this:
Option 1: Use VPN Server’s DNS
Set your VPN server as the DNS server in the client config:
[Interface]
PrivateKey = <client-private-key>
Address = 10.0.0.2/32
DNS = 10.0.0.1
This routes ALL DNS through the VPN (simple but may slow DNS for non-VPN sites).
Option 2: Run Pi-hole / AdGuard Home on the VPN
Run Pi-hole or AdGuard Home on your server, accessible via the WireGuard IP. You get split-tunnel routing PLUS ad-blocking on all DNS queries:
[Interface]
DNS = 10.0.0.1 # Pi-hole on WireGuard server
Option 3: Conditional DNS (Advanced)
On Linux clients, use resolvconf or systemd-resolved to route only specific domains through the VPN DNS:
[Interface]
PostUp = resolvectl dns %i 10.0.0.1; resolvectl domain %i ~home.lan
PostDown = resolvectl revert %i
This sends .home.lan queries to the VPN DNS and everything else to your normal DNS.
Per-Application Split Tunnel (Linux)
WireGuard routes at the network level, not per-app. But you can use network namespaces to route specific applications through the VPN:
# Create a network namespace
sudo ip netns add vpn
# Move the WireGuard interface into it
sudo ip link set wg0 netns vpn
# Run an application inside the namespace
sudo ip netns exec vpn firefox
This is advanced and most users don’t need it. If you need per-app control, consider using Tailscale which supports exit nodes and ACLs for finer-grained routing.
Mobile Device Configuration
iOS / Android
The WireGuard mobile app supports split tunneling via AllowedIPs. In the app:
- Edit your tunnel configuration
- Under “Peer,” set
Allowed IPsto your specific subnets (e.g.,10.0.0.0/24, 192.168.1.0/24) - Remove
0.0.0.0/0if present
On-Demand Rules (iOS)
iOS WireGuard supports on-demand activation:
- Activate on Wi-Fi: Connect to VPN only when on untrusted networks
- Activate on cellular: Stay connected on mobile data
- Exclude home Wi-Fi: Don’t use VPN when already on your home network
Configure in the WireGuard iOS app under tunnel → Edit → On Demand.
Common Mistakes
- Forgetting IP forwarding on the server — Without
net.ipv4.ip_forward=1, the server won’t route split-tunnel traffic to your LAN. - Wrong
AllowedIPson the server side — The server’s[Peer]section for each client must include that client’s VPN IP:AllowedIPs = 10.0.0.2/32. Don’t put0.0.0.0/0on the server’s peer config unless the client is an exit node. - DNS not routing through VPN — You can reach
10.0.0.xby IP butnextcloud.homedoesn’t resolve. Set theDNSfield in[Interface]or use conditional DNS. - Docker networks not reachable — If your containers use
172.17.0.0/16and you only route10.0.0.0/24, you won’t reach containers. Add the Docker subnet toAllowedIPs. - Using
0.0.0.0/0as a “catch-all” with exclusions — WireGuard’sAllowedIPsis additive, not subtractive. You can’t say “route everything EXCEPT YouTube.” Use specific subnets you DO want to route.
Next Steps
- Set up WireGuard if you haven’t already
- Run Pi-hole on your server for VPN-wide ad blocking
- Configure Headscale for easier key management with split tunneling built in
- Learn about Docker Networking to understand container subnet routing
Related
Get self-hosting tips in your inbox
Get the Docker Compose configs, hardware picks, and setup shortcuts we don't put in articles. Weekly. No spam.
Comments