31

I want to configure the server to show a maintenance page when it exist. I tried this code and works:

location / {
    try_files /maintenance.html $uri $uri/ @codeigniter;
}

But I noticed it would be served with a 200 status code, and it can cause confusion to search engines. I think the best practice would be returning a 503 status code. On google I find several relevant pages about it, like this. However, they use if to make the redirect and according to nginx documentation it isn't safe to use ifs.

Is there a way of doing it without using if? Is safe to use if in this case?

Thanks.

NeDark
  • 463
  • 1
  • 6
  • 10

4 Answers4

36

Here is what I do.

            if (-f $document_root/maintenance.html) {
                    return 503;
            }
            error_page 503 @maintenance;
            location @maintenance {
                    rewrite ^(.*)$ /maintenance.html break;
            }

If the file is there it will show the maintenance page. Once you remove the file you will go back to normal.

Mike
  • 22,310
  • 7
  • 56
  • 79
  • 2
    Yeah, that is the same code that is on the link in the question. I'm actually asking if it's safe to use `if`s in this case since it should not be used according to [documentation](http://wiki.nginx.org/IfIsEvil). – NeDark Sep 13 '11 at 19:43
  • 1
    And that same documentation: `In some cases it's also possible to move ifs to server level (where it's safe as only other rewrite module directives are allowed within it).` The maintenance error_page as Mike showed is normally set in server {} context. – Regan Nov 13 '13 at 13:18
  • 1
    I did the same except just did a 'return 503' without checking the existence of the file. That way I can just enable/disable the site (using Debian's "sites-available"/"sites-enabled" layout) by symlinking and turn on the maintenance page. – Asfand Qazi Jul 14 '15 at 11:18
  • 7
    Sounds like this would be a performance hit: NGINX will need to check for the existance of a file for every request... – Marc Sep 14 '17 at 07:32
  • 3
    Marc, it isn't since commonly accessed files are stored in filesystem cache which is in memory. – Mike Feb 19 '18 at 03:00
  • Every examples I've stumbled upon using the `if (-f $document_root/maintenance.html) {` claims this works. My `if (-f ...)` statement never seems to work even when the maintenance.html page exists. I've read about the "If is Evil" (https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/) article, but didn't shed any light as to why it doesn't work on my end. I tried removing the "503" error_page on the main `nginx.conf`, and still keep getting a `500 Internal Server Error`. Any ideas? – chamberlainpi Nov 25 '20 at 13:53
  • @Mike I am not convinced, but since this is a simple solution, I will use it. – Obay Abd-Algader Jul 18 '21 at 12:02
10

I think the best practice would be returning a 500 status code.

I think you mean 503 instead of 500.

they use if to make the redirect and according to nginx documentation it isn't safe to use ifs.

No. Only return is 100% safe inside if in location context.

According to nginx documentation, you can specify an HTTP status code as the last argument to try_files. I've tried this but it didn't work.

quanta
  • 51,413
  • 19
  • 159
  • 217
  • 1
    A possible problem with returning 503 is that you don't know if the shutdown was for maintenance purposes, or there is an issue with the web application. Am I right? – Obay Abd-Algader Jul 18 '21 at 12:04
1

If the maintenance page only has HTML

No asset file (CSS, JS, ...)

location = @maintenance {
    root html/;
    # `break`: use this `location` block
    rewrite ^ "/maintenance.html" break;
}

location / {
    error_page 503 @maintenance;
    return 503;

    # ...
}

For maintenance page that has asset file (CSS / JS / ...)

The flow of this is:

  • If URI is /, return 503
    • Internal redirect to /maintenance.html
  • If URI found in maintenance directory (for asset), return file with status 200
  • All other request, redirect to /
# for handle maintenance web page
server {
    listen unix:/var/run/maintenance.nginx.sock;

    # for Windows
    # listen 8000;
    
    location @index {
        # use redirect because if URI has sub-folder ($uri == /path/path/),
        # the relative path for asset file (CSS, JS, ...) will be incorrect
        rewrite ^ / redirect;
    }

    location = / {
        # maintenance page URI
        error_page 503 /maintenance.html;

        return 503;
    }

    # use RegExp because it has higher priority
    location / {
        root html/maintenance/;

        # redirect all URI to index (503) page (except asset URI),
        # asset URI still return status 200
        try_files $uri @index;
    }
}

# original server block
server {
    listen 80;
    location / {
        proxy_pass http://unix:/var/run/maintenance.nginx.sock:;

        # for Windows
        # proxy_pass http://127.0.0.1:8000;
    }

    # ...
}
  • You can put the config in a maintenance.conf, include maintenance.conf when in maintenance.

  • I will not use if (-f <file>) because it will try to check if the file exist on every request

If you need bypass some IP address

More detail here

Ref: Nginx Maintenance

Steely Wing
  • 321
  • 2
  • 4
0

This config works for me:

server {
  server_name _;
  listen 443 ssl http2;
  listen [::]:443 ssl http2;
  location ~* \.(css|png|js|jpg|jpeg|ico) {
      root /static/maintenance;
  }
  error_page 503 @maintenance;
  location @maintenance {
    root /static/maintenance;
    rewrite ^(.*)$ /index.html break;
  }
  location / {
    return 503;
  }
}

It returns /static/maintenance/index.html file with code 503 for every request.

It doesn't change URL with redirections.

Resources like

  • /static/maintenance/main.css,
  • /static/maintenance/favicon.ico,
  • etc.

are available with code 200.

vdshb
  • 171
  • 1
  • 4
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community May 17 '23 at 10:26