Document global DNS config for ACME
- commit
- 0b16d6a9f036f233cdd290a606e7da2bdb566fd3
- author
- brice · · 2026-05-01 14:01 UTC
- parent
- 0537081
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
2 files · +22 -0
M docs/config/reference.md +11 -0
| @@ -23,6 +23,14 @@ registry_allowed_ips = [] # IPs or CIDR ranges allowed to acc | |||
| 23 | 23 | proxy_allowed_ips = [] # IPs or CIDR ranges allowed to reach the proxy (empty = allow all, e.g. Cloudflare IPs) | |
| 24 | 24 | registry_listen_address = "" # Bind address for registry (empty = all interfaces, "127.0.0.1" = loopback only) | |
| 25 | 25 | ||
| 26 | + | # ============================================================================= | |
| 27 | + | # DNS | |
| 28 | + | # ============================================================================= | |
| 29 | + | [dns] | |
| 30 | + | resolvers = ["1.1.1.1:53", "8.8.8.8:53"] # Recursive resolvers for public DNS visibility checks | |
| 31 | + | propagation_timeout = "5m" # Max wait for DNS-01 TXT propagation | |
| 32 | + | polling_interval = "5s" # Interval between DNS-01 propagation checks | |
| 33 | + | ||
| 26 | 34 | # ============================================================================= | |
| 27 | 35 | # AUTHENTICATION (required - Gordon won't start without credentials configured) | |
| 28 | 36 | # ============================================================================= | |
| @@ -204,6 +212,9 @@ keep_last = 3 # Keep N newest tags per repository | |||
| 204 | 212 | | `server.registry_allowed_ips` | `[]` | IPs or CIDR ranges allowed to access the registry (empty = allow all) | | |
| 205 | 213 | | `server.proxy_allowed_ips` | `[]` | IPs or CIDR ranges allowed to reach the proxy (empty = allow all) | | |
| 206 | 214 | | `server.registry_listen_address` | `""` | Bind address for registry (empty = all interfaces) | | |
| 215 | + | | `dns.resolvers` | `["1.1.1.1:53", "8.8.8.8:53"]` | Recursive resolvers used for public DNS visibility checks, including ACME DNS-01 propagation | | |
| 216 | + | | `dns.propagation_timeout` | `"5m"` | Maximum time to wait for DNS-01 TXT records to become visible through configured recursive resolvers | | |
| 217 | + | | `dns.polling_interval` | `"5s"` | Interval between DNS-01 propagation checks | | |
| 207 | 218 | | `tls.acme.enabled` | `false` | Enable public ACME certificates (requires `server.tls_port > 0`) | | |
| 208 | 219 | | `tls.acme.email` | `""` | ACME account email when enabled | | |
| 209 | 220 | | `tls.acme.challenge` | `"auto"` | ACME challenge mode: `auto`, `http-01`, or `cloudflare-dns-01` | | |
| @@ -23,6 +23,14 @@ registry_allowed_ips = [] # IPs or CIDR ranges allowed to acc | |||||
| 23 | proxy_allowed_ips = [] # IPs or CIDR ranges allowed to reach the proxy (empty = allow all, e.g. Cloudflare IPs) | 23 | proxy_allowed_ips = [] # IPs or CIDR ranges allowed to reach the proxy (empty = allow all, e.g. Cloudflare IPs) | ||
| 24 | registry_listen_address = "" # Bind address for registry (empty = all interfaces, "127.0.0.1" = loopback only) | 24 | registry_listen_address = "" # Bind address for registry (empty = all interfaces, "127.0.0.1" = loopback only) | ||
| 25 | 25 | ||||
| 26 | + | # ============================================================================= | |||
| 27 | + | # DNS | |||
| 28 | + | # ============================================================================= | |||
| 29 | + | [dns] | |||
| 30 | + | resolvers = ["1.1.1.1:53", "8.8.8.8:53"] # Recursive resolvers for public DNS visibility checks | |||
| 31 | + | propagation_timeout = "5m" # Max wait for DNS-01 TXT propagation | |||
| 32 | + | polling_interval = "5s" # Interval between DNS-01 propagation checks | |||
| 33 | + | ||||
| 26 | # ============================================================================= | 34 | # ============================================================================= | ||
| 27 | # AUTHENTICATION (required - Gordon won't start without credentials configured) | 35 | # AUTHENTICATION (required - Gordon won't start without credentials configured) | ||
| 28 | # ============================================================================= | 36 | # ============================================================================= | ||
| @@ -204,6 +212,9 @@ keep_last = 3 # Keep N newest tags per repository | |||||
| 204 | | `server.registry_allowed_ips` | `[]` | IPs or CIDR ranges allowed to access the registry (empty = allow all) | | 212 | | `server.registry_allowed_ips` | `[]` | IPs or CIDR ranges allowed to access the registry (empty = allow all) | | ||
| 205 | | `server.proxy_allowed_ips` | `[]` | IPs or CIDR ranges allowed to reach the proxy (empty = allow all) | | 213 | | `server.proxy_allowed_ips` | `[]` | IPs or CIDR ranges allowed to reach the proxy (empty = allow all) | | ||
| 206 | | `server.registry_listen_address` | `""` | Bind address for registry (empty = all interfaces) | | 214 | | `server.registry_listen_address` | `""` | Bind address for registry (empty = all interfaces) | | ||
| 215 | + | | `dns.resolvers` | `["1.1.1.1:53", "8.8.8.8:53"]` | Recursive resolvers used for public DNS visibility checks, including ACME DNS-01 propagation | | |||
| 216 | + | | `dns.propagation_timeout` | `"5m"` | Maximum time to wait for DNS-01 TXT records to become visible through configured recursive resolvers | | |||
| 217 | + | | `dns.polling_interval` | `"5s"` | Interval between DNS-01 propagation checks | | |||
| 207 | | `tls.acme.enabled` | `false` | Enable public ACME certificates (requires `server.tls_port > 0`) | | 218 | | `tls.acme.enabled` | `false` | Enable public ACME certificates (requires `server.tls_port > 0`) | | ||
| 208 | | `tls.acme.email` | `""` | ACME account email when enabled | | 219 | | `tls.acme.email` | `""` | ACME account email when enabled | | ||
| 209 | | `tls.acme.challenge` | `"auto"` | ACME challenge mode: `auto`, `http-01`, or `cloudflare-dns-01` | | 220 | | `tls.acme.challenge` | `"auto"` | ACME challenge mode: `auto`, `http-01`, or `cloudflare-dns-01` | | ||
M docs/config/server.md +11 -0
| @@ -92,6 +92,11 @@ Gordon can obtain public certificates through Let's Encrypt-compatible ACME when | |||
| 92 | 92 | [server] | |
| 93 | 93 | tls_port = 8443 | |
| 94 | 94 | ||
| 95 | + | [dns] | |
| 96 | + | resolvers = ["1.1.1.1:53", "8.8.8.8:53"] | |
| 97 | + | propagation_timeout = "5m" | |
| 98 | + | polling_interval = "5s" | |
| 99 | + | ||
| 95 | 100 | [tls.acme] | |
| 96 | 101 | enabled = true | |
| 97 | 102 | email = "admin@example.com" | |
| @@ -114,6 +119,12 @@ For Cloudflare Full/Strict, Cloudflare terminates browser TLS at the edge and co | |||
| 114 | 119 | ||
| 115 | 120 | Static certificates have priority, then public ACME certificates, then Gordon's internal CA fallback. Gordon uses the `go-acme/lego` ACME client, including its DNS-provider support for Cloudflare DNS-01. | |
| 116 | 121 | ||
| 122 | + | DNS-01 uses the Cloudflare API to create TXT records, then checks public DNS visibility through `[dns].resolvers`. These resolvers are recursive resolvers (for example Cloudflare DNS or Google DNS), not the authoritative DNS provider. A domain can be hosted at Cloudflare while Gordon verifies propagation through Google DNS. | |
| 123 | + | ||
| 124 | + | The defaults avoid relying on host-local DNS. This matters on hosts using Tailscale MagicDNS, split-horizon corporate DNS, or Pi-hole, where `/etc/resolv.conf` may not reflect public DNS visibility as Let's Encrypt sees it. | |
| 125 | + | ||
| 126 | + | Because Gordon's ACME challenge mode is global, `cloudflare-dns-01` requires a Cloudflare token that can read zones and edit DNS records for every zone used by configured HTTPS routes. If that is not desirable, use `http-01` until Gordon supports per-route or per-zone challenge policy. | |
| 127 | + | ||
| 117 | 128 | #### Direct HTTP Onboarding | |
| 118 | 129 | ||
| 119 | 130 | When `tls_port` is non-zero, direct HTTP clients (those not arriving through a trusted proxy) are restricted to CA onboarding paths only: | |
| @@ -92,6 +92,11 @@ Gordon can obtain public certificates through Let's Encrypt-compatible ACME when | |||||
| 92 | [server] | 92 | [server] | ||
| 93 | tls_port = 8443 | 93 | tls_port = 8443 | ||
| 94 | 94 | ||||
| 95 | + | [dns] | |||
| 96 | + | resolvers = ["1.1.1.1:53", "8.8.8.8:53"] | |||
| 97 | + | propagation_timeout = "5m" | |||
| 98 | + | polling_interval = "5s" | |||
| 99 | + | ||||
| 95 | [tls.acme] | 100 | [tls.acme] | ||
| 96 | enabled = true | 101 | enabled = true | ||
| 97 | email = "admin@example.com" | 102 | email = "admin@example.com" | ||
| @@ -114,6 +119,12 @@ For Cloudflare Full/Strict, Cloudflare terminates browser TLS at the edge and co | |||||
| 114 | 119 | ||||
| 115 | Static certificates have priority, then public ACME certificates, then Gordon's internal CA fallback. Gordon uses the `go-acme/lego` ACME client, including its DNS-provider support for Cloudflare DNS-01. | 120 | Static certificates have priority, then public ACME certificates, then Gordon's internal CA fallback. Gordon uses the `go-acme/lego` ACME client, including its DNS-provider support for Cloudflare DNS-01. | ||
| 116 | 121 | ||||
| 122 | + | DNS-01 uses the Cloudflare API to create TXT records, then checks public DNS visibility through `[dns].resolvers`. These resolvers are recursive resolvers (for example Cloudflare DNS or Google DNS), not the authoritative DNS provider. A domain can be hosted at Cloudflare while Gordon verifies propagation through Google DNS. | |||
| 123 | + | ||||
| 124 | + | The defaults avoid relying on host-local DNS. This matters on hosts using Tailscale MagicDNS, split-horizon corporate DNS, or Pi-hole, where `/etc/resolv.conf` may not reflect public DNS visibility as Let's Encrypt sees it. | |||
| 125 | + | ||||
| 126 | + | Because Gordon's ACME challenge mode is global, `cloudflare-dns-01` requires a Cloudflare token that can read zones and edit DNS records for every zone used by configured HTTPS routes. If that is not desirable, use `http-01` until Gordon supports per-route or per-zone challenge policy. | |||
| 127 | + | ||||
| 117 | #### Direct HTTP Onboarding | 128 | #### Direct HTTP Onboarding | ||
| 118 | 129 | ||||
| 119 | When `tls_port` is non-zero, direct HTTP clients (those not arriving through a trusted proxy) are restricted to CA onboarding paths only: | 130 | When `tls_port` is non-zero, direct HTTP clients (those not arriving through a trusted proxy) are restricted to CA onboarding paths only: | ||