nginx maintenance mode

Sim

Well-known member
On my old vBulletin based site, I had a maintenance mode I could enable which redirected all traffic to a static HTML error page temporarily with a 503 return code - so I could play around with the forum files without needing XenForo to be operational.

For some reason I'm having a lot of difficulty getting the same code to work with XenForo - which I suspect is something to do with the differences in how the PHP files are loaded between my two server configs.

Any nginx gurus out there have any suggestions which they know work?

This is what worked with my vB site - I just uncommented the first three lines and restarted nginx to put it into maintenance mode and commented them out to make the site live again.

Code:
    #if ($remote_addr != "my.ip.address") {
    #    return 503;
    #}
    error_page 503 @maintenance;

    location @maintenance {
        rewrite ^(.*)$ /error503.html break;
    }

The main difference between my server blocks for vBulletin and XenForo is that my XF version includes the try_files directive for pretty URLs.

Code:
location / {
    try_files $uri $uri/ /index.php?$uri&$args;
}

Could it be this which is stopping my maintenance mode from working?
 
Probably not this, but have you tried putting the 503 return line below the definition lines?

Liam
 
The main difference between my server blocks for vBulletin and XenForo is that my XF version includes the try_files directive for pretty URLs.

What did your vBulletin directive look like, did it use "Location /" also? I suspect that that is overriding any other directive you set.

XenForo returns a 503 if the board is unavailable, IIRC, so couldn't you just put your maintenance message in the "Board is closed" message in your admin options?

You can still work on it as an admin.

Just seems like a lot of trouble to put up a maintenance message, in my opinion.
 
XenForo returns a 503 if the board is unavailable, IIRC, so couldn't you just put your maintenance message in the "Board is closed" message in your admin options?

You can still work on it as an admin.

Just seems like a lot of trouble to put up a maintenance message, in my opinion.

The point is to hide XenForo while I'm working on things at a server level where I can't assume that XenForo is actually running (eg database offline or files not all there).

Typically I use this when I'm doing a full database backup where the database is offline for a short period and I want to avoid giving errors to users - instead I direct them to a page with information about what's going on and links to our chatroom where they can get status updates.

If I was only working on XenForo configuration or design changes or something, I wouldn't bother with the nginx maintenance mode and would just use XenForo's maintenance mode.

I have a hunch about what the problem with my config might be - will do some testing today and report back.
 
Hi I've been able to do it like this for a while now;
Code:
geo $maintenance {
    default yes;
    # ip white list
    127.0.0.1 no;
    123.yourIP.123 no;
}

server {
    # ...

    location / {
        if (-f /etc/nginx/maintenance.file) {
            set $tmp clo;
        }
        if ($maintenance = yes) {
            set $action "${tmp}se";
        }
        if ($action = close) {
            return 503;
        }

        # ...
    }

    error_page 503 /503.html;
}
Code:
touch /etc/nginx/maintenance.file - close site
rm /etc/nginx/maintenance.file - open site
That will go to the 503 page but you just change to return what you like.
I just have all encompassing 50x page for maintenance.

error_page 500 502 503 504 /custom_50x.html;
location = /custom_50x.html {
root /usr/share/nginx/html;
internal;


example in full config;
Code:
geo $maintenance {

    default yes;
    # ip white list
    127.0.0.1 no;
    123.yourIP.xxx no;
    }

    server {
    listen       80;
    server_name  www.website.com;
   # strip www.requests
    return 301 http://website.com$request_uri;
    }

    server {
    listen  80;
    server_name website.com;
    # access_log /srv/www/website/logs/access.log;
    error_log /var/log/nginx/website.log;
    root /srv/www/website;

    # https://github.com/openresty/headers-more-nginx-module
     more_clear_headers 'Server*';
     more_clear_headers 'X-Powered*';
     more_clear_headers 'X-Page*';
     more_set_headers 'X-Powered-By: Hodor';

    # control error pages / 503 maintenance-mode page
    error_page 500 502 503 504 /custom_50x.html;
    location = /custom_50x.html {
    root /usr/share/nginx/html;
    internal;
    }

    location / {
      # Redirect SSL to HTTP.
      if ($http_x_forwarded_proto = "https") {
      return 301 http://website.com$request_uri;
      }

   # Maintenance 503 Page
   # touch /etc/nginx/maintenance.file - close site
   # rm /etc/nginx/maintenance.file - open site
   # These if's are not evil! *true story*

     if (-f /etc/nginx/maintenance.file) {
            set $tmp clo;
        }
        if ($maintenance = yes) {
            set $action "${tmp}se";
        }
        if ($action = close) {
            return 503;
        }

    #  This sends everything through index.php and keeps the appended query string intact.
        try_files $uri $uri/ /index.php?$uri&$args;
        index index.html index.htm index.php;
        }

    # Block public access to important files, folders, admin.php.
    location ~ /(\.|internal_data|library|install|admin.php|passwords.txt)  {
      allow 127.0.0.1;
      allow 123.yourIP.xxx
      deny all;
      }
    # log access to denied file in /etc/nginx/ but don't log 404 and also deny all to dot files
      location ~ /\. {
        access_log denied;
        log_not_found off;
        deny all;
     }

   location ~ \.php$ {
   # Pass all .php files onto a php-fpm/php-fcgi server.
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        if (!-f $document_root$fastcgi_script_name) {
        return 404;
        }
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass 127.0.0.1:9000;
        include fastcgi_params;
        #fastcgi_intercept_errors on;
        }

     # Module ngx_http_stub_status_module
     # http://nginx.org/en/docs/http/ngx_http_stub_status_module.html
      location ~ ^/(status|ping)$ {
        access_log off;
        allow 127.0.0.1;
        allow 123.yourIP.xxx;
        deny all;
        include fastcgi_params;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
     }

     # add some expires.
     location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
       expires 1y;
       log_not_found off;
       }

}

edit; geo module is already baked in so no need to recompile anything.
http://nginx.org/en/docs/http/ngx_http_geo_module.html
 
Last edited:
Top Bottom