Caddy’s magic isn’t just that it serves HTTP/3; it’s that it just works with almost zero configuration.
Let’s see Caddy in action. Imagine you have a static HTML file named index.html in a directory called site:
<!DOCTYPE html>
<html>
<head>
<title>Hello, HTTP/3!</title>
</head>
<body>
<h1>Welcome to my HTTP/3 server!</h1>
</body>
</html>
To serve this file over HTTP/3, all you need is this Caddyfile:
:443 {
root * /path/to/your/site
file_server
}
Now, run Caddy with this configuration:
caddy run --config /path/to/your/Caddyfile
When you visit https://your-domain.com in a modern browser (like Chrome or Firefox), Caddy will automatically negotiate HTTP/3 if your client and network support it. You’ll see your index.html file served, and if you inspect the network tab in your browser’s developer tools, you’ll see the connection is indeed using the h3 protocol. Caddy handles the TLS certificate acquisition (via Let’s Encrypt by default) and the QUIC handshake automatically.
The core problem Caddy solves is simplifying modern web serving. Historically, setting up TLS, managing certificates, configuring HTTP/2, and then adding HTTP/3 was a complex, multi-step process involving various tools and intricate configurations. Caddy consolidates all of this into a single, opinionated binary. It prioritizes sensible defaults and automates the tedious parts.
Internally, Caddy leverages the quic-go library for its HTTP/3 implementation. When a client initiates a connection to Caddy’s HTTPS port (443 by default), Caddy first performs a standard TLS handshake over TCP. If the client supports QUIC and the h3 ALPN (Application-Layer Protocol Negotiation) extension is advertised during the TLS handshake, Caddy will then initiate a QUIC connection. The HTTP/3 frames are then multiplexed over this QUIC connection. Caddy’s internal request processing pipeline, defined by directives like file_server and reverse_proxy, operates on top of this HTTP/3 connection.
The most surprising thing about Caddy is its automatic certificate management. You don’t need to manually generate CSRs, obtain certificates from an authority, or configure renewal. As long as Caddy can reach the Let’s Encrypt ACME server on ports 80 or 443 from the public internet for the domain it’s serving, it will automatically obtain and renew certificates for you. This is enabled by default for any site configured with a domain name. If you use an IP address or a private hostname, it won’t attempt automatic certificate management.
The next concept you’ll likely encounter is how to integrate Caddy with backend applications using reverse_proxy, especially when those backends might not directly support HTTP/3 themselves.