When putting a website into maintenance mode, many developers use a simple file-serving approach like:
location / {
try_files /maintenance.html $uri $uri/ @codeigniter;
}
While functional, this returns HTTP 200 OK status, which creates several issues:
- Search engines may index the maintenance page content
- Monitoring systems won't detect the maintenance state
- API consumers won't understand the temporary nature
The proper HTTP response code for maintenance is 503 because:
- It explicitly indicates temporary unavailability
- Search engines will typically come back later
- Properly informs all HTTP clients (browsers, APIs, crawlers)
- Works well with retry-after headers for scheduled maintenance
Instead of using if conditions (which Nginx explicitly warns against), we can leverage error_page
:
# Create a custom error page for maintenance mode
error_page 503 @maintenance;
location @maintenance {
root /path/to/maintenance/files;
rewrite ^(.*)$ /maintenance.html break;
}
location / {
# Check for maintenance file existence
try_files $uri $uri/ @app;
# Normal application handler
location @app {
# Your regular application proxy_pass/fastcgi_pass here
proxy_pass http://app_server;
}
}
To activate maintenance mode:
# Create maintenance trigger file
touch /path/to/maintenance.flag
# Reload nginx
nginx -s reload
Then modify your nginx config to check for this file:
location / {
# Check for maintenance flag first
try_files /maintenance.flag @app;
# If maintenance.flag exists, this will return 503
error_page 503 @maintenance;
}
For planned maintenance windows, add headers:
location @maintenance {
root /path/to/maintenance/files;
rewrite ^(.*)$ /maintenance.html break;
add_header Retry-After 3600;
add_header Cache-Control "no-cache";
}
When putting a website into maintenance mode, many developers accidentally serve the maintenance page with a 200 (OK) status code. This creates several issues:
- Search engines may index your maintenance page
- API consumers won't know the service is temporarily unavailable
- Monitoring systems won't properly detect the downtime
The common solution found online suggests using if statements to redirect to a maintenance page:
if (-f /var/www/maintenance.html) {
return 503;
}
However, as noted in the official Nginx documentation, if statements should generally be avoided because:
- They may behave unexpectedly in certain contexts
- They can cause performance issues
- They don't always work the way you'd expect
Here's a safer approach that properly returns a 503 status code without using if statements:
error_page 503 /maintenance.html;
location / {
try_files /maintenance.html $uri $uri/ =503;
}
This configuration works by:
- First checking if maintenance.html exists
- If it exists, serving it with a 503 status
- If it doesn't exist, continuing with normal processing
For a production-ready solution, you might want to include these additional elements:
# Maintenance mode configuration
location = /maintenance.html {
internal;
}
error_page 503 /maintenance.html;
location / {
# Check for maintenance file first
try_files /maintenance.html $uri $uri/ @proxy;
# Additional headers for maintenance
add_header Retry-After 3600;
add_header Cache-Control "no-cache";
}
location @proxy {
# Your normal proxy pass or fastcgi configuration
proxy_pass http://backend;
}
To make it easier to enable/disable maintenance mode, create these simple shell commands:
# Enable maintenance
enable_maintenance() {
touch /var/www/maintenance.html
systemctl reload nginx
}
# Disable maintenance
disable_maintenance() {
rm -f /var/www/maintenance.html
systemctl reload nginx
}
This gives you a clean way to toggle maintenance mode while ensuring proper HTTP status codes and avoiding problematic if statements.