Transport Security (TLS)

DNS Transport Security

Nexus GSLB supports four DNS transports. UDP and TCP are always active when the DNS server starts. DNS over TLS (DoT, RFC 7858) and DNS over HTTPS (DoH, RFC 8484) are opt-in and require a TLS certificate.

License: DoT and DoH are available on all license tiers. A valid TLS certificate (manual or ACME-provisioned) is required. See Automated TLS Certificates for DNS-01 certificate provisioning.


Transport overview

Transport Protocol Default port Config key RFC
DNS/UDP Plain UDP 5353 dns.port RFC 1035
DNS/TCP Plain TCP 5353 dns.port RFC 7766
DoT TLS-wrapped TCP 853 dns.dot RFC 7858
DoH HTTPS (HTTP/2) 443 dns.doh RFC 8484

UDP and TCP share a port and are always started together. DoT and DoH each require their own port and certificate.


DNS/UDP and DNS/TCP

Standard DNS. UDP handles most queries; TCP is used automatically when a response exceeds the EDNS0 buffer size or for zone transfers (AXFR).

dns:
  listenAddr: "0.0.0.0"
  port: 53          # standard; use 5353 if running without root

No additional configuration is needed.


DNS over TLS (DoT)

Wraps the standard DNS wire format in a TLS connection on port 853 (RFC 7858). Resolvers like Quad9, Cloudflare 1.1.1.1, and Android Private DNS connect using DoT.

Configuration

dns:
  dot:
    enabled: true
    port: 853             # standard; omit to use the default
    certFile: "/etc/gslb/tls.crt"
    keyFile:  "/etc/gslb/tls.key"

certFile and keyFile are required when enabled: true. TLS 1.2 is the minimum version; TLS 1.3 is preferred.

Testing DoT

# kdig (from knot-dnsutils)
kdig -d @<nexus-server-ip> +tls-ca +tls-host=<hostname> gslb.cc SOA

# or with openssl
openssl s_client -connect <nexus-server-ip>:853 -servername <hostname>

DNS over HTTPS (DoH)

Serves DNS queries over HTTPS at a configurable path (default /dns-query) per RFC 8484. Supports both GET (with base64url-encoded ?dns= parameter) and POST (with application/dns-message body). HTTP/2 is used automatically when the client supports it.

Configuration

dns:
  doh:
    enabled: true
    port: 443             # standard; omit to use the default
    certFile: "/etc/gslb/tls.crt"
    keyFile:  "/etc/gslb/tls.key"
    path: "/dns-query"    # optional; defaults to /dns-query

certFile and keyFile are required when enabled: true.

Testing DoH

# GET (base64url-encoded query)
curl -s "https://<nexus-server-ip>/dns-query?dns=$(echo -n '\x00\x00\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x04gslb\x02cc\x00\x00\x01\x00\x01' | base64 -w0 | tr '+/' '-_' | tr -d '=')" \
  -H "Accept: application/dns-message" --output - | hexdump -C

# POST (recommended)
curl -s -X POST "https://<nexus-server>/dns-query" \
  -H "Content-Type: application/dns-message" \
  --data-binary @query.bin \
  -o response.bin

A simpler test with dog (a user-friendly DNS client):

dog gslb.cc SOA --https @https://<nexus-server>/dns-query

Browser / resolver configuration

To point Firefox or a system resolver at a Nexus DoH endpoint:

  • Firefox: Preferences → Network Settings → DNS over HTTPS → Custom → https://<nexus-server>/dns-query
  • Android: Private DNS → <nexus-server-hostname> (uses DoT; DoH is browser-level only)
  • Windows 11: Network adapter → DNS → "DNS over HTTPS" → https://<nexus-server>/dns-query

Sharing port 443 with the API or WebUI

The DoH listener is a separate http.Server instance from the API server. If both DoH and the API server need port 443, run the API on a different port and put a reverse proxy (Caddy/nginx) in front to route /dns-query to the DoH port.

Caddy example:

nexus.example.com {
    # Route DoH queries to the DoH listener
    handle /dns-query {
        reverse_proxy 127.0.0.1:5443
    }
    # Everything else goes to the API/WebUI
    handle {
        reverse_proxy 127.0.0.1:8080
    }
}

In this setup, configure DoH on a non-standard port (port: 5443) and bind it to 127.0.0.1.


Mutual TLS (mTLS) for DoT/DoH

Nexus does not currently enforce client certificate authentication on DoT or DoH endpoints. For intranet deployments that require mTLS, place a TLS-terminating proxy (Caddy with tls { client_auth { mode require_and_verify } }) in front of the DoT/DoH ports.


Cache-Control on DoH responses

Nexus sets Cache-Control: max-age=<min-ttl> on DoH responses, derived from the minimum TTL across all answer records. Responses with no answer records receive Cache-Control: no-cache, no-store. This allows RFC 8484-compliant clients to cache responses without a separate caching proxy.


Listener status

The cluster status page in the WebUI shows which DNS transports are active on each node, along with the ports they are listening on. The same information is available via the API:

curl https://nexus-api.example.com/api/v1/cluster/status \
  -H "Authorization: Bearer $GSLB_API_KEY" | jq .dns

Response:

{
  "udp": true,
  "tcp": true,
  "dot": true,
  "doh": false,
  "udpPort": 53,
  "tcpPort": 53,
  "dotPort": 853
}


Was this article helpful?
© 2026