Most broken WireGuard configurations are not wrong about a value; they put the right value on the wrong side. A private key belongs to this machine, a peer carries the other machine's public key, and an address sits in the interface block even though it describes where the tunnel lives. Read the file as two directions meeting, then check what the helper script added on top. The protocol itself has fewer fields than the file does, and the extra ones are worth knowing separately.

Interface keys describe this machine

The interface block holds this endpoint's own identity. PrivateKey is that identity and never leaves the host; the matching public key is derived from it and is what other peers list. ListenPort is where this side receives handshakes, so two clients behind one address need different ports.

Address is the tunnel address this host answers on, written with a prefix length because it is also the source it will use. Getting the prefix wrong here changes which destinations the host believes are on-link, which produces failures that look like routing rather than configuration.

Everything else in a [Interface] block with a real-world client is usually added by wg-quick: DNS, MTU, Table, and the hook lines. They are not protocol fields, and a bare wg setup ignores them entirely.

Each peer entry describes one other side

A [Peer] block is the remote party. PublicKey is that party's derived key, never their private key, and PresharedKey is an optional extra secret both sides must hold identically. Endpoint is where to send, and PersistentKeepalive asks this host to send a packet after the interval when nothing else is going out.

Two mistakes account for most of the confusion here. Copying your own private key into a peer block makes the two ends share one identity, and the handshake fails in a way that logs poorly. Leaving Endpoint out on a client is usually intentional, because the server learns the address from the incoming handshake; leaving it out on a server that must initiate is not. Also remember that keepalive keeps a NAT mapping open, and it does not improve throughput or reduce latency, so thirty seconds of extra packets buys nothing when traffic already flows.

AllowedIPs is routing, not a permission list

AllowedIPs is WireGuard's cryptokey routing. Outbound, it decides which peer receives a packet based on its destination. Inbound, it decides whether a packet arriving from that peer is accepted based on its source. The same field does both jobs, which is why it is not an access-control list and not a list of permitted websites.

A narrow AllowedIPs on the server for a client means the server will only accept packets claiming those sources, and will only send those destinations to that client. Widen one side without widening the other, and you get a tunnel that comes up and passes nothing.

What wg-quick adds around the protocol

wg-quick reads the same file and performs the network steps the protocol leaves to the operating system. It assigns the interface address, adds routes derived from AllowedIPs, writes the resolver settings, and runs the hook commands in order.

That layer explains the classic asymmetry. A file with 0.0.0.0/0 and a DNS line gives a client a default route and a resolver, and it does nothing at all to the server's forwarding or NAT rules. Those belong to the server's own configuration, and no client file can supply them.

Keep one owner for the file. Editing it by hand while SaveConfig is enabled means your edit disappears the next time the interface goes down, and the interface will not tell you it happened.

Check the applied state, not the file

The file is an intention. The applied state is what the kernel holds, and they diverge whenever a helper, a drop-in or a hook edited something after activation.

Read the live state and the addressing together, then compare both with what you wrote:

sudo wg show
ip -4 addr show dev wg0
ip -4 route show dev wg0
grep -v "^#" /etc/wireguard/wg0.conf

If the peer list is empty, the interface was created without its configuration being applied. If addresses and routes exist but counters stay at zero, the file loaded and the handshake is failing, which is a key or endpoint problem rather than a section-order problem. Compare the two views before editing, because the gap between them is usually the actual fault.

Pennadoù liammet