maint

August 2, 2026 ยท View on GitHub

Toggle nginx maintenance mode for any site, no reload needed.

nginx doesn't have a built-in maintenance mode. Most people end up copying the same if block into every site's config and then manually touching or removing some flag file whose path they have to remember. maint just wraps that pattern in a small CLI plus two reusable nginx snippets, so putting a site up (or back down) takes one command.

$ maint example.com on
Maintenance mode ON for example.com (/etc/nginx/maintenance/example.com.on)
$ maint example.com status
example.com: MAINTENANCE ON (since 2026-08-02 18:40:11)
$ maint example.com off
Maintenance mode OFF for example.com

You don't need to reload nginx to flip a site on or off. The only time you need a reload is the first time you wire a site in, since that's the only step that actually touches the nginx config.

Install

Quick install

curl -fsSL https://maint.spaceplane.dev/install.sh | sudo bash

From source

git clone https://github.com/glidecraft/nginx-maint.git
cd nginx-maint
sudo ./install.sh

From a .deb

sudo dpkg -i maint_1.1.0_all.deb

Grab the .deb from Releases, or build your own with packaging/build-deb.sh.

Either way you end up with:

  • /usr/local/sbin/maint, the CLI
  • /etc/nginx/snippets/maintenance.conf and maintenance-page.conf, the nginx snippets
  • /etc/nginx/maintenance/, where flag files live
  • /var/www/maintenance/maintenance.html, the default maintenance page

Wiring a site in

Whole site. Add this inside the site's server {} block, not inside a location:

server {
    server_name example.com;

    set $maintenance_flag /etc/nginx/maintenance/example.com.on;
    include snippets/maintenance.conf;

    # ... rest of the config
}

The path has to end in .on, that's the suffix maint appends by default for whatever site name you give it. Miss it (or typo the site name) and maint example.com on will happily report success while doing nothing, since it's touching a file nginx was never told to check. maint --list will catch a mismatch like that if it happens.

Reload nginx once after adding this. From then on it's just:

maint example.com on|off|status

Part of a site. Sometimes you need something like /.well-known/ or a webhook endpoint to stay reachable even while the rest of the site is down (this is basically why partial gating exists at all, it's an easy mistake to take down federation or webhook traffic during an otherwise harmless maintenance window):

server {
    server_name example.com;
    include snippets/maintenance-page.conf;

    location /.well-known/ {
        # left alone, always reachable
    }

    location / {
        set $maintenance_flag /etc/nginx/maintenance/example.com.on;
        if (-f $maintenance_flag) { return 503; }
        # ... rest of the config
    }
}

Customizing

  • The page. /var/www/maintenance/maintenance.html is just a static file, edit it however you like. You can also point a site's snippet at a different root if you want a different page per site.
  • Sites that already have their own maintenance mechanism. If a site already gates itself off some other flag file and you'd rather not duplicate that, add a line to /etc/maint/overrides.conf:
    example.com=/var/www/example.com/.maintenance
    
    maint example.com on|off|status will use that path instead of the default /etc/nginx/maintenance/example.com.on.
  • Flag directory. Set the MAINT_FLAG_DIR env var if /etc/nginx/maintenance doesn't fit your setup, e.g. on a box with per-user nginx configs.

Commands

maint <site> on|off|status   toggle or check one site
maint --list                 list every site wired into nginx, with its state
maint --version

maint <site> on also curls the site right after touching the flag and tells you if it didn't actually get a 503 back. That catches the most common mistake: the nginx config's $maintenance_flag path not matching what maint just touched (usually a missing .on, or a typo in the site name).

maint --list reads the live nginx config instead of just looking at which flag files happen to exist, so it shows every site you've wired in, not only the ones currently in maintenance mode. It also flags any site where the nginx config's flag path doesn't match what maint would use for that site, which usually means the same mismatch.

License

MIT