2026-10-23 · Q&A guide

Nginx: Route 404s to PHP-FPM for Custom Error Pages

Fix Nginx 404 handling by using error_page with recursive processing to pass requests to PHP-FPM for dynamic custom error pages.

Why Standard Configs Fail

The default `error_page 404 = /error404.php;` directive often fails because Nginx attempts to serve the file directly from the filesystem if the `location` block is not explicitly configured to handle internal redirects. When a 404 occurs, Nginx looks for the file defined in `error_page`. If that file is a PHP script, Nginx must re-route the request to the PHP handler. Without proper internal redirect handling, Nginx serves the raw file or fails silently, displaying the default HTML error page.

Enable Recursive Error Pages

The critical directive is `recursive_error_pages on;`. This allows Nginx to process error pages if the error page handler itself generates an error or if the initial request was already an error. Without this, if the `error_page` directive points to a PHP file, and that PHP file triggers another 404 or 500, Nginx will not re-process the error, leading to the default Nginx error output.

Correct Location Block Configuration

Ensure your PHP location block includes `try_files` or relies on the `root` directive correctly. The `error_page` directive must be placed in the same context as the `location` block or the `server` block to apply properly.

```nginx server { listen 80; server_name mydomain.co.uk; root /var/www/viovet_frontend; # Critical: Allow error pages to be processed recursively recursive_error_pages on; # Define the error page handler error_page 404 /error404.php; location ~ \.php$ { try_files $uri =404; include /etc/nginx/fastcgi.conf; fastcgi_pass phpfastcgiservers; fastcgi_intercept_errors on; } } ```

Handling Non-404 Errors

If you only want to intercept 404s and let other errors (like 500) pass through to the default handler, specify only the 404 code in `error_page`. For other status codes, ensure `fastcgi_intercept_errors on;` is set if you want Nginx to handle them, or remove it to let PHP-FPM return its own error headers and body.

Debugging Internal Redirects

Use `X-Forwarded-For` and `X-Real-IP` headers in your PHP error page to verify that the original request URI is being passed correctly. If the PHP script still doesn't execute, check the Nginx error log for `open() failed` or `Permission denied` errors related to the `error404.php` file path.

Takeaway: Use `recursive_error_pages on;` and ensure the `error_page` directive points to a valid PHP file handled by your FastCGI location block.

People also ask

Why does my PHP error page show the Nginx default page?

Nginx is not re-routing the internal request to the PHP handler. Ensure `recursive_error_pages on;` is set and the PHP location block is correctly defined.

Can I use `error_page 404 = @error;` instead?

Yes, this creates a named location `@error` that you can explicitly route to your PHP script, offering more control over the internal redirect logic.

Inspired by a public discussion on Stack Overflow. This article is an original explanation for learners.

← All posts