This is because by default, the php_fastcgi directive is set up to use index.php as a fallback with try_files. Most modern PHP applications use index.php as a request router, so 404s are typically served by the index.
If this isn’t how you want to set up your index, what you can do instead is add the 404 fallback to the end of your own try_files to override the one built-into php_fastcgi. I’m not sure how the best way to return HTTP status 404 if doing it with a fallback like that though. I’ll get back to you on that after some experimentation.
For all the other most common HTTP error codes, I will wait for the PR to be reviewed hoping to have a general solution with the handle_errors directive.
That’s right, Caddy v2 doesn’t have a status directive. I had a typo in my post originally, I think I changed it to status_code while you were typing your response. The PR I wrote is to add a new status_code directive, so it doesn’t exist yet in the build you’re using.
The problem with respond here is that it doesn’t continue the middleware chain if it’s encountered, so it won’t allow a fallthrough to file_server, it’ll instead just serve an empty HTTP 404 response.
My PR is to add a new status_code directive that does continue the middleware chain but just ensures the status code is set at the end.
This might ultimately change though, there’s a possibility we make an update to the respond directive to make it continue the middleware chain if no body is specified.
You might have noticed that doing it that way, your HTTP request will still return HTTP status 200 even though your 404.html page is rendered. That’s not really ideal if any bots or whatever make requests to your site, because they’ll think any URL at all is a valid page. That’s why the status_code directive (or an improved respond directive) is needed for you here.