Caddy’s automatic TLS provisioning is so robust that most people never even think about it, yet it’s the engine that makes "just works" possible.

Let’s provision a wildcard certificate for *.example.com and see how Caddy handles it.

# Assume you have Caddy installed and running.
# Create a Caddyfile in your current directory.
echo '
*.example.com {
    reverse_proxy localhost:8080
}
' > Caddyfile

# Start Caddy in the foreground for easy monitoring.
# You'll see it automatically obtain a certificate.
caddy run

When you hit https://app.example.com (or any subdomain), Caddy will:

  1. Intercept the request: It sees a request for a hostname it doesn’t have a certificate for.

  2. Check ACME challenges: It knows it needs to prove control over *.example.com to an ACME server (like Let’s Encrypt).

  3. Choose a challenge type: By default, Caddy prefers the HTTP-01 challenge for simplicity when it’s already serving HTTP or HTTPS. If that’s not feasible (e.g., no open ports), it falls back to DNS-01.

  4. Perform the challenge:

    • HTTP-01: Caddy temporarily serves a specific file (/.well-known/acme-challenge/...) on the requested hostname. The ACME server queries this file over HTTP. For wildcard certificates, this is not directly supported by HTTP-01 for the wildcard itself. Instead, Caddy will typically provision a separate certificate for each specific subdomain requested that matches the wildcard pattern, or use a shared certificate for all subdomains if configured. The wildcard is a pattern, not a single certificate for all subdomains at once through HTTP-01.
    • DNS-01: This is the primary method for provisioning wildcard certificates. Caddy needs to create a TXT record in your DNS zone. You’ll need to configure Caddy with your DNS provider’s API credentials. The TXT record will look something like _acme-challenge.example.com with a specific token value. Caddy then tells the ACME server to check this record. Once validated, the ACME server issues the certificate.

    Example DNS-01 Configuration (using Cloudflare):

    *.example.com {
        reverse_proxy localhost:8080
    
        tls {
            dns cloudflare {
                api_token YOUR_CLOUDFLARE_API_TOKEN
            }
        }
    }
    

    Replace YOUR_CLOUDFLARE_API_TOKEN with your actual Cloudflare API token. Caddy will then use this token to create the necessary _acme-challenge TXT records.

  5. Issue and install certificate: Upon successful validation, the ACME server issues the certificate, and Caddy automatically downloads and installs it, ready to serve HTTPS.

The Mental Model:

Caddy acts as an ACME client. When a client (your browser) requests a hostname for which Caddy doesn’t have a valid certificate, Caddy initiates a process to obtain one. For wildcard domains (*.example.com), the DNS-01 challenge is the standard and most reliable method. Caddy automates the interaction with your DNS provider to create the necessary TXT records, proving you control the domain. Once validated, it gets the certificate and serves it. The reverse_proxy directive is just one example of what you can do once Caddy is serving your domain securely.

The core problem Caddy solves here is the operational overhead of managing TLS certificates. Manually obtaining, renewing, and deploying certificates for multiple subdomains is a significant burden. Caddy abstracts this entirely. The tls directive, when left to its defaults, tells Caddy to "do whatever it takes" to get a certificate. For wildcards, this means enabling DNS-01 challenges.

The Caddyfile you saw is extremely simple. The *.example.com pattern tells Caddy to match any subdomain under example.com. When a request comes in for app.example.com, Caddy needs a certificate for app.example.com. If app.example.com is the first subdomain requested that matches *.example.com, Caddy will initiate the ACME process. If you later request api.example.com, Caddy will check if it already has a wildcard certificate that covers api.example.com. If it doesn’t, it might obtain a new certificate for api.example.com or extend the existing wildcard coverage if the ACME server supports it and Caddy’s configuration allows. The key is that Caddy provisions individual certificates for specific hostnames that match the wildcard pattern, rather than one giant certificate for all subdomains.

The reverse_proxy directive is where the actual traffic goes after Caddy has secured the connection. Caddy acts as a reverse proxy, terminating TLS and forwarding the request to your backend application, which might be running on localhost:8080 or any other address.

The most surprising thing about Caddy’s wildcard provisioning is that it doesn’t provision a single, monolithic certificate for *.example.com that magically covers all subdomains simultaneously via HTTP-01. Instead, it uses the wildcard pattern to trigger the acquisition of certificates for specific subdomains as they are requested, primarily using the DNS-01 challenge. This means Caddy is constantly interacting with your DNS provider behind the scenes to ensure coverage for any subdomain you throw at it.

If you haven’t configured a dns provider within the tls directive for wildcard certificates, Caddy will likely fail to provision them and instead present you with a public, insecure, self-signed certificate for the first subdomain it encounters that matches the pattern.

You’ll next want to explore managing multiple domains and subdomains within a single Caddyfile.

Want structured learning?

Take the full Caddy course →