DynDNS unter Unifi konfigurieren (Dream Machine Pro)

Mit ** gekennzeichnete Links auf dieser Seite sind Affiliate-Links.

Suchergebnisse

DynDNS unter Unifi konfigurieren (Dream Machine Pro)
DynDNS unter Unifi konfigurieren (Dream Machine Pro)
  • 29.02.2024
  • Level 1
  • UniFi
  • DNS

Wie Du weißt, nutze ich eine UniFi Dream Machine Pro. Sobald man von außen auf sein System zugreifen möchte, braucht man einen dynamischen DNS Dienst. Das ist nötig, weil sich die öffentliche IP-Adresse an privaten Internetanschlüssen in unregelmäßigen Abständen ändern kann. Wir brauchen aber eine Konstante, um nicht jedes Mal neue IP-Adressen auswendig lernen zu müssen. Dafür gibt es verschiedene Dienste, welche sich von außen aktualisieren lassen. Unser System Zuhause geht also aktiv auf den Dienst zu und sagt “hier ist meine neue IP-Adresse, bitte im DNS anpassen”.

Für genau dieses Thema gibt es viele Anbieter. Für die FritzBox gibt es beispielsweise MyFritz. Eventuell hast Du auch schon einmal von no-ip.com oder DuckDNS gehört. Ich nutze mittlerweile ganz gerne den Dienst von Dennis Schröder: ipv64.net. Wie genau man diesen mit UniFi konfiguriert, zeige ich Dir in diesem Beitrag.

Video

Hausbau-Kurs

Update-URL konfigurieren

Auf den Einstellungen von Deinem WAN-Interface findest Du Dynamic DNS:

  • Service: custom
  • Hostname: Deine URL (z. B. youtube.home64.de)
  • Username: none
  • Password: Account Update Token von ip64.net
  • Server: https://ipv4.ipv64.net/update?hostname=%h

Außerdem gibt es weitere Platzhalter, welche je (je nach Dienst) in der Url benötigt werden:

  • %u: Username
  • %p: Password
  • %h: Hostname (siehe oben für IPv64)
  • %i: IP-Address

all-inkl.de DDNS Update-Url

ALL-INKL.COM - Webhosting Server Hosting Domain Provider

** Affiliate-Link

Ich bin zum Beispiel seit 2013 Kunde bei all-inkl.com ** und dort lautet die Url dyndns.kasserver.com/?myip=%i.

hetzner.de DDNS

Bei Hetzner ist das etwas komplizierter. Die API wurde Ende 2025 komplett umgestellt. Die DNS-Einstellungen sind seitdem auch in der Hetzner Console. Siehe Hetzner Dokumentation. Dort kann man in einem Projekt unter Sicherheit -> API-Tokens ein neues Token erstellen (Lesen und Schreiben).

Eine Zone für die jeweilige Domain sollte man schon haben (das passiert automatisch). Ein Projekt kann dabei natürlich mehrere Zones haben.

Alle Resource Record Sets (RRSets) dieser Zone kann man dann wie folgt ermitteln. Siehe Hetzner Dokumentation. Der Name der Zone muss natürlich angepasst werden:

curl -H "Authorization: Bearer <API-TOKEN>" \
  "https://api.hetzner.cloud/v1/zones/haus-auto.com/rrsets"

Ein A-Record für meine Subdomain habe ich bereits in der Hetzner Console manuell erstellt (mit TTL 300)! Diesen möchte ich jetzt aktualisieren. Die Update-Url lautet:

https://api.hetzner.cloud/v1/zones/$ID_OR_NAME/rrsets/$RR_NAME/$RR_TYPE

  • Meine Zone heißt haus-auto.com
  • Resource Record ist die Subdomain. Bei mir im Beispiel pub.
  • Resource Record Type ist ein A-Record: A. Für IPv6 wäre es AAAA.
  • In diesem Beispiel ist die neue IP 4.4.4.4
curl -X POST -H "Authorization: Bearer <API-TOKEN>" -H "Content-Type: application/json" \
  -d '{"records": [{"value": "4.4.4.4", "comment": "DynDNS"}]}' \
  "https://api.hetzner.cloud/v1/zones/haus-auto.com/rrsets/pub/A/actions/set_records"

Klappt! Das Problem ist, dass man per Unifi-Oberfläche keine HTTP POST-Requests ausführen kann. Also baue ich einen kleinen Wrapper in PHP, welchen ich auf dem gleichen Hetzner-Server ablege. Den habe ich ja eh schon. UniFi ruft dann das PHP-Script per HTTP-GET auf und übergibt alle nötigen Parameter. Das PHP-Script macht daraus dann einen POST-Request und baut das passende JSON zusammen. Die Datei nenne ich dyndns.php:

<?php
// v0.2
declare(strict_types=1);
header('Content-Type: application/json');

// Debug logging (optional)
//$logEntry = sprintf("[%s] %s" . PHP_EOL, date('Y-m-d H:i:s'), json_encode($_GET));
//file_put_contents(__DIR__ . '/debug.log', $logEntry, FILE_APPEND | LOCK_EX);

$ipAddress = $_GET['ip'] ?? null;
$hostname  = $_GET['hostname'] ?? null;
$type = $_GET['type'] ?? 'A';

if ($ipAddress === null || $hostname === null) {
    http_response_code(400);
    echo json_encode([
        'status' => 'error',
        'message' => 'Missing GET parameter. Required: ip, hostname'
    ]);
    exit;
}

if (!filter_var($ipAddress, FILTER_VALIDATE_IP)) {
    http_response_code(400);
    echo json_encode([
        'status' => 'error',
        'message' => 'Invalid IP-Address'
    ]);
    exit;
}

$parts = explode('.', $hostname, 2);
$count = count($parts);

if ($count < 2) {
    http_response_code(400);
    echo json_encode([
        'status' => 'error',
        'message' => 'Domain is invalid'
    ]);
    exit;
}

$subdomain = $parts[0];
$domain = $parts[1];

if ($count < 2) {
    http_response_code(400);
    echo json_encode([
        'status' => 'error',
        'message' => 'Hostname is too short (must contain two dots - e.g. test.example.com)'
    ]);
    exit;
}

$targetUrl = sprintf(
    'https://api.hetzner.cloud/v1/zones/%s/rrsets/%s/%s/actions/set_records',
    $domain,
    $subdomain,
    $type
);

$payloadData = [
    'records' => [
        [
            'value'   => $ipAddress,
            'comment' => 'DynDNS'
        ]
    ]
];

$jsonPayload = json_encode($payloadData);

if ($jsonPayload === false) {
    http_response_code(500);
    echo json_encode([
        'status' => 'error',
        'message' => 'JSON encoding failed'
    ]);
    exit;
}

$authUser = $_SERVER['PHP_AUTH_USER'] ?? null;
$authPass = $_SERVER['PHP_AUTH_PW'] ?? null;

// Fallback
if (($authUser === null) && isset($_SERVER['HTTP_AUTHORIZATION'])) {
    if (str_starts_with(strtolower($_SERVER['HTTP_AUTHORIZATION']), 'basic ')) {
        list($authUser, $authPass) = explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)), 2);
    }
}

/*
if ($authUser !== 'egal') {
    http_response_code(400);
    echo json_encode([
        'status' => 'error',
        'message' => 'Incorrect username. Script is protected by owner.'
    ]);
    exit;
}
*/

$ch = curl_init($targetUrl);

curl_setopt_array($ch, [
    CURLOPT_POST           => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT        => 5,
    CURLOPT_POSTFIELDS     => $jsonPayload,
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer {$authPass}",
        'Content-Type: application/json',
        'Accept: application/json'
    ],
]);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curlError = curl_error($ch);

curl_close($ch);

if ($response === false) {
    http_response_code(502);
    echo json_encode([
        'status' => 'error',
        'message' => 'Connection to Hetzner API failed',
        'details' => $curlError
    ]);
} else {
    http_response_code(200);
    echo json_encode([
        'status' => 'success',
        'responseCode' => $httpCode,
        'details' => json_decode($response)
    ]);
}

Der Aufruf sieht dann wie folgt aus (in UniFi):

haus-auto.com/dyndns.php?hostname=%h&ip=%i

Ich nutze also die Parameter:

  • Hostname für die Zone (= Domain) und Resource Record (= Subdomain). Wird automatisch zerlegt.
  • Username ist ungenutzt und kann frei gewählt werden (darf nicht leer bleiben)
  • Password ist das API-Token (wird per Basic Auth übergeben, um nicht in den Logs zu stehen)

Hetzner DynDNS API

»Hetzner DynDNS API«

Info: Auf welchem Server das PHP-Script liegt, ist egal. Theoretisch könntest Du auch meine URL für Dein System nutzen. Aber ich habe eine Prüfung auf einen Username eingefügt, damit mein Server nicht zig Anfragen gegen die Hetzner-API stellt (siehe oben), wenn andere das Script aufrufen. Daher wird das nicht klappen!
Wichtig: Das Script wurde auf meinen Anwendungsfall angepasst. Sollte Deine TLD .co.uk sein, wird das Script nicht mehr funktionieren. Für den Root-Record @ könnte es ebenfalls Probleme geben, da dies kein gültiger Hostname für UniFi ist. Es könnten also ggf. Anpassungen nötig werden!

Update manuell anstoßen

Falls Du den SSH-Zugriff (als root) auf Deiner Dream Machine Pro freigeschaltet hast, kannst Du ein Update über die Shell manuell anstoßen. Dafür kannst Du folgenden Befehl nutzen:

inadyn -n -1 --force -f /run/ddns-ppp0-inadyn.conf

Transparenz-Hinweis (Level 1: Komplett selbst finanziert)

An diesem Beitrag ist kein Hersteller beteiligt! Sämtliche Produkte habe ich selber gekauft und trage die kompletten Kosten für diesen Beitrag alleine! Die Inhalte wurden somit von niemandem gesehen oder abgestimmt. Es handelt sich zu 100 Prozent um meine persönliche Meinung und Erfahrung! Danke an die Community, dass ich solche Inhalte für die Allgemeinheit zur Verfügung stellen kann!

» Mehr erfahren

Du willst mehr?

Smart-Home-Trainings von A-Z

Steig' noch tiefer in die Themen ein und meistere Deine Projekte! Über 17.000 Teilnehmer konnten sich schon von der Qualität der Online-Kurse überzeugen.

Abonniere jetzt den Newsletter für
spannende Neuigkeiten! interessante Angebote! neue Kurs-Inhalte!
* Durch Angabe meiner E-Mail-Adresse erkläre ich mich damit einverstanden, dass mir unregelmäßig Informationen und Produktempfehlungen aus dem Themengebiet »Smart Home« zugesendet werden. Mit dem Eintrag akzeptiere ich die Datenschutzbestimmungen. Meine Einwilligung kann ich jederzeit widerrufen.