Caddy Server: Automatic HTTPS Without Configuration
PROGRAMMING LANGUAGES March 14, 2026, 11:30 p.m.

Caddy Server: Automatic HTTPS Without Configuration

Caddy Server has become the go‑to web server for developers who want HTTPS without spending hours tweaking TLS settings. In just a few lines of configuration Caddy can fetch, install, and renew certificates automatically, letting you focus on building your app instead of wrestling with OpenSSL.

What Is Caddy and Why Automatic HTTPS Matters

Caddy is a modern, cross‑platform web server written in Go. Its hallmark is the zero‑config philosophy: you write a simple Caddyfile, start the binary, and Caddy does the rest. This includes provisioning TLS certificates from Let’s Encrypt (or any ACME‑compatible CA) the moment a request arrives.

Automatic HTTPS removes the biggest barrier to secure deployments. No more manual CSR generation, no cron jobs to reload certificates, and no risk of serving stale or mismatched keys. For small projects, startups, and even large enterprises, the time saved translates directly into faster releases and happier users.

Zero‑Config Philosophy in Action

  • Write a domain name, and Caddy talks to the ACME server.
  • Certificates are stored securely on disk and rotated automatically.
  • HTTPS is enforced by default; HTTP is redirected unless you explicitly opt out.

How Caddy Gets HTTPS for Free

Behind the scenes Caddy implements the ACME protocol, the same standard Let’s Encrypt uses. When a client connects, Caddy checks if a valid certificate exists for the host. If not, it initiates a challenge—typically HTTP‑01 or TLS‑ALPN‑01—to prove domain ownership.

Once the challenge succeeds, Let’s Encrypt issues a certificate, which Caddy stores and immediately serves. The process repeats automatically before the certificate expires, usually 30 days before the 90‑day validity window closes.

Certificate Lifecycle

  1. Domain name appears in the Caddyfile.
  2. Caddy queries its local storage for an existing cert.
  3. If missing or expiring, Caddy starts an ACME challenge.
  4. Let’s Encrypt validates the challenge and returns a cert.
  5. Caddy saves the cert and serves it on the next request.
  6. Renewal is triggered automatically, without downtime.

Getting Started: A Minimal Caddyfile

The fastest way to see Caddy’s magic is to write a one‑liner Caddyfile. Place this file in the same directory as the Caddy binary and run caddy run. Caddy will listen on port 80, perform the ACME handshake, and serve HTTPS on port 443.

example.com {
    root * /var/www/example
    file_server
}

In this snippet:

  • example.com tells Caddy which host to manage.
  • root * sets the document root for static files.
  • file_server enables a simple static file handler.

When you navigate to https://example.com, Caddy silently obtains a certificate, redirects HTTP to HTTPS, and serves the files from /var/www/example. No extra flags, no TLS blocks, no secret keys.

Real‑World Use Cases

1. Hosting a Static Site on a Custom Domain

Static sites are the bread and butter of Caddy’s automatic HTTPS. Whether you’re using a static site generator like Hugo or just plain HTML, Caddy can serve it securely with zero extra work.

myblog.com {
    root * /srv/myblog/public
    encode gzip
    file_server
}

The encode gzip directive compresses assets on the fly, improving load times while the HTTPS layer stays fully managed.

2. Securing a JSON API Behind a Reverse Proxy

Many modern applications expose a RESTful API that needs TLS termination at the edge. Caddy can act as a reverse proxy, handling HTTPS and forwarding traffic to an internal service running on a private port.

api.myapp.com {
    reverse_proxy localhost:8080
    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
    }
}

Here, Caddy terminates TLS, adds a strong HSTS header, and proxies requests to the backend. The backend can remain HTTP‑only, simplifying container networking.

3. Multi‑Domain SaaS Platform with On‑Demand TLS

For SaaS platforms serving hundreds of custom subdomains (e.g., customer1.app.com, customer2.app.com), pre‑provisioning certificates is impractical. Caddy’s on‑demand TLS feature obtains certificates the first time a new host is requested.

{
    on_demand_tls {
        ask      https://auth.myplatform.com/allow
        interval 12h
    }
}

*.app.com {
    reverse_proxy localhost:9000
}

The global block enables on‑demand TLS and defines an ask endpoint that authorizes which domains may receive a certificate. This protects you from abuse while keeping the user experience seamless.

Pro tip: Cache the results of your ask endpoint locally to reduce latency on subsequent certificate requests.

Advanced Tweaks Without Breaking Automation

While Caddy works great out of the box, real deployments often need fine‑tuning. The good news is that most tweaks integrate cleanly with the automatic TLS flow.

Custom TLS Parameters

If you need to enforce a specific TLS version or cipher suite, you can add a tls block without disabling automatic renewal. Caddy will apply the settings to newly issued certificates while still handling renewals.

secure.example.com {
    tls {
        protocols tls1.2 tls1.3
        ciphers TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
    }
    reverse_proxy localhost:5000
}

Only the selected host receives these constraints; other sites continue with the defaults.

Wildcard Certificates for Subdomains

Wildcard certificates reduce the number of ACME requests when you control many subdomains under a single parent domain. Caddy can request a wildcard cert using DNS‑01 challenges, provided you supply API credentials for your DNS provider.

{
    acme_dns cloudflare {
        api_token $CLOUDFLARE_API_TOKEN
    }
}

*.example.org {
    tls {
        dns cloudflare
    }
    file_server
}

Replace cloudflare with the appropriate DNS provider module. The tls { dns cloudflare } stanza tells Caddy to use the DNS‑01 challenge, which is required for wildcard issuance.

Pro tip: Store your DNS API tokens in environment variables and reference them with $VARIABLE to keep secrets out of the Caddyfile.

Common Pitfalls & How to Debug

Even with automation, things can go sideways. Understanding the most frequent issues helps you resolve them quickly.

  • Port 80 blocked: ACME HTTP‑01 challenges need port 80 reachable from the internet. Ensure firewalls or cloud security groups allow inbound traffic.
  • Rate limiting: Let’s Encrypt enforces strict limits (e.g., 50 certificates per domain per week). Use wildcard certs or on‑demand TLS to stay within limits.
  • DNS propagation delays: DNS‑01 challenges require the TXT record to be visible globally. Some DNS providers have slow propagation; consider using a provider with low TTL.

Caddy’s built‑in logging provides clear insight. Run Caddy with --log-level DEBUG to see the ACME flow, challenge attempts, and renewal actions.

caddy run --config Caddyfile --adapter caddyfile --log-level DEBUG

Look for lines prefixed with acme to trace certificate issuance. Errors will often include a descriptive message such as “dns challenge failed” or “http challenge timeout”.

Pro tip: Use Caddy’s admin API (http://localhost:2019) to query the current certificate status programmatically. For example, curl localhost:2019/idle returns JSON with certificate expiry dates.

Performance and Security Benefits of Automatic HTTPS

Beyond convenience, automatic TLS brings measurable performance gains. Modern browsers prioritize HTTPS connections and enable HTTP/2 by default. Caddy’s HTTP/2 and optional HTTP/3 support means lower latency and better multiplexing for static assets and API calls.

Security-wise, Caddy enforces best‑practice defaults: HSTS with preload, secure headers, and OCSP stapling. Because certificates are renewed automatically, you avoid the dreaded “certificate expired” outage that can happen with manual processes.

Integrating Caddy into CI/CD Pipelines

Automation doesn’t stop at runtime. You can embed Caddy in your build pipeline to validate configuration syntax and test TLS acquisition in a staging environment.

# Example GitHub Actions step
- name: Validate Caddyfile
  run: |
    docker run --rm -v ${{github.workspace}}:/etc/caddy caddy:2 caddy validate --config /etc/caddy/Caddyfile

Running Caddy in a container ensures the same binary version across developers and CI agents, eliminating “it works on my machine” discrepancies.

Scaling Caddy in Production

When you need to serve millions of requests, you can horizontally scale Caddy behind a load balancer. Because each instance handles its own TLS lifecycle, you don’t need a shared certificate store—Caddy will fetch the same cert on each node.

For Kubernetes users, the official Caddy Helm chart supports automatic TLS out of the box. Simply annotate your Ingress with caddy.io/auto_https: "on" and let the controller manage certs for every service.

Conclusion

Caddy Server’s automatic HTTPS feature transforms what used to be a manual, error‑prone process into a seamless, developer‑friendly experience. By leveraging ACME, on‑demand TLS, and smart defaults, Caddy lets you launch secure sites, APIs, and SaaS platforms with just a few lines of configuration. Whether you’re serving a personal blog or a multi‑tenant production service, Caddy’s zero‑config approach saves time, reduces risk, and keeps your users’ data protected—all without you having to touch a private key.

Share this article