Files
management/hosts/cfgmon.md
T
Thore CimbalandClaude Opus 5 8e98a39447 Backlogs zentral strukturieren
Bisher lag der Backlog als BACKLOG.md in threadnet-operating und damit
in einem Repo, das nur einen Stack auf einem Host beschreibt. Da die
Arbeit inzwischen mehrere Hosts umfasst, hier ein File pro Host plus
shared/ fuer Themen, die sich nicht pro Host trennen lassen.

Uebernommen und auf die Hosts verteilt:
- CFGMON: Cert-Erneuerung inkl. IPv6-Firewall, nicht versionierter
  Portainer-Stack (traefik/gitea/cadvisor), offener Remote-Write-
  Receiver, Grafana-API-Credentials; dazu drei erledigte Punkte von
  heute als Historie
- game: Host von CFGMON aus nicht erreichbar, 2 Targets down
- matrix: Mailversand klaeren, bevor die Zone gehaertet wird
- k3s: pusht auf den offenen Receiver, liegt aber schon im privaten Netz
- shared/zone-axion1337: DNS-Bereinigung und Apex-DMARC-Policy

Konventionen in README.md, Vorlage in TEMPLATE.md. IDs sind pro File
fortlaufend und werden nicht wiederverwendet. Praefix fuer DNS-Themen
ist ZONE-, nicht DNS-, weil DNS-01 der Name eines ACME-Challenge-Typs
ist und hier laufend als Fachbegriff vorkommt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 12:00:00 +00:00

8.9 KiB

CFGMON

Monitoring-Stack, Gitea und der Reverse Proxy für alles Öffentliche.

Hostname CFGMON
OS Ubuntu 24.04.4 LTS
IPv4 188.245.193.243
IPv6 2a01:4f8:c17:93eb::1
Privat 10.0.0.3 (enp7s0, Hetzner-Netz — dort liegt auch k3s auf 10.0.0.2)
DNS rohana.axion1337.de → Gitea, selendis.axion1337.de → Grafana
Stand 2026-07-30

Dienste

Container Image Compose-Projekt Definition
prometheus prom/prometheus:v3.3.1 monitoring sorb/threadnet-operating, monitoring/
loki grafana/loki:3.7.1 monitoring dito
grafana grafana/grafana:12.0.0 monitoring dito
alloy grafana/alloy:v1.16.0 monitoring dito
node-exporter prom/node-exporter:v1.9.1 monitoring dito
traefik traefik:v3.7.9 thread-net-git nicht versioniert, Portainer-Stack in /data/compose/8
gitea gitea/gitea:latest thread-net-git dito
cadvisor gcr.io/cadvisor/cadvisor:latest thread-net-git dito
portainer_agent portainer/agent:2.27.5 standalone, kein Compose

Prometheus-Jobs: operating_prometheus, operating_node-exporter, operating_cadvisor, operating_traefik (alle lokal), k3s_host_node (10.0.0.2:9100), pterodactyl_host_node und gameserver_cadvisor (beide 157.90.155.206, siehe game).


CFGMON-01 — Zertifikatserneuerung braucht offene Ports (IPv4 und IPv6)

Status: offen — zeitkritisch ab 2026-09-28

Das Cert für selendis.axion1337.de wurde am 2026-07-30 ausgestellt und läuft am 2026-10-28 ab. Traefik erneuert ca. 30 Tage vorher, also ab Ende September. Gitea (rohana.axion1337.de) hängt am selben Resolver und ist damit genauso betroffen — inklusive der Erreichbarkeit dieses Repos per HTTPS.

Traefik nutzt TLS-ALPN-01 (--certificatesresolvers.letsencrypt.acme.tlschallenge=true). Die Challenge läuft ausschließlich über Port 443, erreichbar aus dem offenen Internet. Bei gesperrtem Port scheitert sie mit:

urn:ietf:params:acme:error:connection :: Timeout during connect (likely firewall problem)

Traefik liefert dann sein Default-Self-Signed-Cert aus. Das fällt niemandem auf, bis jemand die Seite aufruft — genau so ist es am 2026-07-30 passiert.

Eine IP-Allowlist ist keine Option: Let's Encrypt veröffentlicht seine Validierungs-IPs nicht und prüft seit Einführung der Multi-Perspective Validation aus mehreren Regionen gleichzeitig.

IPv6 ist der Fallstrick. rohana, selendis (und noch www.*, siehe ZONE-01) haben AAAA-Records auf 2a01:4f8:c17:93eb::1. Damit validiert LE bevorzugt über IPv6. Die Hetzner-Cloud-Firewall braucht für 443 deshalb eine Regel mit Quelle ::/00.0.0.0/0 deckt IPv6 nicht mit ab. Fehlt sie, scheitert die Erneuerung, obwohl IPv4 offen ist.

Vom Host aus ist das nicht verifizierbar: eine Verbindung auf die eigene öffentliche Adresse läuft lokal und sagt nichts über den Weg von außen. Das Ausliefern über IPv6 funktioniert (rohana und selendis antworten mit 200, Traefik lauscht auf [::]:443) — das ist aber nicht dasselbe wie von außen erreichbar.

Nächster Schritt: Entscheidung zwischen

  • A — Port 443 zur Erneuerung öffnen, für IPv4 und IPv6. Nichts umbauen, aber alle ~60 Tage daran denken, und das Scheitern fällt nicht auf.
  • B — auf DNS-01 umstellen (empfohlen). Validierung über einen TXT-Record, kein offener Port nötig, läuft bei dichter Firewall durch. Braucht ein API-Token für die Zone bei IONOS, als Secret für Traefik hinterlegt. Ermöglicht zusätzlich Wildcard-Certs (*.axion1337.de), also künftige Subdomains ohne Portöffnung. Setzt voraus, dass der Traefik-Stack anfassbar ist — siehe CFGMON-02.

CFGMON-02 — Traefik, Gitea und cAdvisor sind nicht versioniert

Status: offen

Die drei laufen im Compose-Projekt thread-net-git aus /data/compose/8, einem von Portainer verwalteten Stack. Es gibt kein Repo dazu. Betroffen ist damit ausgerechnet die Infrastruktur, an der alles andere hängt:

  • Traefik — die einzige Stelle, an der Entrypoints, ACME-Resolver und Zertifikatsspeicher definiert sind. Die Resolver-Namen aus dieser Datei sind der Grund, warum ein Label certresolver=le monatelang ins Leere zeigte.
  • Gitea — hostet die Repos, in denen die Infrastruktur beschrieben wird. Das ist ein Bootstrapping-Problem: die Definition von Gitea könnte in Gitea liegen, wäre bei einem Ausfall aber genau dann nicht erreichbar, wenn man sie braucht.
  • cAdvisor — wird von Prometheus als operating_cadvisor gescrapt, ist also eine Abhängigkeit des Monitoring-Stacks, die selbst außerhalb der IaC liegt.

Nächster Schritt: Stack-Definition aus Portainer exportieren (/data/compose/8/docker-compose.yml plus zugehörige Files), in ein Repo überführen und dabei die :latest-Tags pinnen — gitea/gitea:latest und cadvisor:latest machen jeden Pull zu einem unkontrollierten Update. Beim Übertragen denselben Projektnamen thread-net-git beibehalten, sonst legt Compose neue leere Volumes an. Für Gitea zusätzlich klären, wo die Definition liegen soll, damit sie bei einem Gitea-Ausfall erreichbar bleibt.


CFGMON-03 — Prometheus-Remote-Write und Loki sind öffentlich ohne Auth

Status: offen

Prometheus läuft mit --web.enable-remote-write-receiver und Port 9090 ist veröffentlicht, weil der k3s-Cluster und der Matrix-Server dorthin pushen. Loki ist auf 3100 ebenfalls veröffentlicht.

Ein offener Remote-Write-Receiver ohne Auth erlaubt Fremden, beliebige Metriken einzuspeisen — damit lassen sich Dashboards und Alerts unbrauchbar machen — und über die Query-API alle Daten auszulesen. Bei Loki auf 3100 gilt dasselbe für Logs, die typischerweise mehr Interna enthalten als Metriken.

In monitoring/docker-compose.yml steht dazu bereits ein Warnhinweis als Kommentar, umgesetzt ist er nicht.

Nächster Schritt: Beide Ports per Hetzner-Cloud-Firewall auf die Absender einschränken. Sauberer wäre, sie gar nicht öffentlich zu binden: k3s liegt mit 10.0.0.2 im selben privaten Netz wie CFGMON (10.0.0.3), der Push könnte also über das private Netz laufen. Für den Matrix-Server auf 49.13.132.245 prüfen, ob er in dasselbe Netz aufgenommen werden kann — siehe matrix.


CFGMON-04 — Grafana-Admin-Credentials aus .env gelten nicht für die HTTP-API

Status: offen, geringe Priorität

GF_SECURITY_ADMIN_USER und GF_SECURITY_ADMIN_PASSWORD greifen nur beim allerersten Start mit leerem Volume. Der Live-Admin wurde offenbar später in der UI geändert, die Werte aus der .env sind damit funktionslos. Verifikation von Datasources und Dashboards läuft deshalb über grafana.db statt über die API.

Kein Defekt, aber eine Falle: die .env sieht aus, als wäre sie die Quelle der Wahrheit, ist es aber nicht.

Nächster Schritt: entweder das echte Admin-Passwort in die .env nachziehen und dokumentieren, dass es nur den Ersteinrichtungsfall abdeckt, oder einen Service-Account mit API-Token für Verifikationszwecke anlegen. Letzteres ist sauberer, weil dafür kein Admin-Passwort nötig ist.


Erledigt

CFGMON-05 — Monitoring-Stack unter IaC bringen · erledigt 2026-07-30

Der Stack lief aus /opt/monitoring ohne Versionierung und mit :latest-Tags. Jetzt in sorb/threadnet-operating unter monitoring/, Images gepinnt, Grafana-Datasources und 9 Dashboards provisioniert. Projektname monitoring beibehalten, dadurch blieben die Volumes erhalten.

CFGMON-06 — Grafana-Certresolver zeigte ins Leere · erledigt 2026-07-30

Das Label sagte certresolver=le, Traefik kennt den Resolver aber als letsencrypt. Traefik protokollierte Router uses a nonexistent certificate resolver und lieferte für selendis.axion1337.de sein Default-Self-Signed-Cert aus. Aus dem Altbestand in /opt/monitoring unverändert übernommen und dort mindestens seit dem 2026-07-27 vorhanden.

Behoben in threadnet-operating, Commit a400f8a. Cert von Let's Encrypt (YR2) ausgestellt, gültig bis 2026-10-28 — die Nachfolge davon ist CFGMON-01.

CFGMON-07 — Alloy verlor seine Positions-Datei bei jedem Deploy · erledigt 2026-07-30

--storage.path=/var/lib/alloy/data war gesetzt, aber ohne Volume: die Positions-Datei lag im Container-Layer. Nach jedem Recreate las Alloy alle Docker-Logdateien von vorn, worauf Loki alles älter als 7 Tage mit HTTP 400 abwies (timestamp too old, reject_old_samples). Betroffen waren nur Alt-Logzeilen bis zurück zu 2025, keine aktuellen Daten.

Behoben durch ein alloy_data-Volume, Commit edac97e. Verifiziert: Positions überleben --force-recreate, zweiter Recreate erzeugt 0 Fehler.