Files
bf-infra/adguard
Christoph Emsenhuber 7edf01b021 TP23 Stufe 5: HA-Self-Service + Dashboard-Draft + Doku-Nachzug
- agh-exception.py: Creds aus Env/Datei (Mac ~/.secrets + HAOS /config), Domain/IP-Validierung
- HA-Self-Service dokumentiert: shell_command + Helper/Timer/2 Automations (adguard/ha-self-service.md)
- Eigenes Dashboard 'dns-ausnahmen' (1. Draft, sections) inkl. Repro-JSON
- teilprojekte.md: TP23 Quick-Index + dated Update + Ist-Stand-Block nachgezogen
  (Stufe 1-5 durch; offen nur Stufe 6 Bypass-Sperre -> separate Session)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-06 16:45:00 +02:00
..

AdGuard Home — agh-bf1 (.36) / agh-bf2 (.37) · TP23 Stufe 2/4/5

Das AGH-Paar (pve LXC 110/111, 10.40.20.36 / .37) ist der Client-Resolver des BF-Netzes (DHCP liefert beide in allen 7 VLANs). Upstream: DoH zum CF-Gateway; conditional [/bf.emsenhuber.net/] → 10.40.20.1. Kein natives HA → Sync ist Betriebsaufwand.

Dateien

Datei Zweck
AdGuardHome.yaml Repo-SSoT der Config. Passwort-Hashes REDIGIERT ('<redacted>') — keine Secrets im Git. Echte Hashes leben auf den Geräten; Klartext des API-Users in ~/.secrets.
agh-sync.py check (Drift .36↔.37) · push (SSoT auf beide, gestaffelter Restart, reinjiziert Hashes live).
agh-exception.py Exception-Primitive (Stufe 5) gegen beide Instanzen.

Client-Policy (Stufe 4, clients.persistent)

Ein VLAN = eine CIDR-Gruppe. Alle nutzen denselben CF-Upstream-Filter; Divergenz = per-Client-Toggle.

Gruppe CIDR filtering safe_search parental
grp-main 10.40.10.0/24 an (global) – –
grp-infra 10.40.20.0/24 aus – –
grp-iot 10.40.30.0/24 an – –
grp-media 10.40.40.0/24 aus – –
grp-untrusted 10.40.50.0/24 an – –
grp-guest 10.40.90.0/24 an on on
grp-mgmt 10.40.99.0/24 aus – –
dns-bypass-exempt 10.40.10.183 + .82 aus – –

filtering aus bei INFRA/MEDIA/MGMT = bewusste Reduktion (Streaming/Server/Mgmt nicht brechen), per Gruppe rückholbar.

Sync-Invariante

AGH schreibt die YAML beim Restart um (normalisiert) → nicht gegen die Repo-Datei diffen, sondern .36 == .37. Genau das prüft agh-sync.py check.

Exception-Contract (Stufe 5 — was die HA-Schicht auslöst)

Auth: Basic, User automation (~/.secrets → AGH_AUTOMATION_*). Immer auf .36 UND .37.

🔴 Wichtig für D: die beiden AGH-Endpunkte sind read-modify-write, kein simples Append — set_rules ersetzt die ganze Liste, clients/update braucht das volle Client-Objekt. Ein zustandsloses HA-rest_command reicht deshalb nicht; agh-exception.py ist die Referenz-RMW-Implementierung, die D aufruft (Deploy-Weg auf HAOS in Etappe D zu entscheiden: shell_command/command_line gegen die deployte CLI oder ein dünner Wrapper-Endpunkt).

Aktion CLI AGH-API (RMW)
Domain global entsperren allow-domain <d> GET /control/filtering/status → +@@||<d>^ → POST /control/filtering/set_rules
Entsperrung zurück unallow-domain <d> dito, Regel entfernen
Client entfiltern unfilter <ip> GET /control/clients → Objekt, filtering_enabled=false → POST /control/clients/update
Client wieder filtern refilter <ip> dito, zurück auf global

Kein Timing in der CLI — Ablauf/Revert macht der Aufrufer (HA-Timer) und, ab Stufe 6, der RouterOS-Backstop.

RouterOS-Backstop (Stufe 6, noch NICHT gebaut)

Analog jit-admin (routeros/tp5-etappe4-input-mgmt.rsc): Address-List jit-dns-bypass mit timeout + Forward-Regel, die dieser Liste 53/853 nach außen erlaubt — der Fail-safe, falls HA den Revert verpasst. Gebaut via Nautobot GC (kein Direkt-Write), erst wenn die Bypass-Sperre scharf geschaltet wird.