{ # The panel is the only thing served, and it is behind a login: no reason # for the server to announce its version to anybody scanning. frankenphp order php_server before file_server auto_https off servers { trusted_proxies static private_ranges } } {$SERVER_NAME:-:80} { root * /app/public encode zstd gzip # Uploaded images. `public/storage` is a symlink into the storage volume, # so this is what actually serves what the collective uploads — and it is # the one path an SSR frontend fetches on every page view, so it is cached # hard and never touched by PHP. @media path /storage/* header @media Cache-Control "public, max-age=31536000, immutable" # The frontend is a separate application on another origin. @api path /api/* header @api { X-Content-Type-Options nosniff } header { X-Content-Type-Options nosniff X-Frame-Options SAMEORIGIN Referrer-Policy strict-origin-when-cross-origin -Server } php_server { # Laravel's own health route, so the container can be probed without # touching the database. try_files {path} /index.php } # The health probe runs every 30 seconds and would otherwise be most of # the access log. `log_skip` is the directive for this — `exclude` inside # `log` is not valid in Caddy 2. @health path /up log_skip @health log { output stdout format json } }