Wireguard VPN Server auf FreeBSD

Wireguard är ett snabbt, modernt och enkelt VPN-system som kan användas för att skapa många olika konfigurationer. Jag använder det för olika ändamål på mina servrar, till exempel för att koppla ihop mina servrar med varandra, men också för att kunna komma åt mina interna tjänster (bland annat Jellyfin Media Server) när jag är på resande fot via klienter som min mobiltelefon. Här är en kort beskrivning av hur jag har konfigurerat min VPN-server och lägger till nya klienter.

Installation

FreeBSD har ett kärnmodul för wireguard, som redan finns som standard. Vi behöver därför bara installera verktygen för detta. Dessutom vill jag få mina konfigurationer till klienterna via QR-kod.

pkg install wireguard-tools libqrencode

Konfigurera

Konfigurationen går mycket snabbt. Först behöver man nycklar för servern. Kommandona ska köras som root i /usr/local/etc/wireguard:

umask 077
wg genkey > server.key
wg genpsk > server.psk
wg pubkey <  server.key >  server.pub

Nu skapar man en gränssnittskonfiguration. Till exempel filen wg0.conf:

[Interface]
Address = 172.16.3.1/24
ListenPort = 12345
PrivateKey = <KEY AUS server.key>

# Clients:

Jag har inte konfigurerat någon klient här. Istället använder jag ett litet skript för att flexibelt lägga till nya klienter. För detta har jag skapat katalogen wg0_clients, där jag skapar klientkonfigurationerna. I denna katalog har jag sedan två shell-skript. Med det ena skapar jag konfigurationen för min klient, det andra visar motsvarande konfiguration som QR-kod på min terminal, så att jag kan lägga till VPN med en mobiltelefon via QR-kodskannern. Här är det första skriptet för att skapa konfigurationen

#!/usr/local/bin/bash

# Configurable variables
SERVER_PUBLIC_KEY="SERVER PUBLIC KEY (server.pub)"
SERVER_IP="vpn.example.com"
SERVER_PORT="12345"
PRIVATE_DIR="/usr/local/etc/wireguard/wg0_clients"
SERVER_CONF="/usr/local/etc/wireguard/wg0.conf"

# get client name
if [ $# -ne 2 ]; then
        echo "A client name and IP must be specified"
        echo "./create_conf.sh CLIENTNAME IP"
        exit 1
fi

CLIENT_NAME=$1
CLIENT_IP=$2

CLIENT_PRIVATE_KEY=$(wg genkey)
CLIENT_PUBLIC_KEY=$(echo $CLIENT_PRIVATE_KEY | wg pubkey)
CLIENT_PSK=$(wg genpsk)

# create client_conf
cat > $PRIVATE_DIR/$CLIENT_NAME.conf << EOF
[Interface]
PrivateKey = $CLIENT_PRIVATE_KEY
Address = $CLIENT_IP/32

[Peer]
PublicKey = $SERVER_PUBLIC_KEY
PreSharedKey = $CLIENT_PSK
Endpoint = $SERVER_IP:$SERVER_PORT
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 60
EOF

# write Server Conf
echo "#Client $CLIENT_NAME" >> $SERVER_CONF
echo "[Peer]" >> $SERVER_CONF
echo "PublicKey = $CLIENT_PUBLIC_KEY" >> $SERVER_CONF
echo "PreSharedKey = $CLIENT_PSK" >> $SERVER_CONF
echo "AllowedIPs = $CLIENT_IP" >> $SERVER_CONF

Detta skript får ett namn för klienten. Det genererar nödvändiga nycklar och skriver en klientkonfiguration. Dessutom kompletterar det serverns konfigurationsfil så att den nu har en klient. För att kunna starta Wireguard-servern måste Wireguard aktiveras och gränssnitten skrivas in i rc.conf. Dessutom ska servern också fungera som gateway, så vi måste aktivera det också. För att göra detta lägger man till följande rader i /etc/rc.conf

wireguard_enable="YES"
wireguard_interfaces="wg0"
gateway_enable="YES"

Därefter kan man starta tjänsten med:

service wireguard start

Med följande kommando kan du se status för klienterna:

wg show

När du lägger till nya klienter med ovanstående skript måste du starta om tjänsten en gång:

service wireguard restart

För att kunna skriva ut klientkonfigurationen som QR-kod använder jag följande skript, som främst hjälper mig att komma ihåg den nödvändiga kommandot:

#!/usr/local/bin/bash

if [ $# -ne 1 ];then
        echo "./print_qr.sh CLIENT"
        exit 1
fi

CLIENT=$1

qrencode -t ansiutf8 < $CLIENT.conf

Brandvägg

Om man har en brandvägg på eller framför sin server måste man naturligtvis också öppna motsvarande port. Wireguard använder UDP för datatrafiken. Dessutom behövs en NAT så att klienterna också kan komma åt offentliga nätverk. Här är ett exempel för pf-brandväggen under FreeBSD:

nat on $external_if inet from $vpn_net to any -> $server_pub_ip
pass in on $external_if proto udp from any to $server_pub_ip port 12345

Makron $vpn_net $external_if och $server_pub_ip måste naturligtvis definieras i förväg. Eftersom alla har olika behov för sin server går jag inte in på detaljer här.