Wireguard configuration
Overview
Wireguard is exposed as a network-interface representing each available VPN (ex:
wg0, wg1, ...
).
Each VPN has a prv/pub keypair, and each connection between two nodes has a pre-shared-key.
In order to make a connection, both servers must be running wireguard, and list the other as a peer.
Key Setup
# Setup Private Key for each Server wg genkey > keyname.prv # generate private key cat keyname.prv | wg pubkey > keyname.pub # generate public key chmod 600 keyname.* # set permissions# Setup Pre-Shared-Key for each pairing of servers wg genpsk > host1--host2.psk wg genpsk > host1--host3.psk
Configuration
NOTE:
In order to use wireguard within a FreeBSD jail, it's networking must be setup using vnet
Persistent
Each network interface receives it's own configuration, with information about the peers it is able to connect to.
Configuration
The interface IP defines the address AND the private network range.
Here we are using a/24
subnet, which means that there are 254 addresses available.
The AllowedIPs are defined in/32
(I don't understand why).For more background on subnets/CIDR notation, see Networking Overview and ipv4.
# /etc/wireguard/wg0.conf [Interface] Address = 10.0.0.1/24, fdc9:281f:04d7:9ee9::1/64 PrivateKey = PEER_A_PRIVATE_KEY ListenPort = 55555 [Peer] PublicKey = PEER_B_PUBLIC_KEY PresharedKey = PEER_A-PEER_B-PRESHARED_KEY AllowedIPs = 10.0.0.2/32, fdc9:281f:04d7:9ee9::2/128 # wireguard ip of server Endpoint = peer-b.example:51902 # public ip of server [Peer] PublicKey = PEER_C_PUBLIC_KEY PresharedKey = PEER_A-PEER_C-PRESHARED_KEY AllowedIPs = 10.0.0.3/32, fdc9:281f:04d7:9ee9::3/128
wg showconf > /etc/wireguard/wg0.conf # dump dynamic connfiguration to file wg-quick up wg0 # activate VPNSystem Service
systemd
systemctl enable wg-quick@<iface>.service # [Linux] start VPN at bootFreeBSD init
# /etc/rc.conf wireguard_enable="YES" wireguard_interfaces="wg0 wg1 wg2" # interfaces to start at bootservice wireguard startNAT endpoints
If one side of your connection is behind NAT, you must keep the connection alive from the side with a static ip as an endpoint.
You can do this withPersistentKeepalive = 25
.This is configured on the side behind NAT (since it is not always reachable).
# /etc/wireguard/wg-*.conf [Peer] Endpoint = 1.1.1.1:55555 PersistentKeepalive = 25 # adjust to suit your firewall state rules # ...DHCP endpoints
NOTE:
Doesn't seem necessary if I use PersistentKeepalive as outlined for NATIf your IP address changes (DHCP, dyndns, ...), you'll need to periodically re-run a script to keep your connection alive. Docs recommend to run every 30s in a cron job.
# once per minute * * * * * /bin/sh -c 'for i in /etc/wireguard/*.conf; do /usr/share/wireguard-tools/examples/reresolve-dns/reresolve-dns.sh "$i"; done'Alternatively Arch Wiki has suggestion for systemd service which runs every 30s.
Multiple Interfaces
This may be unecessary - I had some issues with packet routing on hosts
with multiple interfaces, and multiple peers attached to an interface.
My problem was solved with a reboot (and possibly more importantly by rebooting the NAT'd connections.
jim salter blogged about having multiple wireguard interfaces on one host
his setup includedPostUp/PostDown
instructions that created routing table entries, and solidified connections with a ping.# NOTE: linux specific [Interface] Address = 10.0.0.2/24 PrivateKey = PRIVATE_KEY_FROM_CLIENT1 # set up routing from server/wg0 to server/wg1 PostUp = route add -net 10.0.1.0/24 gw 10.0.0.1 ; ping -c1 10.0.0.1 # <-- (this) PostDown = route delete -net 10.0.1.0/24 gw 10.0.0.1 # <-- (this to) SaveConfig = falseBefore doing this, I'd try the DHCP setup.
Dynamic
You can also create/configure interfaces dynamically if you'd like.
Linux
# create network interface ip link add dev wg0 type wireguard # nodes require unique private addrs # add ipv4 and optionally ipv6 ip addr add 10.0.0.1/24 dev wg0 ip addr add fdc9:281f:04d7:9ee9::1/64 dev wg0 # configure connection to `host2` # (repeated for each server being connected) wg set wg0 private-key /path/to/host.prv wg set wg0 peer host2.pub \ preshared-key /path/to/host1--host2.psk \ allowed-ips 10.0.0.2/32,fdc9:281f:04d7:9ee9::2/128 # activate VPN ip link set wg0 up
Firewall Setup
- allow UDP traffic on configured
Endpoint:ListenPort
(public ip)- allow any traffic on
wg*
interfacenftables example
host with wireguard:#!/usr/sbin/nft -f # /etc/nftables.conf table inet filter { chain input { type filter hook input priority 0; policy drop; # accept wg0 traffic # (you may want to allowlist ports) iif wg0 accept; # accept wireguard connection init traffic udp dport $wireguard_port ip daddr $public_ip accept; # ... } }pf example
# /etc/pf.conf ext_if="jail0" wg_if="wg0" wg_port="55555" block log all pass out all # accept wg0 traffic # (you may want to restrict ports) pass in on $wg_if # accept wireguard connection init traffic pass in on $ext_if proto udp to $public_ip port $wg_portIf this is a vnet jail, you'll also need to make sure that traffic gets passed to the jail where it's pf can take over the ruleset.
# /etc/pf.conf (jail host) set skip on jail_epairs # ifconfig interface group set skip on bridge0 block log all pass out all # ...rules...
Testing
NOTE:
If you're having trouble, check out wireguard debugging
Firstly, confirm that your interface is up, and has been assigned an ip addr.
sudo ip addr # 3: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000 # link/none # inet 10.0.0.1/24 scope global wg0 # valid_lft forever preferred_lft foreverAlso confirm the interface is displayed with info
sudo wg # interface: wg0 # public key: lkjAsdflkjoasiduffjweklrjdsoiaujfasljelkjouifsad # private key: (hidden) # listening port: 55555 # # peer: kljasdfurjjafu3rjlkjsaf9wrjjasfkljlkjaweruiouasdfj= # preshared key: (hidden) # allowed ips: 10.0.0.2/32I had some initial issues with firewall. Try watching dropped packets.
Note this could be pf inside the jail, pf outside the jail, or the firewall on the target inbound/outbound side.ping $target # on $source/$target sudo journalctl -f --dmesg | grep $wg_port # linux sudo tcpdump -n -e -ttt -i pflog0 port $wg_port # freebsd # even on failure, issuing `wg` should show 'latest handshake' # with information about the failure.If you're getting connection refused, but pf/nftables is not recording any dropped packets - make sure you're binding your server to
0.0.0.0
, the FQDN, or the server's ip address (and not 127.0.0.1).