Skip to content

Conversation

@likt0r
Copy link

@likt0r likt0r commented Oct 26, 2025

Add Hetzner Networking DNS Provider

Overview

Adds support for the new Hetzner Cloud DNS API with the hetznernetworking provider. This is a separate provider from the existing hetzner provider, offering modern RRSet-based operations and wildcard domain support.

Features

  • Wildcard domain support (*.example.com)
  • Bearer token authentication
  • RRSet-based API operations
  • IPv4/IPv6 support
  • Configurable TTL

Configuration

{
  "settings": [
    {
      "provider": "hetznernetworking",
      "zone_identifier": "example.com",
      "domain": "sub.example.com",
      "token": "your-api-token",
      "ttl": 600,
      "ip_version": "ipv4"
    }
  ]
}

API Endpoints

  • GET /v1/zones/{zone}/rrsets/{name}/{type} - Get records
  • POST /v1/zones/{zone}/rrsets/{name}/{type}/actions/add_records - Create records
  • POST /v1/zones/{zone}/rrsets/{name}/{type}/actions/set_records - Update records

Testing

  • Compiles without errors
  • Wildcard domains working
  • API integration verified

Breaking Changes

None - purely additive change. Legacy hetzner provider remains unchanged.

Documentation

@JarodSch
Copy link

Can someone merge this?

@NiklasReisser
Copy link

I'd be interested in this as well.

Out of curiosity (I don't know much about Go):

  • What is the hetznercloud provider used for? It seems incomplete.
  • When trying to build the docker container, I get a few linter errors (after removing hetznercloud, which gives other errors):
internal/provider/providers/hetznernetworking/create.go:30: the line is 137 characters long, which exceeds the maximum of 120 characters. (lll)
	urlString := fmt.Sprintf("https://api.hetzner.cloud/v1/zones/%s/rrsets/%s/%s/actions/add_records", p.zoneIdentifier, rrName, recordType)
internal/provider/providers/hetznernetworking/update.go:32: the line is 137 characters long, which exceeds the maximum of 120 characters. (lll)
	urlString := fmt.Sprintf("https://api.hetzner.cloud/v1/zones/%s/rrsets/%s/%s/actions/set_records", p.zoneIdentifier, rrName, recordType)
internal/provider/providers/hetznernetworking/update.go:19:2: unused-parameter: parameter 'recordID' seems to be unused, consider removing or renaming it as _ (revive)
	recordID string, ip netip.Addr,
	^
internal/provider/providers/hetznernetworking/getrecord.go:102:14: do not define dynamic errors, use wrapped static errors instead: "fmt.Errorf(\"domain %s is not a subdomain of zone %s\", domain, zone)" (err113)
		return "", fmt.Errorf("domain %s is not a subdomain of zone %s", domain, zone)
		           ^
The command '/bin/sh -c golangci-lint run --timeout=10m' returned a non-zero code: 1

Am I doing something wrong?

@suntorytimed
Copy link

I have built the container and pushed it as suntorytimed/ddns-updater:hetzner-cloud-dns to Docker Hub and replaced the container and provider information on my TrueNAS homeserver. Works flawlessly. Thank you @likt0r for your work. @qdm12 would be nice to get this merged and pushed officially.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants