Host-Wireguard mit NordVPN Container

Hinweis

Die Anleitung kann veraltet sein und kann als Inspiration genutzt werden!

Wireguard Clients durch Nordvpn tunneln

Wer kennt es nicht, man möchte mehrere Geräte durch einen VPN Tunnel leiten, aber nicht auf jedem die App installieren, oder andere VPN Konfigurationen nutzen.Deshalb möchte ich hier beschreiben, wie ein Nordvpn Tunnel im Docker gebaut wird und beliebig viele Wireguard-Clients angebunden werden können.Der gesamte Traffic der Wireguard-Clients wird in den Nordvpn Tunnel geroutet, sodass die Clients die ausgehende IP-Adresse des Nordvpn Tunnels erhalten. Die Anleitung geht davon aus, dass systemd-networkd und Docker verwendet wird! Das verwendete IP-Netz für die Clients ist 192.168.20.0/24 (192.168.20.1 - 192.168.20.254). Der Server erhält die .1, alle Clients aufsteigend ab .2.

Wireguard einrichten

Im Archlinux-Wiki ist eine ausführliche Anleitung zu finden (https://wiki.archlinux.org/title/WireGuard), deshalb hier eine kurze Zusammenfassung:

Keypairs des Servers erstellen

Hier wird ein private Key (server.key), der daraus abgeleitete public Key (server.pub) und ein Preshared Key (server_client1.psk) generiert. Für den Server wird nur ein einziger privater Schlüssel benötigt, allerdings sollte jede Verbindung einen eigenen PSK erhalten. Der letzte Befehl kann beliebig wiederholt werden (client1 zu client2, client3, … ändern!):

mkdir /etc/wireguard
cd /etc/wireguard

(umask 0077; wg genkey > server.key)
wg pubkey < server.key > server.pub
wg genpsk > server_client1.psk
Wireguard Tunnel einrichten

Bitte beachten, dass jeder Client eine eigene WireGuardPeer Sektion erhalten muss. In diese muss der Public-Key des Clients und der gemeinsame, beidseitig identische PSK hinterlegt werden. Die IP-Adressen können ebenfalls angepasst werden, je nach Bedarf.

mkdir -p /etc/systemd/network/
cd /etc/systemd/network/

PKEY=$(cat /etc/wireguard/server.key)
PSK1=$(cat /etc/wireguard/server_client1.psk)

echo "
[NetDev]
Name=wg0
Kind=wireguard
Description=Wireguard VPN direct tunnel for multi devices

[WireGuard]
PrivateKey = ${PKEY}
ListenPort = 12345

[WireGuardPeer]
PublicKey = <CLIENTS_PUBLIC_KEY>
AllowedIPs = 192.168.20.2/32
PresharedKey = ${PSK1}" > wg0.netdev


echo "
[Match]
Name=wg0

[Network]
Address=192.168.20.1/24" > wg0.network

Nordvpn konfigurieren

Wie bereits erwähnt, wird Docker benötigt und der Container baut die VPN Verbindung auf. Dadurch dass dieser in einem eigenen Netzwerkbereich isoliert ist, kann Nordpvn zwar Firewall-Regeln und Routen konfigurieren, diese verändern aber nichts am Host selbst, was sehr wünschenswert ist.

Docker-Container Konfiguration

Hierfür bietet sich die Erstellung eines Tokens an, diesen erhält man von Nordpvn:https://my.nordaccount.com/de/dashboard/nordvpn/Runterscrollen zum Punkt Zugangstoken, einen erstellen und in die Variable TOKEN speichern (xxxxxxxxxxxxxxxxxxx ersetzen):

# Debian / Ubuntu
apt-get update; apt-get install docker-compose

# Archlinux
pacman -Syu docker-compose

TOKEN="xxxxxxxxxxxxxxxxxxx"
mkdir -p /srv/docker/nordvpn
cd /srv/docker/nordvpn
echo "
version: "3"
services:
  nvpn1:
    image: ghcr.io/bubuntux/nordvpn
    container_name: "nordvpn_1"
    restart: unless-stopped
    environment:
      TOKEN: ${TOKEN}
      # alle Netze die über Nordvpn geroutet werden sollen, kommasepariert hinterlegen
      NET_LOCAL: 192.168.20.0/24
    cap_add:
    - NET_ADMIN
    - NET_RAW
    networks:
      default:
        ipv4_address: 192.168.21.2

networks:
  default:
    driver: bridge
    ipam:
      driver: default
      config:
        - subnet: 192.168.21.0/24
    driver_opts:
      com.docker.network.bridge.name: br_nordvpn" > docker-compose.yml

# Container hochfahren
docker-compose up -d
Systemd-Networkd Netzwerkkonfiguration

Die Routing Tabelle 333 ist wilkürlich gewählt und kann eine beliebige Zahl sein. Beim Eintrag ist wichtig, dass der Name des Interfaces (br_nordvpn) dem der Bridge entspricht, damit in der Routing-Tabelle das richtige Interface hinterlegt wird!

echo "
[Match]
Name=br_nordvpn

# Docker setzt auf dem Host nicht zwingend die IP-Adresse
# dies wird Systemd-Networkd korrigieren
[Network]
Address=192.168.20.1/24
ConfigureWithoutCarrier=yes

# das Netz der Docker Bridge muss in die Routing Tabelle 333
[Route]
Destination=192.168.21.0/24
Table=333

# der gesamte Internet-Traffic wird über den Nordvpn Docker-Container geroutet
[Route]
Destination=0.0.0.0/0
Gateway=192.168.21.2
Table=333

# Traffic eingehend vom Absendernetz (Wireguard) wird über Einträge aus der Routing-Tabelle 333 geroutet
# ohne die Policy würde die Haupttabelle gelten und es ohne Nordvpn im Internet landen
# sollen weitere Tunnel / Netze berücksichtigt werden, einfach pro Netz (!) eine RoutingPolicyRule hinterlegen
[RoutingPolicyRule]
From=192.168.20.0/24
Table=333" > /etc/systemd/network/br_nordvpn.network

# Berechtigungen korrigieren
chown -R systemd-network:systemd-network /etc/systemd/networkd/
chmod 750 /etc/systemd/networkd/
chmod 640 /etc/systemd/networkd/

# Netzwerk Daemon reload
systemctl reload systemd-networkd

Im Anschluss wird die Routing Tabelle und Rule angelegt. Dies kann man nun prüfen:

ip rule show
...
32765:  from 192.168.20.0/24 lookup 333 proto static


ip route show table 333
default via 192.168.21.2 dev br_nordvpn proto static
192.168.21.0/24 dev br_nordvpn proto static scope link

Nun sollte Traffic bereits über Nordvpn geleitet werden. Im Container kann man auch die Routen prüfen:

docker exec -ti nordvpn_1 bash

ip route
# der Gesamte Traffic wird nach der Verpackung in das Nordvpn Paket über den Host in das Internet geroutet
default via 192.168.21.1 dev eth0
# das Wireguard Netz muss bekannt sein, bzw. wird vom Container explizit hinterlegt. Ohne die Angabe in LOCAL_NET (docker-compose.yml) würde Traffic von diesem Netz verworfen...
192.168.20.0/24 via 192.168.21.1 dev eth0
# das Docker Netz mit Absender-IP des Docker Containers
192.168.21.0/24 dev eth0 proto kernel scope link src 192.168.21.2


# für technisch interessierte Personen kann man sich auch die Firewall-Regeln ansehen:
iptables -nvL
iptables -t nat -nvL

Wireguard auf Client

Je nachdem welchen Client man verwendet (App, Windows App, etc.) muss die Konfiguration ggf. etwas angepasst werden. Aber hier ein Beispiel für die Windows App:

[Interface]
PrivateKey = <CLIENTS PRIVATE KEY MEIST VORGENERIERT>
Address = 192.168.20.11/32

[Peer]
PublicKey = <PUB KEY DES SERVERS>
PresharedKey = <SERVER CLIENT1 PSK>
# route das gesamte Internet über den Tunnel (wenn nicht gewünscht 0.0.0.0/0 durch entsprechende Netze ersetzen. Zum Beispiel 1.1.1.1, 8.8.8.8, 8.8.4.0/24, ...)
AllowedIPs = 0.0.0.0/0
Endpoint = <IP DES SERVERS>:12345
# Keepalive check alle 30 Sekunden
PersistentKeepalive = 30

Nach einer Verbindung mit dem Wireguard Tunnel dürfte man nun für den Traffic ins Internet eine IP-Adresse aus dem Nordvpn Netz nutzen. Natürlich nur, wenn auch der Wireguard Port (12345 UDP) freigeschaltet wurde. Sollte ein anderer Port gewählt worden sein, müsste man dies berücksichtigen ;)