WireGuard VPN: Server Setup and Multi-peer Configs

Fast, kernel-native VPN for your homelab. Covers server setup, multiple peers, and split-tunneling.

WireGuard is a modern VPN protocol that uses the Noise protocol framework, Curve25519 for key exchange, ChaCha20-Poly1305 for symmetric encryption, and BLAKE2s for hashing. Its implementation in the Linux kernel (mainlined since 5.6) is compact enough to audit and fast enough to saturate a gigabit link on modest hardware. This guide sets up a WireGuard server on a Debian 12 host and adds multiple client peers with both full-tunnel and split-tunnel configurations.

1. Install WireGuard

WireGuard is in the main Debian and Ubuntu repositories:

apt update && apt install -y wireguard wireguard-tools

Confirm the kernel module loads:

modprobe wireguard
lsmod | grep wireguard

2. Generate server keys

wg genkey | tee /etc/wireguard/server_private.key |   wg pubkey > /etc/wireguard/server_public.key
chmod 600 /etc/wireguard/server_private.key
cat /etc/wireguard/server_public.key

3. Server configuration

Create /etc/wireguard/wg0.conf:

[Interface]
Address = 10.8.0.1/24
ListenPort = 51820
PrivateKey = <contents of server_private.key>

# NAT: replace eth0 with your outbound interface
PostUp = iptables -A FORWARD -i %i -j ACCEPT;          iptables -A FORWARD -o %i -j ACCEPT;          iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT;            iptables -D FORWARD -o %i -j ACCEPT;            iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

Enable IP forwarding:

echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl -p

Open the firewall port and start the interface:

ufw allow 51820/udp
systemctl enable --now wg-quick@wg0
wg show

4. Generate and add peer keys

Repeat for each client. On the client machine (or generate on the server and transfer securely):

wg genkey | tee laptop_private.key | wg pubkey > laptop_public.key
wg genpsk > laptop_preshared.key   # optional extra layer

Add the peer to the server’s wg0.conf:

[Peer]
# laptop — Priya's ThinkPad
PublicKey = <laptop_public.key>
PresharedKey = <laptop_preshared.key>
AllowedIPs = 10.8.0.2/32
systemctl reload wg-quick@wg0
# or live-reload without restart:
wg addpeer <pubkey> preshared-key <pskfile> allowed-ips 10.8.0.2/32

5. Client configuration: full tunnel

On the client machine, create /etc/wireguard/wg0.conf:

[Interface]
Address = 10.8.0.2/32
PrivateKey = <contents of laptop_private.key>
DNS = 10.8.0.1  # Pi-hole / Unbound on the server

[Peer]
PublicKey = <server_public.key>
PresharedKey = <laptop_preshared.key>
Endpoint = vpn.yourdomain.net:51820
AllowedIPs = 0.0.0.0/0, ::/0  # full tunnel
PersistentKeepalive = 25
wg-quick up wg0
ping 10.8.0.1

PersistentKeepalive = 25 sends a keepalive packet every 25 seconds. This is necessary when the client is behind NAT and the server needs to be able to reach it. Omit it if the client always initiates connections.

6. Split-tunnel configuration

For a client that should only route homelab subnets through the VPN (and use its local network for everything else), change AllowedIPs:

[Peer]
...
AllowedIPs = 10.8.0.0/24, 192.168.10.0/24, 192.168.20.0/24
# Omit PersistentKeepalive if client-initiated only

The AllowedIPs field doubles as a routing table: WireGuard will route packets matching those subnets into the tunnel. Everything else goes out the default route.

7. Multiple peers example

A server config with two peers:

[Interface]
Address = 10.8.0.1/24
ListenPort = 51820
PrivateKey = <SERVER_PRIVATE_KEY>
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

[Peer]
# laptop
PublicKey = <LAPTOP_PUB>
PresharedKey = <LAPTOP_PSK>
AllowedIPs = 10.8.0.2/32

[Peer]
# phone
PublicKey = <PHONE_PUB>
PresharedKey = <PHONE_PSK>
AllowedIPs = 10.8.0.3/32

8. Verifying the tunnel

wg show
# On client:
curl -4 ifconfig.me       # should return server's public IP on full tunnel
traceroute 192.168.10.1   # should route through VPN on split tunnel

9. QR codes for mobile clients

Install qrencode and print a QR code the WireGuard mobile app can scan:

apt install -y qrencode
qrencode -t ansiutf8 < /etc/wireguard/client-phone.conf

Do this in a terminal session you trust; the QR encodes the private key.