Introduction — what you’ll learn and who this is for

This updated September 2026 guide shows exactly how to implement deterministic, per‑IP (per‑prefix) split‑tunneling with WireGuard across Linux, Windows, macOS and Android — and at the router/edge. This is for privacy‑conscious users, sysadmins, and power hobbyists who already run a WireGuard peer and need predictable routing, minimal latency, and verifiable DNS behavior. You’ll get updated tooling notes, IPv6 realities, practical router strategies, and verification workflows that reflect the 2026 landscape.

Prerequisites and context

  • A working WireGuard peer (server + client). Examples use interface name wg0.
  • Admin/root access on each device to modify routes, firewall rules and DNS settings.
  • Comfort with command‑line tools: ip, nft/iptables (nft preferred), ip rule, PowerShell, pf, and DNS tools (dig, tcpdump).
  • Awareness that IPv6 and encrypted DNS are integral in 2026 — design routing and DNS for both to avoid leaks.

Why per‑destination split‑tunneling remains the right tool in 2026

  • Deterministic control when you own destinations (corporate networks, home NAS, cloud services).
  • Lower complexity and better auditability than trying to bind arbitrary apps to interfaces on desktop OSes.
  • Performance: only selected traffic crosses the tunnel, reducing latency and egress costs at the peer.

High‑level approach (what you’ll implement)

  1. List exact IPv4 and IPv6 prefixes to send over the tunnel (AllowedIPs where relevant).
  2. On each OS, apply route/policy rules that prefer the WireGuard interface (use fwmark→policy routing on Linux, interface routes on Windows/macOS, allowed‑apps or proxies where applicable).
  3. Make DNS explicit: split DNS or forwarding‑over‑tunnel so queries for tunneled zones go through the VPN using DoH/DoT/DoQ where possible.
  4. Verify with traceroute/tcpdump and automated probes; add monitoring for tunnel health and failover logic.
  5. Automate reapplication of rules on network changes and persist across reboots.

1) Linux (desktop/server) — use policy routing (nftables + fwmark) and explicit IPv6 handling

Linux remains the most capable platform for per‑IP split‑tunneling. In 2026 the best pattern is stable: mark packets (nftables), use ip rule to select a dedicated routing table that points at wg0, and persist via systemd or NetworkManager hooks. eBPF is now a practical alternative for high‑performance classification, but nftables + ip rule is easier and auditable for most deployments.

Why this method?

It supports per‑destination, per‑user and cgroup-based policy, handles IPv6, and survives interface index churn when you use stable names and automation hooks.

Concrete example — route 198.51.100.0/24 and 2001:db8:abcd::/48 via wg0

  1. Confirm wg interface:
    ip addr show dev wg0
    ip -6 route show dev wg0
  2. Create a routing table entry:
    echo "200 wg-route" | sudo tee -a /etc/iproute2/rt_tables
  3. Populate the table (use default dev or a next hop if your peer advertises one):
    sudo ip route add default dev wg0 table wg-route
    sudo ip -6 route add default dev wg0 table wg-route
  4. Add ip rule for fwmark:
    sudo ip rule add fwmark 0x1 table wg-route
  5. Use nftables to mark matching destinations (IPv4 & IPv6):
    sudo nft add table inet vpn
    sudo nft 'add chain inet vpn mangle_output { type route hook output priority -150; policy accept; }'
    sudo nft add rule inet vpn mangle_output ip daddr 198.51.100.0/24 meta mark set 0x1
    sudo nft add rule inet vpn mangle_output ip6 daddr 2001:db8:abcd::/48 meta mark set 0x1
  6. Per‑user or per‑cgroup:
    sudo nft add rule inet vpn mangle_output uid 1001 meta mark set 0x1
    # or use cgroup2 classification for app slices
  7. Persist and automate: save with nftables-save and add a systemd unit After=wg-quick@wg0.service to reapply ip rules when the tunnel comes up.

IPv6 action item: create ip -6 rules and nft rules for AAAA hosts and split DNS for IPv6 zones. Leaving IPv6 on the default path is still the most common leak vector.

Advanced option: eBPF

By late 2026, small eBPF programs (via libbpf, cilium BPF tooling or tc) are widely used to mark packets with lower overhead and earlier in the stack. Use eBPF when you need high throughput or low latency classification; otherwise stick with nftables for maintainability.

2) Windows — persistent interface routes; per‑app via local proxy or MDM per‑app VPN

Windows continues to lack a native, consumer‑grade per‑process route binding API. The reliable pattern for per‑IP split‑tunneling is persistent routes on the WireGuard adapter. For per‑app control, use a local SOCKS/HTTP proxy (bind it to the tunnel) and Proxifier/ProxyCap, or enterprise MDM features (Intune + Windows per‑app VPN APIs) for managed devices.

Per‑IP routing (PowerShell, admin)

  1. Find the WireGuard adapter index:
    Get-NetAdapter | Where-Object Name -Like "*WireGuard*" | Format-Table ifIndex,Name
  2. Add persistent route(s):
    New-NetRoute -DestinationPrefix "198.51.100.0/24" -InterfaceIndex 23 -NextHop 0.0.0.0 -PolicyStore PersistentStore
    If wg shows a gateway IP, set NextHop appropriately.
  3. Validate:
    tracert 198.51.100.10
    Get-NetRoute -DestinationPrefix "198.51.100.0/24"

Per‑app options: local SOCKS proxy bound to wg0 + Proxifier/ProxyCap remains the most practical consumer approach. In enterprise contexts use MDM to deploy per‑app VPN profiles tied to application identity.

3) macOS — route commands, pf and NetworkExtension for apps

macOS supports static route entries and pf for complex redirection. Per‑app split‑tunneling is best done via NetworkExtension (for managed apps) or Proxifier‑style tools. For small deployments, combine route entries with a local DNS forwarder to ensure tunneled name resolution.

Per‑IP routing example

  1. Locate interface:
    ifconfig
  2. Add IPv4 and IPv6 routes:
    sudo route -nv add -net 198.51.100.0/24 -interface wg0
    sudo route -nv add -inet6 2001:db8:abcd::/48 -interface wg0
  3. Use pf tables to redirect DNS for tunneled domains to your VPN DNS or to block accidental leaks.

4) Android — AllowedIPs and per‑app controls now mainstream; watch DNS

Android’s WireGuard client and OEM network stacks have matured. Use AllowedIPs to enumerate prefixes you intend to reach via the tunnel and, where available, the client’s Allowed apps/Excluded apps feature for app‑level policies. For older devices, a local proxy remains an option.

Steps

  1. Import the profile into the official WireGuard app (or a modern client that supports per‑profile DNS).
  2. List prefixes in AllowedIPs (IPv4 and IPv6) instead of 0.0.0.0/0 unless you want a full tunnel.
  3. Use the profile's app allowlist if available on your Android build for per‑app routing.
  4. Verify DNS behavior; set DoH/DoT/DoQ as supported by your client or system resolver.

Router and edge devices — centralize policy routing

In 2026, doing split‑tunneling at the edge is the single biggest operational win. OpenWrt, OPNsense, pfSense derivatives, and many consumer firmwares include WireGuard GUI packages and policy routing. Centralizing reduces per‑device configuration, prevents inconsistent IPv6 handling, and makes monitoring simpler.

  • OpenWrt: use luci‑app‑wireguard + mwan3 or nftables/ipsets to forward only defined prefixes into the tunnel.
  • OPNsense/pfSense: create gateway interactions and policy rules that map source networks or tags to the WireGuard tunnel for IPv4/IPv6.
  • Edge tactics: prefer pushing AllowedIPs from the server side (where appropriate) and use ipsets for large or dynamic prefix lists to avoid per‑device churn.

DNS — still the leak vector to fix first

Encrypting DNS is routine in 2026. The important tasks:

  • Split DNS: forward tunnel‑specific domains to the VPN DNS server (systemd‑resolved, dnsmasq or Unbound on Linux; local forwarders on macOS/Windows).
  • Encrypted DNS for non‑tunneled paths: use DoH/DoT/DoQ to harden the fallback resolver.
  • On platforms that accept DNS in the WireGuard profile, verify that DNS settings are applied per profile rather than globally — otherwise use a local resolver to implement split DNS.

Testing and verification — follow the packets

  • Traceroute/tracert: confirm tunnel hops for tunneled destinations.
  • tcpdump/tshark: capture on wg0 and on the physical NIC:
    sudo tcpdump -i wg0 host 198.51.100.10 or port 53
    sudo tcpdump -i eth0 ip6
  • DNS checks: use dig @
  • Automated probes: add a small synthetic check in your monitoring (curl/dig/traceroute) that verifies tunneled prefixes route via wg0 and raise alerts if they don’t.

Automation & failover — practical patterns

Automation reduces mistakes. Common 2026 patterns:

  • Systemd unit that replays ip rules and nftables state after wg-quick@wg0.service. Use After=network-online.target and add a short retry loop to handle race conditions.
  • NetworkManager dispatcher hooks or nmcli scripts to reapply rules on network changes (Wi‑Fi→cellular).
  • Watchdog: ping a trusted endpoint across the tunnel; if unreachable for N probes, withdraw the ip rule to avoid blackholing and send an alert. Keep logs and a manual rollback script.
  • Router failover: use mwan3 or gateway groups on OPNsense/OpenWrt to switch to backup peers and keep route tables consistent across source subnets.

Common mistakes and how to avoid them

  • Using broad AllowedIPs (0.0.0.0/0, ::/0) by habit — start small and add prefixes explicitly.
  • Neglecting IPv6 — configure ip6 routes and DNS; test AAAA resolution over the tunnel.
  • Relying on client DNS without split DNS — always capture DNS traffic to verify the path.
  • Not persisting rules across interface index changes — automate via systemd/NetworkManager hooks and prefer stable interface names.
  • Assuming per‑app controls exist uniformly — desktop OSes often require proxies, MDM or NetworkExtension frameworks for true per‑app routing.

Pro tips — advanced, pragmatic moves

  • Use nftables sets or ipsets for large, frequently changing destination lists — update sets atomically to avoid rule reloads.
  • Pin critical processes into dedicated cgroups and mark them with nftables for per‑process routing on Linux.
  • Offload classification to the router whenever possible to avoid reconfiguring each endpoint.
  • Integrate synthetic checks (curl/dig/traceroute) into monitoring and alerting so routing regressions are detected early.
  • Document AllowedIPs and routing decisions — transparency is the best defense against accidental full‑tunnels.

Example cross‑platform scenario — corporate subnet + home NAS (updated)

  1. Define: corporate 10.10.0.0/16 (IPv4) and corp IPv6 2001:db8:10::/48; home NAS 198.51.100.42 (IPv4) and 2001:db8:home::42 (IPv6).
  2. Linux: nftables + ip rule table wg-route, persisted via systemd. Use nftables sets for the multiple corporate prefixes.
  3. Windows: New‑NetRoute for 10.10.0.0/16 and NAS IPs on the WireGuard adapter; local SOCKS proxy + Proxifier for per‑app routing if required.
  4. macOS: route commands for IPv4/IPv6 + pf table to redirect corp domains to the VPN DNS.
  5. Android: AllowedIPs include defined prefixes; use profile Allowed apps for corp apps where available.
  6. Router: push and centralize these prefixes (OpenWrt/OPNsense) and use ipsets for dynamic lists so endpoints stay minimal.
  7. Verify: traceroute into corp and NAS, tcpdump on wg0, dig against corp DNS for AAAA and A records.

When to choose per‑destination vs per‑app

Pick per‑destination when you control destinations and they have stable IP ranges. Pick per‑app when IP footprints are dynamic and you can control the app (proxy settings, NetworkExtension, MDM). For small teams, a hybrid model (edge policy + local proxy exceptions) is the most practical and maintainable approach.

Conclusion

Sept 2026: WireGuard per‑IP split‑tunneling is a solved operational pattern if you design for IPv6 and DNS from day one. Use nftables + ip rule on Linux, interface routes on Windows/macOS, AllowedIPs and app allowlists on Android, and push policy to the edge when you can. Automate reapplication of rules, test with packet captures, and monitor tunnel health. Do these things and you’ll have predictable, high‑performance VPN behavior without the surprises.

Quick checklist before you finish

  • List exact IPv4 and IPv6 prefixes to tunnel; add them to AllowedIPs where applicable.
  • Implement platform routing: nftables + ip rule on Linux; New‑NetRoute on Windows; route/pf on macOS; AllowedIPs & per‑app on Android.
  • Configure split DNS and encrypted DNS; verify with tcpdump and dig.
  • Automate startup and network‑change hooks; add a simple tunnel watchdog.
  • Test thoroughly (traceroute, tcpdump, DNS checks) and document the plan.

FAQ

Do I need to configure IPv6 separately for split‑tunneling?

Yes. IPv6 is a separate routing plane. If you only configure IPv4, IPv6 traffic will often use your ISP path and leak. Add ip -6 routes, nft/ip6 rules, and ensure AAAA lookups for tunneled domains resolve over the VPN DNS.

Can I rely on the WireGuard client to push split DNS automatically?

Sometimes — but don’t assume. WireGuard profiles can suggest DNS servers and many clients accept them per profile. For split DNS (VPN DNS only for specific domains), you’ll usually need a stub resolver (systemd‑resolved, dnsmasq, Unbound or a local forwarder) to forward those zones over the tunnel. Always verify with packet capture.

Is per‑app split‑tunneling doable on Windows without third‑party tools?

Not reliably for consumer devices. Windows lacks an easy per‑process route binding API. Enterprise MDM and Windows per‑app VPN APIs can help in managed environments; for standalone users, proxies (SOCKS/HTTP) + Proxifier/ProxyCap are the most practical route.

Should I put all routing logic on my router instead of each client?

Yes, when you can. Centralizing policy routing at the edge reduces per‑device complexity, prevents IPv6 inconsistencies, and simplifies monitoring. Use router firmware that supports WireGuard and policy routing (OpenWrt/OPNsense/pfSense) and keep client configs minimal.

What’s the fastest way to detect a routing regression?

Integrate small synthetic probes (traceroute/dig/curl) into your monitoring stack that assert tunneled prefixes route via wg0 and that corp DNS replies come from the VPN DNS. Alert on unexpected changes and keep packet captures for forensic diagnosis.