DNS-01 & Wildcard Certificates
Relevant source files
The following files were used as context for generating this wiki page:
Kamal-proxy implements a robust certificate management system that supports both HTTP-01 and DNS-01 challenges. The DNS-01 implementation is critical for provisioning wildcard certificates, which cannot be validated via standard HTTP challenges. The system centralizes these operations within the SANCertManager, utilizing the go-acme/lego library to interface with various DNS providers.
This module allows for automated SAN (Subject Alternative Name) batching, per-zone DNS provider mapping, and opportunistic collapsing of subdomains into wildcard certificates to minimize ACME API rate limit consumption.
Sources: CLAUDE.md:14-15, internal/server/san_cert_manager.go:68-87
Architecture and Components
The certificate management architecture is built around the SANCertManager, which coordinates between the ACME client, domain grouping logic, and specific challenge solvers.
Component Overview
| Component | Responsibility |
|---|---|
SANCertManager | The primary orchestrator for certificate lifecycle, batching, and storage. |
DomainGrouper | Analyzes domain sets to determine if they should be collapsed into wildcards. |
certObtainer | Interface for the ACME issuance strategy (DNS-01 vs HTTP-01). |
ProviderSelection | Logic for routing specific domains to specific DNS providers based on zone mappings. |
DynamicDomainManager | Manages certificates for domains discovered at runtime via external sources. |
Sources: internal/server/san_cert_manager.go:90-136, internal/server/domain_group.go:60-70, internal/server/dynamic_domains.go:73-85
Logical Flow of Certificate Issuance
The following diagram illustrates how the proxy decides between DNS-01 and HTTP-01, and how wildcards are handled.
The system prioritizes DNS-01 when a provider is available but allows for HTTP-01 fallback for non-wildcard domains if configured.
Sources: internal/server/san_cert_issuance.go:23-61
Wildcard Strategy and Domain Grouping
Wildcard certificates (*.example.com) are utilized to cover multiple single-level subdomains under a registrable root. The DomainGrouper determines the optimal strategy based on the available DNS providers and the nature of the requested domains.
Grouping Logic
- Root Domain Identification: Uses Public Suffix List to identify the registrable domain (e.g.,
example.com). - Subdomain Analysis: Checks if subdomains are single-level (e.g.,
app.example.comis valid,api.v1.example.comis multi-level). - Strategy Selection:
- StrategyWildcard: Selected if 2 or more subdomains exist,
PreferWildcardis enabled, and a DNS provider is available. - StrategySAN: Batches up to 100 concrete domains into one certificate if wildcarding is not possible.
- StrategyIndividual: Default for single domains or where grouping is inappropriate.
- StrategyWildcard: Selected if 2 or more subdomains exist,
Sources: internal/server/domain_group.go:88-164, internal/server/san_cert_manager.go:48-52
Domain Collapsing in Issuance
During the planIssuanceDomains phase, sibling subdomains are collapsed into a wildcard identifier. Notably, the apex domain is always included separately because a wildcard (*.example.com) does not cover the root (example.com).
Sources: internal/server/san_cert_issuance.go:74-100, internal/server/domain_group.go:175-185
DNS-01 Provider Configuration
The proxy supports multiple DNS providers simultaneously. This is necessary for fleets managing domains across different DNS hosts (e.g., Cloudflare and Hetzner).
Per-Zone Mapping
Configuration allows mapping specific DNS zones to specific providers. The SANCertManager maintains a registry of dnsObtainers indexed by provider name.
Credentials and Initialization
DNS providers are initialized using environment variables (e.g., CLOUDFLARE_DNS_API_TOKEN). If a zone mapping is explicitly configured but the required credentials for that provider are missing, the proxy will fail to boot to prevent silent issuance failures.
Sources: internal/server/san_cert_zones.go:28-36, internal/server/acme/providers/factory.go:44-54
Partitioning and Rate Limiting
To maintain stability and adhere to ACME provider constraints, the proxy enforces strict partitioning and rate limiting.
Provider Partitioning
An ACME order cannot span multiple DNS providers. If a batch of domains covers multiple zones handled by different providers, the splitByProviderZone function partitions the batch. The proxy only issues the partition containing the requested domain, returning others to the "pending" state.
Sources: internal/server/san_cert_zones.go:100-120, internal/server/san_cert_issuance.go:106-116
Token Bucket Rate Limit
All issuance paths—whether triggered by a TLS handshake, a dynamic domain poll, or a certificate renewal—must acquire a token from a shared tokenBucket. This prevents the proxy from exceeding ACME order limits during massive service deployments or domain discovery.
Sources: internal/server/san_cert_manager.go:114-116, internal/server/san_cert_manager.go:463-466, internal/server/dynamic_domains.go:100-107
Summary of DNS-01 Features
| Feature | Description | File Path |
|---|---|---|
| Wildcard Support | Provisioning of *.domain.com certificates. | san_cert_issuance.go |
| Multi-Provider | Support for different DNS providers for different zones. | san_cert_zones.go |
| Auto-Detection | Detection of DNS provider from environment variables. | acme/providers/factory.go |
| SAN Batching | Combining up to 100 domains to reduce API calls. | san_cert_manager.go |
| Pre-flight Probes | Verifying domain routing before attempting ACME orders. | dynamic_domains.go |
DNS-01 and wildcard certificate support in kamal-proxy provides the necessary infrastructure for large-scale, multi-tenant environments where standard HTTP-01 challenges are insufficient. By utilizing zone-based routing and intelligent domain grouping, the system ensures efficient and reliable TLS termination.