FreeBSD: How to Set Up a Simple and Actually Working Wireguard Server
In my quest to get a Wireguard setup working, I have come across many guides and tutorials. All of them were missing crucial information or operating off outdated information. Often just subtle instructions are broken. In a cascade with other points of potential failure, this quickly becomes a frustrating game of whack-a-mole with lots of dead ends.
That being said, here’s a minimal setup that works, as of today, on a Raspberry Pi 3 with a single Ethernet connection, running FreeBSD 13.2.
First off, install the required software:
pkg install wireguard wireguard-tools libqrencode
Enable Wireguard service:
service wireguard enable
sysrc wireguard_interfaces="wg0"
Enable IP forwarding and activate it immediately:
sysrc gateway_enable=YES
sysctl -w net.inet.ip.forwarding=1
Set up firewall and logging:
service pf enable
service pflog enable
# /etc/pf.conf
ext_if="ue0"
wg_net="10.10.10.0/24"
scrub in all
nat on $ext_if from $wg_net to any -> ($ext_if)
pass log all
service pf start
service pflog start
Then generate the server keys:
cd /usr/local/etc/wireguard/
umask 077
wg genkey | tee /usr/local/etc/wireguard/server_private.key | wg pubkey | tee /usr/local/etc/wireguard/server_public.key
You’re going to need client keys as well. This example assumes an iPhone for naming but the process is the same for any client:
cd /usr/local/etc/wireguard/
umask 077
wg genkey | tee /usr/local/etc/wireguard/iphone_private.key | wg pubkey | tee /usr/local/etc/wireguard/iphone_public.key
wg genpsk > iphone_preshared.key
Create the server configuration:
# /usr/local/etc/wireguard/wg0.conf
[Interface]
Address = 10.10.10.1/32 # address the server will bind to
ListenPort = 51820
PrivateKey = your-private-server-key-here
[Peer]
AllowedIPs = 10.10.10.2/32
PreSharedKey = your-preshared-client-key
PublicKey = your-public-client-key
Create the client configuration:
# /usr/local/etc/wireguard/wg_iphone.conf
[Interface]
PrivateKey = your-private-client-key
Address = 10.10.10.2/32
DNS = 9.9.9.9 # optional, useful to avoid DNS leaks
[Peer]
PublicKey = your-public-server-key
PreSharedKey = your-preshared-client-key
AllowedIPs = 0.0.0.0/0 # entire Internet
Endpoint = your-external-ip-or-host:51820
PersistentKeepalive = 30
For additional clients, repeat the key generation with different filenames.
Then add another [Peer]
section with a unique IP and the clients’ key
contents to the server configuration. Also create a respective client
configuration. Restart Wireguard after you have changed the server
configuration.
To ease transfer to iPhone, generate a QR code and import via camera in the Wireguard app:
qrencode -t ansi < wg_iphone.conf
Start the Wireguard service:
service wireguard start
You should now be able to connect successfully with the iPhone and reach both your internal network as well as the internet.
A couple of notes:
- Remember to set up port forwarding in your router if you do this at home. Wireguard exclusively uses UDP.
- DNS could be a local server like Adguard Home. This is what I do. This way you get comprehensive ad blocking everywhere.
- If you run into issues, first reboot the machine. If things still won’t work,
inspect the connection logs with
tcpdump -n -e -i pflog0
. - In almost all cases when connections do not work, you either forgot to set up IP forwarding, have other firewall rules in place that interfere or the NAT rule is wrong.
- I have found handshake reliability to be flaky. You may need to stop and start the client connection multiple times for it to work.