3.8 KiB
Hetzner-DNS: die alte API ist abgeschaltet
Gemessen am 31. Juli 2026, am Live-Server und von außen.
https://dns.hetzner.com/api/v1/zones → 301 → https://console.hetzner.com/ (HTML)
https://api.hetzner.cloud/v1/zones → 401 ohne Token, 200 mit dem Token des Betreibers
Hetzner hat die DNS-Verwaltung am 7. Oktober 2025 in die Cloud-Konsole verlegt. Die alte DNS-Konsole ging am 20. Mai 2026 in den Nur-Lese-Betrieb; seither leitet der alte Endpunkt auf die Weboberfläche um. Alte Token und Zonen-IDs sind mit der neuen Konsole nicht kompatibel und wurden nicht übernommen.
Was dadurch kaputt ist
App\Services\Dns\DnsTokenCheck— meldetzone_not_found, obwohl Token und Zone in Ordnung sind. Seit v1.3.77 meldet es immerhin ehrlichzone_list_unreadablemit dem Anfang der HTML-Antwort.App\Services\Dns\HttpHetznerDnsClient— das ist das Teure. Er legt den A-Eintrag jeder Kundeninstanz an. Solange er auf den alten Endpunkt zeigt, stirbt jede Bereitstellung inConfigureDnsAndTls— nachdem der Kunde bezahlt hat. Genau der Satz steht als Begründung auf der Bereitschaftsseite.- Der Token des Betreibers ist bereits ein Cloud-Token und antwortet mit 200. Es fehlt nur der Code.
Die neue Schnittstelle
Aus https://docs.hetzner.cloud/cloud.spec.json gezogen, nicht geraten.
Anmeldung: Authorization: Bearer <token> — nicht mehr Auth-API-Token.
Basis: https://api.hetzner.cloud/v1
| Zweck | Aufruf |
|---|---|
| Zonen auflisten | GET /zones → {"zones":[{id,name,…}], "meta":{…}} |
| Eine Zone direkt | GET /zones/{id_or_name} — der Name geht direkt, kein Suchen mehr |
| Eintragssatz anlegen | POST /zones/{zone}/rrsets |
| Eintragssatz ersetzen | POST /zones/{zone}/rrsets/{name}/{type}/actions/set_records |
| Eintragssatz löschen | DELETE /zones/{zone}/rrsets/{name}/{type} |
Das Modell hat sich geändert: keine einzelnen Records mehr, sondern
RRSets, adressiert über {name}/{typ}. Ein RRSet trägt mehrere Werte.
set_records ersetzt den ganzen Satz — damit wird das Schreiben idempotent, was
der alte Client mit Suchen-und-Aktualisieren nachbauen musste.
Rumpf beim Anlegen, Pflichtfelder name, type, records:
{ "name": "kunde", "type": "A", "ttl": 60,
"records": [{"value": "203.0.113.10"}] }
Zwei Fallen im name:
- Er darf nicht auf den Zonennamen enden.
kunde, nichtkunde.clupilot.cloud— der alte Client hat den vollen Namen geschickt. - Für die Zonenwurzel ist es
@, und er muss klein geschrieben sein.
PUT /zones/{zone}/rrsets/{name}/{type} ist nicht das Schreiben der Werte —
es setzt nur labels. Wer dort die Records erwartet, schreibt ins Leere.
Was zu tun ist
HttpHetznerDnsClientauf Basis, Kopfzeile und RRSets umstellen. Der Zonen-Lookup entfällt: der Name geht direkt in den Pfad.DnsTokenCheckdito. Die Schreibprobe bleibt der Kern der Prüfung — ein lesender Token sieht sonst genauso aus wie ein schreibender, und der Unterschied fällt erst auf, wenn ein Kunde bezahlt hat.FakeHetznerDnsClientund die Tests nachziehen.- Den Namen ohne Zonensuffix bilden — Falle 1 oben. Ein Test, der genau das
festhält, ist billiger als der erste Kunde, dessen Adresse
kunde.clupilot.cloud.clupilot.cloudheißt.
Wieso das so lange gesucht wurde
Die Prüfung stufte nur 401 und 403 als abgelehnt ein und las danach den Rumpf.
Jede andere Antwort — hier eine 301 auf eine HTML-Seite — hatte kein zones,
und ?? [] machte daraus „keine Zone in diesem Konto". Eine Aussage über ein
fremdes Hetzner-Konto, hergeleitet aus einer Antwort, die niemand angesehen hat.
v1.3.76 und v1.3.77 haben das behoben; die Meldung zeigt jetzt Status und die
ersten Zeichen der Antwort. Ohne diese zwei Schritte wäre die Ursache weiter im
Dunkeln.