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.confandmaintenance-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.htmlis just a static file, edit it however you like. You can also point a site's snippet at a differentrootif 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/.maintenancemaint example.com on|off|statuswill use that path instead of the default/etc/nginx/maintenance/example.com.on. - Flag directory. Set the
MAINT_FLAG_DIRenv var if/etc/nginx/maintenancedoesn'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