Serve and route requests
Shape the response
Add compression, security headers, redirects, and rewrites while keeping internal and client-visible changes distinct.
A response is more than a body. Headers, compression, and redirects all shape what the client receives. Caddy gives each one a small directive.
Redirect vs rewrite
Let’s 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 to the new address. The URL in the browser changes.
A rewrite is internal. Caddy changes the URI it processes, and the client never finds out. The URL in the browser stays the same.
Three directives
Here’s a site block that uses compression, a header, and a redirect:
:8080 {
encode zstd gzip
header X-Content-Type-Options nosniff
redir /old /new 308
respond /new "new location"
}
encode compresses responses when the client says it supports it. header sets a response header on every response. redir sends the client from /old to /new.
Notice the 308 status. Pick 308 over 301 when the request method must survive the redirect. Some clients turn a 301 POST into a GET, and a 308 forbids that.
Watch the redirect happen
Two curl commands show both halves:
curl -I http://127.0.0.1:8080/old
curl -L http://127.0.0.1:8080/old
The first prints the raw 308 Permanent Redirect with Location: /new. The second follows the redirect and prints new location. Two requests happened, and you can see both in the log.
Inspect the headers
Now let’s look at 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 in the response. Don’t worry if Content-Encoding is missing. encode skips tiny bodies, where compression costs more than it saves. Serve a real HTML file and it kicks in.
Be careful with security headers
nosniff is safe nearly everywhere. It tells browsers to trust your Content-Type and not guess.
But don’t paste a full Content-Security-Policy from a blog post. A CSP describes what your site loads: which scripts, which styles, which images. A copied one either breaks your site or allows so much that it protects nothing. Build it from your application’s real behavior, one directive at a time, and test after each addition.
Try this: change 308 to 301 and repeat the curl -I command. Then send a POST with curl -X POST -L -v to both versions and compare the method curl uses on the second request. With 301 it becomes a GET. With 308 it stays a POST.
Lesson completed