Skip to main content

DNS publishing

When you publish a service as vault.example.com, something has to turn that name into the address of one of your nodes. Clouduler can do this for you: it writes the A, AAAA and CNAME records into your Cloudflare zone and keeps them correct as services move, nodes fail and stacks are removed.

It only ever deletes records it created itself. Everything else in your zone is left alone.

How it works​

  1. Desired records. From the replicated state, Clouduler works out which hostnames exist (stack routes and the dashboard) and which node addresses each should point at.
    • On a subnetted network (internal or private) the record is an A or AAAA pointing at the node's IP on that network, with TTL 1 (automatic) and not proxied by Cloudflare.
    • On a public network the records come from the node's public address block: ipv4 becomes an A record, ipv6 an AAAA record, domain a CNAME.
  2. Which nodes. The proxy.dns_publish mode decides which nodes are listed (see below).
  3. Reconcile. Every 60 seconds the leader compares the desired records with the live zone. It deletes records it owns that are no longer wanted, creates missing ones, then updates changed ones. A "Reconcile DNS" button runs it immediately.
  4. Ownership tag. For each name Clouduler also writes a TXT record at _clouduler.<fqdn> with content like "cluster=homelab;key=...", and sets the record comment to managed by clouduler (homelab). Only records carrying the tag are ever deleted.
  5. Zone matching. The longest configured zone that covers a hostname is used. A hostname outside every zone is skipped with the status no cloudflare zone covers this hostname.

DNS publishing and certificate issuance share the same Cloudflare token and zone list. See Proxy and TLS.

Set it up​

  1. Create a Cloudflare API token (guide).
  2. Open Settings > Network and the Cloudflare DNS page. Switch on Manage DNS with Cloudflare, list your DNS zones, paste the API token and press Save token.
  3. On Settings > Network > Networks, set a DNS domain on each network that serves routes. Leave Publish to DNS provider (Cloudflare) on for the networks whose names you want in Cloudflare.
  4. Apply. Open DNS (/dns) to watch the records.
/dns
DNS: certificates, DNS records and the TLS fingerprint.

The DNS records panel lists every record Clouduler manages with its state. Reconcile DNS runs a pass now. Copy fingerprint under TLS fingerprint copies the dashboard certificate fingerprint you need for clouduler init --join.

/settings/network?page=cloudflare
Settings, Network, Cloudflare DNS.

Publish modes​

proxy.dns_publish has two values. It has no control in the web UI, so edit cluster.yaml and run clouduler config reload.

ModeRecords published for a routeTrade-off
all-nodes (default)Every node that serves the route gets an A or AAAA record, whether or not it runs the container.Simple and resilient: any node can proxy the request to wherever the container is. More records, and traffic takes an extra hop through the cluster network.
owning-nodeOnly the nodes that actually run the container. Stale records are deleted.Clients connect straight to the node that runs the service. Requires the co-location rule below.

The co-location constraint​

With owning-node, all services that share a proxy hostname must run on the same node, so there is one clear owner. The scheduler enforces this. If it cannot place a service on the same node as the others it shares a host with, placement fails with:

must share a node with {keys} already placed on {anchors}

Pins, constraints, drives or capacity that rule out that node make the stack unplaceable. See Placement. Switch back to all-nodes if you want services with a shared hostname to spread across nodes.

Switching modes is safe: records that are no longer wanted are deleted first on the next reconcile pass (every 60 seconds, leader only). Switching to owning-node deletes the records of nodes that do not run the service; switching back creates them again.

Reconcile behaviour​

  • Prefers an existing match. When a live record already matches a desired one, Clouduler keeps it instead of picking an arbitrary candidate. This avoids a bug where duplicate-content errors blocked deletes forever.
  • Hand-made records are left alone. An identical record you created yourself is noted as unclaimed and not touched. Records Clouduler does not own are never deleted.
  • CNAME exclusivity. A CNAME cannot share a name with other records. If both are wanted, the address record wins over the CNAME. Conflicting records that Clouduler owns are deleted.
  • Order. Deletes first, then creates, then updates. Benign duplicate errors from Cloudflare (codes 81057, 81044, 81058) are treated as "already there".
  • Error attribution. A failure that affects the whole zone (for example bad credentials) is shown against the zone. A per-record failure is shown against the affected hostnames only.
  • The dashboard hostname is published from the leader.
  • Retries. The Cloudflare client makes at most 5 attempts (4 retries, with exponential backoff) on 429 and 5xx responses.

Names for clients without Cloudflare​

If you do not use Cloudflare, or set publish_dns: false on a network, nothing is written to a public zone. Your clients still need a way to resolve vault.lan.example.com. Options: your own DNS, /etc/hosts, or Clouduler's built-in cluster DNS server.

Open Settings > Network > Reverse proxy. Switch on Run a cluster DNS server, tick the DNS server networks to listen on, and optionally change the DNS server port (default 53). Then point your router or clients at a node's address on one of those networks.

/settings/network?page=proxy
Settings, Network, Reverse proxy: the cluster DNS server fields.

The server answers according to the network the client is on. A client on a subnetted network gets the node's own LAN address for a public hostname (so LAN traffic does not hairpin through your router), and names the cluster does not own are forwarded upstream. It returns REFUSED to clients outside the configured networks, and for names it does not own to clients outside a subnetted network, so a public listener cannot be used as an open resolver. networks defaults to every subnetted network. It re-reads the config every 5 seconds. Ports below 1024 need root, which the daemon has. Remember to open port 53 on the nodes' firewall for your LAN (see Ports and firewall).

Options​

Option
Type / default
Reload
Description
enumdefault all-nodes
live reload
all-nodes: every node's address is published for every proxied hostname. owning-node: only the nodes running the containers are published, stale records are deleted and the scheduler co-locates containers that share a hostname.
Watch out: No UI control; edit the file. See DNS publishing.
booldefault false
live reload
Turns on the cluster DNS server that answers by the client's network.
Watch out: Re-read every 5 seconds.
list of network namesdefault [] (every subnetted network the node has an address on)
live reload
Networks to listen on, at the node's address on each. A public network is served only when listed.
Watch out: Errors: no network named NAME; NAME has no node address to listen on.
portdefault 53
live reload
UDP and TCP port of the cluster DNS server. Below 1024 needs root.
Watch out: Must not be 0.
booldefault true
live reload
When false, the network's names are not written to Cloudflare. Only proxy.dns_server answers them.
Watch out: false is allowed only on internal and private networks. A public network is always published.
objectdefault absent
live reload
Enables Cloudflare DNS management. The API token is a sealed cluster secret set from the UI.
Watch out: When present, zones must be non-empty.
list of zone namesno default
live reload
Zones Clouduler may write records into. The longest matching zone wins.
Watch out: Required when cloudflare is set. Every network domain and the dashboard hostname must sit inside one.

Troubleshooting​

SymptomLikely causeWhat to do
Record never appearsHostname outside every cloudflare.zones entry, or the network has no domain.Check DNS status for no cloudflare zone covers this hostname. Add the zone.
cloudflare auth failed: ...Bad or under-privileged token. The token is not verified when saved.Rotate the token under Settings > Network > Cloudflare DNS. It needs Zone, DNS and Edit permissions.
zone X not foundThe zone name does not exist in the account behind the token.Fix the zone list or token.
cloudflare api error CODE: MESSAGECloudflare rejected a record.Read the code; several failures are summarised as N records failed to apply: ....
this node holds no cluster key when saving a tokenThe node you are using has no cluster key.Use a node that holds the key.
Old records remainThey were not created by Clouduler, or the tag is missing.Delete them in Cloudflare yourself.
Placement fails with must share a node with ...owning-node co-location.Free the anchor node or switch to all-nodes.
A name resolves to the wrong placeAnother record (CNAME or hand-made) conflicts.Remove or fix the foreign record, then press Reconcile DNS.

Quirks and gotchas​