ACME / Let's Encrypt Certificates

Automated TLS Certificates for GSLB-Served Domains

When Nexus GSLB is the authoritative nameserver for a zone, standard ACME challenge methods break down:

  • HTTP-01 — the CA's validation request hits whichever node the GSLB currently returns, not necessarily the one requesting the certificate.
  • TLS-ALPN-01 — same problem; the certificate is on one node but the challenge may land on another.

The correct method is DNS-01: the ACME client writes a _acme-challenge.<domain> TXT record and the CA verifies it via DNS. Because Nexus controls the zone, it can serve that TXT record directly — no external DNS provider needed.

Nexus implements RFC 2136 Dynamic DNS Update with TSIG authentication, which is the standard protocol ACME clients use to write and delete challenge records. Caddy, acme.sh, certbot, and lego all support it.

License: Automated ACME certificate management (api.tls.acme) requires the paid tier or above. Manual TLS (providing your own cert/key files) is available on all tiers. Contact licensing@gslb.nexus to upgrade.


How it works

  1. You create a TSIG key via the Nexus API. The key is stored in the database and loaded into the DNS server immediately — no restart required.
  2. You configure your ACME client (e.g. Caddy) with the key name and secret.
  3. When a certificate is requested or renewed, the ACME client sends a TSIG-signed DNS UPDATE to Nexus port 53 (TCP). Nexus writes the _acme-challenge TXT record.
  4. The CA queries _acme-challenge.<domain> and sees the record. Challenge passes.
  5. The ACME client sends another UPDATE to delete the TXT record. Nexus removes it.
  6. The certificate is installed and auto-renewed on this schedule indefinitely.

Each node manages its own certificate independently. There is no shared certificate or cross-node distribution step.


Prerequisites

  • Nexus GSLB is the authoritative nameserver for the zone (e.g. gslb.cc).
  • Port 53 TCP is open between the node running the ACME client and the Nexus DNS server. If the ACME client runs on the same node as Nexus, 127.0.0.1 works.
  • The Nexus API is accessible (default port 8080).

Step 1 — Create a TSIG key

Create one key per node so that a compromised node's key can be revoked independently.

curl -s -X POST https://nexus-api.example.com/api/v1/dns/tsig-keys \
  -H "Authorization: Bearer $GSLB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "caddy-lon01.gslb.cc.", "algorithm": "hmac-sha256."}' \
  | jq .

Response:

{
  "id": "a1b2c3d4...",
  "tenantId": "default",
  "name": "caddy-lon01.gslb.cc.",
  "algorithm": "hmac-sha256.",
  "secret": "dGhpcyBpcyBhIGJhc2U2NC1lbmNvZGVkIHNlY3JldA==",
  "createdAt": 1716000000
}

Save the secret value now. It is shown once and never returned again.

Key naming convention: caddy-<nodename>.<zone>. — any valid DNS name in the served zone works.


Install the caddy-dns/rfc2136 module. With xcaddy:

xcaddy build --with github.com/caddy-dns/rfc2136

Or use the official Caddy Docker image with the module pre-built (check the Caddy download page and select the rfc2136 DNS provider).

Caddyfile:

admin.gslb.cc {
    reverse_proxy localhost:3000

    tls {
        dns rfc2136 {
            server 127.0.0.1        # Nexus DNS server; use node IP if remote
            tsig_key_name caddy-lon01.gslb.cc.
            tsig_key_value dGhpcyBpcyBhIGJhc2U2NC1lbmNvZGVkIHNlY3JldA==
            tsig_algorithm hmac-sha256
        }
    }
}

Port 53 TCP — Caddy's rfc2136 module defaults to TCP for DNS UPDATE messages. Ensure the Nexus DNS server is reachable on TCP/53 from the Caddy host (if running on the same node, 127.0.0.1 is fine).

Reload Caddy:

systemctl reload caddy
# or: caddy reload --config /etc/caddy/Caddyfile

Caddy will request a certificate from Let's Encrypt on first load and renew it automatically ~30 days before expiry.


Step 3 — Configure acme.sh (alternative)

# Install acme.sh
curl https://get.acme.sh | sh

# Issue certificate using RFC 2136
NSUPDATE_SERVER="127.0.0.1"
NSUPDATE_KEY="caddy-lon01.gslb.cc."
NSUPDATE_KEY_SECRET="dGhpcyBpcyBhIGJhc2U2NC1lbmNvZGVkIHNlY3JldA=="
NSUPDATE_TSIG_ALGO="hmac-sha256"

~/.acme.sh/acme.sh --issue \
  --dns dns_nsupdate \
  -d admin.gslb.cc \
  --server letsencrypt

acme.sh's dns_nsupdate hook calls nsupdate with TSIG to create and delete the challenge record.


Multi-node setup

Each node should have its own TSIG key. Create a separate key for each:

# lon-01
curl -X POST .../api/v1/dns/tsig-keys \
  -d '{"name": "caddy-lon01.gslb.cc.", "algorithm": "hmac-sha256."}'

# eu-01
curl -X POST .../api/v1/dns/tsig-keys \
  -d '{"name": "caddy-eu01.gslb.cc.", "algorithm": "hmac-sha256."}'

# lab-01
curl -X POST .../api/v1/dns/tsig-keys \
  -d '{"name": "caddy-lab01.gslb.cc.", "algorithm": "hmac-sha256."}'

Each Caddy instance uses its own key name and secret. Configure each node's Caddyfile independently.

Because each node contacts Nexus on 127.0.0.1:53, the challenge records are written to the local DB and replicated to all nodes via the NATS state sync. This means the CA's validation query will see the record regardless of which Nexus node it resolves to.


Verifying the setup

Check that the TXT record is being served correctly after Caddy writes it (you can trigger this manually):

# Write a test TXT record via the API
curl -X POST .../api/v1/dns/txt-records \
  -H "Authorization: Bearer $GSLB_API_KEY" \
  -d '{"name": "_acme-challenge.admin.gslb.cc.", "value": "testtoken123", "ttl": 60}'

# Query it
dig +short TXT _acme-challenge.admin.gslb.cc @<nexus-server-ip>
# Expected: "testtoken123"

# Clean up
curl -X DELETE .../api/v1/dns/txt-records/<id>

Health check considerations

With the HTTP health check host fix now in place (see Health Checks), configure your pool health check to probe the FQDN, not the IP:

{
  "type": "http",
  "port": 443,
  "httpPath": "/ui",
  "httpHost": "admin.gslb.cc",
  "tls": true,
  "httpExpectedStatus": 200
}

This ensures the TCP connection reaches the node IP while presenting admin.gslb.cc as both the TLS SNI and HTTP Host header — which Caddy will match against its configured site block.


Security

  • TSIG keys grant write access to TXT records in the zone. Keep secrets out of version control.
  • Scope each key to a single node. Revoke a compromised key with DELETE /api/v1/dns/tsig-keys/<id> — the key is removed from the live DNS server immediately without a restart.
  • Nexus rejects RFC 2136 UPDATE messages that are not TSIG-signed with REFUSED. Unauthenticated update attempts are not possible.
  • UPDATE operations are restricted to TXT record type. Nexus does not allow RFC 2136 to modify A, AAAA, or any other record types.

Was this article helpful?
© 2026