Linux: WireGuard VPN mit Mullvad

Mullvad Logo WireGuard Logo

WireGuard ist eine Anwendung und ein Protokoll, mit dem sich neben OpenVPN VPNs realisieren lassen. Mit dem Privoxy Proxy, dem Anbieter Mullvad (TOS) und WireGuard sollen WireGuard basierte „VPN“ Tunnel genutzt werden, die mehr als zwei Server ("Multihop") und zusätzlich einen Mullvad SOCKS-Proxy als Nodes verwenden, die in zufälligen Intervallen zufällig rotieren. Zusätzlich wird eine zweite Konfiguration zur Anwendung von Port Forwarding eingerichtet, um lokale Dienste oder P2P-Anwendungen über Mullvads WireGuard „VPN“ anzubieten bzw. mit anderen Internetnutzern zu nutzen. Auf die Nutzung der Mullvad VPN "App" wird dabei verzichtet.

Mullvad wurde als Anbieter ausgewählt, weil er nach verschiedenen Reviews, Audits usw. neben IVPN und vielleicht noch 1 – 2 weiteren Anbietern am vertrauenswürdigsten erscheint. Siehe z. B. VPN Testing Reveals Poor Privacy and Security Practices, Hyperbolic Claims von Consumer Reports oder Signals of Trustworthy VPNs von CDT. Mullvad stellt nebenbei die Infrastruktur für das "Mozilla VPN". Ein Nachteil, den Mullvad hat: Außer in den UKUSA-Staaten, Brasilien, Japan, Hong Kong, Israel und Singapur hat Mullvad keine weiteren Server im außereuropäischen Ausland.

Installation

Kernel

 Device Drivers
  --> Network device support
    <*> WireGuard secure network tunnel
    [*] Debugging checks and verbose messages (optional z. Überprüfung)
    <*> Universal TUN/TAP device driver support

wireguard-tools & Verzeichnis

sudo aptitude install wireguard-tools
sudo mkdir /etc/wireguard/{pf,reserve}
sudo chmod 700 /etc/wireguard

Das wireguard-tools Paket enthält die wg, wg-quick Anwendungen und die wg-quick systemd Unit.

Konfiguration

Schlüsselpaar

sudo -i
wg genkey | tee /etc/wireguard/reserve/privatekey | wg pubkey > /etc/wireguard/reserve/publickey

Schlüssel-Eingabe

Nach der Anmeldung bei Mullvad WireGuard configuration file generator aufrufen und unter 2. Generate a WireGuard keyManage WireGuard Keys den Inhalt der privatekey Datei einfügen und mit Import key importieren, um den öffentlichen Schlüssel zu Mullvad zu exportieren.

Die Schlüssel, wie auch die Konfiguration zur Portweiterleitung, sollte man in Abständen austauschen und dabei beachten, dass danach auch die Angabe des PrivateKey in den Mullvad Konfigurationsdateien und die Portangaben entsprechend aktualisiert werden müssen.

Multihop-Konfiguration

Mullvad Multihop-Konfiguration
Unter 3. Select one or multiple exit locations möglichst viele Kombinationen aus Entry → Exit WireGuard-Servern zusammenstellen und dabei möglichst die UKUSA Länder (Großbritannien, Australien, Neuseeland, Kanada, USA), Deutschland und Schweden meiden. Nach jeder Kombination die Konfigurationsdatei mit Download file herunterladen. Alle mlvd*.conf Dateien werden nach /etc/wireguard/reserve/ verschoben. Alle Konfigurationsdateien werden nach folgendem Schema geändert:

/etc/wireguard/reserve/mlvd*.conf
[Interface]
PrivateKey = string
Address = a.b.c.d/32 (der WG-Netzwerkschnittstelle)
DNS = 127.0.0.1
TABLE = off
PostUp = /etc/wireguard/reserve/wg-routes.sh
 
[Peer]
PublicKey = string (Schlüssel v. Exit-Server)
AllowedIPs = 0.0.0.0/0
Endpoint = ip-adresse (v. Entry-Server):multihop-portnummer (v. Exit-Server)

Zur Namensauflösung wird ein lokales, anonymisierendes DNS Resolver-System verwendet. Die Namensauflösung findet mit Ausnahme der Mullvad Domainnamen außerhalb des WireGuard Systems über Dnsmasq → DNSCrypt-Proxy → Tor statt. Mit TABLE = off werden zunächst keine Routen in der Routing-Tabelle (route -n) angelegt. Über die PostUp Anweisung wird das wg-routes.sh Skript-Snippet nach Einrichten der Mullvad WireGuard-Netzwerkschnittstelle per bash ausgeführt, das mlvd* Routen schaltet, die Traffic über die WireGuard-Netzwerkschnittstelle bzw. WireGuard-Tunnel leiten.

/etc/wireguard/reserve/wg-routes.sh
if=$(wg show interfaces)
 
ip route add a.0.0.0/8 dev $if
ip route add 193.138.218.74/32 dev $if
ip route add 185.213.154.90/32 dev $if
ip route add e.f.g.h/32 dev $if

Der untere [Peer] Bereich muss nicht geändert werden. Später wird der Privoxy Proxy so eingerichtet, dass er Traffic an einen Mullvad SOCKS-Proxy weiterleitet – d. h. der Traffic durchläuft WG-Entry → WG-Exit → WG-SOCKS-Proxy. Für alle Anwendungen oder Dienste, deren Traffic über Mullvad bzw. WireGuard getunnelt werden soll, kann dann Privoxy als Proxy angegeben werden. Für Anwendungen und Dienste, deren Traffic direkt zum Zielserver verlaufen soll, wird entweder kein Proxy angegeben oder in der Privoxy Konfiguration Ausnahmen für Zieladdressen eingetragen, so dass der Traffic nicht über die WireGuard-Netzwerkschnittstelle, sondern die herkömmliche Netzwerkschnittstelle verläuft ("Split Tunneling"). Server kann man weiterhin über Tor ansprechen, wenn für deren Adressen entsprechende Weiterleitungsregeln in der Privoxy Konfiguration hinterlegt sind.

Der Mullvad DNS-Server public-dns.mullvad.net (193.138.218.74) oder ns1.mullvaddns.net (185.213.154.90) wird für die Auflösung der Mullvad Domainnamen verwendet. Dafür ändert man die dnsmasq.conf Datei:

/etc/dnsmasq.conf
server=/.mullvad.net/193.138.218.74#53
server=/.mullvad.net/185.213.154.90#53

Mullvad Connection check
DNS-Resolver per DNSCrypt-Proxy (links), Mullvad DNS-Server (rechts) im Mullvad Connection check

Multihop Auswahl & Start

/etc/systemd/system/wg-vpn-one.service
[Unit]
Description=VPN-Changer for WireGuard
After=network-online.target nss-lookup.target
Wants=network-online.target
 
[Service]
Type=OneShot
ExecStart=/etc/systemd/scripts/wg-vpn-random.sh
 
[Install]
WantedBy=multi-user.target
sudo systemct enable wg-vpn-one.service

Mit der Dienste-Unit wird direkt nach dem Start von systemd initial eine WireGuard-Netzwerkschnittstelle eingerichtet.

Aus der Menge der gespeicherten Multihop-Konfigurationen soll anschließend in Intervallen die bestehende WireGuard-Netzwerkschnittstelle bzw. Konfiguration zufällig durch eine andere Konfiguration ersetzt werden. Mittels einer systemd Timer-Unit wird dazu über eine systemd Dienste-Unit ein entsprechendes Skript ausgeführt:

/etc/systemd/scripts/wg-vpn-random.sh
#!/usr/bin/sh
 
wgroot=/etc/wireguard
mullvadrandom="$(ls $wgroot/reserve/ | grep conf | cut -d. -f1 | shuf -n 1).conf"
vpn=$(wg show interfaces)
 
if [ -n $vpn ]; then
  systemctl stop wg-quick@wg0.service
  sleep 3
fi
 
cp -f $wgroot/reserve/$wgrandom $wgroot/wg0.conf && \
cp -f $wgroot/reserve/*key $wgroot/ && \
systemctl start wg-quick@wg0.service && \
printf "Mullvad VPN via $mullvadrandom\n"
 
exit 0
/etc/systemd/system/wg-vpn-random.service
[Unit]
Description=VPN-Changer for WireGuard
After=network-online.target nss-lookup.target
Wants=network-online.target
 
[Service]
ExecStart=/etc/systemd/scripts/wg-vpn-random.sh
/etc/systemd/timer/wg-vpn-random.timer
[Unit]
Description=VPN-Changer for WireGuard
 
[Timer]
OnBootSec=N1min
OnUnitActiveSec=N1min
AccuracySec=0
RandomizedDelaySec=N2min
 
[Install]
WantedBy=timers.target
sudo systemctl enable /etc/systemd/timer/wg-vpn-random.timer

Mit dem Timer wird N1 Minuten nach dem Systemstart (u. N1 Minuten später als wg-vpn-one.service) und danach alle N1 Minuten mit einer zufälligen Zeitverzögerung von 0 – N2 Minuten nach letzter Aktivierung die gleichnamige Dienste-Unit gestartet. Über die vom Timer ausgelöste Dienste-Unit wird das Skript ausgeführt, das aus den gespeicherten Multihop-Konfigurationen eine Konfiguration zufällig auswählt, mit der und der wg-quick Dienste-Unit die WireGuard-Netzwerkschnittstelle eingerichtet wird. Eine eventuell bereits bestehende WireGuard-Netzwerkschnittstelle wird zuvor abgebaut.

SOCKS

Für die Mullvad SOCKS-Proxys, die Privoxy zur Weiterleitung verwenden soll, stellt man sich Listen der Kennungen aller SOCKS-Proxys des Landes zusammen, in dem der Traffic letztendlich vom Proxy zum Zielserver ausgehen soll. Das Land sollte nicht Bestandteil der obigen Multihop-Konfigurationen sein. Wenn z. B. alle SOCKS-Proxys amerikanischer WireGuard-Server verwendet werden, wird z. B. keine Multihop-Konfiguration Luxemburg → WG-US1 → Proxy-US2 oder Luxemburg → WG-US1 → Proxy-US1 verwendet.

Jeder Mullvad WireGuard-Server hat auch eine SOCKS-Adresse, die man in der Server-Übersicht von Mullvad einsehen kann:

SOCKS-Relays

Oben: Server, der vom Speichermedium läuft („DISK“). Unten: Server, der nur im Speicher läuft („RAM“).

Für die „wg-socks.txt“ Liste interessiert nur der tld* Bestandteil vor der .relays.mullvad.net Domain, der für alle Proxys des ausgewählten Landes in die wg-tld-socks.txt Liste untereinander weggeschrieben wird. Dafür kann man sich zuerst die Liste aller Mullvad WireGuard-Server herunterladen (mit torsocks -a 127.0.0.1 -P 9050 -q über Tor). Danach wird für jedes gewünschte Zielland eine eigene „wg-tld-socks.txt“ Liste mit allen DISK und RAM Hostnamen erstellt und ein wg-socks.txt Symlink gesetzt:

/etc/systemd/scripts/wg-socks-update.sh
#!/usr/bin/sh
 
user="$(id -un 1000)"
sucmd="sudo -H -u $user"
 
cd /downloadpfad/
$sucmd torsocks -a 127.0.0.1 -P 9050 -q wget -q -nv -O v1.json https://api.mullvad.net/public/relays/wireguard/v1/
 
if [ -s /downloadpfad/v1.json ] ; then
  cat v1.json | egrep -o tld[0-9]+- | sort -t "-" -k 1.3n | sed -r '/^tld[0-9]{1,3}/ s/-/-wg-socks5/' > wg-tld-socks.txt ; \
  cat v1.json | egrep -o tld-[a-z]{3}-wg-[0-9]{3} | sort -t "-" -k 2.1,2.3d | sed -r '/^tld-[a-z]{3}-wg-[0-9]{3}/ s/wg-/wg-socks5-/' >> wg-tld-socks.txt ; \
  mv -f wg-*.txt /etc/wireguard/
  rm v1.json
  exit 0
else
  rm v1.json
  exit 1
fi
sudo ln -s /etc/wireguard/wg-tld-socks.txt /etc/wireguard/wg-socks.txt

Für die Aktualisierung der Liste(n) kann man ebenfalls einen systemd Timer anlegen, der sie täglich aktualisiert:

/etc/systemd/system/wg-socks-update.service
[Unit]
Description=Mullvad SOCKS Update
 
[Service]
Type=oneshot
ExecStart=/etc/systemd/scripts/wg-socks-update.sh
/etc/systemd/timer/wg-socks-update.timer
[Unit]
Description=Mullvad SOCKS Update
 
[Timer]
OnCalendar=*-*-* 00:00:00
AccuracySec=30m
Persistent=true
RandomizedDelaySec=1800
 
[Install]
WantedBy=timers.target
sudo systemctl enable /etc/systemd/timer/wg-socks-update.timer

SOCKS Auswahl & Privoxy

Aus der Menge der in der wg-socks.txt Liste gespeicherten Einträge soll in Intervallen zufällig ein Eintrag ausgewählt werden, der in der Privoxy Konfiguration den Mullvad SOCKS-Proxy ersetzt, an den der Traffic über den WireGuard-Tunnel weitergeleitet wird. Anschließend wird Privoxy neu gestartet.

/etc/privoxy/config
forward-socks4 / tldN-wg.socks5.relays.mullvad.net:1080 . # DISK
forward-socks4 / tld-abc-wg-socks5-nnn.relays.mullvad.net:1080 . # RAM

Privoxy Konfiguration zur Weiterleitung an Mullvad SOCKS-Proxy.

Mittels einer systemd Timer-Unit wird über eine systemd Unit ein entsprechendes Skript ähnlich wie zur Auswahl der Multihop-Konfiguration ausgeführt:

/etc/systemd/scripts/wg-socks-random.sh
#!/usr/bin/sh
 
pp=/etc/privoxy
socksrandom=$(cat /etc/wireguard/wg-socks.txt | shuf -n 1)
 
cd $pp/
sed -r '/^forward-socks4\ \/\ [a-z]{2}.*\.relays\.mullvad\.net/ s/\ [a-z]{2}.*\.relays\.mullvad\.net/\ '"$socksrandom"'\.relays\.mullvad\.net/' \
<config >config_tmp && chown :privoxy config_tmp && mv config_tmp config && \
systemctl stop privoxy.service && systemctl start privoxy.service && \
printf "Privoxy/VPN verwenden $socksrandom.relays.mullvad.net als Exit\n"
 
exit 0
/etc/systemd/system/wg-socks-random.service
[Unit]
Description=SOCKS-Changer for WireGuard
 
[Service]
ExecStart=/etc/systemd/scripts/wg-socks-random.sh
/etc/systemd/timer/wg-socks-random.timer
[Unit]
Description=SOCKS-Changer for WireGuard
 
[Timer]
OnBootSec=60
OnUnitActiveSec=50min
AccuracySec=0
RandomizedDelaySec=9min
 
[Install]
WantedBy=timers.target
sudo systemctl enable /etc/systemd/timer/wg-socks-random.timer

Verbindungscheck

Mit dem Skript und optionalem systemd Timer wird alle 3 Minuten überprüft, ob eine Zieladresse erreichbar ist. Bei Verbindungsproblemen wird zuerst eine neue Mullvad Konfiguration ausgewählt. Bei weiterhin nicht erreichbarer Zieladresse wird danach der SOCKS-Proxy gewechselt.

/etc/systemd/scripts/wg-vpn-check.sh
#!/bin/sh
 
proxy="privoxy-hostname:8118"
checkurl="https://host.domain.tld"
urlstatus="$(curl --tlsv1.2 --tls-max 1.3 --ipv4 --connect-timeout 10 --retry 1 --proto https,http --proxy $proxy --capath /etc/ssl/certs --no-sessionid --location --max-redirs 3 -s -S --head $checkurl | grep 503 | tail -n 1 | cut -d ' ' -f2)"
vpnstatus="$(systemctl status wg-vpn-random.service | grep loaded | cut -d ' ' -f7)"
 
if [ "$urlstatus" = 503 -a $vpnstatus = loaded ]; then
	systemctl start wg-vpn-random.service
	sleep 10
fi
 
urlstatus="$(curl --tlsv1.2 --tls-max 1.3 --ipv4 --connect-timeout 10 --retry 1 --proto https,http --proxy $proxy --capath /etc/ssl/certs --no-sessionid --location --max-redirs 3 -s -S --head $checkurl | grep "200 OK" | cut -d ' ' -f2)"
 
if [ -z "$urlstatus" -a $vpnstatus = loaded ]; then
	systemctl start wg-socks-random.service
else
	exit 0
fi
 
exit 0
/etc/systemd/system/wg-vpn-check.service
[Unit]
Description=VPN-Check for WireGuard
After=network-online.target nss-lookup.target
Wants=network-online.target
 
[Service]
ExecStart=/etc/systemd/scripts/wg-vpn-check.sh
/etc/systemd/timer/wg-vpn-check.timer
[Unit]
Description=VPN-Check for WireGuard
 
[Timer]
OnBootSec=333
OnUnitActiveSec=3min
AccuracySec=0
 
[Install]
WantedBy=timers.target
sudo systemctl enable /etc/systemd/timer/wg-vpn-check.timer

Port Forwarding

Mittels Port Forwarding kann man einen Port, den ein lokaler Dienst oder eine lokale Anwendung nutzt, von außen und außerhalb der Mullvad WireGuard-Verbindungen für andere Internetnutzer erreichbar machen, um ihnen z. B. Server-Dienste anzubieten oder mit ihnen per P2P-Anwendungen zu nutzen. Der ein- und ausgehende Traffic wird dabei wie oben ebenfalls über die WireGuard-Tunnel des Mullvad „VPN“ transportiert. Beim Port Forwarding ist die zusätzliche Nutzung eines SOCKS-Proxy nicht möglich, aber die obige Multihop-Lösung mit zwei WireGuard-Servern.

Einrichtung bei Mullvad

Nach der Anmeldung bei Mullavd wählt man Manage devices and ports:

Unter Port Forwarding wählt man über Select a city aus der Liste eine Stadt aus. In den dort verorteteten WireGuard Exit-Servern wird die zugeteilte Portnummer und Verknüpfung zum Account eingetragen. Mit den IP-Adressen der später genutzten Exit-Server tritt der lokale Dienst bzw. die lokale Anwendung später nach außen in Erscheinung und die Exit-Server nehmen über die zugeteilte Portnummer externe Verbindungen entgegen.

Anschließend wählt man über Select a device den Namen eines bereits eingerichteten Schlüssels aus und klickt abschließend den Add port Button an. Danach erscheint die Ausgabe der Portweiterleitung, z. B. „us-qas-portnummer“.

Danach erstellt man wie oben mehrere Multihop-Konfigurationen, die alle als Exit-Server WireGuard-Server der Stadt verwenden, die man unter Port Forwarding aus der Liste ausgewählt hatte.

Konfiguration

Alle mlvd*.conf Dateien werden nach /etc/wireguard/pf/ verschoben. Alle Konfigurationsdateien werden nach folgendem Schema geändert:

/etc/wireguard/pf/mlvd*.conf
[Interface]
PrivateKey = string
Address = a.b.c.d/32 (der WG-Netzwerkschnittstelle)
DNS = 127.0.0.1
TABLE = off
PostUp = ip route add 0.0.0.0/1 dev wg0
PostUp = ip route add 128.0.0.0/1 dev wg0
PostUp = ip route add entry-ip/32 via gateway-ip dev nic-name
PostUp = /etc/wireguard/pf/wg-vpn-pf-postup.sh
PreDown = ip route del 0.0.0.0/1 dev wgnet0
PreDown = ip route del 128.0.0.0/1 dev wgnet0
PreDown = ip route del entry-ip/32 via gateway-ip dev nic-name
PostDown = /etc/wireguard/pf/wg-vpn-pf-postdown.sh
 
[Peer]
PublicKey = string (Schlüssel v. Exit-Server)
AllowedIPs = 0.0.0.0/0
Endpoint = ip-adresse (v. Entry-Server):multihop-portnummer (v. Exit-Server)

Laut Routing & Network Namespace Integration wurde die „klassische Lösung“ zum Überschreiben der Standard-Route gewählt, um im Gegensatz zum Split Tunneling jeden Datenverkehr über das Mullvad WireGuard „VPN“ zu leiten. Auf der Seite wird auch erklärt, wie man stattdessen regelbasiertes Routing oder Netzwerk-Namensräume (Beispiel: Wireguard vpn with network namespace on NixOS) verwendet.

/etc/wireguard/pf/wg-vpn-pf-postup.sh
sudo systemctl stop wg-vpn-random.timer
sudo firewall-cmd --zone=name --add-service=name
# oder sudo firewall-cmd --zone=name --add-port=portnr/tcp
/etc/wireguard/pf/wg-vpn-pf-postdown.sh
sudo firewall-cmd --zone=name --remove-service=name
# oder sudo firewall-cmd --zone=name --remove-port=portnr/tcp

Über die beiden Skript-Snippets wird ein noch laufender Timer zum Wechseln der ersten WireGuard-Konfiguration in Intervallen beendet. Ein ähnlicher Timer wird beim Port Forwarding nicht eingesetzt, weil es sich um Dienste bzw. Anwendungen handelt, die längerfristig über stabile bzw. statische Verbindungen angeboten und genutzt werden sollen. Beim Start bzw. der Beendigung werden Paketfilter-Regeln für die Dienste bzw. Anwendungen aktiviert bzw. deaktiviert. Beide Skripte kann man um weitere Kommandos ergänzen, die bei der Verwendung von Port Forwarding ausgeführt werden sollen.

lokale Einrichtung

Im Router richtet man unter Freigabe oder Port-Forwarding eine Port-Weiterleitung mit dem zugeteilten Mullvad-Port ein. Wenn auf dem Rechner, auf dem der Dienst oder die Anwendung läuft, ein Paketfilter aktiv ist, richtet man für den Dienst bzw. den Mullvad-Port eine entsprechende Genehmigung ein. Zum Beispiel mit firewalld:

sudo firewall-cmd --permanent --new-service=name
sudo firewall-cmd --permanent --service=name --add-port=portnr/tcp
sudo firewall-cmd [--permanent] --zone=name --add-service=name
oder
sudo firewall-cmd [--permanent] --zone=name --add-port=portnr/tcp

In der Konfiguration des Servers bzw. der Anwendung wird ebenfalls der zugeteilte Mullvad-Port eingetragen und wenn nötig die Mullvad WireGuard-Netzwerkschnittstelle.

Start

/etc/systemd/service/wg-vpn-pf.service
[Unit]
Description=VPN-PF-Changer for WireGuard
After=network-online.target nss-lookup.target
Wants=network-online.target
 
[Service]
ExecStart=/etc/systemd/scripts/wg-vpn-pf.sh
/etc/systemd/scripts/wg-vpn-pf.sh
#!/usr/bin/sh
 
wgroot=/etc/wireguard
wgrandom="$(ls $wgroot/pf/ | grep conf | cut -d. -f1 | shuf -n 1).conf"
vpn=$(wg show interfaces)
 
if [ -n $vpn ]; then
 systemctl stop wg-quick@wg0.service
 sleep 3
fi
 
cp -f $wgroot/pf/$wgrandom $wgroot/wg0.conf && \
cp -f $wgroot/pf/*key $wgroot/ && \
systemctl start wg-quick@wg0.service
 
exit 0

Analog zur ersten Konfiguration wird mit der systemd Unit das Skript ausgeführt, das aus den gespeicherten Multihop-Konfigurationen eine Konfiguration zufällig auswählt, mit der und der wg-quick Dienste-Unit die WireGuard-Netzwerkschnittstelle eingerichtet wird. Eine eventuell bereits bestehende WireGuard-Netzwerkschnittstelle wird zuvor abgebaut.

Mit systemctl start wg-wpn-pf.service oder systemctl start wg-vpn-random.service && systemctl start wg-vpn-random.timer kann man zwischen Wireguard mit oder ohne Port Forwarding hin- und herschalten.

Für beide Konfigurationen können zwei verschiedene Schlüsselpaare verwendet werden. Wenn für das Port Forwarding ein zweites Schlüsselpaar erstellt wird, speichert man es unter /etc/wireguard/pf/, importiert den Schlüssel in Mullvad und ordnet ihn bei Einrichtung des Port Forwardings auf Mullvad über Auswahl seines Namens zu. Wird nur ein Schlüsselpaar verwendet, kopiert man das Schlüsselpaar von /etc/wireguard/reserve/ nach /etc/wireguard/pf/.

Verweise auf aktuelle Seite