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>
This commit is contained in:
Thore Cimbal
2026-07-30 12:00:00 +00:00
co-authored by Claude Opus 5
commit 8e98a39447
8 changed files with 687 additions and 0 deletions
+6
View File
@@ -0,0 +1,6 @@
# Nichts Betriebliches hier ablegen -- dieses Repo enthaelt nur Text.
*.env
.env
*.token
*.key
*.pem
+72
View File
@@ -0,0 +1,72 @@
# Backlogs
Zentrale Sammlung offener Punkte über alle Hosts und Dienste hinweg. Ein Eintrag
landet hier, wenn er bewusst nicht sofort erledigt wurde — damit er nicht in einer
Chat-Historie oder einem Kopf verschwindet.
## Aufbau
```
hosts/ ein File pro Host, benannt nach dem Hostnamen
shared/ Themen, die mehrere Hosts betreffen (DNS-Zone, Mail-Policy)
TEMPLATE.md Vorlage für einen neuen Host
```
Faustregel für die Einordnung: **Der Eintrag gehört dorthin, wo die Arbeit
stattfindet, nicht dorthin, wo das Symptom auftritt.** Ein down-Target in Prometheus
auf CFGMON, dessen Ursache ein blockierter Port auf dem Gameserver ist, gehört nach
`hosts/game.md` — mit Querverweis von CFGMON.
## Hosts
| Host | Adressen | Rolle | Backlog |
|---|---|---|---|
| **CFGMON** | `188.245.193.243`, `2a01:4f8:c17:93eb::1`, privat `10.0.0.3` | Monitoring-Stack, Gitea, Traefik | [hosts/cfgmon.md](hosts/cfgmon.md) |
| **game** | `157.90.155.206` (`game.axion1337.de`) | Pterodactyl / Gameserver | [hosts/game.md](hosts/game.md) |
| **matrix** | `49.13.132.245` (`matrix.axion1337.de`) | Matrix-Homeserver | [hosts/matrix.md](hosts/matrix.md) |
| **k3s** | privat `10.0.0.2` | k3s-Cluster | [hosts/k3s.md](hosts/k3s.md) |
## Übergreifend
| Thema | Backlog |
|---|---|
| DNS-Zone `axion1337.de` und Mail-Policy (IONOS) | [shared/zone-axion1337.md](shared/zone-axion1337.md) |
## Konventionen
**IDs** sind pro Datei fortlaufend mit einem Präfix, das den Ort benennt:
`CFGMON-01`, `GAME-01`, `MATRIX-01`, `K3S-01`, `ZONE-01`. IDs werden **nicht
wiederverwendet** — ein erledigter Punkt behält seine Nummer, damit Querverweise und
Commit-Messages dauerhaft stimmen.
Das Präfix für DNS-Themen ist bewusst `ZONE-` und nicht `DNS-`: `DNS-01` ist der
Name eines ACME-Challenge-Typs und käme in genau diesen Backlogs ständig als
Fachbegriff vor.
**Status:**
| Wert | Bedeutung |
|---|---|
| `offen` | noch nicht angefasst |
| `in Arbeit` | läuft gerade |
| `wartet auf …` | blockiert, mit Angabe worauf |
| `erledigt` | fertig, mit Datum — Eintrag bleibt stehen, siehe unten |
Erledigte Punkte werden **nicht gelöscht**, sondern auf `erledigt` gesetzt und nach
unten in den Abschnitt „Erledigt" verschoben. Der Grund: bei mehreren Hosts ist die
Frage „haben wir das damals eigentlich gemacht, und warum so?" häufiger als die
Frage „was ist noch offen".
**Jeder Eintrag braucht** einen Status, eine Beschreibung des tatsächlichen
Zustands, und einen konkreten nächsten Schritt. Wenn eine Aussage nicht verifiziert
ist, wird das dazugeschrieben — eine unbestätigte Vermutung, die wie ein Befund
aussieht, kostet beim nächsten Mal mehr Zeit als sie spart.
**Zeitkritisches** bekommt ein Datum in der Statuszeile, nicht nur „bald".
## Verhältnis zu den Projekt-Repos
Dieses Repo hält die offenen Punkte. Die **Konfiguration** liegt weiter in den
jeweiligen Projekt-Repos, z. B. `sorb/threadnet-operating` für den
Monitoring-Stack auf CFGMON. Damit nichts doppelt geführt wird, verweisen die
Projekt-Repos hierher statt eigene Backlog-Dateien zu pflegen.
+58
View File
@@ -0,0 +1,58 @@
# <hostname>
<Ein Satz: welche Rolle hat der Host.>
| | |
|---|---|
| **Hostname** | |
| **OS** | |
| **IPv4** | |
| **IPv6** | |
| **Privat** | |
| **DNS** | |
| **Stand** | JJJJ-MM-TT |
> Solange der Host nicht direkt inventarisiert wurde: diesen Hinweis stehen lassen
> und dazuschreiben, woher die Angaben stammen. Eine unbestätigte Vermutung, die wie
> ein Befund aussieht, kostet beim nächsten Mal mehr Zeit als sie spart.
## Dienste
| Container / Dienst | Version | Compose-Projekt | Definition |
|---|---|---|---|
| | | | |
Wichtig in der Spalte „Definition": ob die Konfiguration versioniert ist und wo. Ein
Dienst, der nur in einer Portainer- oder händischen Installation existiert, gehört als
eigener Backlog-Eintrag erfasst.
---
## <PRÄFIX>-01 — <Kurztitel, benennt das Problem, nicht die Lösung>
**Status:** offen | in Arbeit | wartet auf … | erledigt JJJJ-MM-TT
<Was ist der tatsächliche Zustand. Was wurde davon verifiziert und wie — was ist
Vermutung. Wenn es ein Symptom gibt: was sagt es, und was sagt es nicht.>
<Warum ist es ein Problem. Bei nicht offensichtlichen Fällen: welcher Schaden
entsteht, wenn es so bleibt.>
**Nächster Schritt:** <Konkret genug, dass jemand ohne den Kontext dieses Gesprächs
anfangen kann. Bei mehreren Optionen die Empfehlung benennen und begründen, statt
alle gleichwertig aufzulisten.>
<Bei Abhängigkeiten: Querverweis auf den blockierenden Eintrag, und wenn die
Reihenfolge wichtig ist, warum.>
---
## Erledigt
### <PRÄFIX>-NN — <Kurztitel> · erledigt JJJJ-MM-TT
<Was war das Problem, was war die Ursache, wie wurde es behoben, womit ist es
verifiziert. Commit-Hash oder Repo-Pfad, wenn es einen gibt.>
<Erledigte Einträge behalten ihre ID und werden nicht gelöscht: „haben wir das damals
gemacht, und warum so?" ist die häufigere Frage als „was ist noch offen".>
+187
View File
@@ -0,0 +1,187 @@
# 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](game.md)).
---
## 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](../shared/zone-axion1337.md)) 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 `::/0`
`0.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).
---
## 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](matrix.md).
---
## 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-01--zertifikatserneuerung-braucht-offene-ports-ipv4-und-ipv6).
### 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.
+74
View File
@@ -0,0 +1,74 @@
# game
Pterodactyl- / Gameserver-Host.
| | |
|---|---|
| **IPv4** | `157.90.155.206` |
| **IPv6** | kein AAAA-Record |
| **DNS** | `game.axion1337.de` |
| **Privat** | unbekannt — siehe GAME-01 |
| **Stand** | 2026-07-30 |
> **Nicht inventarisiert.** Alle Angaben hier stammen aus Beobachtungen von CFGMON
> aus. Auf dem Host selbst wurde nichts geprüft. Beim ersten direkten Zugriff
> sollten OS, Dienste und Compose-Projekte hier nachgetragen werden.
---
## GAME-01 — Host von CFGMON aus nicht erreichbar, 2 Prometheus-Targets down
**Status:** offen — Ursache liegt auf diesem Host oder in dessen Firewall
Zwei Scrape-Targets sind down. Das bestand **schon vor** dem Monitoring-Rework vom
2026-07-30, ist also kein Regressionsschaden aus der Umstellung.
| Job | Target | Fehler |
|---|---|---|
| `gameserver_cadvisor` | `157.90.155.206:8080` | `context deadline exceeded` |
| `pterodactyl_host_node` | `157.90.155.206:9100` | `context deadline exceeded` |
Von CFGMON aus geprüft: der Host antwortet **nicht auf Ping** (100 % packet loss) und
auf keinem der beiden Ports. Das Problem ist also nicht die Prometheus-Konfiguration,
sondern die Erreichbarkeit. Mögliche Ursachen, von wahrscheinlich nach unwahrscheinlich:
1. Die Hetzner-Cloud-Firewall dieses Hosts lässt `188.245.193.243` nicht auf
8080/9100 — passend zum restriktiven Firewall-Setup der Umgebung.
2. cAdvisor und node-exporter laufen nicht (mehr) oder binden nur auf `127.0.0.1`.
3. Der Host ist abgeschaltet oder umgezogen und die IP ist veraltet. Dagegen spricht,
dass `game.axion1337.de` weiter auf sie zeigt.
**Nächster Schritt:** auf dem Host prüfen, ob die beiden Exporter laufen und worauf
sie binden, dann die Firewall entsprechend öffnen.
**Empfehlung: nicht über die öffentliche IP.** CFGMON scrapt den k3s-Host bereits
über das private Netz (`10.0.0.2:9100`) und der ist up — das ist das Modell, das
hier funktioniert. Wenn dieser Host in denselben Hetzner-vSwitch aufgenommen wird
(CFGMON hat `10.0.0.3`), braucht es für das Monitoring **gar keine im Internet
offenen Ports**. Zwei Exporter öffentlich erreichbar zu machen wäre der schlechtere
Weg: node-exporter gibt detaillierte Host-Interna preis, cAdvisor die komplette
Container-Landschaft.
Danach in `threadnet-operating` die Targets in `monitoring/prometheus/prometheus.yml`
von der rohen IP auf die private Adresse bzw. den DNS-Namen umstellen — aktuell
stehen dort öffentliche IPs, obwohl mit `game.axion1337.de` ein Name existiert.
**Solange offen:** die beiden Targets in Grafana als *known down* behandeln, damit
sie kein Dauer-Alerting erzeugen.
---
## GAME-02 — `www.game.axion1337.de` ist überflüssig
**Status:** offen, geringe Priorität
Es existiert ein A-Record `www.game.axion1337.de``157.90.155.206`, angelegt nach
IONOS-Default-Muster. Bei einer Subdomain ist ein `www.`-Präfix überflüssig, siehe
die Begründung in [ZONE-01](../shared/zone-axion1337.md).
**Nicht verifiziert**, ob auf diesem Host etwas auf den Namen hört — von CFGMON aus
ist er nicht erreichbar. Bei `rohana` und `selendis` liefert das äquivalente
Konstrukt einen Zertifikatsfehler.
**Nächster Schritt:** prüfen, ob der Name irgendwo verlinkt oder konfiguriert ist,
sonst A-Record löschen.
+46
View File
@@ -0,0 +1,46 @@
# k3s
k3s-Cluster.
| | |
|---|---|
| **Privat** | `10.0.0.2` (Hetzner-Netz, zusammen mit CFGMON auf `10.0.0.3`) |
| **Öffentlich** | unbekannt — kein DNS-Name zugeordnet |
| **Stand** | 2026-07-30 |
> **Nicht inventarisiert.** Bekannt ist nur, was von CFGMON aus sichtbar ist: die
> private Adresse, ein laufender node-exporter auf `9100`, und dass der Cluster per
> Remote-Write an Prometheus pusht. Beim ersten direkten Zugriff Distribution,
> k3s-Version, Nodes und Workloads hier nachtragen. Möglicherweise zugehörig:
> `sorb/axion1337.chat-gitops`.
**Bemerkenswert:** Dieser Host ist der einzige, der von CFGMON aus **über das private
Netz** gescrapt wird (`k3s_host_node``10.0.0.2:9100`) — und der einzige
Remote-Host, dessen Target `up` ist. Das ist das Modell, das für
[game](game.md#game-01--host-von-cfgmon-aus-nicht-erreichbar-2-prometheus-targets-down)
und [matrix](matrix.md#matrix-02--pusht-per-remote-write-auf-einen-offenen-prometheus)
angestrebt werden sollte.
---
## K3S-01 — Pusht per Remote-Write auf einen offenen Prometheus
**Status:** offen — Gegenstück zu [CFGMON-03](cfgmon.md#cfgmon-03--prometheus-remote-write-und-loki-sind-öffentlich-ohne-auth)
Der Cluster schreibt Metriken per Remote-Write an Prometheus auf CFGMON. Der Receiver
dort ist auf `188.245.193.243:9090` öffentlich und **ohne Authentifizierung**
erreichbar — jeder im Internet kann dort beliebige Metriken einspeisen und alle Daten
auslesen.
Anders als bei [matrix](matrix.md) ist die Lösung hier ohne Vorbedingungen
erreichbar: der Cluster liegt mit `10.0.0.2` **schon** im privaten Netz mit CFGMON
(`10.0.0.3`), das Scraping in die Gegenrichtung läuft bereits darüber.
**Nächster Schritt:** die Remote-Write-URL in der Cluster-Konfiguration von der
öffentlichen Adresse auf `10.0.0.3:9090` umstellen. Wenn danach kein Absender mehr
über die öffentliche Adresse pusht — Matrix ist der verbleibende, siehe
[MATRIX-02](matrix.md#matrix-02--pusht-per-remote-write-auf-einen-offenen-prometheus)
— kann Port 9090 auf CFGMON zugemacht werden.
Reihenfolge beachten: erst umstellen und verifizieren, dass Metriken weiter ankommen,
dann die Firewall zuziehen. Andernfalls fehlen Daten, ohne dass es auffällt.
+83
View File
@@ -0,0 +1,83 @@
# matrix
Matrix-Homeserver.
| | |
|---|---|
| **IPv4** | `49.13.132.245` |
| **IPv6** | kein AAAA-Record |
| **DNS** | `matrix.axion1337.de` |
| **Stand** | 2026-07-30 |
> **Nicht inventarisiert.** Alle Angaben stammen aus DNS-Abfragen und der
> Prometheus-Konfiguration auf CFGMON. Auf dem Host selbst wurde nichts geprüft.
> Beim ersten direkten Zugriff OS, Dienste und Compose-Projekte hier nachtragen.
> Verwandte Repos, noch nicht zugeordnet: `sorb/axion1337.chat-gitops`,
> `sorb/element-web`, `sorb/ThreadNet-Stack`.
---
## MATRIX-01 — Klären, ob der Server Mail als `@matrix.axion1337.de` verschickt
**Status:** offen — **blockiert die Mail-Härtung der Zone**
Für `matrix.axion1337.de` existiert der komplette IONOS-Mail-Satz: `MX mx00/mx01`,
`TXT "v=spf1 include:_spf-eu.ionos.com ~all"`, `CNAME s1-ionos._domainkey` und
`CNAME autodiscover`. Bei `selendis` ist dasselbe Muster reine Altlast aus dem
Anlegen der Subdomain und wird entfernt.
**Hier nicht ungeprüft übernehmen.** Matrix-Homeserver verschicken typischerweise
Mail für Registrierungsbestätigungen, Passwort-Resets und Benachrichtigungen. Wenn
der Absender `…@matrix.axion1337.de` lautet, sind SPF und DKIM auf diesem Namen
**funktional nötig** — sie zu löschen oder auf `-all` zu setzen würde den Mailversand
zerlegen, und zwar auf eine Weise, die erst auffällt, wenn sich jemand nicht
registrieren kann.
**Nächster Schritt:** in der SMTP-Konfiguration des Homeservers den `From:`-Absender
nachsehen (bei Synapse: `email.notif_from` in der `homeserver.yaml`). Dann:
- **Absender lautet auf `matrix.axion1337.de`:** SPF und DKIM behalten und prüfen,
ob sie den tatsächlichen versendenden Host abdecken. Läuft der Versand nicht über
IONOS, ist das aktuelle `include:_spf-eu.ionos.com` falsch und der echte Relay
muss aufgenommen werden.
- **Absender lautet anders** (z. B. auf den Apex): Härtung wie bei `selendis`
Null-MX, `v=spf1 -all`, `_dmarc` mit `p=reject`.
In beiden Fällen kann `autodiscover.matrix` weg: das ist ein Exchange-/Outlook-
Mechanismus, für Matrix-Föderation irrelevant — die läuft über `.well-known` bzw.
SRV-Records.
Dieser Punkt blockiert außerdem `sp=reject` am Apex, siehe
[ZONE-02](../shared/zone-axion1337.md).
---
## MATRIX-02 — Pusht per Remote-Write auf einen offenen Prometheus
**Status:** offen — Gegenstück zu [CFGMON-03](cfgmon.md#cfgmon-03--prometheus-remote-write-und-loki-sind-öffentlich-ohne-auth)
Dieser Host schreibt Metriken per Remote-Write an Prometheus auf CFGMON. Der
Receiver dort ist auf `188.245.193.243:9090` öffentlich und **ohne
Authentifizierung** erreichbar.
**Nächster Schritt:** prüfen, ob dieser Host in das private Hetzner-Netz aufgenommen
werden kann, in dem CFGMON (`10.0.0.3`) und der k3s-Host (`10.0.0.2`) liegen. Dann
kann der Push über die private Adresse laufen und Port 9090 muss nicht mehr
öffentlich offen sein. Falls nicht möglich: Firewall-Regel auf CFGMON, die 9090 auf
`49.13.132.245` und die k3s-Absender einschränkt.
Wichtig bei der Umstellung: die Remote-Write-URL liegt in der Konfiguration **dieses**
Hosts, die Firewall-Regel auf CFGMON. Beides muss zusammen geändert werden, sonst
brechen die Metriken ab.
---
## MATRIX-03 — `www.matrix.axion1337.de` ist überflüssig
**Status:** offen, geringe Priorität
A-Record `www.matrix.axion1337.de``49.13.132.245`, nach IONOS-Default-Muster
angelegt. Begründung siehe [ZONE-01](../shared/zone-axion1337.md). **Nicht
verifiziert**, ob auf dem Host etwas auf den Namen hört.
**Nächster Schritt:** prüfen und sonst löschen.
+161
View File
@@ -0,0 +1,161 @@
# DNS-Zone `axion1337.de` und Mail-Policy
Übergreifend, weil die Zone alle Hosts abdeckt und die Mail-Policy sich nicht pro
Host trennen lässt.
| | |
|---|---|
| **Registrar / DNS** | IONOS (`ns1098.ui-dns.biz`, `ns1022.ui-dns.com`, `ns1070.ui-dns.org`, `ns1059.ui-dns.de`) |
| **Apex** | `217.160.0.140` / `2001:8d8:100f:f000::2e9` — IONOS-Hosting, nicht eigene Infrastruktur |
| **Mail** | IONOS (`mx00.ionos.de`, `mx01.ionos.de`) |
| **Stand** | 2026-07-30 |
> **Die Aufstellung ist nicht garantiert vollständig.** Zonentransfer ist verweigert,
> DNS erlaubt kein Enumerieren. Die Records unten stammen aus gezielten Abfragen und
> der IONOS-Oberfläche. Für eine vollständige Prüfung entweder die ungefilterte
> IONOS-Liste durchgehen oder die Certificate-Transparency-Logs abfragen (zeigt alle
> Namen, für die je ein Cert ausgestellt wurde).
## Bekannter Bestand
| Name | A | AAAA | Ziel |
|---|---|---|---|
| `axion1337.de` | `217.160.0.140` | `2001:8d8:100f:f000::2e9` | IONOS-Hosting |
| `www` | `217.160.0.140` | dito | IONOS-Hosting — hier ist `www` **legitim** |
| `rohana` | `188.245.193.243` | `2a01:4f8:c17:93eb::1` | CFGMON, Gitea |
| `selendis` | `188.245.193.243` | `2a01:4f8:c17:93eb::1` | CFGMON, Grafana |
| `game` | `157.90.155.206` | — | Pterodactyl |
| `matrix` | `49.13.132.245` | — | Matrix-Homeserver |
| `ftp` | `217.160.233.227` | `2001:8d8:1000:30f5:…` | IONOS-Default |
| `www.rohana`, `www.selendis`, `www.game`, `www.matrix` | wie ohne `www` | teils | überflüssig, siehe ZONE-01 |
Mail-Records existieren auf `selendis` und `matrix` (MX ×2, SPF, DKIM-CNAMEs,
`autodiscover`), auf `rohana` und `game` nicht.
---
## ZONE-01 — IONOS-Default-Records bereinigen
**Status:** `rohana` und `selendis` in Arbeit (User setzt direkt um, 2026-07-30);
`game`, `matrix`, `ftp` offen
IONOS legt beim Anlegen einer Subdomain automatisch einen kompletten Mail-Satz mit an
— MX, SPF, DKIM-CNAMEs, `autodiscover` — und ein `www.`-Paar. Auch für Hosts, auf
denen nie Mail läuft.
### Warum `www.` bei einer Subdomain überflüssig ist
Das Muster stammt aus der Zeit, als der Webserver einer Domain der Host `www` war,
und hält sich für **Apex-Domains**: `axion1337.de` und `www.axion1337.de` sollen
dasselbe liefern, weil Leute beides tippen. Beim Apex ist das also richtig und bleibt.
Auf eine Subdomain überträgt es sich nicht. `rohana.axion1337.de` **ist** schon der
Hostname des Dienstes; `www.rohana.axion1337.de` heißt wörtlich „der Webserver des
Webservers". Das tippt und verlinkt niemand.
Verifiziert für `www.rohana` und `www.selendis`: kein Traefik-Router matcht die Namen,
Traefik liefert sein `TRAEFIK DEFAULT CERT` aus, TLS bricht mit Zertifikatsfehler ab.
Die Namen funktionieren also ohnehin nicht — wer dort landet, sieht etwas Kaputtes.
Sie zum Funktionieren zu bringen hieße Router plus Cert-SAN, also mehr Teile, die bei
jeder Erneuerung mitvalidieren müssen, für null Nutzen.
### Warum die Mail-Records nicht ersatzlos gelöscht werden
Zwei Fallstricke, die Löschen zur schlechteren Variante machen:
- Ohne SPF existiert **keine Aussage** darüber, wer als dieser Name senden darf. Das
bestehende `~all` ist nur Softfail und wird von vielen Empfängern akzeptiert — eine
ungenutzte Subdomain mit gültigen MX und Softfail-SPF ist ein brauchbarer
Spoofing-Vektor.
- **Fehlt ein MX-Record, weichen Absender per RFC 5321 auf A/AAAA aus.** Mail an
`@rohana.axion1337.de` würde also Port 25 auf `188.245.193.243` ansprechen.
Richtig ist, „hier gibt es keine Mail" explizit zu erklären: Null-MX (RFC 7505), SPF
`-all`, DMARC `p=reject`.
### rohana.axion1337.de
**Löschen:** `A www.rohana`, `AAAA www.rohana`
**Anlegen:**
| Typ | Name | Wert |
|---|---|---|
| MX | `rohana` | `.` (Priorität 0) |
| TXT | `rohana` | `v=spf1 -all` |
| TXT | `_dmarc.rohana` | `v=DMARC1; p=reject;` |
**Nicht anfassen:** `A rohana`, `AAAA rohana` — daran hängen Gitea und das Zertifikat.
### selendis.axion1337.de
**Löschen:** `MX mx00.ionos.de`, `MX mx01.ionos.de`,
`CNAME s1-ionos._domainkey.selendis`, `CNAME s2-ionos._domainkey.selendis`,
`CNAME s42582890._domainkey.selendis`, `CNAME autodiscover.selendis`,
`A www.selendis`, `AAAA www.selendis`
**Ändern** — den bestehenden TXT editieren, **nicht** einen zweiten anlegen: zwei
SPF-Records auf einem Namen ergeben einen PermError, die Prüfung fällt dann komplett
aus.
| Typ | Name | von | auf |
|---|---|---|---|
| TXT | `selendis` | `v=spf1 include:_spf-eu.ionos.com ~all` | `v=spf1 -all` |
**Anlegen:** `MX selendis` = `.` (Priorität 0), `TXT _dmarc.selendis` =
`v=DMARC1; p=reject;`
**Nicht anfassen:** `A selendis`, `AAAA selendis`.
**Vorab prüfen:** ob im IONOS-Mail-Bereich ein Postfach oder eine Weiterleitung für
`selendis.axion1337.de` existiert. Wenn ja, entfallen die MX-Änderungen.
**Falls IONOS `.` als MX-Ziel ablehnt** — kommt vor: MX löschen und nur die
TXT-Records setzen. `-all` und `p=reject;` greifen trotzdem, es fehlt nur die
explizite „nimmt keine Mail an"-Aussage.
### Noch offen
- **`game`** und **`matrix`**: `www.`-Records, siehe
[GAME-02](../hosts/game.md#game-02--wwwgameaxion1337de-ist-überflüssig) und
[MATRIX-03](../hosts/matrix.md#matrix-03--wwwmatrixaxion1337de-ist-überflüssig).
- **Mail-Records auf `matrix`**: **erst** [MATRIX-01](../hosts/matrix.md) klären. Wenn
der Homeserver Mail als `@matrix.axion1337.de` verschickt, sind SPF und DKIM dort
funktional nötig.
- **`ftp.axion1337.de`** → `217.160.233.227`: IONOS-Default aus dem Hosting-Paket,
zeigt auf IONOS und nicht auf eigene Infrastruktur — also keine zusätzliche
Angriffsfläche, aber Ballast. Löschen, falls dort kein FTP genutzt wird.
**Nach der Umsetzung von hier aus verifizieren:** dass `www.rohana` und
`www.selendis` nicht mehr auflösen; dass MX, SPF und DMARC greifen und **nur ein**
SPF-Record pro Name existiert; und dass `A`/`AAAA` von `rohana` und `selendis`
unverändert sind und Gitea sowie Grafana weiter über HTTPS antworten. Der letzte
Punkt ist der, bei dem ein Verklicker in der IONOS-Oberfläche wehtun würde.
---
## ZONE-02 — Apex-DMARC ist `p=none` und schützt nichts
**Status:** offen — **blockiert durch [MATRIX-01](../hosts/matrix.md)**
`_dmarc.axion1337.de` enthält `v=DMARC1; p=none;` (via `dmarc.ionos.de`). Das ist
reines Monitoring: Empfänger melden Verstöße, verwerfen aber nichts. Für gefälschte
Mail in deinem Namen ist das kein Hindernis.
Zusätzlich fehlt eine `sp=`-Angabe. Ohne sie **erben alle Subdomains dieses
`p=none`** — auch solche, die nie Mail senden, und auch künftige.
`sp=reject` am Apex wäre daher der effiziente Hebel: deckt alle Subdomains auf einmal
ab, inklusive der noch nicht angelegten, und macht die einzelnen `_dmarc`-Records aus
ZONE-01 auf Dauer entbehrlich.
**Reihenfolge ist hier wichtig.** Zuerst [MATRIX-01](../hosts/matrix.md) klären, dann
für jeden Namen, der tatsächlich Mail versendet, SPF und DKIM korrekt setzen — erst
danach `sp=reject`. Umgekehrt zerlegt es den Mailversand der betroffenen Dienste, und
zwar unbemerkt, weil verworfene Mail beim Absender keinen Fehler produziert.
Für den Apex selbst (dort läuft echte Mail über IONOS) wäre der übliche Weg, `p=none`
erst auf `p=quarantine` zu ziehen, die DMARC-Reports eine Weile zu beobachten und dann
auf `p=reject` zu gehen. Auffällig: unter `s1._domainkey.axion1337.de` war kein
DKIM-Record auffindbar, obwohl die Subdomains DKIM-CNAMEs von IONOS haben — das wäre
beim Härten mitzuprüfen.