V2 Custom error handling

My Caddy version



Debian 10


    root * /var/www
    import common.conf


# php hook
php_fastcgi unix//var/run/php/php7.3-fpm.sock

# compress response
encode gzip

# clean url
try_files {path}.php {path} 

# logging
log {
    output file /var/log/caddy/access.log

# custom errors
handle_errors {
    @404 {
        expression {http.error.status_code} == 404
    rewrite @404 /err_img/404.html


When a non existent page is requested, the custom 404 is not served. The index.php at root dir is served instead.

simplified log entry for fake.html

No redirection. Status 200

2020-04-26 06:54:03||/fake.html|GET|HTTP/2.0|200|

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.

I wrote a PR to add a feature that should make this easier for you in Caddy v2.1


You would do something like this:

try_files {path}.php {path} /err_img/404.html
status_code /err_img/404.html 404
1 Like

With the second line status I get:

reload: adapting config using caddyfile: /etc/caddy/common.conf:9: unrecognized directive: status

According to the doc, status is a V1 directive that has been replaced by respond. I adapted your suggestion accordingly.

This config doesn’t work: the custom 404.html is not served.

try_files {path}.php {path} /err_img/404.html
respond /err_img/404.html 404

This one does work.

try_files {path}.php {path} /err_img/404.html

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.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.