This repository has been archived on 2026-09-17. You can view files and clone it, but you cannot make any changes to its state, such as pushing and creating new issues, pull requests or comments.
nixos-config/docs/session-2026-09-12-pinix-traefik.md
pijukka d326031f38 docs: Session-Uebergabe zu Traefik auf pinix, Intent-Status nachgezogen
Format wie docs/session-2026-09-12-ipv6-plattform.md, an das diese Session
anschliesst. Haelt fest, was verifiziert ist, was ausdruecklich nicht
getestet wurde (Reboot-/Reconnect-Probe) und welche Entscheidungen offen
beim Nutzer liegen (Zertifikatskette, Wildcard via BIND).

Der Intent sagte noch "noch nicht ausgefuehrt"; Schritte 1 bis 5 sind
erledigt, Schritt 6 nicht.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019jNMZkpvA9QuNEPg9BA6oY
2026-09-12 15:28:26 +02:00

8.7 KiB

Session 12.09.2026 (Teil 2): Traefik auf pinix, öffentlicher IPv6-Eingang

Übergabe für die nächste Session

Gearbeitet wurde auf tnix (nicht auf blunix), Branch dev, alles gepusht. Vorgänger dieser Session: IPv6-Mobilfunkzugang und Plattformplanung. Auftrag war der Intent, dessen Schritte 3 bis 5 jetzt umgesetzt sind.

Stand: https://ipv6-test.0ff.space/ wird von pinix beantwortet, über Traefik auf pinix, mit eigenem Let's-Encrypt-Zertifikat. Kein VPS, kein Tailnet, kein Cloudflare-Proxy im Datenpfad — Cloudflare hält nur den AAAA-Eintrag, der unverändert blieb. Der nginx-Test auf tnix ist entfernt.

Nächster sinnvoller Schritt: Schritt 6 des Intents — Reboot- und Reconnect-Probe. Die ist ausdrücklich nicht gelaufen. Das öffentliche Präfix rotiert nachweislich (auf Mangos usb0 liegt neben der aktiven Adresse noch 2a01:599:106:e90d:94dd:42ff:fe9a:627f als deprecated). Vor der Probe einen lokalen Rückweg sichern und den Zeitpunkt abstimmen.

Arbeitsweise, auf die sich Nutzer und Agent geeinigt haben

Editiert wird auf tnix im Repo, gebaut und aktiviert wird lokal auf pinix, committet wird erst, wenn es auf der Zielhardware läuft:

rsync -a --delete --exclude .git ./ pinix:/home/drone/nixos-config-build/
ssh pinix 'cd /home/drone/nixos-config-build && \
  sudo nixos-rebuild switch --flake path:.#pinix --no-reexec'

Begründung: kein Commit pro Zwischenstand, kein Closure-Transfer, kein Umweg über Forgejo; der rsync kostet etwa 1,5 s. Der nixbuild.net-Store bleibt für große Kompilierläufe. /home/drone/nixos-config auf pinix ist der Recovery-Checkout, kein Arbeitsplatz.

Gesicherte Ergebnisse

  • pinix kann wieder von Forgejo fetchen. /etc/ssh/ssh_known_hosts war leer; der Pin für Port 2222 lag früher im auskommentierten localServices/forgejo.nix. Seit 355b42e steht er global in hosts/globalServices/forgejo-known-host.nix. Henne-Ei: der Pin liegt selbst im Repo, ein Pull konnte ihn also nicht holen — der rsync-Bauweg war der Ausweg. Recovery-Checkout per --ff-only nachgezogen.
  • Traefik auf pinix, hosts/pinix/localServices/traefik.nix. Abgeleitet von blunix, aber bewusst ohne Cloudflare-DNS-Challenge (kein API-Token, kein Secret, dafür keine Wildcard), ohne api/Dashboard, ohne ip_nonlocal_bind, log.level INFO statt TRACE.
  • Statische Testseite, hosts/pinix/localServices/ipv6-test.nix, nach dem Muster von blunix' launcher.nix: static-web-server auf 127.0.0.1:8001, Route im Dienstmodul statt in einer zentralen Liste. Die Seite nennt pinix beim Namen, damit ein alter tnix-Pfad auffällt.
  • Mango-DNAT umgelegt, scripts/configure-mango-ipv6-web.sh ist jetzt parametrisiert (TARGET_IP, PUBLIC_IP, WAN_DEV, PORT_MAP, RULE_PREFIX, STALE_PREFIXES), räumt Regeln früherer Ziele vorher weg und ermittelt die öffentliche Adresse zur Laufzeit statt sie einzutragen. Aufruf vom LAN aus: ssh root@192.168.8.1 'sh -s' < scripts/configure-mango-ipv6-web.sh. Backup je Lauf unter /root/ipv6-web-firewall-backup.* auf dem Mango.
  • SNAT-Rückwegregeln entfallen ersatzlos. Sie waren nötig, weil tnix seine Default-Route auf dem iPhone-Hotspot behielt; pinix' Default-Route zeigt ohnehin auf den Mango. Sechs Regeln wurden zu drei, und die echte Client-Adresse steht wieder im Traefik-Log statt fdee:3c40:44f0::1.
  • Extern 8080 → intern 80, weil auf pinix nur Traefik mit 80/443 lauscht. Der alte Link bleibt gültig und läuft über die HTTPS-Weiterleitung des Proxys.
  • Zertifikat per ACME HTTP-01, Resolver le, Speicher /var/lib/traefik/acme.json. Traefik-Log: Validations succeeded, also hat Let's Encrypt pinix von außen über IPv6 erreicht.
  • tnix-Testserver entfernt. Damit fiel die statische ULA auf enp0s31f6 weg, die dort ein schwarzes Loch erzeugte: das Interface ist DOWN, lieferte aber trotzdem die On-Link-Route für fdee:3c40:44f0::/64, sodass tnix das gesamte LAN-Präfix in ein totes Interface schickte. Über IPv4 lief derselbe Weg einwandfrei — eine hübsche Falle, falls sie anderswo nochmal auftaucht.

Gemessene Zustände (12.09.2026, vor weiterer Aktivierung neu prüfen)

Prüfung Ergebnis
curl von tnix, HTTPS mit --resolve auf pinix' ULA 200, „Hallo von pinix."
Port 80 auf pinix 301 auf HTTPS
unbekannter Hostname an Traefik 404, kein Catch-all
openssl s_client gegen pinix:443 vollständige Kette, Verify return code: 0 (ok)
pinix IPv6-Uplink RA-Default-Route via fe80::9683:c4ff:fe12:ab4d, github.com 200

Adressen: pinix LAN-ULA fdee:3c40:44f0:0:dea6:32ff:fe48:c6c8 (SLAAC aus MAC dc:a6:32:48:c6:c8), Mango öffentlich 2a01:598:ec1e:ce00:94dd:42ff:fe9a:627f, Mango LAN fdee:3c40:44f0::1 bzw. 192.168.8.1.

Fallstrick, der Zeit gekostet hat

Der Intent verlangt eine „stabile LAN-Zieladresse". Der naheliegende Weg — networking.interfaces.end0.ipv6.addresses wie in tnix' ipv6-web-test.nix — nimmt dem Host das Internet: sobald ein Interface eine statische IPv6-Adresse bekommt, schreibt das NixOS-dhcpcd-Modul für dieses Interface noipv6rs in die generierte dhcpcd.conf. Keine Router-Solicitation, keine RA-Default-Route — und pinix' Uplink ist IPv6-only. Sichtbar wird das erst nach dem switch, weil dabei dhcpcd neu startet und die vorhandenen Adressen mitnimmt.

Zurückgebaut. Ziel ist jetzt die SLAAC-Adresse, die aus MAC und ULA-Präfix ohnehin deterministisch entsteht — dieselbe Adresse, nur ohne den Nebeneffekt. Im Modul kommentiert. Wer eine wirklich unabhängige statische Adresse will, muss die Default-Route mit lösen; ein erster Versuch damit war laut eb2022e schon auf tnix gescheitert.

Offene Punkte

  • Zertifikatskette. Ein externer Abruf über einen Client mit älterem CA-Bundle scheitert reproduzierbar an unable to verify the first certificate; die Kette läuft über ISRG Root YR. pinix' eigenes Bundle und openssl akzeptieren sie (Verify return code: 0). Verdacht: das Root ist noch nicht überall im Trust Store, ältere Android-Geräte dürften dasselbe Problem haben. Möglicher Fix: preferredChain im ACME-Resolver. Das erzwingt eine Neuausstellung, also vorher den Eintrag aus acme.json räumen. Vom Nutzer noch nicht entschieden.
  • Reboot-/Reconnect-Probe (Intent Schritt 6) steht aus, siehe oben.
  • Wildcard über selbst gehostetes BIND wurde besprochen und zurückgestellt, nicht verworfen. Begründung: ein autoritativer NS braucht einen zuverlässig erreichbaren Host, und genau diese Eigenschaft ist für pinix noch nicht nachgewiesen. Die Fehlerfolgen sind asymmetrisch — HTTP-01 kaputt heißt eine Seite ohne Zertifikat, autoritativer DNS kaputt heißt 0ff.space löst nirgends mehr auf, samt Mail, XMPP-Föderation und ActivityPub. Ein nur über IPv6 erreichbarer NS schließt zudem alle IPv4-only-Resolver aus. Vorgeschlagene Reihenfolge: erst Eingang stabilisieren, dann als Zwischenstufe _acme-challenge delegieren (nimmt Cloudflare den API-Token weg, ohne die Auflösung der Domain an den Mobilfunkanschluss zu hängen), vollautoritatives BIND als eigene Entscheidung mit Sekundären. Siehe docs/roadmap.md.
  • Subdomains wie auf blunix sind erklärtes Ziel. Die Routing-Ebene trägt das bereits: DNAT arbeitet auf Adresse und Port, jede weitere Subdomain ist nur ein Traefik-Router. Nicht mitskalieren: ein Zertifikat pro Hostname bei HTTP-01, ein AAAA je Subdomain auf eine rotierende öffentliche Adresse, und IPv4-only-Besucher erreichen einen IPv6-only-Eingang gar nicht — dafür bliebe blunix als zweiter Eingang.

Dateien und Arbeitsstand

Commits auf dev, in dieser Reihenfolge:

Commit Inhalt
54ea39e docs/pinix-minimalbetrieb.md: Forgejo-Fetch behoben, Henne-Ei festgehalten
31a8e0f pinix: minimales Traefik plus Testseite, noch ohne TLS
61b4d1f TLS über ACME HTTP-01, Mango-Skript parametrisiert, DNAT umgelegt
4558f86 tnix: IPv6-Testserver entfernt

Aktive Generationen nach der Session: pinix w9dr3gl14dxwm5hb6l0rv7fxs0h83ahg-nixos-system-pinix, tnix vjmsfk6kdgynnzdc0pz53cf5knbi02qr-nixos-system-tnix.

Verworfen wurde eine uncommittete Änderung in hosts/tnix/configuration.nix, die das WLAN zurück auf den iPhone-Hotspot gestellt hätte — ein switch damit hätte tnix aus dem Netz geworfen, in dem es gerade hängt.

Rückbau auf den vorherigen Stand: dest_ip in den Mango-Regeln zurück auf tnix' ULA fdee:3c40:44f0:0:ca5b:76ff:fe96:e24 (oder das Skript mit TARGET_IP=... erneut laufen lassen) und auf tnix die Generation vor 4558f86 booten, die den nginx-Test noch enthält.