Default error messages and blank white screens degrade the user experience during outages or maintenance work. In Seravo's environment, you can implement custom maintenance and error pages at several levels, depending on how deep in the stack the error occurs:
WordPress drop-in files (
wp-content/): The recommended approach for maintenance mode (maintenance.php), database errors (db-error.php), and PHP fatal errors (php-error.php).Static
index.html: The fastest fallback solution that bypasses PHP entirely.Server-level rules (
nginx): Works even if the entire PHP process crashes.
WordPress Built-in Maintenance Mode (maintenance.php)
During updates, WordPress uses a built-in maintenance mode, which you can also toggle manually using WP-CLI commands:
# Enable maintenance mode
wp maintenance-mode activate
# Disable maintenance mode
wp maintenance-mode deactivate
When maintenance mode is active, WordPress automatically returns an SEO-friendly 503 Service Unavailable status code to visitors. You can customize the visual appearance of this page by creating the file /data/wordpress/htdocs/wp-content/maintenance.php and adding your own HTML structure and styles to it.
Server-Level Maintenance Page (nginx)
If you want to temporarily route all traffic to a maintenance page at the server level without loading WordPress, create the file /data/wordpress/nginx/maintenance.conf.
To prevent search engines from indexing the maintenance page as the site's actual content, always return a 503 HTTP status code and a Retry-After header:
# Redirect all requests except the maintenance file itself to a 503 status
if ($uri != "/maintenance.html") {
return 503;
}
error_page 503 @maintenance;
location @maintenance {
add_header Retry-After 3600 always;
rewrite ^(.*)$ /maintenance.html break;
}
Next, create the static /data/wordpress/htdocs/maintenance.html file and apply the nginx changes with the following command:
wp-restart-nginx
If you need to temporarily redirect all traffic to a completely different server, you can use the rule return 302 https://status.example.com/; instead.
Minimal Static Maintenance Page (index.html)
In Seravo's nginx configuration, index.html is prioritized as the primary directory index before index.php. If you place a file at /data/wordpress/htdocs/index.html, the server will serve it to all visitors arriving at the homepage without executing PHP or booting WordPress.
A static page serves as a highly effective fallback during events like a Distributed Denial of Service (DDoS) attack or a severe traffic spike, as delivering a simple HTML file consumes significantly fewer server resources than executing PHP and WordPress.
Custom Database Error Page (db-error.php)
If WordPress cannot establish a connection to the database, it automatically looks for a file at /data/wordpress/htdocs/wp-content/db-error.php. By creating this file, you can replace the stark default WordPress message with your own branded error page.
Be sure to set a 503 status code and disable caching at the top of the file so the error page is not stored in the HTTP cache:
<?php
http_response_code( 503 );
header( 'Retry-After: 600' );
header( 'Cache-Control: no-store, no-cache, must-revalidate, max-age=0' );
header( 'Pragma: no-cache' );
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Temporary Connection Error</title>
</head>
<body>
<h1>Site is Temporarily Unavailable</h1>
<p>A connection to the database could not be established right now. Please try again in a few minutes.</p>
</body>
</html>
Note: db-error.php is executed before the theme or plugins are loaded, meaning you cannot use WordPress theme functions (such as get_header()) within this file.
Custom PHP Fatal Error Pages (php-error.php and index.php)
Option A: WordPress Native php-error.php (Recommended)
Modern WordPress (version 5.2 and newer) includes a built-in Recovery Mode that catches fatal PHP errors and sends an email link to the administrator. You can customize the error page shown to visitors by creating /data/wordpress/htdocs/wp-content/php-error.php in the exact same manner as the db-error.php file above.
Option B: Early Shutdown Handler in index.php
If you also want to catch early parse errors (E_PARSE) that occur before WordPress's native error handler is loaded, you can register a PHP shutdown handler (register_shutdown_function) at the top of /data/wordpress/htdocs/index.php to display a static 500.html page to the visitor:
<?php
function custom_error_handler_at_shutdown() {
$error = error_get_last();
if ( $error && in_array( $error['type'], array( E_ERROR, E_PARSE ), true ) ) {
http_response_code( 500 );
header( 'Cache-Control: no-store, no-cache, must-revalidate, max-age=0' );
header( 'Pragma: no-cache' );
if ( file_exists( __DIR__ . '/500.html' ) ) {
include __DIR__ . '/500.html';
}
}
}
register_shutdown_function( 'custom_error_handler_at_shutdown' );
define( 'WP_USE_THEMES', true );
require __DIR__ . '/wordpress/wp-blog-header.php';
Custom Error Pages via nginx
We recommend handling errors primarily at the WordPress and PHP levels. However, if necessary, you can configure nginx to intercept error codes returned by PHP-FPM by creating /data/wordpress/nginx/error-pages.conf:
fastcgi_intercept_errors on;
error_page 500 502 503 504 /wp-content/500.html;
Apply the configuration with wp-restart-nginx.
Troubleshooting Note: Enabling fastcgi_intercept_errors on; replaces PHP's native error output with the static file, which can make debugging more difficult during development. Additionally, during certain outages, Seravo's HTTP cache may serve a stale cache version of the page instead of the error page.
Common Issues and Troubleshooting
Changes to
nginxsettings are not taking effect: The server does not load new.conffiles automatically. Always run thewp-restart-nginxcommand after making changes, and clear the cache usingwp-purge-cacheif necessary.Error or maintenance page gets stuck in the cache: Ensure your custom PHP error pages send the
Cache-Control: no-store, no-cache, must-revalidate, max-age=0header and return the correct error code (500or503) so the HTTP cache or browser does not save the error page as a normal page load.Maintenance mode stays on after an interrupted update: If the site displays "Briefly unavailable for scheduled maintenance" after an update has finished or failed, delete the hidden file
/data/wordpress/htdocs/.maintenancefrom the web root, or run the commandwp maintenance-mode deactivate.Custom
db-error.phporphp-error.phpdisplays a blank page: The file is likely calling WordPress theme or core functions (likewp_head()oresc_html()) that have not been loaded at the time the error occurs. Keep your error pages as fully standalone HTML/PHP files and check/data/log/php-error.logfor any underlying errors.
See Also
Well-designed error and maintenance pages keep your visitors informed during unexpected outages and protect your site's search engine visibility using proper HTTP status codes. If you need assistance testing custom nginx rules or error pages, our support team is ready to help at [email protected].
