WireGuardLab
Isometric blue shield with a padlock over a grid floor, linked by glowing lines to cube and server peer nodes on a dark navy background
configuration

WireGuard Allowed IPs: What to Set on Each Peer and Why

WireGuard allowed IPs act as a per-peer routing table and source filter. The values to use for full tunnel, split tunnel, servers and site-to-site.

By WireGuardLab Editorial · · 7 min read

WireGuard Allowed IPs (the AllowedIPs line in each [Peer] block) does two jobs: it is the list of destinations routed to that peer, and the list of source addresses accepted from it. On a server, set each client to its own tunnel /32. On a client, list what you want tunneled: 0.0.0.0/0, ::/0 for everything, specific subnets for split tunnel.

Examples below use tunnel subnet 10.7.0.0/24, home LAN 192.168.10.0/24, a second site at 192.168.20.0/24, and a server on UDP 51820.

How does AllowedIPs work in both directions?

Outbound, AllowedIPs is a routing table: the interface matches a packet’s destination against every peer’s list, picks the most specific match, and encrypts to that peer’s key. Inbound, it is an access control list: after decryption, the inner source address must fall inside the sending peer’s list, or the packet is discarded.

The WireGuard project calls this cryptokey routing, and the wg(8) reference defines the field as addresses “from which incoming traffic for this peer is allowed and to which outgoing traffic for this peer is directed.” Three consequences:

  • A prefix belongs to one peer per interface. Two peers on wg0 cannot both own 192.168.20.0/24. Overlapping prefixes of different lengths are fine; the longer one wins.
  • No match, no send. A packet in wg0 whose destination no peer covers has no key to encrypt to.
  • It filters sources, not destinations. The server’s entry 10.7.0.2/32 stops that client spoofing other tunnel addresses. It does not stop 10.7.0.2 reaching every host on your LAN; that is the forward firewall’s job.

The handshake side is covered in WireGuard explained: keys, AllowedIPs and NAT traversal.

What should AllowedIPs be on the server and the client?

On the server, or any hub, each peer gets only the addresses that live behind it: its tunnel /32 plus any LAN it routes. On a client, AllowedIPs lists every destination the tunnel should carry. The two sides are not mirror images, and copying one config’s list into the other breaks both.

Config being editedPeer blockAllowedIPsEffect
Remote-access serverLaptop10.7.0.2/32One address per client
Remote-access serverPhone10.7.0.3/32One address per client
Laptop, full tunnelServer0.0.0.0/0, ::/0All traffic via the server
Laptop, split tunnelServer10.7.0.0/24, 192.168.10.0/24Tunnel and home LAN only
Site A gatewaySite B10.7.0.20/32, 192.168.20.0/24Site B tunnel IP and LAN
Site B gatewaySite A10.7.0.1/32, 192.168.10.0/24Site A tunnel IP and LAN

The server side of the first two rows:

[Interface]
Address    = 10.7.0.1/24
ListenPort = 51820
PrivateKey = <server private key>

[Peer]
# laptop
PublicKey  = <laptop public key>
AllowedIPs = 10.7.0.2/32

[Peer]
# phone
PublicKey  = <phone public key>
AllowedIPs = 10.7.0.3/32

The interface Address is a /24; each peer gets a /32. Give the laptop 10.7.0.0/24 instead and it becomes the catch-all for every tunnel address no other peer claims: the phone’s /32 still wins for 10.7.0.3, but the laptop may now send from, and receive traffic for, any unassigned 10.7.0.x address, which undoes the per-client source filtering. For dual-stack, add each client’s IPv6 address, e.g. 10.7.0.2/32, fd07::2/128. The Ubuntu server and client walk-through builds both files, including the forwarding and NAT a full-tunnel server needs.

Full tunnel, split tunnel, and excluding a subnet

Full tunnel is 0.0.0.0/0, ::/0, both halves. On Linux, wg-quick(8) adds a route for every AllowedIPs entry, and for a default route it uses ip-rule(8) policy routing so the encrypted UDP toward the endpoint doesn’t loop back into the tunnel.

Split tunnel lists only what you need:

[Peer]
PublicKey  = <server public key>
Endpoint   = vpn.example.net:51820
AllowedIPs = 10.7.0.0/24, 192.168.10.0/24

Check the DNS = line against that list. If the client resolves through 192.168.10.1, that address must sit inside AllowedIPs, or queries leave via the café Wi-Fi toward a private address that doesn’t exist there.

WireGuard has no exclude syntax. To tunnel everything except a range, pick one of three approaches:

  1. Compute the complement. The Pro Custodibus AllowedIPs calculator does the subtraction; removing 10.0.1.0/24 from 10.0.0.0/8 alone yields 16 blocks.
  2. Let a more specific route win. On Linux, keep the broad AllowedIPs and add a longer-prefix route for the excluded range out the physical interface. Pro Custodibus suggests this on Linux and saves the calculator for platforms, such as phones, that don’t expose the routing table.
  3. Use the client checkbox. Android’s “Exclude private IPs”, as Jason Donenfeld specified it in July 2018, swaps 0.0.0.0/0 for a fixed list of 30 prefixes. It drops 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16, and because it stops at 208.0.0.0/4, 224.0.0.0/3 (multicast and reserved) is left out too. ::/0 is untouched.

On desktop Linux you may need none of this: the same thread notes wg-quick already keeps local-network traffic out of the tunnel via ip-rule’s suppress_prefixlength.

Windows has a quirk. Per the wireguard-windows network notes, a tunnel with exactly one peer holding a /0 enables a kill-switch that blocks everything except the tunnel’s own packets, loopback, DHCP, NDP, and port 53 to the configured DNS servers. Writing 0.0.0.0/1, 128.0.0.0/1 and ::/1, 8000::/1 routes the same traffic without it; the editor’s checkbox toggles between the forms. Keep the kill-switch on laptops that roam onto untrusted Wi-Fi.

How do you change AllowedIPs on a running tunnel?

Use wg set, which replaces a peer’s whole list by default, or prefix entries with + and - to add or remove single prefixes. Incremental updates shipped for Linux in wireguard-tools v1.0.20250521 and need a kernel with the matching netlink flag. For edits to the file, wg syncconf reloads without dropping sessions.

# replace the whole list
wg set wg0 peer <pubkey> allowed-ips 10.7.0.20/32,192.168.20.0/24

# incremental: add one prefix, remove another
wg set wg0 peer <pubkey> allowed-ips +192.168.21.0/24,-192.168.20.0/24

# reload wg0.conf without restarting the interface
wg syncconf wg0 <(wg-quick strip wg0)

The incremental form matters on busy gateways. Per the kernel’s WireGuard netlink spec, a replace removes “all current allowed IPs of this peer” before adding the new list, so traffic to prefixes you meant to keep can briefly find no peer. The WGALLOWEDIP_F_REMOVE_ME flag removes one prefix instead, and the wireguard-tools commit from May 2025 wires it into wg set.

Two caveats. Neither command touches the kernel routes wg-quick created at up, so a new prefix also needs ip route add 192.168.21.0/24 dev wg0. And with SaveConfig = true, wg-quick writes live state back to the file at shutdown, overwriting edits made while the interface was up.

Common AllowedIPs mistakes and their symptoms

Same prefix on two peers. WireGuard accepts it silently and gives the prefix to one peer, as a 2019 report on the WireGuard list found. The pfSense WireGuard settings docs are blunt: with duplicates, “only the last peer in the list will be configured properly.” In wg show wg0 allowed-ips, a peer showing (none) lost.

Host bits in the prefix. Netgate notes entries are “transformed into proper subnet start boundaries,” so 10.7.0.5/24 becomes 10.7.0.0/24. The 2019 report was the IPv6 version: fd00:dead:beef:1000::/32 and fd00:dead:beef:1001::/32 are the same /32.

Two full-tunnel peers on one interface. Only one can own 0.0.0.0/0. Failover between two exit servers needs two interfaces, wg0 and wg1, not two peers.

Remote LAN listed, nothing comes back. The gateway’s tunnel IP answers ping, but LAN hosts stay silent. AllowedIPs neither enables forwarding (net.ipv4.ip_forward=1) nor gives LAN hosts a return path. When WireGuard runs on a LAN box rather than the router, as in the Raspberry Pi setup, masquerade on the Pi or add a static route on the router for 10.7.0.0/24 via the Pi’s LAN address, e.g. 192.168.10.5.

Treating AllowedIPs as a firewall. To limit the phone to one NAS on TCP 443, filter the forward path, accept before drop:

# assumes an existing inet filter table with a forward chain
nft add rule inet filter forward iifname "wg0" ip saddr 10.7.0.3 ip daddr 192.168.10.20 tcp dport 443 accept
nft add rule inet filter forward iifname "wg0" ip saddr 10.7.0.3 drop

Watch for shadowing: a broad iifname "wg0" accept earlier in the chain matches first and makes both rules dead code.

How to verify your AllowedIPs

wg show wg0 allowed-ips          # prefix-to-peer map as the kernel holds it
ip route get 192.168.20.10       # should report dev wg0
ip rule show                     # full tunnel: wg-quick's fwmark and suppress_prefixlength rules
ping -c 3 10.7.0.1               # tunnel reachability
mtr -n -c 10 192.168.20.10       # path to a remote-LAN host
dig @192.168.10.1 nas.home.arpa  # DNS through the tunnel

If small pings pass and large transfers stall, AllowedIPs is fine and the problem is packet size; the WireGuard MTU calculator walks through the fix.

FAQ

What does AllowedIPs 0.0.0.0/0 mean in WireGuard?

It means every IPv4 destination is routed to that peer, and that peer may send from any IPv4 source address. On a client it creates a full tunnel; add ::/0 to cover IPv6 as well. On a server, giving one client 0.0.0.0/0 sends every destination no other peer covers to that client.

What is the difference between Address and AllowedIPs in WireGuard?

Address sets your own interface IP, such as 10.7.0.2/24, and is a wg-quick option rather than part of the WireGuard protocol. AllowedIPs lives inside a [Peer] block and lists the addresses reachable through, and accepted from, that peer. One describes the local end of the tunnel; the other describes the remote end.

Should WireGuard AllowedIPs be /32 or /24?

Use /32 on the server side: each client’s peer entry should hold its single tunnel address, or /128 for IPv6, plus any LAN behind it. On the client, the server’s entry can be the whole tunnel subnet, 10.7.0.0/24, if clients should reach each other through the server, or 10.7.0.1/32 if not.

Do I need ::/0 in AllowedIPs if I only use IPv4?

Yes, if the client has IPv6 connectivity and you want a full tunnel. With only 0.0.0.0/0, IPv6 traffic skips the tunnel and leaves through the local network with the client’s real address. Adding ::/0 pulls IPv6 into the tunnel; if the server has no IPv6 uplink, dual-stack apps generally fall back to IPv4.

Why does WireGuard connect but no traffic passes?

Check AllowedIPs first. A recent handshake in wg show proves the keys and endpoint are right, so missing traffic usually means the destination is absent from the sender’s AllowedIPs, the source address is absent from the receiver’s entry for that peer, or the gateway lacks IP forwarding and a return route.

Sources

  1. WireGuard: Cryptokey Routing (project homepage)
  2. wg(8) manual page, wireguard-tools
  3. wg-quick(8) manual page
  4. wireguard-tools commit: ipc: linux: support incremental allowed ips updates
  5. Linux kernel documentation: wireguard netlink specification
  6. wireguard-windows: Network Configuration Quirks (kill-switch)
  7. WireGuard mailing list: Exclude Private IPs in Android App (July 2018)
  8. WireGuard mailing list: Overlapping AllowedIPs Configuration (May 2019)
  9. Netgate pfSense documentation: WireGuard Settings
  10. Pro Custodibus: WireGuard AllowedIPs Calculator
#wireguard #allowedips#routing#split-tunnel #wg-quick

Related