How to Set Up the Caddy Web Server on Ubuntu (With Automatic HTTPS)
If you have ever spent an afternoon wrestling with certbot, cron renewal jobs, and verbose virtual-host blocks, the appeal of Caddy becomes obvious within minutes. Caddy is a modern, open-source web server written in Go that does one thing better than almost anything else in its class: it handles TLS certificates for you, automatically. Put a real domain in your config, reload the server, and Caddy obtains and renews a Let’s Encrypt certificate with no extra steps. This guide walks through how to setup Caddy on Ubuntu from the official apt repository, write your first Caddyfile, manage the service with systemd, and use Caddy as a reverse proxy for an application backend.
Key Takeaways
• Caddy is a modern web server known for automatic HTTPS — it obtains and renews Let’s Encrypt certificates with zero manual configuration.
• You install it on Ubuntu from Caddy’s official apt repository (add the repo key and source, then `apt install caddy`).
• Configuration lives in a Caddyfile with simple, readable syntax: a site block per domain, plus directives like `reverse_proxy` and `file_server`.
• Caddy runs as a systemd service; you manage it with `systemctl` and apply config changes with `caddy reload` (a graceful, zero-downtime reload).
• To get an automatic certificate, you only need a real, publicly resolvable domain pointed at your server’s IP.
What is Caddy and why use it on Ubuntu?
Caddy is a general-purpose web server and reverse proxy designed for simplicity and security by default. Where older servers treat HTTPS as an opt-in feature you bolt on afterward, Caddy treats encrypted connections as the default behavior. When you specify a domain name in your configuration, Caddy automatically provisions a publicly trusted TLS certificate through the ACME protocol (using Let’s Encrypt or ZeroSSL) and keeps it renewed in the background.
A few qualities make Caddy especially attractive for Ubuntu servers:
- Readable configuration. The Caddyfile format is concise and human-friendly compared to the block-heavy syntax of older servers.
- Automatic HTTPS. No separate certificate tooling, no renewal cron jobs, no manual restarts after a cert rotates.
- Single static binary. Caddy ships as one self-contained executable with sane, secure defaults.
- Built-in reverse proxy. Proxying to a Node.js, Python, Go, or other application backend is a one-line directive.
Caddy suits everything from a small static site to a production application gateway, which is why it has become a popular choice for developers provisioning their own .
How do you install Caddy on Ubuntu from the official apt repository?
The recommended way to setup Caddy on Ubuntu is through the official Cloudsmith-hosted apt repository maintained by the Caddy project. This gives you signed packages and clean upgrades through your normal package manager. Run the following commands on Ubuntu (these work on current LTS releases such as 22.04 and 24.04):
“`bash
sudo apt update 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 apt update sudo apt install -y caddy “`
After installation, verify the binary and confirm the service is running:
“`bash caddy version systemctl status caddy “`
Installing the package via apt automatically registers Caddy as a systemd service and starts it. If you open your server’s IP address in a browser at this point, you’ll see Caddy’s default welcome page — proof the web server is live.
What does a Caddyfile look like?
The Caddyfile is the heart of Caddy’s configuration. When you install via apt, the default config lives at `/etc/caddy/Caddyfile`. Its structure is built around site blocks: each block begins with one or more addresses (a domain, a port, or a wildcard) followed by directives inside curly braces.
A static file server
The simplest useful site serves static files. The `file_server` directive turns a directory into a website:
“`caddyfile example.com { root * /var/www/example.com file_server } “`
Because `example.com` is a real domain, Caddy will automatically obtain and serve a valid HTTPS certificate for it — you don’t add a single line about TLS.
A reverse proxy to an application backend
The most common production use case is putting Caddy in front of an application — a Node.js API on port 3000, a Python service on port 8000, or similar. The `reverse_proxy` directive handles this:
“`caddyfile app.example.com { reverse_proxy localhost:3000 } “`
That two-line block gives you a public HTTPS endpoint at `app.example.com` that transparently forwards traffic to your backend on port 3000 — with the certificate fully managed for you.
Combining directives and multiple sites
A single Caddyfile can hold many sites and mix directives. For example, serving a static marketing site while proxying an API:
“`caddyfile example.com { root * /var/www/site file_server encode gzip }
api.example.com { reverse_proxy localhost:8080 } “`
Here is a quick reference for the directives you’ll reach for most often when you setup Caddy on Ubuntu:
| Caddyfile directive | What it does |
|---|---|
| `root * |
Sets the document root for the site |
| `file_server` | Serves static files from the root directory |
| `reverse_proxy |
Forwards requests to a backend app or service |
| `encode gzip zstd` | Compresses responses for faster delivery |
| `tls |
Customizes TLS/ACME behavior (optional — auto by default) |
| `header` | Adds or modifies response headers |
| `redir` | Issues HTTP redirects |
How do you run and manage Caddy with systemd?
Because the apt package installs Caddy as a systemd service, day-to-day management uses familiar `systemctl` commands:
“`bash sudo systemctl status caddy # check service health sudo systemctl start caddy # start the service sudo systemctl stop caddy # stop the service sudo systemctl restart caddy # full restart sudo systemctl enable caddy # start on boot (default after apt install) “`
After editing `/etc/caddy/Caddyfile`, you don’t need a disruptive restart. The preferred way to apply changes is a graceful reload, which loads the new configuration with zero downtime:
“`bash sudo systemctl reload caddy “`
Before reloading, it’s good practice to validate your configuration so a typo doesn’t take the site offline:
“`bash caddy validate –config /etc/caddy/Caddyfile “`
If you want to format the Caddyfile consistently, `caddy fmt –overwrite /etc/caddy/Caddyfile` tidies indentation and spacing. Logs are available through `journalctl -u caddy –no-pager` for troubleshooting.
The killer feature, stated plainly: Caddy’s automatic HTTPS is not a plugin, a wizard, or a setup step you run once — it is the server’s default mode of operation. The moment a publicly resolvable domain appears in a site block and that domain’s DNS points at your server, Caddy completes an ACME challenge, installs a Let’s Encrypt certificate, and schedules its own renewal well before expiry. There is no `certbot` to install, no renewal cron job to forget, no manual `nginx -s reload` after a cert rotates, and no 2 a.m. outage because a certificate quietly expired. You manage domains, and Caddy manages certificates — that division of labor is the entire reason teams switch.
How does automatic HTTPS actually work?
When Caddy starts a site that uses a domain name, it performs an ACME challenge with the certificate authority to prove you control that domain. For this to succeed, two conditions must hold:
- Your domain’s DNS must resolve to your server’s public IP address (an A or AAAA record).
- Ports 80 and 443 must be reachable from the internet so the certificate authority can validate the challenge. Make sure your firewall (and any cloud security group) allows them:
“`bash sudo ufw allow 80/tcp sudo ufw allow 443/tcp “`
Once validated, Caddy stores the certificate, serves HTTPS, transparently redirects HTTP to HTTPS, and renews automatically. This is exactly why a reliable network and stable public IP matter — automatic HTTPS depends on the certificate authority being able to reach your server consistently.
How does Caddy compare to Nginx and Apache?
Caddy, Nginx, and Apache are all capable web servers, and the right pick depends on your priorities. The table below summarizes the practical trade-offs.
| Factor | Caddy | Nginx / Apache |
|---|---|---|
| HTTPS setup | Automatic, zero-config | Manual (certbot + renewal) |
| Configuration style | Concise Caddyfile | More verbose, block-heavy |
| Default security | HTTPS by default | HTTP by default |
| Maturity & ecosystem | Newer, growing | Long-established, vast |
| Granular tuning | Good for most needs | Extremely fine-grained |
| Module ecosystem | Plugins via xcaddy | Huge module library |
In short: Caddy wins on simplicity and automatic HTTPS, while Nginx and Apache win on maturity, ecosystem breadth, and fine-grained control for highly specialized workloads. For most modern web apps and reverse-proxy scenarios, Caddy gets you to a secure, production-ready state with dramatically less configuration. If your team already runs a large, finely tuned legacy stack, the established servers remain excellent. Many administrators even run them side by side on different .
Run Caddy on infrastructure you fully control
To install and run Caddy (or Nginx, or Apache) the way this guide describes, you need a server with root access and a stable, well-connected network so automatic HTTPS can complete its certificate challenges reliably. DarazHost VPS and dedicated servers give you exactly that: full root control to install your preferred web server, point a domain, and configure a Caddyfile however your project demands. With fast SSD storage, a dependable network for ACME validation and uptime, and 24/7 expert support, DarazHost is a solid foundation for hosting sites and application backends behind Caddy. Explore or to get started.
Frequently asked questions
Do I need to install certbot to get HTTPS with Caddy? No. Caddy includes automatic HTTPS natively. As long as a real, publicly resolvable domain is in your Caddyfile and ports 80 and 443 are open, Caddy obtains and renews Let’s Encrypt certificates on its own — certbot is unnecessary.
Where is the Caddyfile located after installing via apt? The default Caddyfile lives at `/etc/caddy/Caddyfile`. Edit it with your preferred editor, run `caddy validate` to check it, then apply changes with `sudo systemctl reload caddy`.
Can Caddy serve HTTPS for localhost or an internal domain? Yes. For local development, Caddy issues its own internally trusted certificate for hostnames like `localhost`. Publicly trusted Let’s Encrypt certificates, however, require a real domain that the certificate authority can validate over the internet.
How do I reload Caddy without downtime after changing the config? Use `sudo systemctl reload caddy` (or `caddy reload –config /etc/caddy/Caddyfile`). This performs a graceful reload that applies the new configuration without dropping active connections.
Is Caddy a good choice as a reverse proxy? Yes — it is one of Caddy’s strongest use cases. A single `reverse_proxy localhost:PORT` directive gives any app backend a public HTTPS endpoint with automatic certificates, load-balancing options, and health checks built in.