Serve and route requests
Shape the response
Add compression, security headers, redirects, and rewrites while keeping internal and client-visible changes distinct.
10 minute lesson
A response is more than a body. Headers, compression, and redirects all shape what the client receives, and Caddy gives each one a small directive.
Get the vocabulary right first, because two similar-sounding things behave very differently. A redirect is visible to the client: Caddy answers with a 3xx status and a Location header, and the client makes a second request. A rewrite is internal: Caddy changes the URI it processes, and the client never finds out.
:8080 {
encode zstd gzip
header X-Content-Type-Options nosniff
redir /old /new 308
respond /new "new location"
}
encode compresses responses when the client supports it. header sets a response header on every response. redir sends the client from /old to /new with a permanent 308 — pick 308 over 301 when the request method must survive the redirect, because clients may turn a 301 POST into a GET.
Watch the redirect happen:
curl -I http://127.0.0.1:8080/old
curl -L http://127.0.0.1:8080/old
The first command shows the raw 308 Permanent Redirect with Location: /new. The second follows it and prints the final body. Two requests happened — you can see both in the log.
Now inspect the headers on the destination:
curl -s -D - -H "Accept-Encoding: gzip" http://127.0.0.1:8080/new -o /dev/null
You’ll see X-Content-Type-Options: nosniff on the response. Don’t worry if Content-Encoding is missing here: encode skips tiny bodies, where compression costs more than it saves. Serve a real HTML file and it kicks in.
A word of caution on security headers. nosniff is safe nearly everywhere. But don’t paste a full Content-Security-Policy from a blog post. CSP describes what your site actually loads, so a copied one either breaks the site or allows so much that it protects nothing. Derive it from your application’s real behavior, one directive at a time, and test after each addition.
Lesson completed