Let's Encrypt hat *.lukasrosier.com und lukasrosier.com ausgestellt (issuer YE1, gueltig bis 11.12.2026), per DNS-01 gegen das eigene BIND, ohne fremden API-Token. Delegiert ist nur _acme-challenge, der Apex samt MX, SPF und DKIM bleibt bei Cloudflare. Der Weg dorthin ging ueber drei Fehlerbilder, die alle dieselbe Ursache hatten, und das ist der eigentliche Merkposten: von innerhalb dieses Netzes ist die Propagationsvorpruefung nicht durchfuehrbar. 1. Systemresolver (Mango) liefert die SOA, auf NS-Abfragen aber nichts -- sein Forwarder bedient NS nicht. lego: "could not determine authoritative nameservers". 2. Eigenes unbound: SERVFAIL. Es rekursiert bis zur Delegation, die auf die oeffentliche Mango-Adresse zeigt, und die ist von innen nicht erreichbar, weil die DNAT-Regeln reflection=0 tragen. 3. Fremder Resolver (Quad9) findet die NS korrekt, aber lego fragt den autoritativen Server danach direkt ab -- und landet wieder auf der oeffentlichen Adresse, wo Mangos eigener Forwarder statt unseres BIND antwortet: "did not return the expected TXT record". Also dnsPropagationCheck = false. Das ist keine Nachlaessigkeit: pruefen kann nur Let's Encrypt von aussen, und genau das passiert. Dass die Delegation von aussen traegt, ist unabhaengig belegt -- Quad9 und Google liefern beide NS, SOA und TXT aus unserem BIND. Wieder einschaltbar, sobald am Mango Hairpin fuer Port 53 aktiv ist. Nebenbefund, ebenfalls im Kommentar: der NS einer delegierten Zone muss mit der Delegation im Elternteil uebereinstimmen. Die Challenge-Zone nannte zuerst ns1.lukasrosier.com, das oeffentlich ueber den Wildcard auf blunix' IPv4 auflaest -- kein Nameserver. Jetzt ipv6-test.0ff.space, derselbe Name wie in der Cloudflare-Delegation, dessen AAAA der mango-dns-Timer nachfuehrt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Aw4viUJyXGP8ANocHiF15q
66 lines
3.2 KiB
Nix
66 lines
3.2 KiB
Nix
{ config, ... }:
|
|
{
|
|
# Wildcard-Zertifikat fuer domain2 ueber DNS-01 gegen das *eigene* BIND.
|
|
#
|
|
# Bewusst ueber das NixOS-Modul `security.acme` und nicht ueber Traefiks
|
|
# eigenen certificatesResolver, obwohl blunix es dort so macht:
|
|
#
|
|
# - Der Zustand liegt unter /var/lib/acme pro Zertifikat statt in Traefiks
|
|
# undurchsichtiger acme.json, in der alle Zertifikate zusammen stecken.
|
|
# - Andere Dienste auf diesem Host koennen dasselbe Zertifikat lesen,
|
|
# ohne Traefik zu sein -- Prosody oder ein Mailserver spaeter genauso.
|
|
# - Erneuerungs-Timer, Units und Reload-Hooks kommen vom Modul, das ist
|
|
# der Upstream-Weg statt eigener Mechanik (CLAUDE.md: Upstream-Module
|
|
# gegenueber eigenen Patches bevorzugen).
|
|
#
|
|
# Der TSIG-Schluessel ist dasselbe agenix-Secret, das bind.nix zu BINDs
|
|
# key-Syntax rendert. Es liegt in Environment-Form vor, genau was
|
|
# `environmentFile` erwartet (RFC2136_NAMESERVER, _TSIG_KEY,
|
|
# _TSIG_ALGORITHM, _TSIG_SECRET) -- ein Secret, kein zweites Format.
|
|
security.acme = {
|
|
acceptTerms = true;
|
|
defaults.email = config.adminEmail;
|
|
|
|
certs."${config.domain2}" = {
|
|
domain = config.domain2;
|
|
# Der eigentliche Zweck: HTTP-01 kann keine Wildcards, DNS-01 kann es.
|
|
extraDomainNames = [ "*.${config.domain2}" ];
|
|
|
|
dnsProvider = "rfc2136";
|
|
environmentFile = config.age.secrets.bindAcmeTsig.path;
|
|
|
|
# Aus: die Pruefung ist von diesem Host aus strukturell nicht
|
|
# durchfuehrbar. Am 12.09.2026 in drei Schritten durchgemessen, jeder
|
|
# mit eigenem Fehlerbild:
|
|
#
|
|
# 1. Systemresolver (Mango): liefert die SOA, auf eine NS-Abfrage aber
|
|
# gar nichts -- sein Forwarder bedient NS-Eintraege nicht. lego
|
|
# meldet "could not determine authoritative nameservers".
|
|
# 2. Eigenes unbound: SERVFAIL. Es rekursiert korrekt bis zur
|
|
# Delegation, die auf die *oeffentliche* Adresse des Mango zeigt,
|
|
# und die ist von innen nicht erreichbar -- die DNAT-Regeln tragen
|
|
# `reflection=0`.
|
|
# 3. Fremder Resolver (Quad9): findet die NS korrekt, aber lego fragt
|
|
# den autoritativen Server danach *direkt* ab. Von innen landet das
|
|
# wieder auf der oeffentlichen Mango-Adresse, wo derselbe Hairpin
|
|
# greift und Mangos eigener Forwarder antwortet statt unseres BIND
|
|
# -- "did not return the expected TXT record".
|
|
#
|
|
# Kern: jeder Weg von innen endet an derselben Hairpin-Grenze. Der
|
|
# Verzicht auf die Vorpruefung ist deshalb kein Nachlassen der
|
|
# Sorgfalt, sondern die Anerkennung, dass nur Let's Encrypt selbst von
|
|
# aussen pruefen kann -- und genau das tut es. Dass die Delegation von
|
|
# aussen funktioniert, ist unabhaengig belegt: Quad9 und Googles
|
|
# Resolver liefern beide NS, SOA und TXT aus unserem BIND.
|
|
#
|
|
# Wieder einschaltbar, sobald am Mango Reflection/Hairpin fuer Port 53
|
|
# aktiv ist; dann ist "[2620:fe::fe]:53" als dnsResolver der Weg.
|
|
dnsPropagationCheck = false;
|
|
|
|
# Traefik liest die Dateien aus /var/lib/acme; ueber die Gruppe bekommt
|
|
# es Leserecht, ohne dass die Schluesseldatei weltlesbar wird.
|
|
group = "traefik";
|
|
reloadServices = [ "traefik.service" ];
|
|
};
|
|
};
|
|
}
|