Feature/hetzner dns provider#5091
Conversation
Add native support for Hetzner Cloud DNS API (api.hetzner.cloud). Hetzner is migrating from dns.hetzner.com to Cloud Console, with the old API shutting down in May 2026. Features: - Bearer token authentication - A and AAAA record support - Multiple hostnames (comma-separated) - Configurable TTL
## Features - Multi-account support (multiple Hetzner API tokens) - Multi-zone DNS management - Dynamic DNS with automatic failover between WAN interfaces - IPv4 and IPv6 (Dual-Stack) support - Direct DNS management (view/edit/delete records) - Change history with undo functionality - Notifications (Email, Webhook, Ntfy) - Configuration backup/restore Supports both Hetzner Cloud API and legacy DNS Console API.
Bugfixes: - Fix DNS record edit mode (editing TTL no longer fails with "Failed to create record") - Fix error dialog titles showing "Danger" instead of "Error" - Add detailed error messages with record info for debugging - Fix TTL dropdown not being populated Improvements: - Integrate notifications into automatic DNS update flow - Add global default TTL setting for DynDNS entries (60s default) - Add "Save & Apply TTL to All Entries" button - Move DynDNS TTL settings from Scheduled to DNS Entries tab - Simplified TTL settings UI
- Fix TTL updates and add TTL dropdown selector - Add plugin concepts for UniFi and MikroTik integration - Integrate notifications into automatic DNS update flow - Add global default TTL setting for DynDNS entries - Add "Apply TTL to All Entries" button - Fix DNS record edit mode and improve error dialogs - Move DynDNS TTL settings from Scheduled to DNS Entries tab - Fix TTL dropdown and simplify settings layout - Auto-save TTL before applying to all entries - Simplify TTL UI to single Save & Apply button - Move Import to DNS Entries, add DynDNS button to DNS Management - Add grouped record display with filter and search in DNS Management
### DNS Management Improvements - Sort zone groups alphabetically - Persist collapsed group state in localStorage - Fix zone search visibility - move to separate container - Preserve collapsed group state on refresh - Add DNS Management improvements: sorting, search, zone groups ### Import & Account Handling - Fix Import from Hetzner account dropdown ### DKIM & TXT Records - Fix DKIM wizard field sizes - Improve TXT record value display with smart formatting - Show TXT record subtypes (SPF, DKIM, DMARC, Google, MS) in DNS Management ### DynDNS Entries - Fix default TTL loading from settings API - Use default DynDNS TTL when creating entries from DNS Management - Mark A/AAAA records already configured as DynDNS with green bolt icon ### Record Edit/Delete - Add synthetic record IDs for rrsets API - Fetch record data live from API for edit/delete - Refactor edit/delete to lookup record data from cache - Fix edit/delete handlers for new TXT value display ### UI/UX - Fix gateway auto-selection to use sorted order instead of exact priority values - Add grouped record display with filter and search in DNS Management - Move Import to DNS Entries, add DynDNS button to DNS Management - Simplify TTL UI to single Save & Apply button
|
@ArcanConsulting We're not really sure yet if this fits our plugin scope, reviewing these large amounts of code takes a lot of time and we're not sure about the number of users interested in it. Keeping a project like this alive, also requires a time investment in the long run from your end. Are there already people using this? In some cases it's better to offer a package from your own infrastructure to avoid maintenance issues in the long run from our end which also makes clearer for the user that this isn't a part of our distribution. |
I built this primarily for my own infrastructure - I manage ~30 domains on Hetzner and needed proper multi-zone DynDNS with failover support. The existing solutions didn't cover my requirements. I understand the review burden for a plugin this size. I'm happy to maintain it as a community package from my own repo - that removes the long-term maintenance concern from your side. If it gains traction and proves stable, we can revisit official inclusion. Could you point me to docs on setting up a community package repo? |
|
building the index is part of the package manager |
|
The rough sequence is as seen in the tools repo: From a project perspective it's not useful to document how all of this works. Other documentation about it exists in FreeBSD. Cheers, |
net/hclouddns/src/opnsense/scripts/ddclient/lib/account/hetzner_cloud.py
Outdated
Show resolved
Hide resolved
net/hclouddns/src/opnsense/scripts/HCloudDNS/lib/hetzner_api.py
Outdated
Show resolved
Hide resolved
API Changes (based on Hetzner feedback):
- Migrate to proper rrset-actions endpoints for record updates
- Use POST /zones/{zone_id}/rrsets/{name}/{type}/actions/set_records
- Add async action polling - wait for success/error status before continuing
Performance:
- Switch from sequential to parallel DNS update processing (ThreadPoolExecutor)
- Deduplicate entries by (zone_id, record_name, record_type) before processing
- Thread-safe state access with locks
Notifications:
- Single batch notification per update run instead of per-entry
- Clean title format with gateway names:
"HCloudDNS: Failover WAN_Primary → WAN_Backup"
"HCloudDNS: Failback WAN_Backup → WAN_Primary"
"HCloudDNS: DynIP Update on WAN_Primary"
- Records listed once in body (no duplication)
- Grouped by domain with proper spacing
net/hclouddns/src/opnsense/scripts/ddclient/lib/account/hetzner_cloud.py
Show resolved
Hide resolved
net/hclouddns/src/opnsense/scripts/ddclient/lib/account/hetzner_cloud.py
Show resolved
Hide resolved
- Fix Log File tab URL to use core module path - Fix TTL updates: use dedicated change_ttl endpoint per Hetzner API spec (PR opnsense#5091 feedback), split update_record into set_records + change_ttl - Fix Implement forceInterval for periodic forced DNS updates - Fix Remove insecure SSL context (CERT_NONE) from gateway_health.py - Fix atomic file writes with 0600 permissions via write_state_file() - Fix service showing as disabled in OPNsense service overview by adding nocheck flag and proper start/stop/restart configd actions - Notification channels side by side: Ntfy | Email | Webhook (col-md-4) - Align Save/Test buttons at bottom of all wells using flexbox - Align Export/Import buttons at bottom of backup wells - Add deploy.sh - Add install.sh - Add OPNsense standard service buttons (Start/Stop/Restart) via updateServiceControlUI with proper state tracking via flag file - Add syslog-ng filter template matching message("HCloudDNS:") for log capture - Add HistoryController::addEntry() for JSONL history writes - Add SMTP fields to settings - Add email notifications via system mail - Add HMAC-SHA256 webhook signatures (X-HCloudDNS-Signature header) - Add dry-run/preview mode with UI dialog - Add read_history.py and manage_history.py configd scripts - Add M2_1_0.php migration to export existing history - Add hetzner_api_v2.py with TokenBucket rate limiter and 429 retry - Add clickable error link in status bar that jumps to DNS Entries tab - Add CARP-aware mode: DNS updates only run on CARP master node, backup node skips all operations with fail-open for standalone systems - Add CARP VHID filter: monitor all interfaces (default) or a specific VHID to determine master/backup status - Add CARP syshook (20-hclouddns) to trigger DNS update on failover - Add model migration M2_0_3 for new carpAware/carpVhid fields - Update hcloud_api.py wrapper with v2 routing and update_ttl() - Update export/import, deploy script, and package manifest - Move DNS change history from config.xml to JSONL file backend - Delete unused v1 update_records.py script - Delete HetznerCloudAPI (v1) class, use HetznerCloudAPIv2 with rate limiting - Rewrite HistoryController.php to use configd instead of model - Clean up old hcloudddns (double-D) plugin artifacts in deploy.sh to prevent crashes from the Dec 2025 rename
|
Quick update on the latest changes: Addressed review feedback:
New features:
Bug fixes:
The plugin is running stable on my infrastructure (~30 domains). Happy to address further feedback. |
FIX: The health check was only checking "has IP = up", ignoring OPNsense's actual dpinger monitoring. A gateway with a stale DHCP lease would still show as up even when dpinger reported it down. Now queries OPNsense's Gateways class + dpinger_status() and matches by interface name (wan, opt1, etc.) — the same interface field already used in the plugin's gateway dropdown. The ping-based check had no source binding, so it always went through the default gateway — reporting all gateways as up even when one was down. Now queries OPNsense's own gateway_status.php which uses dpinger for accurate per-gateway health monitoring. FIX: Replace → (U+2192) with -> in ntfy Title headers. urllib encodes headers as latin-1 which cannot represent unicode characters. The message body (sent as UTF-8 data) is unaffected.
Add CAA wizard with CA presets for record creation Add Pinned/favorite zones with localStorage persistence Add DNS health check (NS delegation, SOA consistency, MX, SPF, DMARC, CAA, CNAME apex) Add DNS propagation monitor across Hetzner nameservers Add Zone export (BIND format) and import with preview Add Record templates (mail server, Google Workspace, Microsoft 365, basic website, custom) Add Audit dashboard with change history, detail view, and revert capability Add Global record search across all zones with type filter, debounced live search, and Refresh All Add Record cloning between zones via existing createRecord API Add Keyboard shortcuts (/ s r i t h ?) with help modal Add DNSSEC status check via DNSKEY/DS DNS queries with shield badge per zone Add DNSSEC integrated into health check as additional check item Fix checkbox data-type from "string" to "boolean" in gateways, accounts, entries Fix The health check was only checking "has IP = up", ignoring OPNsense's actual dpinger monitoring. A gateway with a stale DHCP lease would still show as up even when dpinger reported it down. Now queries OPNsense's Gateways class + dpinger_status() and matches by interface name (wan, opt1, etc.) — the same interface field already used in the plugin's gateway dropdown. The ping-based check had no source binding, so it always went through the default gateway — reporting all gateways as up even when one was down. Now queries OPNsense's own gateway_status.php which uses dpinger for accurate per-gateway health monitoring. Change Maintenance notifications are now deferred until DNS records have actually been updated (failover/failback complete), preventing premature or duplicate notifications.
Summary
New plugin for comprehensive Hetzner DNS management in OPNsense.
Features
Supports both Hetzner Cloud API and legacy DNS Console API.
Screenshots









Technical Details
Testing
Checklist