How to Configure Custom Error Pages for Nginx Reverse Proxy When Backend Server Fails


2 views

When running Nginx as a reverse proxy, users often encounter blank pages or generic browser error messages when the backend server becomes unavailable. This creates a poor user experience compared to serving a properly styled error page.

Here's a complete configuration that handles both proxy routing and custom error pages:

server {
    listen 80;
    server_name example.com;
    
    # Access logs and document root
    access_log /var/log/nginx/access.log;
    root /var/www/nginx;
    
    # Custom error handling
    error_page 500 502 503 504 /50x.html;
    
    location = /50x.html {
        internal;
        root /usr/share/nginx/html;
    }
    
    # Proxy configuration
    location / {
        proxy_pass http://192.168.1.78;
        proxy_intercept_errors on;
        proxy_next_upstream error timeout invalid_header;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

proxy_intercept_errors: This crucial directive tells Nginx to handle backend errors (like 502 Bad Gateway) instead of passing them directly to the client.

error_page: Defines which HTTP status codes should trigger your custom error page and its location.

For more sophisticated error handling, you can implement different pages for different error codes:

error_page 502 /502.html;
error_page 503 /503.html;
error_page 504 /504.html;

location = /502.html {
    internal;
    root /var/www/error_pages;
}

location = /503.html {
    internal;
    root /var/www/error_pages;
}

After implementing these changes, test your configuration by:

  1. Reloading Nginx: sudo nginx -s reload
  2. Stopping your backend service temporarily
  3. Accessing your frontend URL to verify the custom error page appears

The custom error pages should be lightweight HTML files to minimize impact during failure scenarios. Avoid embedding large assets or complex JavaScript that might fail to load when the system is already under stress.


When running Nginx as a reverse proxy, users often encounter generic 502 Bad Gateway errors when backend servers become unavailable. These default error pages provide poor user experience and minimal debugging information.

To properly handle backend failures, your nginx.conf needs these critical components:

server {
    listen 80;
    server_name yourdomain.com;
    
    # Custom error page location
    root /var/www/custom_errors;
    
    # Define error pages for various status codes
    error_page 500 502 503 504 /5xx.html;
    error_page 404 /404.html;
    
    location / {
        proxy_pass http://backend_server;
        proxy_intercept_errors on;  # Crucial for custom error handling
        proxy_next_upstream error timeout invalid_header;
        proxy_next_upstream_tries 3;
        include /etc/nginx/proxy_params;
    }
    
    location = /5xx.html {
        internal;
    }
    
    location = /404.html {
        internal;
    }
}

proxy_intercept_errors: This directive tells Nginx to handle responses from the backend server that contain status codes 300 or greater. When enabled, Nginx will serve your custom error pages instead of passing through the backend's errors.

proxy_next_upstream: Defines in which cases a request should be passed to the next server in the upstream group. The parameters shown cover most common failure scenarios.

Your custom error pages should include:

  • Clear status information
  • Suggested actions for users
  • Contact information
  • Minimal branding
  • Optional: Automatic refresh mechanism

Example 5xx.html template:

<!DOCTYPE html>
<html>
<head>
    <title>Service Temporarily Unavailable</title>
    <meta http-equiv="refresh" content="30">
    <style>
        body { font-family: sans-serif; text-align: center; padding: 50px; }
        h1 { font-size: 50px; }
        .logo { margin-bottom: 20px; }
    </style>
</head>
<body>
    <div class="logo">
        <img src="/logo.png" alt="Company Logo">
    </div>
    <h1>503 Service Unavailable</h1>
    <p>We're experiencing technical difficulties. Our team has been notified.</p>
    <p>The page will automatically refresh in 30 seconds.</p>
    <p><a href="/">Try again now</a></p>
</body>
</html>

For more sophisticated setups, consider:

# Map different error conditions to specific pages
map $status $error_page {
    404     /404.html;
    502     /maintenance.html;
    default /error.html;
}

server {
    # ... other config ...
    error_page 404 500 502 503 504 = @error_handler;
    
    location @error_handler {
        root /var/www/custom_errors;
        try_files $uri /error.html =404;
    }
}

After implementing these changes:

  1. Reload Nginx: sudo nginx -s reload
  2. Test by temporarily stopping your backend service
  3. Verify the custom error page appears
  4. Check logs: tail -f /var/log/nginx/error.log

Complement your error pages with proper monitoring:

  • Configure alerts for 5xx errors
  • Track error page views in your analytics
  • Set up uptime monitoring for backend services