1. The problem I’m having:
I’m trying to setup Caddy to proxy traffic to a KirbyCMS instance and I want it to send a specific Cache-Control
header for my /media/
path when the response is a non-successful one. I’ve tried a few different matchers and using routes vs handles but can’t seem to get the right combo going.
At the moment if I make a successful request (like below) you can see that on the response the correct Cache-Control
header is added.
❯ curl -vso/dev/null 'http://localhost:8080/media/pages/reviews/we-are-warriors/a7746fefba-1730334929/jloh-600x.avif' -H 'If-Modified-Since: Thu, 31 Oct 2024 00:35:47 GMT' -H 'If-None-Match: "d59kjp9nf5m21uov"' -H 'Priority: u=5'
* Host localhost:8080 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
* Trying [::1]:8080...
* Connected to localhost (::1) port 8080
GET /media/pages/reviews/we-are-warriors/a7746fefba-1730334929/jloh-600x.avif HTTP/1.1
Host: localhost:8080
User-Agent: curl/8.7.1
If-Modified-Since: Thu, 31 Oct 2024 00:35:47 GMT
If-None-Match: "d59kjp9nf5m21uov"
Priority: u=5
Accept: application/json, */*
* Request completely sent off
HTTP/1.1 304 Not Modified
Cache-Control: public,max-age=31536000,immutable
Etag: "d59kjp9nf5m21uov"
Server: Caddy
Vary: Accept-Encoding
Date: Thu, 31 Oct 2024 01:29:28 GMT
* Connection #0 to host localhost left intact
But if I make a 404 response, its also added:
❯ vcurl 'http://localhost:8080/media/pages/reviews/we-are-warriors/a7746fefba-1730334929s/jloh-600x.avif' -H 'If-Modified-Since: Thu, 31 Oct 2024 00:35:47 GMT' -H 'If-None-Match: "d59kjp9nf5m21uov"' -H 'Priority: u=5'
* Host localhost:8080 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
* Trying [::1]:8080...
* Connected to localhost (::1) port 8080
GET /media/pages/reviews/we-are-warriors/a7746fefba-1730334929s/jloh-600x.avif HTTP/1.1
Host: localhost:8080
User-Agent: curl/8.7.1
If-Modified-Since: Thu, 31 Oct 2024 00:35:47 GMT
If-None-Match: "d59kjp9nf5m21uov"
Priority: u=5
Accept: application/json, */*
* Request completely sent off
HTTP/1.1 404 Not Found
Cache-Control: public,max-age=31536000,immutable
Content-Type: text/html; charset=UTF-8
Server: Caddy
Status: 404 Not Found
X-Powered-By: PHP/8.2.7
Date: Thu, 31 Oct 2024 01:31:33 GMT
Content-Length: 563
I completely understand Caddy is acting as designed here and doing everything correctly, I would prefer to not add the Cache-Control
header in this instance though and fallback to the global one set elsewhere in the config.
I’ve tried changing my /media/*
handle to this:
# Define a matcher to check for successful responses (200 status code)
@success {
expression {http.error.status_code} == 0 || {http.error.status_code} == 200
}
header @success {
Cache-Control "public,max-age=31536000,immutable"
}
And also tried setting a default handle_error
block (I think this is what it should be used for?)
handle_errors 404 {
header {
Cache-Control "private,max-age=0,must-revalidate"
}
}
But no luck there.
Ideally I’d want:
- Serve file system assets directly
- Anything that isn’t on the FS pass to PHP
- If its a successful request for
/media/*
or/assets/*
, add the customCache-Control
header - Otherwise, use the default global one
Hopefully that makes sense?
2. Error messages and/or full log output:cat .
3. Caddy version:
❯ caddy --version
5.8.4
4. How I installed and ran Caddy:
Nix/DevBox adding to local dev environment.
a. System environment:
Installed via Nix/DevBox locally on OSX. DevBox runs the services by process-compose
, not quite sure what that is but it runs the service locally.
b. Command:
caddy run --config={$DEVBOX_PROJECT_ROOT}/devbox.d/caddy/Caddyfile
c. Service/unit/compose file:
version: "0.6"
processes:
caddy:
command: "caddy run --config=$CADDY_CONFIG"
availability:
restart: on_failure
max_restarts: 5
d. My complete Caddy config:
# See https://caddyserver.com/docs/caddyfile for more details
{
admin 0.0.0.0:2020
auto_https disable_certs
http_port 8800
https_port 4443
}
:8080 {
root * {$DEVBOX_PROJECT_ROOT}/public/
#encode gzip
handle /assets/* {
# Handle versioned assets
@versionedAssets {
path_regexp versionedAssets ^(.+)\.(?:[0-9a-f]+)\.(js|css)$
}
handle @versionedAssets {
# Try to serve the versioned file, then the unversioned file
try_files {path} {http.regexp.versionedAssets.1}.{http.regexp.versionedAssets.2}
header Cache-Control "public,max-age=31536000,immutable"
}
file_server {
precompressed br
}
}
handle /media/* {
php_fastcgi 127.0.0.1:{$PHPFPM_PORT} {
try_files {path} _internal/cache/pages/{path}/index.html _internal/cache/pages/{path} index.php
}
file_server {
precompressed br
}
header {
Cache-Control "public,max-age=31536000,immutable"
}
}
# Pass all other requests to PHP
handle {
header {
Cache-Control "public,max-age=0,must-revalidate"
}
php_fastcgi 127.0.0.1:{$PHPFPM_PORT} {
try_files {path} _internal/cache/pages/{path}/index.html _internal/cache/pages/{path} index.php
}
file_server {
precompressed br
}
}
header {
Cache-Control "public,max-age=0,must-revalidate"
}
log {
output file {$CADDY_LOG_DIR}/caddy.log
}
}
5. Links to relevant resources:
Thanks in advance for any help!