IPv64.net VPN Gateway Docker Client - Suche Hilfe

Natürlich soll man auf das Gateway nicht nur via Smartphone oder PC darauf zu greifen können, sondern auch viele Anwender haben nur eine Synology o.ä. irgendwo stehen.
Ich bin kein Docker Experte, aber ich habe mithilfe von Chatgpt da schon mal was vorbereitet, was auf jeden eine saubere Verbindung herstellt.
Also um Mithilfe wäre ich da dankbar. Postet eure Änderungen/Verbesserungen einfach mal in GIT.

1 „Gefällt mir“

Man nimmt keine :latest Images als Basis.
Stattdessen sollte man immer auf eine feste Version taggen.

COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

Statt das executable Flag erst im Image zu setzen, mach das vorher und lass das Setzen im Image weg. Auch wenn es „nur“ eine Zeile Code ist, erzeugt das einen völlig unnötigen zusätzlichen Layer für das Image.

ENV WG_TOKEN=""

Hier kann man sich streiten, ob man das Secret als Umgebungsvariable aufnehmen möchte oder als ob ein File besser wäre. Während die Umgebungsvariable natürlich einfacher zu setzen ist, ist der Token beim File-Mount nicht unmittelbar für jeden direkt zu lesen. Das erhöht die Sicherheit.

Statt #!/bin/sh verwende #!/usr/bin/env sh. Das respektiert die Umgebung in der das Script ausgeführt wird.

tail -f /dev/null

ist eine schlechte Option einen Container am Leben zu halten.
Entweder starte den Dienst im Vordergrund, so dass der Prozess nicht stirbt oder mach wenigstens ein tail -f auf ein relevantes Logfile, so dass der Container einen relevanten Log erzeugt.

Aber was genau war jetzt deine Frage? :smiley:

Meine Frage war einfach nur ob mir jemand helfen kann beim container, weil ich bin da einfach kein Experte. Die Basics sind mir klar, aber experte eben nicht.

Kannst deine Wunschänderungen in das GIT pushen und ich akzeptiere da einfach mal ?

Habe ein paar Anpassungen gemacht und als Pull-Request gestelt.

Was hältst du davon, wenn wir statt dem tail auf /dev/null Nutzungsdaten anzeigen?
Kannst du dafür einen Endpunkt bauen? Den könnte man dann in einem while loop mit sleep alle x Minuten abfragen.

Finde ich eine sehr gute idee. Ich leite deine änderung mal ins Master.. wie auch immer das geht. GIT und ich sind keine Freunde. :wink:

Wenn du einen Endpunkt stellen kannst, der die interessanten Daten liefert, könnte man den in der entrypoint.sh periodisch abfragen:

z.B.

while true; do
  curl -fsSL "https://ipv64.net?wgstats=${WG_TOKEN}"
  sleep 300
done

Der könnte dann einfach plaintext raus schreiben, wie die Stats sind, z.B.:

[🌐] ↗ 23.81 MB | ↙ 9.20 MB |  ⏳ 00:05:18 | ⠿ 0.03 / 50.00 GB
[🌐] ↗ 8.58 GB | ↙ 4.41 GB |  ⏳ 1 10:07:23 | ⠶ 12.99 / 50.00 GB
[🌐] ↗ 16.64 GB | ↙ 9.78 GB |  ⏳ 3 06:43:16 | ⠴ 26.42 / 50.00 GB

Man müsste man nur mal überschlagen, was das so an zusätzlicher Last generiert.
Wenn jeder Client im 5 Minuten-Takt eine Anfrage gegen deine Infrastruktur schiebt, kann das ja schon einiges aus machen. Insbesondere je nach dem, wie die Anfragen dahinter weiterverarbeitet werden müssen, um die Werte aufzubereiten.

1 „Gefällt mir“

Ich finde die Idee gut. Nimm ruhig mal genau die URL die du da nutzt. Ich progge das die nächsten Stunden / Tage da rein.

So sieht das Query aus:

curl -fsL "https://ipv64.net/?wgstats=${WG_TOKEN}"

Achtung: Der Merge Request sollte 2 Commits beinhalten. Im Zweiten habe ich das sleep nochmal auf 300s gesetzt. Zum Testen hatte ich mit 30s getestet..

[:globe_with_meridians:] :up_right_arrow: 16.64 GB | :down_left_arrow: 9.78 GB | :hourglass_not_done: 3 06:43:16 | ⠴ 26.42 / 50.00 GB

Habs mal hinzugefügt, aber wofür soll das stehen ? - :hourglass_not_done: 3 06:43:16 ?? Handshake ?

Bonusfrage: Wie handhabt man denn dann das Routing? Das eben genau diese Verbindung vom Hauptsystem diesen Container nimmt als Routingbridge ?

Ich hätte gedacht:
Datenvolume up | Datenvolume down | Verbindungsdauer | Verbrauch vom Kontingent
Jeweils mit Symbolen, damit es ansprechender ausschaut. :smiley:

Wobei die Verbidnungsdauer als Tage Stunden:Minuten:Sekunden formatiert ist.
Aber theoretisch kannst du eigentlich alles da hin schreiben. Das Script nimmt ja einfach die erste Zeile aus dem, was der Endpunkt zurück gibt. :smiley:

Zur Bonusfrage:

Ich habe das mit dem Docker Container nur kurz ausprobiert, während ich an dem Script gearbeitet hatte. Bei mir wurde das Interface direkt auf dem Host-System anlegt und scheinbar ist auch der gesamte Traffic darüber gelaufen.

Auf dem Hostsystem habe ich gar nichts zusätzlich konfiguriert. Allerdings war eigentlich auch gar nicht beabsichtigt irgendetwas darüber zu schicken, zum Testen hätte es ja gereicht, dass die Verbindung grundsätzlich aufgebaut wird. :see_no_evil_monkey:

Ich werde den Client mal auf meiner Synology ausprobieren.

Der Container muss dann einfach als Default GW für die internen Geräte angegeben werden, oder? Aber hmm, der weg zurück? Müsste ja fast noch eine Routingfunktion im Container haben?

Ja das ist auch noch meine Frage, hab mich aber noch nicht eingelesen. Probiere dich einfach mal aus. Du bist scheinbar User 1. :smiley:

Hab jetzt auch nochmal getestet. Bei mir tauchen die Routen vom WG Container im Host System wirklich nur auf wenn man

--privileged --network host

dazu setzt. Das sind natürlich schon erhebliche Rechte im System. Aber ich denke ohne das wird es nicht gehen. Das war mein Befehl.
Das ip_forward sollte man setzen, damit er auch wirklich Pakete forwarden darf.

docker run --rm -it -d --privileged --network host --cap-add=NET_ADMIN --sysctl net.ipv4.ip_forward=1 --device /dev/net/tun -e WG_TOKEN="xxxxxxx" ipv64-vpn-gateway-client

Ach und mit IPv6 kam er bei mir auch nicht klar.

Mit --network host nutzt du das Hostnetzwerk. Damit hebst du die Netzwerkisolation auf.
Und mit --privileged kannst du Zugriff auf Host Devices erhalten.

Das bedeutet unterm Strich auch, dass es streng genommen den Container nur zu Einrichten des Interfaces braucht. Den Loop um den Container am Leben zu halten, bräuchte es mit dem Setup tatsächlich nicht. Stirbt der Container, ist das Interface weiterhin auf dem Host-System aktiv.

Angenommen wir modifizieren die entrypoint.sh:

#!/usr/bin/env sh

set -e

SERVICE_BASE_URL="https://ipv64.net/"
WG_CONFIG_URL="${SERVICE_BASE_URL}?wgconfig=${WG_TOKEN}"
WG_STATS_URL="${SERVICE_BASE_URL}?wgstats=${WG_TOKEN}"

##

if [ -z "${WG_TOKEN}" ]; then
  TS=$(date +"%Y-%m-%d %H:%M:%S.%N %Z")
  echo "[ERROR] ${TS} | Missing WG_TOKEN"
  exit 1
fi

# create & enter working directory
mkdir -p /etc/wireguard
if ! cd /etc/wireguard; then
  TS=$(date +"%Y-%m-%d %H:%M:%S.%N %Z")
  echo "[ERROR] ${TS} | Could not create working directory"
  exit 1
fi

# download up to date configuration
TS=$(date +"%Y-%m-%d %H:%M:%S.%N %Z")
echo "[INFO] ${TS} | Downloading WireGuard configuration"
if ! curl -fsL "${WG_CONFIG_URL}" -o ./wg0.conf; then
  TS=$(date +"%Y-%m-%d %H:%M:%S.%N %Z")
  echo "[ERROR] ${TS} | Could not download new configuration"
  exit 1
fi

# connect wireguard tunnel
TS=$(date +"%Y-%m-%d %H:%M:%S.%N %Z")
echo "[INFO] ${TS} | Starting WireGuard interface wg0"
if ! wg-quick up wg0; then
  TS=$(date +"%Y-%m-%d %H:%M:%S.%N %Z")
  echo "[ERROR] ${TS} | Could not start WireGuard interface"
  exit 1
fi

Dann würde uns das reichen:

docker run --rm -d \
  --privileged --network host \
  -e WG_TOKEN="xxxxxxx" ipv64-vpn-gateway-client

Damit wird der Container erstellt, das Interface konfiguriert und der Container verschwindet wieder vollständig.

Ich vermute allerdings, dass das nicht das Verhalten ist, das du dir eigentlich wünschst.

Vermutlich hättest du lieber, dass das wg-Interface nur virtuell im Container existiert und du auf dem Host-System nur den Container als default Gateway setzt, richtig?

Ich glaube das wäre das bessere Verhalten. Wir müssen überlegen, die Zielgruppe sind ja die die sowas auf einem NAS oder so betreibt..

Dann braucht es vermutlich sowas in der Art:

docker network create -d bridge ipv64_vpn

docker run --d --name ipv64_vpn \
  -e WG_TOKEN="xxxxxxx" ipv64-vpn-gateway-client

GATEWAY_ADDRESS=$(docker inspect ipv64_vpn | jq -r '.[0].NetworkSettings.Networks.ipv64_vpn.IPAddress')

Jetzt könnte man auf dem Host-System eine Route setzen, um Traffic in den Container zu werfen.
Im Container braucht es dann noch Konfiguration, um den Traffic vom ipv64_vpn Netzwerk abzunehmen und in wg0 zu werfen bzw. umgekehrt.

Aber an der Stelle sollte vielleicht jemand mit Netzwerk Kenntnissen sagen, was zu tun ist :smiley:

Also ich fasse zusammen.

Variante A: Vollgas Rechte „–privileged --network host“
Funktioniert gut, setzt sich von alleine ins Hostsystem rein, setzt alle Routen etc..
Aber eben hat sehr viel Rechte…
Kann ich mit leben

Variante B: Mehr security
User muss Routen selber setzen, im Container als auch im Hostsystem.
Eigentlich muss er ja auch noch routen setzten im Heimischen Router.

Variante B ist damit nicht praktikabel, denn User sind in der Regel nicht mal in der Lage eine IP-Adresse korrekt zu schreiben..

Ist bleibt bei Variante A
Also so wie du beschrieben hast. Ballerst das als Push rein bei GIT ?

Bei der Variante B könnten wir ja (fast) alles im Container abfackeln.
Dann muss nur auf dem Host System von Nutzer selbst modifiziert werden.

Bei Variante A verlierst du mit dem Container die Steuerungsebene. Ich bin mir nicht sicher, wie das Hostsystem - insbesondere auf einem NAS - damit umgeht, wenn der Tunnel mal weg bricht und neu aufgebaut werden muss.

Ich kann die Änderungen für Variante A pushen.
Ich versuch’s heute Abend noch hin zu bekommen. Wenn nicht spätestens Samstag.

Vielleicht könnte @ItaloBoy dann ja als Versuchsperson herhalten. :smiley:

@Dennis_Admin Schau mal, ob das passt.

Ich habe es jetzt so gebaut, dass wir uns die Varianten nicht grundsätzlich verbauen.

Variante 1:

docker run --rm -it \
  --privileged --network host \
  ipv64-vpn-gateway-client configure

Sollte jetzt nach dem Token fragen, den Tunnel bauen und sich selbst danach beenden sowie den Container entfernen.

Variante 2:

docker run --name ipv64_vpn -d \
  -e "WG_TOKEN=xxxxxx" \
  ipv64-vpn-gateway-client run

Ist allerdings nicht fertig gebaut. Wie gesagt, Die Netzwerk Magie im Container muss noch gebaut werden und man muss eben außen die Route setzen..