Herr Bischoff

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

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

Address = # address the server will bind to
ListenPort = 51820
PrivateKey = your-private-server-key-here

AllowedIPs =
PreSharedKey = your-preshared-client-key
PublicKey = your-public-client-key

Create the client configuration:

# /usr/local/etc/wireguard/wg_iphone.conf

PrivateKey = your-private-client-key
Address =
DNS = # optional, useful to avoid DNS leaks

PublicKey = your-public-server-key
PreSharedKey = your-preshared-client-key
AllowedIPs = # 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.