Both halves are in the base system on FreeBSD 15: the kernel
driver if_wg, and the wg userland at
/usr/bin/wg — the same wireguard-tools the port
ships. Nothing on this page needs a port installed.
VPN as exit point
Selecting a VPN provider
Very few VPN providers allow to use WireGuard with a manual configuration, they usually force you to use their own binary utilities. One exception (I haven’t looked for others) is Mullvad, which allows you to download raw configuration file.
Furthermore it gives you a web API to check the state of your connection:
curl https://am.i.mullvad.net/connected # Plain text connection status curl https://am.i.mullvad.net/ip # IP used for connection curl https://am.i.mullvad.net/json # Full connection description
Configuration
Create VPN interface vpn0:
- it’s a renamed cloned WireGuard interface
- created on a dedicated empty routing table (fib 1)
- associated to group
vpnfor easy management from the firewall
cloned_interfaces="wg0" # Clone wireguard interface create_args_wg0="group vpn fib 1" # Associate wg0 to fib 1 and group vpn ifconfig_wg0_name="vpn0" # Rename wg0 to vpn0
Now we need to generate a key pair that will be used for requesting a configuration for our device.
wg genkey | tee device.key | wg pubkey > device.pubkey
Once the configuration information has been retrieved, it will be used to configure FreeBSD startup scripts.
In the case of Mullvad, the configuration can be generated here:
And you will get something like:
[Interface] PrivateKey = ...........censored.private.key............. Address = 198.51.100.7/32,2001:db8::2/128 DNS = 198.51.100.53 [Peer] PublicKey = ............censored.public.key............. AllowedIPs = 0.0.0.0/0,::0/0 Endpoint = 198.51.100.1:51820
Note that the configuration is generated such that:
- IPv4 and IPv6 assigned addresses are tied to the interface key
- Each endpoint address have a different key
The Address and DNS fields are not used/understood by wg setconf,
and will need to be stripped down from the configuration for later use with it,
using for example:
grep -Ev '^(DNS|Address)' Configuration file downloaded from the VPN provider > /etc/wireguard/vpn0.conf
These removed fields will need to be used in other configuration parts:
Address- will be used directly by
ifconfigin/etc/rc.conf DNS- can be used in
resolv.confto rely on the VPN provided DNS server to avoid DNS leak to your ISP… but if you are already using your own DNS that can be unnecessary
Interface vpn0 is initialized with the IP addresses that have
been allocated for it on the VPN server side:
ifconfig_vpn0_descr="WireGuard VPN interface" ifconfig_vpn0="inet 198.51.100.7/32" ifconfig_vpn0_ipv6="inet6 2001:db8::2/128"
The directive defaultif is not supported
by the interface, it will not be possible to use it to
indicate that we want to be the route by default if none
are present. So we need to add a default route ourselves:
# Define the route by default on the fib 1 routing table as being our vpn route_vpn0_default="-iface vpn0 -fib 1" # Adding vpn0_default to the list of static routes static_routes="... vpn0_default ..."
What /etc/rc.conf still cannot do is load a
configuration into the interface: the base system carries no wireguard
knob of any kind. So /etc/rc.local and
/etc/rc.shutdown.local carry the steps
/etc/rc.conf has no directive for:
When using wg setconf, only the following fields are allowed in the
configuration file:
| Section | Fields |
|---|---|
Interface |
PrivateKey, ListenPort, FwMark |
Peer |
PublicKey, PresharedKey, AllowedIPs, Endpoint, PersistentKeepalive |
# Set initial interface configuration /usr/bin/wg setconf vpn0 /etc/wireguard/vpn0.conf
# Synchronize interface configuration on shutdown /usr/bin/wg syncconf vpn0 /etc/wireguard/vpn0.conf
Incoming VPN
Server configuration
wg genkey | tee server.key | wg pubkey > server.pubkey
$ cat server.key AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0= $ cat server.pubkey BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB1=
# Incoming VPN
wg set vpn0 \
listen-port 51820 \
private-key /etc/wireguard/server.key
If you have firewall, you will need to tailor the following configuration fragment to your need:
scrub in on vpn0 all # Reassemble fragments to avoid ambiguities # If being a NAT and you want to give access to other network resources nat pass on interface to gateway inet from (vpn0:network) to any -> interface to gateway antispoof quick for vpn0 # Basic antispoofing rules pass in on vpn0 # Allows incoming traffic
Generating device configuration
This will need to be done for each device that is allowed to connect to the VPN
-
Create a key pair
Generate private/public key pair wg genkey | tee device.key | wg pubkey > device.pubkey
$ cat device.key CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC2= $ cat device.pubkey DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD3=
-
Create the configuration file. Here the peer is the server to which we will connect to establish the VPN connection, and we will allow routing all the traffic to the VPN (look for:
0.0.0.0/0,::0/0)[Interface] PrivateKey = Interface private key Address = Device allocated IP DNS = DNS considered to be privacy safe [Peer] PublicKey = Peer public key AllowedIPs = 0.0.0.0/0,::0/0 Endpoint = 198.51.100.1:51820
-
Generate a QR-code (optional).
QR-code allows easy integration with android WireGuard application, which can be found on:
- F-Droid: https://f-droid.org/en/packages/com.wireguard.android/
- Play Store: https://play.google.com/store/apps/details?id=com.wireguard.android
Generate QR-code from config file qrencode -t ansiutf8 < device.conf -
Add device peer to the server.
You usually want to restrict the
allowed-ipsto the same set of addresses defined inAddressin the client configuration file.Adding peer to the server side wg set vpn0 peer Peer public key \ allowed-ips Device allocated IP