User:Cmsigler/Wireguard Configuration Guide
Appearance
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