← All cheat sheets

WIREGUARD

Authorized use only. Offensive reference for systems you own or are explicitly permitted to test. You are responsible for staying within the law.

INSTALLATION#

# Debian/Ubuntu
sudo apt install wireguard

# CentOS/RHEL
sudo yum install epel-release elrepo-release
sudo yum install kmod-wireguard wireguard-tools

# macOS
brew install wireguard-tools

# Verify
wg --version

KEY GENERATION#

# Generate private key
wg genkey > privatekey

# Generate public key from private
wg pubkey < privatekey > publickey

# Generate both at once
wg genkey | tee privatekey | wg pubkey > publickey

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

# All in one
umask 077
wg genkey | tee /etc/wireguard/server_private.key | wg pubkey > /etc/wireguard/server_public.key

SERVER CONFIGURATION#

# /etc/wireguard/wg0.conf
[Interface]
PrivateKey = <SERVER_PRIVATE_KEY>
Address = 10.0.0.1/24
ListenPort = 51820
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

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

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

CLIENT CONFIGURATION#

# /etc/wireguard/wg0.conf
[Interface]
PrivateKey = <CLIENT_PRIVATE_KEY>
Address = 10.0.0.2/24
DNS = 1.1.1.1, 1.0.0.1

[Peer]
PublicKey = <SERVER_PUBLIC_KEY>
PresharedKey = <PRESHARED_KEY>
Endpoint = server.example.com:51820
AllowedIPs = 0.0.0.0/0, ::/0    # Route all traffic (full tunnel)
# AllowedIPs = 10.0.0.0/24      # Route only VPN subnet (split tunnel)
PersistentKeepalive = 25         # Keep NAT mappings alive

WG-QUICK COMMANDS#

wg-quick up wg0                  # Start interface
wg-quick down wg0                # Stop interface
sudo systemctl enable wg-quick@wg0   # Auto-start on boot
sudo systemctl start wg-quick@wg0
sudo systemctl stop wg-quick@wg0
sudo systemctl status wg-quick@wg0

WG COMMANDS#

wg                               # Show all interfaces
wg show                          # Detailed status
wg show wg0                      # Show specific interface
wg show wg0 dump                 # Machine-readable output
wg showconf wg0                  # Show running config

# Dynamic peer management (without restart)
wg set wg0 peer <PUBKEY> allowed-ips 10.0.0.4/32 endpoint 1.2.3.4:51820
wg set wg0 peer <PUBKEY> remove  # Remove peer

NAT AND ROUTING#

# Enable IP forwarding
echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.conf
echo 'net.ipv6.conf.all.forwarding = 1' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

# NAT with iptables (in PostUp/PostDown)
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

# NAT with nftables
PostUp = nft add table inet wg; nft add chain inet wg forward { type filter hook forward priority 0 \; }; nft add rule inet wg forward iifname %i accept; nft add rule inet wg forward oifname %i accept
PostDown = nft delete table inet wg

# UFW integration
sudo ufw allow 51820/udp
sudo ufw route allow in on wg0

SITE-TO-SITE VPN#

# Site A server (10.1.0.0/24 network)
[Interface]
PrivateKey = <SITE_A_PRIVATE>
Address = 10.0.0.1/24
ListenPort = 51820

[Peer]
PublicKey = <SITE_B_PUBLIC>
Endpoint = site-b.example.com:51820
AllowedIPs = 10.0.0.2/32, 10.2.0.0/24  # VPN IP + remote LAN

# Site B server (10.2.0.0/24 network)
[Interface]
PrivateKey = <SITE_B_PRIVATE>
Address = 10.0.0.2/24
ListenPort = 51820

[Peer]
PublicKey = <SITE_A_PUBLIC>
Endpoint = site-a.example.com:51820
AllowedIPs = 10.0.0.1/32, 10.1.0.0/24  # VPN IP + remote LAN

KILL SWITCH#

# Block all traffic if VPN drops
[Interface]
PrivateKey = <KEY>
Address = 10.0.0.2/24
DNS = 1.1.1.1
PostUp = iptables -I OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) -m addrtype ! --dst-type LOCAL -j REJECT
PreDown = iptables -D OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) -m addrtype ! --dst-type LOCAL -j REJECT

# Alternative: AllowedIPs = 0.0.0.0/0 already acts as kill switch
# since all traffic is routed through VPN

TROUBLESHOOTING#

# Check interface status
wg show wg0

# Check if port is listening
sudo ss -ulnp | grep 51820

# Test connectivity
ping 10.0.0.1                   # Ping VPN gateway

# Check handshake
wg show wg0 latest-handshakes   # Should show recent timestamp

# Debug kernel module
dmesg | grep wireguard

# Check routing
ip route show table all | grep wg0

# Common issues:
# - Firewall blocking UDP 51820
# - IP forwarding not enabled
# - Wrong AllowedIPs (cryptokey routing)
# - NAT/MASQUERADE not configured
# - DNS not resolving (check DNS= setting)

SECURITY CONSIDERATIONS#

# File permissions
chmod 600 /etc/wireguard/wg0.conf
chmod 600 /etc/wireguard/*key

# Use preshared keys for quantum resistance
# Rotate keys periodically
# Don't share private keys across devices
# Use separate keys per device
# Monitor peer connections
# Log connections via PostUp scripts