Einführung
Deine IPv4/IPv6 soll folgen wie ein treuer Hund, ohne dass du DNS von Hand pflegen musst? Dieses kleine PHP-Skript spielt DynDNS-Server, spricht sowohl die Hetzner Console API als auch die Legacy DNS Console API und versteht sich mit Routern wie einer Fritz!Box. Zuerst kommt die Schritt-für-Schritt-Anleitung für Einsteiger, danach die Nerd-Ecke mit den Details. Neue Zonen lassen sich seit 10. November 2025 nicht mehr in der DNS Console anlegen; plane die Migration in die Hetzner Console ein und halte DNS Console nur während des Umzugs aktiv.
Voraussetzungen
- Ein Hetzner-Account mit mindestens einer DNS-Zone (Hetzner Console oder DNS Console während der Migration).
- PHP mit den Erweiterungen
curlundSQLite3(Webspace oder kleine VM reicht). - Einen Ort für das PHP-Skript und einen Cronjob alle paar Minuten.
- Einen Client, der eine DynDNS-URL aufrufen kann (Router, NAS oder ein einfacher curl-Aufruf).
Schritt 0 - Beispiel-Setup auf Debian/Ubuntu
Falls du von einem blanken Debian/Ubuntu startest, bringen dich diese Befehle zu einem testbaren Endpunkt:
- Voraussetzungen installieren und Ordner für Skripte erstellen
sudo apt update sudo apt install -y apache2 libapache2-mod-php php-cli php-curl php-sqlite3 sudo a2enmod rewrite sudo mkdir -p /var/www/hetzner-ddns sudo chown -R www-data:www-data /var/www/hetzner-ddns
-
Apache-Seite erstellen
Passe
ServerNameauf deinen DynDNS-Endpunkt an. In Produktion solltest du HTTPS (z. B. Let's Encrypt) nutzen.cat <<'EOF' | sudo tee /etc/apache2/sites-available/hetzner-ddns.conf <VirtualHost *:80> ServerName ddns.example.com DocumentRoot /var/www/hetzner-ddns <Directory /var/www/hetzner-ddns> AllowOverride All Require all granted </Directory> </VirtualHost> EOF
- Seite aktivieren
sudo a2ensite hetzner-ddns sudo apachectl configtest sudo systemctl reload apache2
Schritt 1 - Dateien besorgen
Nutze die zu diesem Tutorial gebündelten Dateien in tutorials/hetzner-ddns-bridge/scripts:
Gespiegelt von https://github.com/woehrl/hetzner-dyndns, Commit
11582e6. Kopiere sie auf deinen Webspace oder eine kleine VM.
Für das Beispiel-Setup aus "Schritt 0" müssen die Dateien in /var/www/hetzner-ddns gespeichert werden.
Du brauchst mindestens:
/var/www/hetzner-ddns
├─ hetzner_dyndns.php
├─ hetzner_dyndns.config.php.dist
├─ .htaccess Die Datei von GitHub
└─ hetzner_dyndns_listhosts.php OptionalBeispiel-Befehle:
export path="https://raw.githubusercontent.com/hetzneronline/community-content/refs/heads/master/tutorials/hetzner-ddns-bridge/scripts"
cd /var/www/hetzner-ddns
# Führe folgenden Befehl im Terminal aus,
# um die Dateien zu bestimmen
files=(
hetzner_dyndns.php
hetzner_dyndns.config.php.dist
.htaccess
hetzner_dyndns_listhosts.php
)
# Führe folgenden Befehl im Terminal aus,
# um die zuvor bestimmten Dateien zu kopieren
for f in "${files[@]}"; do
curl "$path/$f" | sudo tee "$f" >/dev/null
doneSchritt 2 - Config anlegen
sudo cp hetzner_dyndns.config.php.dist hetzner_dyndns.config.phpBearbeite hetzner_dyndns.config.php:
| Beschreibung | |
|---|---|
| auth_user | Optional: Username für HTTP Basic Auth. Wenn leer, wird update verwendet. |
| auth_password | Bestimme ein starkes, geteiltes Passwort. Dein Router nutzt es. |
| api_order | Lege fest, welche API zuerst probiert wird: Verwende ['console', 'dns'] für Migration oder ['console'], wenn alle Zonen auf der neuen API liegen. |
| console_token dns_token |
Tokens hinzufügen:
|
| zone_name | Wenn die IP-Adresse für eine Subdomain (z.B. sub.example.com) aktualisiert werden soll, muss hier die Hauptdomain (z.B. example.com) angegeben werden. |
| auth_realm | Optional: Wähle ein Label (z. B. "dynbridge"). |
| history_db | Optional: Zeige auf einen beschreibbaren Pfad (z. B. DIR . '/hetzner_dyndns.sqlite3'). |
| TTL | Optional: Passe die TTL pro Realm an, wenn es schneller oder langsamer propagieren soll. |
Schritt 3 - Sicher ins Netz stellen
- Halte
hetzner_dyndns.config.phpaus öffentlichen Repos und Verzeichnislisten heraus. - Stelle sicher, dass
.htaccessdie DynDNS-Endpunkte auf das Skript umschreibt, damit alte Clients funktionieren:RewriteEngine On RewriteRule ^(nic/update|v3/update)$ hetzner_dyndns.php [L,QSA] - Falls nötig, sorge dafür, dass der PHP-User in die SQLite-Datei und das Debug-Log schreiben darf.
Schritt 4 - Update testen
- Baue die Test-URL (ersetze Domain und Host):
https://dein-ddns-host.example.com/nic/update?hostname=myhost.example.com&myip=203.0.113.10 - Nutze HTTP Basic Auth mit
auth_user/auth_password(User defaultet aufupdate, wenn leer). DynDNS-Clients senden meist irgendeinen Usernamen plus das Passwort; percurlgeht es so:curl -u user:deinPasswort \ "https://dein-ddns-host.example.com/nic/update?hostname=myhost.example.com&myip=$(curl -s ifconfig.me)" - Erfolgreiche Antworten sind
good <ip>(aktualisiert) odernochg <ip>(nichts zu tun). Alles andere: ins Debug-Log schauen.
Schritt 5 - Automatisieren
- Cron alle 5 Minuten (nach Bedarf anpassen):
*/5 * * * * php /path/to/hetzner_dyndns.php --cron --realm=default - Richte deinen Router oder dein NAS auf dieselbe
nic/update-URL mit dem gesetzten Passwort ein. IPv6 klappt, wenn der Clientmyipv6mitsendet. - Legacy-Clients dürfen weiterhin
X-Authentication: <passwort>oder?p=<passwort>(nur Passwort) senden, empfohlen ist Basic Auth.
Schritt 6 - Kurzer Troubleshooting-Spickzettel
- 401 oder Auth-Prompt: Passwort stimmt nicht oder
.htaccessgreift nicht. not_found: falsche Zone oder Hostname, oder fehlende Token-Rechte.- SQLite-Schreibfehler: Dateirechte anpassen oder DB in einen beschreibbaren Pfad verschieben.
- Nichts ändert sich:
api_orderprüfen und das richtige Token pro Realm setzen.
Nerd-Ecke (so funktioniert es wirklich)
- Architektur im Überblick
- Ein PHP-Skript, eine Config, eine SQLite-DB. DynDNS-Aufrufe (
/nic/updateoder/v3/update) werden via.htaccessaufhetzner_dyndns.phpumgeschrieben. - Das Skript authentifiziert mit Benutzername/Passwort, parst Hostname und optionales
realm, cached bekannte Records in SQLite und antwortet sofort mitgood, wenn sich nichts geändert hat.
- Ein PHP-Skript, eine Config, eine SQLite-DB. DynDNS-Aufrufe (
- Konfig-Details
- Gemeinsame Einstellungen:
auth_user,auth_password,auth_realm,history_dbsowie optionaldebug/debug_log. - Benachrichtigungen:
notifications.enabledaktivieren,phpodersmtpwählen, Empfänger setzen und entscheiden, ob bei Erfolg, Fehler oder beidem gemailt wird. - Realms: pro Realm
ttl,api_order,zone_name,console_tokenunddns_token. Setzezone_name, wenn der DynDNS-Endpunkt auf einer Subdomain liegt, du aber die Hauptzone aktualisierst.
- Gemeinsame Einstellungen:
- "Hetzner Console"-API-Ablauf (aktuell)
- Zone über
/zones?name=<zone>mit dem Hetzner Console API-Token finden. - RRsets über
/zones/{id}/rrsets(A und AAAA) holen. - RRset-Namen mit dem Host abgleichen (inkl.
@am Apex). set_recordsaufrufen, um die IPs zu ersetzen. Erfolgreich = Action-Response; Fehler meldennot_foundoder fehlende Rechte.
- Zone über
- "DNS Console"-API-Ablauf (Legacy)
- Zonen-ID mit
/zones?name=<zone>überdns_tokenholen. - A/AAAA-Record-IDs finden, in SQLite cachen und per
PUT /records/{id}aktualisieren. - Fehler bleiben als
needs_syncfür Cron-Retries markiert.
- Zonen-ID mit
- Wechsel zwischen den APIs
- Nutze
['console', 'dns']während der Migration. Wenn Hetzner Consolenot_foundsagt, fällt das Skript auf DNS Console zurück. - Wenn eine Zone komplett auf Hetzner Console läuft,
dns_tokenentfernen oder auf['console']umstellen, um Legacy-Calls zu sparen und dem DNS-Console-Abschaltplan voraus zu sein. - Nach Config-Änderungen
php hetzner_dyndns.php --cronausführen, um offene Jobs abzuarbeiten und beide APIs zu testen.
- Nutze
- Mehrere Zonen und Realms
- Lege pro Zone oder Subdomain einen Realm an. Beispiel: Realm
gjsi.deundddns.gjsi.demit unterschiedlichen Tokens und TTLs. - Nutze
realm=<name>im DynDNS-Query-String, wenn du mehrere Domains über denselben Endpunkt bedienst. - Der optionale CLI-Helfer
hetzner_dyndns_listhosts.phpkann gecachte IPv4/IPv6 pro Realm ausgeben, ohne den HTTP-Endpunkt zu treffen.
- Lege pro Zone oder Subdomain einen Realm an. Beispiel: Realm
- Benachrichtigungen und Observability
- E-Mails zu Erfolgen und Fehlern über PHP
mail()oder SMTP. debugunddebug_logzeichnen Requests und Responses beider APIs plus Benachrichtigungsstatus auf.- Cron-Summen listen Gesamtzahl, Erfolge, Fehler und welche API jeden Host bearbeitet hat.
- E-Mails zu Erfolgen und Fehlern über PHP
- Sicherheit und Deployment
.htaccessblockiert direkte Zugriffe auf PHP und SQLite und lässt nur die DynDNS-Endpunkte durch.- Tokens nur auf DNS scopen und regelmäßig rotieren.
- SQLite-DB und Debug-Log müssen für den PHP-User schreibbar sein; nach Möglichkeit außerhalb öffentlicher Webroots ablegen.
- DynDNS-Endpunkt per HTTPS bereitstellen. Reines HTTP würde dein Passwort verraten.
Ergebnis
Die Bridge liefert dir einen freundlichen DynDNS-Endpunkt, der Hetzners API-Umstellung überlebt. Starte mit dem Schnellstart, damit Updates laufen, und wirf dann einen Blick in die Nerd-Ecke, wenn du Realms, Benachrichtigungen oder das Verhältnis zwischen Hetzner Console und DNS Console feintunen willst.