Wireguard VPN Server auf FreeBSD

Wireguard ist ein schnelles, modernes und einfaches VPN System mit dem man viele verschiedene Setups erstellen kann. Ich nutze es für verschiedene Zwecke auf meinen Servern, zum Beispiel um meine Server untereinander zu verbinden, aber auch um von unterwegs über Clients wie mein Handy auf meine internen Dienste (u.a. Jellyfin Media Server) zugreifen zu können. Hier ist eine kurze Anleitung wie ich meinen VPN Server eingerichtet habe und neue Clients hinzufüge.

Installation

FreeBSD hat ein Kernelmodul für wireguard, welches standardmäßig bereits vorhanden ist. Wir müssen daher nur noch die Tools dazu installieren. Außerdem möchte ich meine Konfigurationen per QR-Code auf die Clients bekommen.

pkg install wireguard-tools libqrencode

Konfigurieren

Die Konfiguration ist sehr schnell erledigt. Zuerst benötigt man Schlüssel für den Server. Die Befehle sollte man als root in /usr/local/etc/wireguard ausführen:

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

Nun erstellt man eine Interface Configuration. Also zum Beispiel die Datei wg0.conf:

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

# Clients:

Ich habe hier keinen Client konfiguriert. Dafür nutze ich ein kleines Skript, um flexibel neue Clients einzufügen. Dazu habe habe ich das Verzeichnis wg0_clients angelegt, dort erstelle ich die Client Konfigurationen. In diesem Verzeichnis habe ich dann 2 Shell Skripte. Mit dem einen erstelle ich die Konfiguration für meinen Client, das zweite gibt die entsprechende Konfiguration als QR-Code auf meinem Terminal aus, sodass ich mit einem Handy den VPN per QR-Code Scanner hinzufügen kann. Hier ist das erste Skript zum erstellen der Konfiguration:

#!/usr/local/bin/bash

# Konfigurierbare Variablen
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"

# hole client name
if [ $# -ne 2 ]; then
        echo "Es muss ein Client Name und eine IP angegeben werden"
        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)

# Erstelle 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

# Schreibe 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

Dieses Skript bekommt einen Namen für den Client übergeben. Es generiert die notwendingen Keys und schreibt eine Client Config. Außerdem ergänzt es die Konfigurationsdatei vom Server, sodass dieser nun einen Client hat. Um nun den Wireguard Server starten zu können, muss Wireguard noch enabled werden und die Interfaces in die rc.conf geschrieben werden. Außerdem soll der Server auch als Gateway dienen, daher müssen wir das ebenfalls aktivieren. Dazu fügt man seiner /etc/rc.conf folgende Zeilen hinzu:

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

Anschließen kann man den Dienst starten mit:

service wireguard start

Mit dem folgenden Befehl sieht man den Status der Clients:

wg show

Wenn man mit dem obigen Skript neue Clients hinzufügt muss man einmal den Dienst neu starten:

service wireguard restart

Um nun die Client Konfiguration als QR-Code ausgeben zu können, nutze ich folgendes Skript, welches mir hauptsächlich hilft den notwendingen Befehl zu merken:

#!/usr/local/bin/bash

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

CLIENT=$1

qrencode -t ansiutf8 < $CLIENT.conf

Firewall

Sollte man eine Firewall auf oder vor seinem Server haben, muss man natürlich noch den entsprechenden Port freigeben. Wireguard nutz UDP für den Datenverkehr. Außerdem benötigt man ein NAT, sodass die Clients auch in öffentliche Netze kommen können. Hier ein Beispiel für die pf Firewall unter 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

Die Makros $vpn_net $external_if und $server_pub_ip müssen natürlich vorher noch definiert werden. Da aber jeder andere Notwendigkeiten für seinen Server hat, gehe ich hier nicht weiter ins Detail.