From 5ee205bd31b7ec09521b2c0d3d6d535da040fc9e Mon Sep 17 00:00:00 2001 From: Christopher Obbard Date: Sat, 31 Jan 2026 02:47:44 +0100 Subject: [PATCH] ddns-scripts: add Hetzner Cloud support Add a new Hetzner DDNS provider using the Hetzner Cloud API (api.hetzner.cloud) with Bearer token authentication. Configuration guide: * set [domain] to domain * set [username] to subdomain (without domain) * set [password] to Bearer API key Signed-off-by: Christopher Obbard --- net/ddns-scripts/Makefile | 33 ++++++++- .../usr/lib/ddns/update_hetzner_cloud.sh | 70 +++++++++++++++++++ .../usr/share/ddns/default/hetzner.com.json | 9 +++ net/ddns-scripts/files/usr/share/ddns/list | 1 + 4 files changed, 112 insertions(+), 1 deletion(-) create mode 100755 net/ddns-scripts/files/usr/lib/ddns/update_hetzner_cloud.sh create mode 100644 net/ddns-scripts/files/usr/share/ddns/default/hetzner.com.json diff --git a/net/ddns-scripts/Makefile b/net/ddns-scripts/Makefile index c3983e0773..e9ac12dbb3 100755 --- a/net/ddns-scripts/Makefile +++ b/net/ddns-scripts/Makefile @@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=ddns-scripts PKG_VERSION:=2.8.2 -PKG_RELEASE:=86 +PKG_RELEASE:=87 PKG_LICENSE:=GPL-2.0 @@ -124,6 +124,17 @@ define Package/ddns-scripts-godaddy/description Dynamic DNS Client scripts extension for 'godaddy.com API v1'. endef +define Package/ddns-scripts-hetzner-cloud + $(call Package/ddns-scripts/Default) + TITLE:=Extension for hetzner.com cloud API + DEPENDS:=ddns-scripts +curl + PROVIDES:=ddns-scripts_hetzner-cloud +endef + +define Package/ddns-scripts-hetzner-cloud/description + Dynamic DNS Client scripts extension for 'hetzner.com cloud API'. +endef + define Package/ddns-scripts-namesilo $(call Package/ddns-scripts/Default) TITLE:=Extension for namesilo.com API v1 @@ -446,6 +457,7 @@ define Package/ddns-scripts-services/install rm $(1)/usr/share/ddns/default/cloud.google.com-v1.json rm $(1)/usr/share/ddns/default/freedns.42.pl.json rm $(1)/usr/share/ddns/default/godaddy.com-v1.json + rm $(1)/usr/share/ddns/default/hetzner.com.json rm $(1)/usr/share/ddns/default/namesilo.com-v1.json rm $(1)/usr/share/ddns/default/digitalocean.com-v2.json rm $(1)/usr/share/ddns/default/dnspod.cn.json @@ -570,6 +582,24 @@ fi exit 0 endef +define Package/ddns-scripts-hetzner/install + $(INSTALL_DIR) $(1)/usr/lib/ddns + $(INSTALL_BIN) ./files/usr/lib/ddns/update_hetzner_cloud.sh \ + $(1)/usr/lib/ddns + + $(INSTALL_DIR) $(1)/usr/share/ddns/default + $(INSTALL_DATA) ./files/usr/share/ddns/default/hetzner.com.json \ + $(1)/usr/share/ddns/default +endef + +define Package/ddns-scripts-hetzner/prerm +#!/bin/sh +if [ -z "$${IPKG_INSTROOT}" ]; then + /etc/init.d/ddns stop +fi +exit 0 +endef + define Package/ddns-scripts-namesilo/install $(INSTALL_DIR) $(1)/usr/lib/ddns $(INSTALL_BIN) ./files/usr/lib/ddns/update_namesilo_com_v1.sh \ @@ -917,6 +947,7 @@ $(eval $(call BuildPackage,ddns-scripts-cloudflare)) $(eval $(call BuildPackage,ddns-scripts-gcp)) $(eval $(call BuildPackage,ddns-scripts-freedns)) $(eval $(call BuildPackage,ddns-scripts-godaddy)) +$(eval $(call BuildPackage,ddns-scripts-hetzner)) $(eval $(call BuildPackage,ddns-scripts-namesilo)) $(eval $(call BuildPackage,ddns-scripts-digitalocean)) $(eval $(call BuildPackage,ddns-scripts-dnspod)) diff --git a/net/ddns-scripts/files/usr/lib/ddns/update_hetzner_cloud.sh b/net/ddns-scripts/files/usr/lib/ddns/update_hetzner_cloud.sh new file mode 100755 index 0000000000..07b0384ace --- /dev/null +++ b/net/ddns-scripts/files/usr/lib/ddns/update_hetzner_cloud.sh @@ -0,0 +1,70 @@ +#!/bin/sh +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# Script to update Hetzner DNS Records using the Cloud API (api.hetzner.cloud) +# +# 2026 Christopher Obbard +# +# Options passed from /etc/config/ddns: +# Domain - the zone name in Hetzner Console (e.g. `example.com`) +# Username - the RRset name within the zone (e.g. `www`) +# Password - Hetzner Console API token (Bearer token) +# +# Reference: https://docs.hetzner.cloud/reference/cloud#tag/zone-rrset-actions/set_zone_rrset_records + +# Hetzner API base URL +__API="https://api.hetzner.cloud/v1" + +# Hetzner API requires a comment. An empty string is fine. +comment="" + +. /usr/share/libubox/jshn.sh + +# Check CURL exists +[ -z "$CURL" ] || [ -z "$CURL_SSL" ] && { + write_log 14 "Hetzner Cloud DDNS script requires cURL with SSL support" + return 1 +} + +# Check options +[ -z "$username" ] && write_log 14 "Hetzner Cloud DDNS: 'username' (rrset name) not set" && return 1 +[ -z "$password" ] && write_log 14 "Hetzner Cloud DDNS: 'password' (API Token) not set" && return 1 +[ -z "$domain" ] && write_log 14 "Hetzner Cloud DDNS: 'domain' not set (Zone name)" && return 1 +[ "$use_ipv6" -eq 1 ] && type="AAAA" || type="A" + +__TYPE="A" +[ "$use_ipv6" -ne 0 ] && __TYPE="AAAA" + +# Create JSON payload for set_records API call +# Payload: +# { "records": [ { "value": "", "comment": "" } ] } +json_init +json_add_array "records" + json_add_object + json_add_string "value" "$__IP" + json_add_string "comment" "$comment" + json_close_object +json_close_array + +__URL="${__API}/zones/${domain}/rrsets/${username}/${__TYPE}/actions/set_records" + +__STATUS=$(curl -Ss -X POST "$__URL" \ + -H "Authorization: Bearer ${password}" \ + -H "Content-Type: application/json" \ + -d "$(json_dump)" \ + -w "%{http_code}\n" -o "$DATFILE" 2>"$ERRFILE") + +if [ $? -ne 0 ]; then + write_log 14 "Curl failed (set_records): $(cat "$ERRFILE")" + return 1 +fi + +# Treat any 2xx as success; otherwise error. +case "$__STATUS" in + 200|201|202) return 0 ;; + *) + write_log 14 "Curl failed (set_records): $__STATUS\nresponse body: $(cat "$DATFILE")" + return 1 + ;; +esac diff --git a/net/ddns-scripts/files/usr/share/ddns/default/hetzner.com.json b/net/ddns-scripts/files/usr/share/ddns/default/hetzner.com.json new file mode 100644 index 0000000000..7bbe027d1b --- /dev/null +++ b/net/ddns-scripts/files/usr/share/ddns/default/hetzner.com.json @@ -0,0 +1,9 @@ +{ + "name": "hetzner.cloud", + "ipv4": { + "url": "update_hetzner_cloud.sh" + }, + "ipv6": { + "url": "update_hetzner_cloud.sh" + } +} diff --git a/net/ddns-scripts/files/usr/share/ddns/list b/net/ddns-scripts/files/usr/share/ddns/list index 8960ca1ee4..7cbf507918 100644 --- a/net/ddns-scripts/files/usr/share/ddns/list +++ b/net/ddns-scripts/files/usr/share/ddns/list @@ -36,6 +36,7 @@ easydns.com goip.de google.com he.net +hetzner.com hosting.de infomaniak.com ipnodns.ru