Creating custom status pages in Caddy v2

Using Caddy Version: v2.0.0-rc.3 h1:z2H/QnaRscip6aZJxwTbghu3zhC88Vo8l/K57WUce4Q=

On Platform: Ubuntu Server 18.04 LTS, 64bit


Now that RC3 is out and the software is nearing its 2.0 release, is there a defined way to create custom status pages within a Caddyfile?

I’ve run across V2: How to achieve custom 404 here on the community forum which told me to see the handle_errors directive or configure the server with JSON which seems significantly more complex than authoring a simple Caddyfile. In addition, the page for the handle_errors doesn’t provide a lot of information for how to configure the errors, only that the handle_errors block should contain <directives>, which brings me back to the directives page but it doesn’t seem like any of the other directives will do what I want Caddy to do which is to serve a custom page instead of a generic 404 that throws the browser’s 404 page or nothing at all.

I guess I could add a try_files or respond directive to serve something to the user, but I wouldn’t even know from reading the handle_errors documentation page what the proper syntax to use would be. This seems like a pretty major thing to resolve for end users before rolling out Caddy v2, as I imagine I can’t be alone in scratching my head on this one.

The way to do it currently is with the (still experimental) CEL expression matcher

handle_errors {
    @404 {
        expression {http.error.status_code} == 404
    }
      
    respond @404 "Oops 404 Try again"
}

You can also match against a list of status codes:

expression {http.error.status_code} in [500, 502]

Good question, it’s on our list! Probably a 2.1 milestone or something: v2: Caddyfile errors directive · Issue #3261 · caddyserver/caddy · GitHub

It’s tricky because there are so many ways to handle errors, which ones do we streamline? We have to be choosy so as to not make the Caddyfile too complex.

To clarify, v2.0 does not mean that we’re doing writing new features. It just means that the foundation is stable. Actually, 2.0 means the beginning of new features, and polish, and better documentation, and more tests, etc. etc. now that the foundation is pretty solid.

The Caddyfile, as nice as it is, is just a (pretty thick, heavy) wrapper over the core of Caddy’s JSON config, so it’s seldom our first priority for development: any features that are proposed and planned and developed aren’t done so from the perspective of the Caddyfile (but an eventual Caddyfile integration is sometimes considered so that it’s easier when that time comes) – but sooner or later, the Caddyfile usually ends up being extended to support the most demanded features. And error pages is one of them, so feel free to contribute to the discussion in the linked issue above and let us know what you’d like to see, and how you’d like it to work!

1 Like

Thanks Matt for your detailed response! I might look into the JSON configuration so I can define my errors in a concrete way, or perhaps even look at the API if I’m able to set them from there. Appreciate it and congratulations on rolling out 2.0!

1 Like

A follow up to anyone that might know: if I were to author a JSON file using the errors object would I still use the expression matcher or is there another way to configure error routes when working with the JSON config that’s more succinct? Been looking at the output from caddy adapt but not super clear on how routes work yet. Wondering if there are any examples to check out somewhere.

That is probably the way you want to do it for now, there are other ways but that is most succinct. For now.

You can learn about how routes work right here in the docs for routes: Modules - Caddy Documentation :slight_smile:

(Routes work the same for both the primary handlers and the error handlers.)

Trying to implement this to return a page instead of a static response. Figured something like this would work but it just returns a blank page. What am I missing?

handle_errors {
  @404 {
    expression {http.error.status_code} == 404
  }

  rewrite @404 /404.html
}

I think you need a file_server directive in there as well for it to actually serve the file.

2 Likes

That did it! thank you!

Hello,
I am also trying to manage custom error templates. I have read this Caddy 2 handle_error examples with custom error pages? - #8 by francislavoie which helped me for this Caddyfile setup.

Let’s say I want to redirect all “errors” status on a specific url /error with a custom template.
So far, here is what is working :

handle_errors {
    @404 {
        expression {http.error.status_code} == 404
    }
    redir @404 /error
}

route /error {
	rewrite * /lib/tpl/error.php
}

Using the ‘in [404,403,500]’ syntax also works for the expression.

I also can use the handle directive instead of route :

handle /error {
	rewrite * /lib/tpl/error.php
}

I am not sure about the difference but the handle seems prefereable as it is just an internal rewrite.

Here is the json part for this :

I hope it can help even if I feel it’s not perfect.

Thanks for sharing :slight_smile:

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