Nearly every WireGuard configuration problem that survives a working handshake comes down to one field, and to the fact that almost nobody reads it correctly. AllowedIPs looks like a routing directive. It is that, and it is also something else at the same time.
What the manual actually says
The wg man page defines it in a single sentence worth reading slowly:
a comma-separated list of IP (v4 or v6) addresses with CIDR masks from which incoming traffic for this peer is allowed and to which outgoing traffic for this peer is directed
Two clauses, two different jobs. Outgoing: packets whose destination falls in that list are sent to this peer. That is the routing half, and it is the one everybody knows. Incoming: packets arriving from this peer are accepted only if their source address falls in the same list. That is an access control list, and it is the half that gets ignored.
This is what WireGuard calls cryptokey routing: the association between a public key and a set of addresses is the entire authorisation model. There is no separate firewall rule deciding which peer may claim which address.
The consequence nobody plans for
Put AllowedIPs = 0.0.0.0/0 on a peer and you have not only routed all your traffic through it. You have also declared that this peer may send you a packet claiming any source address on the internet, and your interface will accept it.
On a client whose only peer is your own server, that is exactly what you want and it is the normal full-tunnel configuration. On a server with several peers, or on any machine where a peer is not fully trusted, it is a hole you opened without noticing.

Why two peers can never share a range
Since the list decides which peer a destination is sent to, the same address cannot belong to two peers at once: the mapping has to be unambiguous. In practice this is why, on the server side, each client gets its own /32 (or /128 in IPv6) rather than the whole subnet.
The asymmetry surprises people. On the client, AllowedIPs describes what you want to reach through the tunnel, often everything. On the server, it describes who that specific peer is allowed to be, usually a single address. The same field, read from two ends, means two different things.
The LAN exclusion problem, and why subtraction does not exist
The most common real question is "how do I route everything except my local network". There is no syntax for subtraction. 0.0.0.0/0 minus 192.168.1.0/24 cannot be expressed, because the field is a list of ranges and nothing more.
The answer is to enumerate the complement: instead of one catch-all, you list the set of CIDR blocks that cover the whole address space apart from the range you want to keep local. It is unglamorous, it produces a long line, and it is the only correct way. The catch-alls themselves are documented plainly: 0.0.0.0/0 matches all IPv4 addresses, ::/0 matches all IPv6.
The symptom that points here
A handshake that completes, and then nothing. wg show displays a recent handshake, the peers clearly found each other, and no traffic passes. When the handshake works, the keys and the endpoint are right by definition, so the problem is downstream, and AllowedIPs is the first place to look: either the destination is not in the list on the sending side, or the source is not accepted on the receiving side.
If the handshake itself never completes, that is a different diagnosis entirely and our handshake troubleshooting guide covers it. And if packets do flow but pages hang halfway, you are probably looking at an MTU problem rather than this field.
Not to be confused with PersistentKeepalive
These two get mixed up because both appear in the peer section and both seem to be about "keeping the connection working". They are unrelated. The manual describes PersistentKeepalive as an interval, between 1 and 65535 seconds, controlling how often an authenticated empty packet is sent to the peer, for the purpose of keeping a stateful firewall or NAT mapping valid. It is disabled by default, and the manual adds that most users will not need it.
AllowedIPs decides what is permitted. PersistentKeepalive decides how often you knock so that a NAT box does not forget you exist.
Getting it right the first time
Set the server peer entries to one address per client and nothing more. Set the client to the ranges you actually want to reach, which for a full tunnel means the catch-alls and for a split tunnel means the specific subnets. Read every AllowedIPs line twice: once as a route, once as a guest list. Our ready-to-use configuration templates apply that separation.
The field is small, it accepts almost anything you type, and it fails silently when it is wrong. That combination is why it deserves more attention than it usually gets.
★ Nuremberg GDPR datacenter · ✓ Dedicated IPv4 included · 200+ Mbps guaranteed
Self-host your VPN on your own VPS → ContaboFull root access · public IPv4 · pick your region→


