Build a WireGuard VPN gateway on FreeBSD
FreeBSD plus pf plus WireGuard is one of the most popular reasons people reach for a BSD VPS: a fast, auditable, self-hosted VPN on an OS with a serious networking pedigree. WireGuard's kernel driver (if_wg) ships in modern FreeBSD, and the userland tools are one pkg away. This walks through a VPN gateway your laptop and phone can route their traffic through.
1. Install the tools and make keys
pkg install wireguard-tools
umask 077
mkdir -p /usr/local/etc/wireguard
cd /usr/local/etc/wireguard
wg genkey | tee server.key | wg pubkey > server.pub
Generate a keypair for each client the same way (or let the client apps do it and paste their public keys in).
2. Configure the tunnel
Create /usr/local/etc/wireguard/wg0.conf. The server holds a private range (here 10.10.0.0/24) and one [Peer] block per client:
[Interface]
Address = 10.10.0.1/24
ListenPort = 51820
PrivateKey = <contents of server.key>
[Peer]
# your laptop
PublicKey = <client public key>
AllowedIPs = 10.10.0.2/32
3. Turn on forwarding and start it
A gateway has to route between the tunnel and the internet, so enable IP forwarding, then bring the interface up with wg-quick:
sysrc gateway_enable=YES
sysctl net.inet.ip.forwarding=1
sysrc wireguard_enable=YES
sysrc wireguard_interfaces=wg0
service wireguard start
4. NAT the tunnel out with pf
Add these to /etc/pf.conf so client traffic is NAT'd to your public IP and the WireGuard port is open, then reload (pfctl -f /etc/pf.conf):
nat on $ext_if from 10.10.0.0/24 to any -> ($ext_if)
pass in on $ext_if proto udp to port 51820 keep state
pass on wg0
See the pf firewall guide for the surrounding ruleset.
5. The client side
On each client, point AllowedIPs = 0.0.0.0/0, ::/0 to route everything through the VPS, set Endpoint to YOUR.IP.ADDRESS:51820, and add the server's public key. Confirm the handshake on the server with:
wg show
A recent handshake and rising transfer counters mean you're up. Because reverse DNS is self-service in the portal, this doubles nicely as a clean-IP exit node you fully control.