User:Cmsigler/Wireguard Configuration Guide
My Personal Step-by-step Guide to Wireguard Setup, Configuration and Operation
CMS, 2022/03/14
Note: These procedures have been developed and deployed on an Arch Linux installation. Other distributions and environments will require modifications to the steps below. YMMV
Note: For information on WireGuard under Arch, see the Arch Linux WireGuard page.
Nomenclature
- Gateway peer: Wireguard "server" peer connected to public Internet
- VPN peer: Wireguard "client" peer; may be located behind, e.g., a NAT router
Initial Setup
Requirements
- Install and use kernel with CONFIG_WIREGUARD
- Install wireguard-tools
Pre-configuration
- Generate keys for each peer [gateway = Gateway peer; vpn = VPN peer]
$ cd ~/wireguard_config $ (umask 0077; wg genkey > gateway.key) $ wg pubkey < gateway.key > gateway.pub $ (umask 0077; wg genkey > vpn.key) $ wg pubkey < vpn.key > vpn.pub
- Optional: Generate pre-shared keys for each peer-to-peer link pair
$ (umask 0077; wg genpsk > gateway-vpn.psk)
- Optional: On gateway peer, set up DNS server for wireguard peers using dnsmasq as server
- Install dnsmasq
- Edit /etc/dnsmasq.conf
- Uncomment domain-needed, bogus-priv, bind-interfaces
- Set "interface=wg0"
- Set "listen-address=::1,127.0.0.1,10.0.0.1,2001:db8:1234:5678::1,fd89:abc1:def2:1::1"
- Optional: Set "cache-size=1000"
Configuration for operation via wg-quick
Example -- Wireguard VPN gateway:
Wireguard configuration
On gateway peer:
/etc/wireguard/wg0.conf
[Interface] Address = 10.0.0.1/24, 2001:db8:1234:5678::1/64, fd89:abc1:def2:1::1/64 ListenPort = 51871 PrivateKey = # GATEWAY_PEER_PRIVATE_KEY [Peer] PublicKey = # VPN_PEER_PUBLIC_KEY PresharedKey = # GATEWAY_PEER-VPN_PEER-PRESHARED_KEY AllowedIPs = 10.0.0.2/32, 2001:db8:1234:5678::2/128, fd89:abc1:def2:1::2/128
On VPN peer:
/etc/wireguard/wg0.conf
[Interface] Address = 10.0.0.2/32, 2001:db8:1234:5678::2/128, fd89:abc1:def2:1::2/128 ListenPort = 51902 PrivateKey = # GATEWAY_PEER_PRIVATE_KEY DNS = 2001:db8:1234:5678::1, 10.0.0.1 [Peer] PublicKey = # VPN_PEER_PUBLIC_KEY PresharedKey = # GATEWAY_PEER-VPN_PEER-PRESHARED_KEY AllowedIPs = 0.0.0.0/0, ::/0 Endpoint = 198.51.100.49:51871
Firewall/filtering configuration (using nftables)
On Gateway peer:
- Input filter
define upstream-if = ens0 define vpn-if = wg0 define mgmt-host = 203.0.113.51 define ssh-port = 22 define vpn-port = 51871 # table inet inet-local-table { chain inet-local-input { type filter hook input priority filter policy drop # Accept localhost traffic iif lo accept # Bad TCP --> reject network scanning iif $upstream-if tcp flags & (fin|syn) == (fin|syn) counter drop iif $upstream-if tcp flags & (syn|rst) == (syn|rst) counter drop iif $upstream-if tcp flags & (fin|syn|rst|psh|ack|urg) == 0 counter drop iif $upstream-if tcp flags & (fin|syn|rst|psh|ack|urg) == (fin|psh|urg) counter drop # Accept Wireguard inbound UDP traffic from peer to VPN port iif $upstream-if udp dport $vpn-port accept # Accept ICMP from Wireguard peers iifname $vpn-if ip protocol icmp limit rate 5/second accept iifname $vpn-if meta l4proto ipv6-icmp limit rate 5/second accept # Allow DNS from Wireguard peers iifname $vpn-if udp dport 53 accept iifname $vpn-if tcp dport 53 accept # Remaining input from VPN interface to VPN server (local) prohibited # -- default policy drop iifname $vpn-if counter drop # Drop invalid (untracked?) packets iif $upstream-if ct state invalid counter drop # Accept established and related tracked connections iif $upstream-if ct state {established, related} accept # Allow connection from given mgmt host on given ssh port iif $upstream-if ip saddr $mgmt-host tcp dport $ssh-port accept # Limit ICMP packets accepted iif $upstream-if ip protocol icmp limit rate 5/second accept iif $upstream-if meta l4proto ipv6-icmp limit rate 5/second accept # Count traffic dropped by default policy counter drop } }
- Forward filter
define upstream-if = ens0 define vpn-if = wg0 # table inet inet-local-table { chain inet-local-forward { type filter hook forward priority filter policy drop # Drop IP forward for upstream invalid packets iif $upstream-if ct state invalid counter drop # Accept IP forward for upstream established and related tracked connections iif $upstream-if ct state {established, related} accept # Accept all VPN traffic to be forwarded upstream iifname $vpn-if oif $upstream-if accept # Count traffic dropped by default policy counter drop } }
- Address translation (NAT) filter
define upstream-if = ens0 define vpn-if = wg0 # table inet inet-local-table { chain inet-local-nat { type nat hook postrouting priority srcnat policy accept # NAT/masquerade all traffic coming from VPN interface, and count iifname $vpn-if oif $upstream-if meta protocol ip counter masquerade } }
Packet forwarding configuration
On Gateway peer:
- sysctl configuration
/etc/sysctl.d/30-ipv4_forward.conf
net.ipv4.ip_forward=1 net.ipv4.conf.default.forwarding=1 net.ipv4.conf.all.forwarding=1 net.ipv4.conf.ens3.forwarding=1 net.ipv4.conf.wg0.forwarding=1
/etc/sysctl.d/30-ipv6_forward.conf
net.ipv6.conf.default.accept_ra = 2 net.ipv6.conf.all.accept_ra = 2 net.ipv6.conf.ens3.accept_ra = 2 net.ipv6.conf.wg0.accept_ra = 2 net.ipv6.conf.default.forwarding=1 net.ipv6.conf.all.forwarding=1 net.ipv6.conf.ens3.forwarding=1 net.ipv6.conf.wg0.forwarding=1
Configuration for operation via systemd-networkd
Example -- Wireguard VPN gateway:
/etc/systemd/network configuration
On gateway peer:
/etc/systemd/network/99-wg0.netdev
[NetDev] Name=wg0 Kind=wireguard Description=WireGuard tunnel wg0 [WireGuard] ListenPort=51871 PrivateKey=#GATEWAY_PEER_PRIVATE_KEY [WireGuardPeer] PublicKey=#VPN_PEER_PUBLIC_KEY PresharedKey=#GATEWAY_PEER-VPN_PEER-PRESHARED_KEY AllowedIPs=10.0.0.2/32 AllowedIPs=2001:db8:1234:5678::2/128, fd89:abc1:def2:1::2/128
On gateway peer:
/etc/systemd/network/99-wg0.network
[Match] Name=wg0 [Network] Address=10.0.0.1/24 Address=2001:db8:1234:5678::1/64 Address=fd89:abc1:def2:1::1/64 IPForward=yes IPMasquerade=ipv4 # or #IPMasquerade=both
On VPN peer:
/etc/systemd/network/99-wg0.netdev
[NetDev] Name=wg0 Kind=wireguard Description=WireGuard tunnel wg0 [WireGuard] ListenPort=51902 PrivateKey=#VPN_PEER_PRIVATE_KEY FirewallMark=0x89ab [WireGuardPeer] PublicKey=#GATEWAY_PEER_PUBLIC_KEY PresharedKey=#GATEWAY_PEER-VPN_PEER-PRESHARED_KEY AllowedIPs=0.0.0.0/0 AllowedIPs=::/0 Endpoint=198.51.100.49:51871
On VPN peer:
/etc/systemd/network/50-wg0.network
[Match] Name=wg0 [Network] Address=10.0.0.2/32 Address=2001:db8:1234:5678::2/128 Address=fd89:abc1:def2:1::2/128 DNS=2001:db8:1234:5678::1 DNS=10.0.0.1 DNSDefaultRoute=yes Domains=~. [RoutingPolicyRule] FirewallMark=0x89ab InvertRule=yes Table=1000 Priority=10 [Route] Gateway=2001:db8:1234:5678::1 GatewayOnLink=yes Table=1000 [Route] Gateway=10.0.0.1 GatewayOnLink=yes Table=1000
Firewall/filtering configuration (using nftables)
On gateway peer:
- Input filter
define upstream-if = ens0 define vpn-if = wg0 define mgmt-host = 203.0.113.51 define ssh-port = 22 define vpn-port = 51871 # table inet inet-local-table { chain inet-local-input { type filter hook input priority filter policy drop # Accept localhost traffic iif lo accept # Bad TCP --> reject network scanning iif $upstream-if tcp flags & (fin|syn) == (fin|syn) counter drop iif $upstream-if tcp flags & (syn|rst) == (syn|rst) counter drop iif $upstream-if tcp flags & (fin|syn|rst|psh|ack|urg) == 0 counter drop iif $upstream-if tcp flags & (fin|syn|rst|psh|ack|urg) == (fin|psh|urg) counter drop # Accept Wireguard inbound UDP traffic from peer to VPN port iif $upstream-if udp dport $vpn-port accept # Accept ICMP from Wireguard peers iifname $vpn-if ip protocol icmp limit rate 5/second accept iifname $vpn-if meta l4proto ipv6-icmp limit rate 5/second accept # Allow DNS from Wireguard peers iifname $vpn-if udp dport 53 accept iifname $vpn-if tcp dport 53 accept # Remaining input from VPN interface to VPN server (local) prohibited # -- default policy drop iifname $vpn-if counter drop # Drop invalid (untracked?) packets iif $upstream-if ct state invalid counter drop # Accept established and related tracked connections iif $upstream-if ct state {established, related} accept # Allow connection from given mgmt host on given ssh port iif $upstream-if ip saddr $mgmt-host tcp dport $ssh-port accept # Limit ICMP packets accepted iif $upstream-if ip protocol icmp limit rate 5/second accept iif $upstream-if meta l4proto ipv6-icmp limit rate 5/second accept # Count traffic dropped by default policy counter drop } }
- Forward filter
define upstream-if = ens0 define vpn-if = wg0 # table inet inet-local-table { chain inet-local-forward { type filter hook forward priority filter policy drop # Drop IP forward for upstream invalid packets iif $upstream-if ct state invalid counter drop # Accept IP forward for upstream established and related tracked connections iif $upstream-if ct state {established, related} accept # Accept all VPN traffic to be forwarded upstream iifname $vpn-if oif $upstream-if accept # Count traffic dropped by default policy counter drop } }
Operation of Wireguard link for VPN
Manual operation via wg-quick
Bring up wg0 interface
$ sudo wg-quick up wg0
systemd operation via wg-quick
Start wg-quick@wg0 service; enable for operation upon reboot
$ sudo systemctl start wg-quick\@wg0 $ sudo systemctl enable wg-quick\@wg0
systemd-networkd operation
- Enable and start systemd-resolved on VPN peer (required by "DNS=" lines under [Network] section)
- Restart systemd-networkd
On gateway peer:
$ sudo systemctl restart systemd-networkd
On VPN peer:
$ sudo systemctl start systemd-resolved $ sudo systemctl enable systemd-resolved $ sudo systemctl restart systemd-networkd
Testing of VPN connection and operation
Read wireguard comm status on gateway and VPN peer(s)
$ sudo wg
Ping peer(s)
On VPN peer:
$ ping -4 -n -c 5 10.0.0.1
On gateway peer:
$ ping -4 -n -c 5 10.0.0.2
Optional: Persistent keepalive
If ping on gateway peer to VPN peer fails, configure devices located behind, e.g., a NAT router for persistent keepalive:
- wg-quick: Add, e.g., "PersistentKeepalive = 15" to [Peer] section of /etc/wireguard/wg0.conf
- systemd-networkd: Add, e.g., "PersistentKeepalive=15" to [WireGuardPeer] section of /etc/systemd/network/99-wg0.netdev
Read packet filter counters
$ sudo nft list ruleset | grep counter
Read packet filter logging
$ journalctl