Skriptgesteuerter Zugriff für Let's Encrypt DNS-01, certbot, acme.sh, eigene Automatisierung.
Alle Endpunkte erwarten einen API-Token. Token werden im Kundenportal → Profil → API-Token erstellt.
hm_<16 Zeichen>_<32 Zeichen>Beide Header-Varianten sind gleichwertig:
# Variante A — eigener Header
curl -H "X-API-Token: hm_xxx_yyy" http://127.0.0.1:8899/api/v1/dns/records?name=test.example.com
# Variante B — Standard-Bearer
curl -H "Authorization: Bearer hm_xxx_yyy" http://127.0.0.1:8899/api/v1/dns/records?name=test.example.com| Scope | Bedeutung |
|---|---|
| dns:read | DNS-Records lesen |
| dns:write | Anlegen, Ändern, Löschen (TXT, A, AAAA, CNAME, MX, SRV, CAA, TLSA, SSHFP) |
Für certbot / acme.sh: dns:write reicht.
Basis-URL: http://127.0.0.1:8899/api
curl -X POST "http://127.0.0.1:8899/api/v1/dns/acme-challenge" \
-H "X-API-Token: hm_xxx_yyy" \
-H "Content-Type: application/json" \
-d '{
"domain": "irc.example.com",
"value": "AbCdEf...",
"ttl": 60
}'Legt automatisch _acme-challenge.irc.example.com TXT "AbCdEf..." an.
{
"success": true,
"name": "_acme-challenge.irc.example.com",
"value": "AbCdEf...",
"zone": "example.com",
"ttl": 60
}curl -X DELETE "http://127.0.0.1:8899/api/v1/dns/acme-challenge" \
-H "X-API-Token: hm_xxx_yyy" \
-H "Content-Type: application/json" \
-d '{
"domain": "irc.example.com",
"value": "AbCdEf..."
}'Ohne value: gesamtes rrset wird gelöscht. Bei paralleler Issuance immer den konkreten value mitgeben.
Funktioniert für TXT, A, AAAA, CNAME, MX, SRV, CAA, TLSA, SSHFP:
curl -X POST "http://127.0.0.1:8899/api/v1/dns/records" \
-H "X-API-Token: hm_xxx_yyy" \
-H "Content-Type: application/json" \
-d '{
"name": "_acme-challenge.irc.example.com",
"type": "TXT",
"content": "AbCdEf...",
"ttl": 60
}'curl "http://127.0.0.1:8899/api/v1/dns/records?name=_acme-challenge.irc.example.com&type=TXT" \
-H "X-API-Token: hm_xxx_yyy"curl -X DELETE "http://127.0.0.1:8899/api/v1/dns/records" \
-H "X-API-Token: hm_xxx_yyy" \
-H "Content-Type: application/json" \
-d '{
"name": "_acme-challenge.irc.example.com",
"type": "TXT",
"content": "AbCdEf..."
}'Ideal, um nach einem Zertifikats-/Schlüsselwechsel (z.B. Mailserver) den TLSA-Record automatisch zu setzen. Format des content: <usage> <selector> <matching-type> <hash> — z.B. 3 1 1 <SHA256-SPKI-Hash>.
curl -X POST "http://127.0.0.1:8899/api/v1/dns/records" \
-H "X-API-Token: hm_xxx_yyy" \
-H "Content-Type: application/json" \
-d '{
"name": "_25._tcp.mail.example.com",
"type": "TLSA",
"content": "3 1 1 <SHA256-SPKI-Hash>",
"ttl": 3600
}'Anhängen (Standard): Der neue Hash wird an den bestehenden rrset angehängt — so kannst du beim Rollover nach DANE-Best-Practice alten und neuen Hash gleichzeitig veröffentlichen. Gleicher Inhalt wird dedupliziert (idempotent, retry-sicher).
Ersetzen: Mit "replace": true im Body wird der komplette TLSA-rrset dieses Namens durch genau diesen einen Record ersetzt — praktisch für einen einfachen „alt gegen neu"-Tausch.
curl -X POST "http://127.0.0.1:8899/api/v1/dns/records" \
-H "X-API-Token: hm_xxx_yyy" \
-H "Content-Type: application/json" \
-d '{
"name": "_25._tcp.mail.example.com",
"type": "TLSA",
"content": "3 1 1 <NEUER-Hash>",
"replace": true
}'curl -X DELETE "http://127.0.0.1:8899/api/v1/dns/records" \
-H "X-API-Token: hm_xxx_yyy" \
-H "Content-Type: application/json" \
-d '{
"name": "_25._tcp.mail.example.com",
"type": "TLSA",
"content": "3 1 1 <ALTER-Hash>"
}'Zwei Hook-Skripte:
auth-hook.sh
#!/usr/bin/env bash
curl -fs -X POST "http://127.0.0.1:8899/api/v1/dns/acme-challenge" \
-H "X-API-Token: $HM_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"domain\":\"$CERTBOT_DOMAIN\",\"value\":\"$CERTBOT_VALIDATION\",\"ttl\":60}"
# DNS-Propagation abwarten
sleep 30cleanup-hook.sh
#!/usr/bin/env bash
curl -fs -X DELETE "http://127.0.0.1:8899/api/v1/dns/acme-challenge" \
-H "X-API-Token: $HM_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"domain\":\"$CERTBOT_DOMAIN\",\"value\":\"$CERTBOT_VALIDATION\"}"Zertifikat anfordern:
chmod +x auth-hook.sh cleanup-hook.sh
HM_TOKEN=hm_xxx_yyy certbot certonly \
--manual --preferred-challenges dns \
--manual-auth-hook ./auth-hook.sh \
--manual-cleanup-hook ./cleanup-hook.sh \
-d irc.example.com -d '*.irc.example.com'acme.sh ist deutlich schlanker und bringt einen eingebauten Renew-Cron mit. Custom-DNS-Hook einrichten:
# acme.sh installieren
curl https://get.acme.sh | sh -s email=du@as.gmbh
# Custom-Hook anlegen
mkdir -p ~/.acme.sh/dnsapi
cat > ~/.acme.sh/dnsapi/dns_hostmaster.sh <<'EOF'
dns_hostmaster_add() {
curl -fs -X POST "http://127.0.0.1:8899/api/v1/dns/acme-challenge" \
-H "X-API-Token: $HM_TOKEN" -H "Content-Type: application/json" \
-d "{\"domain\":\"${1#_acme-challenge.}\",\"value\":\"$2\",\"ttl\":60}"
}
dns_hostmaster_rm() {
curl -fs -X DELETE "http://127.0.0.1:8899/api/v1/dns/acme-challenge" \
-H "X-API-Token: $HM_TOKEN" -H "Content-Type: application/json" \
-d "{\"domain\":\"${1#_acme-challenge.}\",\"value\":\"$2\"}"
}
EOF
# Zertifikat holen
export HM_TOKEN=hm_xxx_yyy
~/.acme.sh/acme.sh --issue --dns dns_hostmaster \
-d deine-domain.de -d '*.deine-domain.de'| Status | Bedeutung |
|---|---|
| 401 | Token fehlt, ist widerrufen oder abgelaufen |
| 403 | Token hat nicht den nötigen Scope (z.B. dns:write fehlt) |
| 404 | Zone nicht gefunden bzw. nicht im Eigentum des Token-Inhabers |
| 502 | PowerDNS-Backend hat einen Fehler zurückgegeben |
dns:read reicht für Monitoring/Backups).last_used_at. Im API-Token-Panel kannst du tote Token erkennen und löschen.