// Engineering Log
What is Caddy: a web server with automatic HTTPS, in simple terms
Published on 2026-09-22
// Fast route
This article belongs to the topic Deploy and reliability.
What is Caddy
Caddy is a web server and reverse proxy that automatically obtains and renews TLS certificates for your domains. Just specify the site name in the configuration, and Caddy will expose it over HTTPS: no certbot, cron jobs, or manual TLS setup required.
The project is written in Go and distributed under the Apache 2.0 license. Current version as of September 2026 — 2.11.4 (June 2026). Caddy is shipped as a single executable with no external dependencies; there is an official package repository for Debian and Ubuntu and a Docker image caddy.
How automatic HTTPS works
For a public domain Caddy obtains a certificate itself if three conditions are met: the domain’s A or AAAA DNS records point to the server, ports 80 and 443 are reachable from the internet, and Caddy has the right to listen on them. By default two ACME certificate authorities are used — Let’s Encrypt and ZeroSSL: if Let’s Encrypt does not issue a certificate, Caddy tries ZeroSSL. Renewal happens in advance and without administrator involvement.
Certificates and keys are stored in Caddy’s data directory. It must be persistent and writable: if the directory is lost, for example when recreating a container without a volume, Caddy requests certificates again and may hit CA rate limits.
For names that cannot get a public certificate — localhost, internal addresses — Caddy issues certificates with its own local certificate authority and attempts to add its root certificate to the system trust store. If there are insufficient permissions (in a container or under an unprivileged user), install the root certificate with the caddy trust command or copy it manually.
Installation
On Debian and Ubuntu Caddy is installed from the official repository:
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo chmod o+r /usr/share/keyrings/caddy-stable-archive-keyring.gpg
sudo chmod o+r /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddyAfter installation Caddy runs as a systemd service caddy, configuration is located at /etc/caddy/Caddyfile. Changes are applied with sudo systemctl reload caddy without interrupting current connections.
Caddyfile: a reverse proxy in three lines
The application listens on port 3000 on the same server, and needs to be exposed at app.example.ru:
app.example.ru {
reverse_proxy localhost:3000
}This is enough: Caddy will obtain a certificate, redirect HTTP to HTTPS, and forward requests to the application. Multiple services are described in separate blocks:
app.example.ru {
reverse_proxy localhost:3000
}
api.example.ru {
reverse_proxy localhost:8000
}
www.example.ru {
redir https://example.ru{uri} permanent
}Static site with response compression:
example.ru {
root * /var/www/example
file_server
encode gzip zstd
}Load balancing between multiple instances of the application is specified in the same directive:
app.example.ru {
reverse_proxy 10.0.0.11:8080 10.0.0.12:8080 {
lb_policy round_robin
health_uri /health
}
}Before applying, it’s useful to check the configuration with caddy validate --config /etc/caddy/Caddyfile, and to normalize its style with caddy fmt.
HTTPS for local development
For development on your own computer use localhost:
localhost {
reverse_proxy localhost:3000
}Caddy will issue a certificate from its local CA, and the browser will open https://localhost without warnings if the root certificate is installed. For custom internal names add the line tls internal to the site block.
Don’t invent names in public zones like app.dev: .dev is a real top-level domain, a certificate for someone else’s name won’t be issued, and browsers require HTTPS for the entire .dev zone.
Caddy in Docker and CI/CD
The caddy image is convenient to connect to a project via Docker Compose: the Caddyfile is stored in the repository alongside the application, and the data directory is placed in a named volume so certificates survive container recreation. There are no steps in the build pipeline to obtain certificates: it is enough to validate the configuration with caddy validate and reload it after deployment.
Common mistakes
- Closed port 80. Even if the site works only over HTTPS, port 80 is needed for domain ownership verification and redirects. Closing it with a firewall will stop issuance and renewal of certificates.
- DNS points to the wrong server. While the A record points to the old hosting or to a CDN, a certificate will not be issued. Switch DNS first, then run Caddy.
- Lost data directory. A container without a volume requests certificates again on each recreation.
- Ports are occupied by another server. If nginx or Apache is already running on 80 and 443, Caddy will not start; two web servers cannot share the same ports.
- Expecting built-in protection from everything. Rate limiting and bot protection are not included in the standard build and are added via third-party modules.
When to choose Caddy
Caddy is good when you need to quickly publish several sites or services over HTTPS on a single server and don’t want to manage certbot and lengthy configurations. If you need advanced load balancing with checks and limits or TCP proxying, see HAProxy; if the infrastructure is already built on nginx and its modules — Nginx; if services constantly appear and disappear in containers — Traefik. A comparison of all five servers is in the article “Caddy vs. Traefik vs. HAProxy vs. Nginx vs. Apache”.
// Similar task
If you are dealing with something similar
This article belongs to one of the main working topics. You can keep reading on the topic, go to the homepage to understand what I do, or open the service pages directly.
Article topic
Deploy and reliability
Docker, CI/CD, releases, monitoring, observability, and incident handling.
Typical tasks behind this topic
- Set up deployment without manual chaos
- Add monitoring, alerts, and baseline observability
- Investigate incidents and stabilize production
// Next step
If you need help with this topic, not just another article, it is better to go straight to the service page. The homepage and topic collection stay available as secondary routes.
Open services// Reviews
Related reviews
Mikhail is an outstanding professional! You can tell he has a great deal of experience. The work was done precisely and on time. We had to tinker a bit because the project installed on the server wasn't perfect, but Mikhail carefully and thoughtfully guided us on what to do and how. In the end, everything worked! I recommend him to anyone who values quality.
Mikhail is an excellent performer! You can tell he has a wealth of experience. The work was done precisely and on time. We had to tinker due to imperfections in the project that was being installed on the server, but …
// Contact
Need help?
Get in touch with me and I'll help solve the problem
I reply within one business day (03:00-13:00 GMT)
Или оставьте заявку здесь:
// Related