Caddy v2 rewrites its internal architecture from the ground up, ditching the monolithic plugin system for a modular, dynamic configuration that allows for hot-reloading without dropping connections.

Let’s see Caddy v2 in action. Imagine you have a simple static site and want to serve it over HTTPS, automatically.

# First, install Caddy v2 (using a package manager is easiest)
# Example for Debian/Ubuntu:
sudo apt install caddy

# Now, create a Caddyfile for your site
cat <<EOF > Caddyfile
example.com {
    root * /var/www/example.com
    file_server
}
EOF

# Start Caddy (this command will vary by installation method)
sudo systemctl start caddy

# And that's it. Caddy will now serve your site from /var/www/example.com
# and automatically obtain and renew an SSL certificate from Let's Encrypt.
# You can verify this by visiting https://example.com in your browser.

The core problem Caddy v2 solves is the complexity of modern web serving: managing TLS certificates, routing requests, load balancing, and serving static files or dynamic applications, all while being easy to configure and operate. It aims to be a "batteries-included" web server that requires minimal boilerplate.

Internally, Caddy v2 uses a request pipeline. When a request comes in, it’s processed by a series of modules defined in its configuration. These modules can be anything from TLS handlers, static file servers, reverse proxies, to authentication modules. The configuration is dynamic, meaning you can change it on the fly without restarting Caddy.

Here’s a breakdown of the key components and how they interact:

  • caddy.json (or Caddyfile): This is your configuration. It defines the sites Caddy will serve, their properties, and the request handlers for each.
  • modules: Caddy v2 is built on a powerful module system. Almost every feature is a module. This makes it extensible and allows for a smaller core binary.
  • request pipeline: For each request, Caddy builds a pipeline of modules. The request flows through these modules, each potentially modifying the request or response, until it’s handled.
  • dynamic config: You can update the configuration while Caddy is running. Caddy will load the new configuration and apply it to new incoming requests without interrupting existing ones. This is often referred to as "hot-reloading."

To migrate from Caddy v1 to v2, the primary change is the configuration format. Caddy v1 used a custom format that was often less structured. Caddy v2 supports two main formats: the Caddyfile (an enhanced, more structured version of the v1 Caddyfile) and JSON. For most users, migrating to the v2 Caddyfile is the simplest path.

Here’s a comparison of a simple v1 Caddyfile and its v2 equivalent:

Caddy v1:

example.com {
    root /var/www/example.com
    gzip
    tls your@email.com
}

Caddy v2 (Caddyfile):

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

Notice the changes:

  • root /var/www/example.com becomes root * /var/www/example.com. The * is a placeholder for matching any path within the root directory.
  • gzip becomes encode gzip. This is part of the new encode directive which supports multiple compression algorithms.
  • tls your@email.com is automatically handled by Caddy v2 if you use a public domain name. You no longer need to explicitly specify your email for automatic HTTPS. Caddy v2 defaults to using Let’s Encrypt. If you need custom TLS configurations, you’d use the tls directive with specific options.

The file_server directive in v2 is a dedicated handler for serving static files, replacing the implicit behavior in v1’s root. Caddy v2 also has a more robust directive system. For instance, instead of just proxy, you have reverse_proxy with many more options for health checks, load balancing algorithms, and more.

The most surprising true thing about Caddy v2’s configuration is how it handles dynamic updates. You don’t just send a SIGHUP signal to reload. Instead, you can use the caddy reload command (or the Admin API) which performs a zero-downtime configuration swap. This means not only are existing connections preserved, but the transition between the old and new configuration is virtually instantaneous for new requests, ensuring a seamless user experience.

The next concept you’ll likely encounter is the Caddy v2 Admin API, which allows for programmatic control and integration of Caddy into larger orchestration systems.

Want structured learning?

Take the full Caddy course →