eZ Community » Blogs » Gaetano Giunta » Tricks of the trade: "displaying nice...

By

Tricks of the trade: "displaying nice error pages" whatever the error is

Friday 18 October 2013 12:05:54 pm

  • Currently 5 out of 5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

This is a request I get from customers often enough that I decided to write a blog post about it.

The need is often phrased differently, but it boils down to "how can I show nice error pages for any type of error possibly happening on my site?".

eZPublish, being the flexibility behemot we all know, already supports tweaking the error pages displayed for common cases such as bad urls (404) or access denied.

Still, the problem is a bit more complex than that, and for a really comprehensive solution we will need to complement eZ tweaking with changes to the webserver configuration.

The following discussion assumes that the webserver in use is Apache, and that php runs as an Apache module - this is by far the most common way to deploy eZ Publish. Similar results can be achieved by using Varnish, Nginx, or php in fastcgi mode.

What is the cause for errors anyway?

When the customers who desire the "nice error page" get asked about the type of errors which are produced by their application, they tend to answer "I have no clue, I just want to catch ALL of them".

Well...

Let's start trying to classify all types of errors which can happen on an eZ site. So far, I have found the following:

  1. errors due to user action, which the eZ kernel understands (user mistypes url or tries to access content he has no right to see). Those are the "kernel errors" defined in error.ini
  2. errors due to the database not being accessible
  3. errors due to a sql error. This has a different effect if happening inside or outside a transaction
  4. errors due to the php script timing out (max. execution time for all php pages is set in php.ini)
  5. errors due to the php script consuming too much memory (again, this is a safety limit set in php.ini)
  6. errors due to fatal php errors (php code not compiling, or compiling but not executing, such as calling a method on a non-object variable)
  7. webserver itself is stopped / hanging / gone on holiday

How can we make sure that the user gets a "nice" page for all the errors above?

Error pages have to be generated not-by-eZPublish

The php engine offers many possibilities to catch error conditions, and to execute code at the end of every request. It is tempting to use such facilities to inject "catch-all" error handlers.

But this will not do.

If we only try to handle all errors from php code running in the eZ Publish context, we are not safe from invalid-php code which prevents the php engine to even start code execution (php code is first parsed then executed).

Error pages have to be static

If we rely on an external php script to dynamically generate the error page (generally a simpler script than the full eZ Publish stack), we might still incur in problems with configuration of php which prevent it from executing at all.

Again, this will not do.

How can we have static pages with the same design as the website?

If the error page has to have the same look and feel that the "real" website, I would thus recommend to set up an error page in eZ with the desired appearance, and use a cronjob to download that page and save it on the hard disk somewhere accessible to the webserver.

How can we configure the webserver to use the desired static pages for all error conditions?

This is where things get a little tricky:

  • Apache has configuration directives to use custom content for error conditions
  • These directives can be used to trap f.e. any url for a missing design resource (css, js, image)
  • They can not be used to trap requests for missing content (those requests are sent to eZ frontend controller file)
  • They can not be used to trap requests resulting in eZ Publish / php sending back a response with an http error code (such as 500, sent back in cases 2, 3, 4, 5 and 6 above). This is because the php engine sends back an error status code for the browser but it internally tells to Apache "all is fine, I finished execution ok"

To overcome this, we can use the built-in proxy module of Apache:

  • the "main site" vhost gets moved behind a "reverse proxy" vhost
  • in the "reverse proxy" vhost, we can trap all errors coming from the "main site", and serve a nice page instead of whatever is in the original response

Without further ado, here is an example of such a vhost configuration:

Listen 88
 
<VirtualHost *:88>
    # Enable reverse proxy
    ProxyPass / http://localhost/
    ProxyPassReverse / http://localhost/
    ProxyRequests off
    # Enable name-based vhost on the upstream server
    ProxyPreserveHost On
    # Log separately
    CustomLog "logs/access_proxy.log" common
    
    # Catch errors 
    ProxyErrorOverride On
    ErrorDocument 500 /errortests/500.html
    
    # Note that if we do not set this up, 404 pages returned from eZ will be
    # discarded in favour of a "plain" apache response
    # works
    ErrorDocument 404 /errortests/404.html
    # works as well - but 404.php has no way of knowing what the originally requested URL was
    #ErrorDocument 404 /errortests/404.php
 
    # ...to be finished: all other error codes!
</VirtualHost>

With this in place, we can be fairly sure that all error types 1 to 6 are managed.

Are there any limitations?

Of course there are.

  1. with this setup, even the standard "kernel errors" pages served by eZPublish get discarded in favour of the static error pages from Apache. Unfortunately there is no way to tell Apache to only rewrite responses for error 500 and let through error 404
  2. this setup might have problems if you use basic-auth, NTLM or such other schemes relying on 401 responses
  3. if the Apache server itself is down, the reverse proxy will not work. A commonly-thought-of workaround would be to use a separate server to host the reverse proxy, but remember: the more hardware you add to your setup, the more you increase the chances for a failure are (statistics!). To be really safe, you would need to have 2 reverse-proxy machines, in load-balancing configuration
  4. what if my upstream internet provider has problems? or if there is an earthquake and there is no more power? Well, though luck. But... unless your website is the red-cross or first-aid one, let me tell you one thing: probably your users have better stuff to do than spend time online to check it out!

Is that all?

This is enough for this instalment. Please feel free to add any comments, questions or if you have even better solutions.

Proudly Developed with from