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
- 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.
- You configure your ACME client (e.g. Caddy) with the key name and secret.
- 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-challengeTXT record. - The CA queries
_acme-challenge.<domain>and sees the record. Challenge passes. - The ACME client sends another UPDATE to delete the TXT record. Nexus removes it.
- 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.1works. - 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.
Step 2 — Configure Caddy (recommended)
Install the caddy-dns/rfc2136 module. With xcaddy:
xcaddy build --with github.com/caddy-dns/rfc2136Or 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.1is fine).
Reload Caddy:
systemctl reload caddy
# or: caddy reload --config /etc/caddy/CaddyfileCaddy 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 letsencryptacme.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.