TTR Networks

Intermediate · WireGuard on Debian: users, routing and keys · section 8 of 10

Managing users

✓ Lab-tested 21 October 2026 on Debian 13.7, wireguard-tools 1.0.20210914, nftables 1.1.3

Adding and removing users is where WireGuard's simplicity shines, and where one convenient habit can take every user offline at once.

Adding a user, live

The usual method is to add the new [Peer] block to wg0.conf, then apply it to the running interface without a restart:

wg syncconf wg0 <(wg-quick strip wg0)

syncconf changes only what differs, so existing users' sessions aren't interrupted. But it makes the interface match the file exactly, and this server's file deliberately has no PrivateKey (it's loaded by PostUp). In the lab, syncconf added carol, and also removed the server's private key: wg show wg0 private-key said (none), and every user's tunnel stopped working, with no error from any command.

So pick one approach and stick to it:

  • Private key in wg0.conf (root-only, chmod 600): wg syncconf is safe. This is the common setup.
  • Private key in its own file, loaded by PostUp: change peers with wg set instead, which never touches the key, and edit the file too so the change survives a restart. If you do use syncconf, follow it with wg set wg0 private-key … straight away.

Removing a user

wg set wg0 peer <their public key> remove takes effect immediately: bob's very next packet was dropped. There's no revocation list to publish and nothing to restart. Remove their block from wg0.conf too, or they'll be back after the next reboot. bob's own client still shows a recent handshake, because from his side nothing told it otherwise; it just stops getting answers.

Preshared keys

For an extra layer, each peer pair can share a symmetric key, made with wg genpsk and added as PresharedKey on both ends. It's mixed into the handshake, which protects today's traffic against a future attacker with a quantum computer that could break the public-key exchange. It's a secret, so treat it like a private key.

carol's [Peer] block, appended to the server's wg0.conf

[Peer]
# carol
PublicKey = P+TMulXP07Ldwcf65Rx1CvXDOxK57C3HWV5aY5oDHEo=
AllowedIPs = 10.9.0.12/32
syncconf with a key-less config (real output)
root@vpn:~# cat peer-carol.conf >> /etc/wireguard/wg0.conf && wg syncconf wg0 <(wg-quick strip wg0) && wg show wg0 peers
hwCdM7ImFlIKfF0sQHngu9THMAenVRLSD1JYIrqR2Qw=
8BpkL72eT8cHe8HTgKE8yWD464E0FVbQGlQ1FPi0tnc=
sh5Ul4rjT56yt7ZYYVSrpJvxEIqKFx/HxkeICJIgGws=
P+TMulXP07Ldwcf65Rx1CvXDOxK57C3HWV5aY5oDHEo=

root@carol:~# wg-quick up wg0 >/dev/null 2>&1 && ping -c 2 -W 1 10.10.0.20 | tail -2
2 packets transmitted, 0 received, 100% packet loss, time 1043ms


root@vpn:~# wg show | sed -n "/hwCdM7/,/^$/p" | grep -E "peer|handshake"
peer: hwCdM7ImFlIKfF0sQHngu9THMAenVRLSD1JYIrqR2Qw=
  latest handshake: 1 minute, 42 seconds ago

root@vpn:~# wg show wg0 private-key
(none)

root@alice:~# ping -c 2 -W 1 10.10.0.20 | tail -2
2 packets transmitted, 0 received, 100% packet loss, time 1035ms
  • Lines 1–5: carol is added; the four peers look right.
  • Lines 7–8: But carol can't connect…
  • Lines 11–13: …and alice's last handshake is getting old.
  • Lines 15–16: The server's private key is gone: the file didn't have one, so syncconf removed it.
  • Lines 18–19: Every user is now cut off.
Putting the key back (real output)
root@vpn:~# wg set wg0 private-key /etc/wireguard/server.key && wg show wg0 public-key
/S03YCIRbPGjlhE53GYhxFEh8LVo/Joel3BkEgWeeXk=

root@carol:~# ping -c 2 -W 1 10.10.0.20 | tail -2
2 packets transmitted, 0 received, 100% packet loss, time 1027ms


root@alice:~# ping -c 2 -W 1 10.10.0.20 | tail -2
2 packets transmitted, 2 received, 0% packet loss, time 1027ms
rtt min/avg/max/mdev = 0.351/0.653/0.955/0.302 ms

root@vpn:~# wg show | grep -E "^peer|handshake"
peer: P+TMulXP07Ldwcf65Rx1CvXDOxK57C3HWV5aY5oDHEo=
  latest handshake: 2 seconds ago
peer: hwCdM7ImFlIKfF0sQHngu9THMAenVRLSD1JYIrqR2Qw=
  latest handshake: 4 seconds ago
peer: 8BpkL72eT8cHe8HTgKE8yWD464E0FVbQGlQ1FPi0tnc=
  latest handshake: 55 seconds ago
peer: sh5Ul4rjT56yt7ZYYVSrpJvxEIqKFx/HxkeICJIgGws=
  latest handshake: 1 minute, 7 seconds ago

root@carol:~# ping -c 2 -W 1 10.10.0.20 | tail -2
2 packets transmitted, 2 received, 0% packet loss, time 1069ms
rtt min/avg/max/mdev = 0.369/0.529/0.689/0.160 ms
  • Lines 1–2: The key is back, and so is the public key users expect.
  • Lines 4–5: carol's first try still fails: her tunnel is waiting a few seconds before retrying its handshake.
  • Lines 8–10: alice works straight away.
  • Lines 12–20: Fresh handshakes all round.
  • Lines 22–24: And carol's retry gets through.
Removing bob (real output)
root@bob:~# ping -c 2 -W 1 10.10.0.20 | tail -2
2 packets transmitted, 2 received, 0% packet loss, time 1014ms
rtt min/avg/max/mdev = 0.611/0.691/0.772/0.080 ms

root@vpn:~# wg set wg0 peer 8BpkL72eT8cHe8HTgKE8yWD464E0FVbQGlQ1FPi0tnc= remove && wg show wg0 peers && wg show wg0 public-key
hwCdM7ImFlIKfF0sQHngu9THMAenVRLSD1JYIrqR2Qw=
sh5Ul4rjT56yt7ZYYVSrpJvxEIqKFx/HxkeICJIgGws=
P+TMulXP07Ldwcf65Rx1CvXDOxK57C3HWV5aY5oDHEo=
/S03YCIRbPGjlhE53GYhxFEh8LVo/Joel3BkEgWeeXk=

root@bob:~# ping -c 2 -W 1 10.10.0.20 | tail -2
2 packets transmitted, 0 received, 100% packet loss, time 1055ms


root@bob:~# wg show | grep -E "handshake|transfer"
  latest handshake: 4 seconds ago
  transfer: 1.07 KiB received, 2.19 KiB sent

root@vpn:~# grep -c "^\[Peer\]" /etc/wireguard/wg0.conf; grep "^# " /etc/wireguard/wg0.conf
3
# /etc/wireguard/wg0.conf on the VPN server  (systemctl enable --now wg-quick@wg0)
# The private key stays in its own root-only file, not in this config.
# One [Peer] per user. AllowedIPs is both the route to them and the only
# source addresses accepted from them.
# alice
# branch: a router, with the branch LAN behind it
# carol
  • Lines 1–3: bob works.
  • Lines 5–9: One command removes his key; the server's own key is untouched.
  • Lines 11–12: His very next ping fails.
  • Lines 15–17: His own client can't tell: from its side, the last handshake was fine.
  • Lines 19–27: bob's block also removed from the file, so he stays gone after a restart.

Check your understanding

Your server's wg0.conf has the private key in PostUp, not as PrivateKey. How should you add a new user without a restart?

  • wg set wg0 peer <key> allowed-ips …, and add the block to the file.
  • wg syncconf wg0 <(wg-quick strip wg0) on its own.
  • systemctl reload wg-quick@wg0.
  • Edit the file; WireGuard rereads it automatically.

Check your understanding

How quickly does removing a user's peer stop them, compared with revoking an OpenVPN certificate?

  • Immediately: their next packet has no key to match.
  • At their next handshake, up to two minutes later.
  • When the server restarts.
  • When their client is restarted.