تخطَّ إلى المحتوى

WireGuard Cheat Sheet

Overview

WireGuard is a fast, modern VPN protocol and implementation designed to be simpler, leaner, and more useful than IPsec and OpenVPN. It uses cutting-edge cryptography including Curve25519 for key exchange, ChaCha20 for encryption, Poly1305 for authentication, BLAKE2s for hashing, and SipHash for hashtable keys. The entire codebase is approximately 4,000 lines — an order of magnitude smaller than IPsec or OpenVPN — making it far easier to audit.

WireGuard operates at Layer 3, creating a virtual network interface (wg0, wg1, etc.) that behaves like any other network interface but encrypts all traffic. It is built into the Linux kernel from version 5.6 onward, and kernel-native performance makes it significantly faster than userspace VPN solutions. WireGuard uses a concept called “cryptokey routing” — each peer is identified solely by its public key, and the allowed IP ranges for that peer determine how packets are routed.

The protocol is stateless by design: there is no handshake phase visible to network observers, no connection state, and endpoints roam freely. If a client changes IP addresses, the tunnel continues working transparently. This makes WireGuard ideal for mobile devices that frequently switch between networks. WireGuard also implements a “silent” mode when no data is flowing — it sends no keepalive packets and leaves no detectable fingerprint on the network when idle.

Installation

Ubuntu/Debian

# Ubuntu 20.04+ and Debian 11+ include WireGuard
sudo apt update && sudo apt install -y wireguard wireguard-tools

# Older Ubuntu via backports
sudo add-apt-repository ppa:wireguard/wireguard
sudo apt update && sudo apt install -y wireguard

# Verify kernel module
modprobe wireguard
lsmod | grep wireguard

RHEL/CentOS/Fedora

# Fedora
sudo dnf install -y wireguard-tools

# RHEL 8/9 with EPEL
sudo dnf install -y epel-release
sudo dnf install -y wireguard-tools kmod-wireguard

# Enable kernel module
sudo modprobe wireguard
echo 'wireguard' | sudo tee /etc/modules-load.d/wireguard.conf

macOS

# Install WireGuard tools via Homebrew
brew install wireguard-tools

# Or use the official macOS app from the App Store
# App Store: "WireGuard"

# Use wg-quick with macOS
sudo wg-quick up /etc/wireguard/wg0.conf

Windows

# Download the official installer from https://www.wireguard.com/install/
# Or via winget
winget install WireGuard.WireGuard

# Or via Chocolatey
choco install wireguard

Docker

# Run WireGuard in Docker (linuxserver image)
docker run -d \
  --name=wireguard \
  --cap-add=NET_ADMIN \
  --cap-add=SYS_MODULE \
  -e PUID=1000 -e PGID=1000 \
  -e SERVERURL=vpn.example.com \
  -e PEERS=phone,laptop \
  -p 51820:51820/udp \
  -v /opt/wireguard:/config \
  -v /lib/modules:/lib/modules:ro \
  --sysctl="net.ipv4.conf.all.src_valid_mark=1" \
  --restart unless-stopped \
  lscr.io/linuxserver/wireguard:latest

Configuration

Key Generation

# Generate private/public key pair
wg genkey | tee privatekey | wg pubkey > publickey

# Generate preshared key (optional, quantum-resistant layer)
wg genpsk > presharedkey

# View keys
cat privatekey
cat publickey

# Generate keys inline (for config)
PRIVATE=$(wg genkey)
PUBLIC=$(echo $PRIVATE | wg pubkey)
echo "Private: $PRIVATE"
echo "Public:  $PUBLIC"

Server Configuration (/etc/wireguard/wg0.conf)

[Interface]
# Server's private key
PrivateKey = <SERVER_PRIVATE_KEY>
# VPN subnet address for this server
Address = 10.0.0.1/24
# UDP port to listen on
ListenPort = 51820
# Enable NAT for internet access through VPN
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
# DNS server for peers (optional)
DNS = 1.1.1.1

[Peer]
# Client 1 - Laptop
PublicKey = <CLIENT1_PUBLIC_KEY>
PresharedKey = <PRESHARED_KEY>
AllowedIPs = 10.0.0.2/32

[Peer]
# Client 2 - Phone
PublicKey = <CLIENT2_PUBLIC_KEY>
AllowedIPs = 10.0.0.3/32

Client Configuration (/etc/wireguard/wg0.conf)

[Interface]
# Client's private key
PrivateKey = <CLIENT_PRIVATE_KEY>
# Client's VPN IP address
Address = 10.0.0.2/24
# Optional: set DNS when tunnel is up
DNS = 10.0.0.1

[Peer]
# Server's public key
PublicKey = <SERVER_PUBLIC_KEY>
PresharedKey = <PRESHARED_KEY>
# Server's public endpoint
Endpoint = vpn.example.com:51820
# Route all traffic through VPN (full tunnel)
AllowedIPs = 0.0.0.0/0, ::/0
# Send keepalive to maintain NAT mapping
PersistentKeepalive = 25

Enable IP Forwarding (Server)

# Enable immediately
sudo sysctl -w net.ipv4.ip_forward=1
sudo sysctl -w net.ipv6.conf.all.forwarding=1

# Make persistent
echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.d/99-wireguard.conf
echo "net.ipv6.conf.all.forwarding=1" | sudo tee -a /etc/sysctl.d/99-wireguard.conf
sudo sysctl -p /etc/sysctl.d/99-wireguard.conf

Core Commands

CommandDescription
wg genkeyGenerate a private key
wg pubkey < privatekeyDerive public key from private key
wg genpskGenerate a preshared key
wg showShow current WireGuard interface status
wg show wg0Show status for specific interface
wg showconf wg0Show full current config for interface
wg set wg0 peer PUB_KEY allowed-ips IPAdd/update a peer dynamically
wg set wg0 peer PUB_KEY removeRemove a peer dynamically
wg-quick up wg0Bring up interface using config file
wg-quick down wg0Bring down interface
wg-quick strip wg0Show config stripped of wg-quick fields
ip link show wg0Show WireGuard network interface
ip addr show wg0Show interface addresses
ip route show table mainShow routing table

Advanced Usage

Split Tunneling (Route Only Specific Traffic)

# Client config — only route specific subnets through VPN
[Peer]
PublicKey = <SERVER_PUBLIC_KEY>
Endpoint = vpn.example.com:51820
# Only route internal subnets through VPN, not all traffic
AllowedIPs = 10.0.0.0/8, 192.168.1.0/24, 172.16.0.0/12
PersistentKeepalive = 25

Kill Switch Configuration

[Interface]
PrivateKey = <CLIENT_PRIVATE_KEY>
Address = 10.0.0.2/24
DNS = 10.0.0.1
# Drop all traffic if VPN goes down
PostUp = iptables -I OUTPUT ! -o wg0 -m mark ! --mark $(wg show wg0 fwmark) -m addrtype ! --dst-type LOCAL -j REJECT
PreDown = iptables -D OUTPUT ! -o wg0 -m mark ! --mark $(wg show wg0 fwmark) -m addrtype ! --dst-type LOCAL -j REJECT

[Peer]
PublicKey = <SERVER_PUBLIC_KEY>
Endpoint = vpn.example.com:51820
AllowedIPs = 0.0.0.0/0, ::/0

Site-to-Site VPN

# Site A server — 192.168.1.0/24 local subnet
[Interface]
PrivateKey = <SITE_A_PRIVATE_KEY>
Address = 10.0.0.1/30
ListenPort = 51820
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT

[Peer]
# Site B
PublicKey = <SITE_B_PUBLIC_KEY>
Endpoint = site-b.example.com:51820
# Allow Site B's VPN IP and local subnet
AllowedIPs = 10.0.0.2/32, 192.168.2.0/24
PersistentKeepalive = 25

# Site B server — 192.168.2.0/24 local subnet
[Interface]
PrivateKey = <SITE_B_PRIVATE_KEY>
Address = 10.0.0.2/30
ListenPort = 51820

[Peer]
# Site A
PublicKey = <SITE_A_PUBLIC_KEY>
Endpoint = site-a.example.com:51820
AllowedIPs = 10.0.0.1/32, 192.168.1.0/24
PersistentKeepalive = 25

IPv6 Dual-Stack

[Interface]
PrivateKey = <PRIVATE_KEY>
Address = 10.0.0.1/24, fd00::1/64
ListenPort = 51820

[Peer]
PublicKey = <PEER_PUBLIC_KEY>
AllowedIPs = 10.0.0.2/32, fd00::2/128

Systemd Integration

# Enable WireGuard interface on boot
sudo systemctl enable wg-quick@wg0
sudo systemctl start wg-quick@wg0
sudo systemctl status wg-quick@wg0

# Restart after config change
sudo systemctl restart wg-quick@wg0

# View logs
journalctl -u wg-quick@wg0 -f

NAT Traversal and Dynamic Endpoints

# Add peer with dynamic endpoint (updates on handshake)
sudo wg set wg0 peer <PUBLIC_KEY> \
  endpoint vpn.example.com:51820 \
  allowed-ips 10.0.0.2/32 \
  persistent-keepalive 25

# Save running config back to file
sudo wg showconf wg0 > /etc/wireguard/wg0.conf

# Dynamic peer management script
#!/bin/bash
# Add peer
wg set wg0 peer "$1" allowed-ips "$2" persistent-keepalive 25
wg-quick save wg0

Common Workflows

Quick Server Setup

# 1. Install WireGuard
sudo apt install -y wireguard-tools

# 2. Generate keys
cd /etc/wireguard
umask 077
wg genkey | tee server_private.key | wg pubkey > server_public.key

# 3. Create server config
cat > /etc/wireguard/wg0.conf << EOF
[Interface]
PrivateKey = $(cat server_private.key)
Address = 10.0.0.1/24
ListenPort = 51820
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o $(ip route | awk '/default/ {print $5}') -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o $(ip route | awk '/default/ {print $5}') -j MASQUERADE
EOF

# 4. Enable IP forwarding
echo "net.ipv4.ip_forward=1" >> /etc/sysctl.d/99-wireguard.conf
sysctl -p /etc/sysctl.d/99-wireguard.conf

# 5. Start and enable
sudo systemctl enable --now wg-quick@wg0

# 6. Open firewall
sudo ufw allow 51820/udp

Adding a New Client

# On server — generate client keys
CLIENT_PRIV=$(wg genkey)
CLIENT_PUB=$(echo $CLIENT_PRIV | wg pubkey)
CLIENT_IP="10.0.0.5"

# Add peer to server (live, no restart)
sudo wg set wg0 peer $CLIENT_PUB allowed-ips ${CLIENT_IP}/32

# Save to config file
sudo wg-quick save wg0

# Create client config (send securely to client)
cat << EOF
[Interface]
PrivateKey = $CLIENT_PRIV
Address = ${CLIENT_IP}/24
DNS = 10.0.0.1

[Peer]
PublicKey = $(cat /etc/wireguard/server_public.key)
Endpoint = $(curl -s ifconfig.me):51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
EOF

Generating QR Codes for Mobile Clients

# Install qrencode
sudo apt install -y qrencode

# Display client config as QR code in terminal
qrencode -t ansiutf8 < /etc/wireguard/client.conf

# Save as PNG for sharing
qrencode -o client-qr.png < /etc/wireguard/client.conf

Monitoring and Diagnostics

# Show all peers and their status
watch -n 1 wg show

# Check handshake timestamps (non-zero = connected)
wg show wg0 latest-handshakes

# Monitor traffic
wg show wg0 transfer

# Capture WireGuard traffic (UDP port 51820)
sudo tcpdump -i eth0 -n 'udp port 51820'

# Check routing
ip route show table main
ip route show table 51820   # WireGuard's routing table

# Test connectivity through tunnel
ping 10.0.0.1               # Ping server VPN IP
traceroute 8.8.8.8          # Verify traffic routing

Tips and Best Practices

PracticeDetails
Protect private keysSet umask 077 before generating; store only in /etc/wireguard/ owned by root
Use preshared keysAdds a symmetric key layer for post-quantum resistance
Restrict AllowedIPsUse specific subnets instead of 0.0.0.0/0 when split tunneling
PersistentKeepalive 25Use only on clients behind NAT; servers should not set this
DNS leaksSet DNS in [Interface] and verify with a DNS leak test
Rotate keys regularlyRegenerate peer keys periodically to limit exposure from compromise
Audit peer listRun wg show regularly to verify all peers are expected
Use port 443Some networks block 51820; WireGuard works on any UDP port
Firewall firstConfigure firewall before starting the tunnel on a server
Log monitoringUse journalctl -u wg-quick@wg0 and set up alerting on handshake failures