NGINX: Step-by-Step Guide to Centralise Custom Error Pages for All Virtual Hosts
When managing multiple websites on a single NGINX server, maintaining consistent and professional error pages is essential for both user experience and operational efficiency. Rather than duplicating error page configurations across each virtual host, a centralised approach simplifies maintenance, improves consistency, and reduces configuration errors.
This article explains how to configure NGINX to serve custom error pages from a single centralised location. The method ensures that all virtual hosts (server blocks) on your server reference a common set of error pages, making it easier to update messages and apply consistent branding or formatting across your entire web infrastructure.
Step 1: Create Error Directory #
Create a directory to store centralised error pages:
sudo mkdir -p /var/www/html/errors
Step 2: Create HTML Error Pages #
Create minimal, self-contained HTML files for each error code
What This Means
- Minimal: Only include the essential content (a title and message).
- Self-contained: Do not use external files (no linked CSS, JS, or images). This ensures the page always loads, even if the rest of your website is broken.
401.html
– Unauthorized #
Create page:
sudo vim /var/www/html/errors/401.html
Add:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>401 – Unauthorized</title>
</head>
<body>
<h1>401 – Unauthorized</h1>
<p>You must be authenticated to access this page or resource.</p>
</body>
</html>
403.html
– Access Denied #
Create page:
sudo vim /var/www/html/errors/403.html
Add:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>403 – Access Denied</title>
</head>
<body>
<h1>403 – Access Denied</h1>
<p>You do not have permission to access this page or resource.</p>
</body>
</html>
404.html
– Not Found #
Create page:
sudo vim /var/www/html/errors/404.html
Add:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>404 – Not Found</title>
</head>
<body>
<h1>404 – Page Not Found</h1>
<p>The page you're looking for doesn't exist or has been moved.</p>
</body>
</html>
500.html
– Internal Server Error #
Create page:
sudo vim /var/www/html/errors/500.html
Add:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>500 – Internal Server Error</title>
</head>
<body>
<h1>500 – Internal Server Error</h1>
<p>Something went wrong. Please try again later.</p>
</body>
</html>
502.html
– Bad Gateway #
Create page:
sudo vim /var/www/html/errors/502.html
Add:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>502 – Bad Gateway</title>
</head>
<body>
<h1>502 – Bad Gateway</h1>
<p>The server received an invalid response from the upstream server.</p>
</body>
</html>
503.html
– Maintenance #
Create page:
sudo vim /var/www/html/errors/503.html
Add:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>503 – Site Under Maintenance</title>
</head>
<body>
<h1>503 – Site Under Maintenance</h1>
<p>I'm currently making updates. The site will be back shortly. Thanks for your patience.</p>
</body>
</html>
504.html
– Gateway Timeout #
Create page:
sudo vim /var/www/html/errors/504.html
Add:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>504 – Gateway Timeout</title>
</head>
<body>
<h1>504 – Gateway Timeout</h1>
<p>The server took too long to respond. Please try again later.</p>
</body>
</html>
Step 3: Set Ownership #
Ensure www-data
owns the error directory and its contents:
sudo chown -R www-data:www-data /var/www/html/errors
Step 4: Configure Nginx #
Edit Main Configuration #
Open configuration file:
sudo vim /etc/nginx/nginx.conf
Add inside the http
block:
http {
...
# Global Error Pages
error_page 401 /errors/401.html;
error_page 403 /errors/403.html;
error_page 500 /errors/500.html;
error_page 502 /errors/502.html;
error_page 503 /errors/503.html;
error_page 504 /errors/504.html;
# Virtual Hosts
...
}
Explanation:
This configures global error handling, meaning:
- All virtual hosts (server blocks) will use these custom error pages by default.
- You can still override them per site if needed by adding
error_page
directives within specificserver
blocks.
Create Snippet: error_pages.conf
#
To avoid repeating configuration across multiple server blocks, create a reusable NGINX snippet for error page routing.
Create the snippet file:
sudo vim /etc/nginx/snippets/error_pages.conf
Add:
# Serve custom error pages internally from /var/www/html/errors/
location = /errors/401.html { root /var/www/html; internal; }
location = /errors/403.html { root /var/www/html; internal; }
location = /errors/500.html { root /var/www/html; internal; }
location = /errors/502.html { root /var/www/html; internal; }
location = /errors/503.html { root /var/www/html; internal; }
location = /errors/504.html { root /var/www/html; internal; }
Explanation:
root /var/www/html
: Specifies the root directory for the error files.internal
: Prevents users from directly accessing the error pages via URL. They are only served by NGINX when an error occurs.
Edit Site Configuration #
Update each site's NGINX configuration to include the custom error handling and optional maintenance mode logic.
Open site configuration file:
sudo vim /etc/nginx/sites-available/<site>
Add snippet inside the server
block:
server {
listen 443;
...
# Include shared error page locations
include snippets/error_pages.conf;
# Maintenance flag + main handler
location / {
if (-f /var/www/html/errors/maintenance.flag) {
return 503;
}
try_files $uri $uri/ /index.php$is_args$args;
}
# PHP handling
location ~ \.php$ {
...
}
}
Explanation:
include snippets/error_pages.conf;
:
Loads the predefined internal error page routes created earlier.if (-f /var/www/html/errors/maintenance.flag) { return 503; }
:- Checks for the presence of a file named
maintenance.flag
- If it exists, NGINX immediately returns a
503 Service Unavailable
status - Used to quickly enable maintenance mode without modifying the server configuration
- Checks for the presence of a file named
Step 5: Reload Nginx #
Test configuration and reload NGINX to apply changes:
sudo nginx -t && sudo systemctl reload nginx
Step 6 (Optional): Test Maintenance Mode #
Enable maintenance mode:
sudo touch /var/www/html/errors/maintenance.flag
sudo systemctl reload nginx
Visit your site in a browser. You should see your custom 503 – Site Under Maintenance page.
Disable maintenance mode:
sudo rm /var/www/html/errors/maintenance.flag
sudo systemctl reload nginx