Maintenance Mode
A flag file that makes Magento answer 503, an IP allow list, and the short part of a deploy that genuinely needs it.
bin/magento maintenance:enable [--ip=<address>]... | [--ip=none]Maintenance mode makes Magento answer every request with HTTP 503 and an error page instead of running the application: the bootstrap requires pub/errors/503.php, which renders the template pub/errors/default/503.phtml. It exists so a release can change the database while nothing else is reading or writing it.
Two files, not a setting
It is file state, not configuration. var/.maintenance.flag existing means the store is down. var/.maintenance.ip holds the addresses that are let through. The commands are maintenance:enable, maintenance:disable, maintenance:status and maintenance:allow-ips. On enable and disable, --ip may be repeated and --ip=none clears the list; maintenance:allow-ips takes the addresses as arguments with --add to append and --none to empty. Because it is only a file, you can delete it by hand when the CLI will not bootstrap.
The window it is for
Only the steps that change shared state: setup:upgrade, which applies declarative schema changes and data patches. setup:upgrade does not enable maintenance mode for you, so enable it yourself. The compile and the static content deploy do not belong in the window at all; they belong on a build machine. deploy:mode:set is the exception that turns maintenance on and off by itself.
What trips people up
The allow list is matched against the address Magento sees. Behind a load balancer or a CDN that is the proxy, so adding your own address does nothing and you watch your own 503 page. Health checks that only read the status code will mark the node dead for the whole window.
Example
bin/magento maintenance:status
# Status: maintenance mode is disabled
# List of exempt IP-addresses: none
bin/magento maintenance:enable --ip=203.0.113.4 --ip=203.0.113.5
# Enabled maintenance mode
# Set exempt IP-addresses: 203.0.113.4, 203.0.113.5
# the only part of the release that needs the store down
bin/magento setup:upgrade --keep-generated
bin/magento cache:flush
bin/magento maintenance:disable
# Disabled maintenance mode
bin/magento maintenance:status
# Status: maintenance mode is disabled
# List of exempt IP-addresses: 203.0.113.4 203.0.113.5When to use it
- Taking the storefront down for the two minutes a schema change needs.
- Letting the office address through so you can click the site while it is closed.
- Recovering a site that is stuck at 503 after a failed release.
- Explaining to a client why their status page went red during a deploy.
More examples
Edit the allow list without touching the flag
maintenance:allow-ips changes the exempt list whether the site is up or down, which is what you need when you are already in the window and realise you cannot see the store. Without --add the list is replaced rather than extended, and --none empties it, which locks out everyone including you. The list is stored in var/.maintenance.ip; the flag file is untouched by this command.
bin/magento maintenance:allow-ips 203.0.113.4
# Set exempt IP-addresses: 203.0.113.4
bin/magento maintenance:allow-ips 198.51.100.7 --add
# Set exempt IP-addresses: 203.0.113.4 198.51.100.7
bin/magento maintenance:allow-ips --none
# Set exempt IP-addresses: none
cat var/.maintenance.ipCheck what visitors are actually getting
Always send the Host header when you test from the node itself, so Magento resolves the right store instead of 127.0.0.1. The body comes from pub/errors/503.php, which renders the template pub/errors/default/503.phtml; to brand it, copy pub/errors/default to another directory under pub/errors and name that directory in the <skin> element of pub/errors/design.xml, so a Composer update does not overwrite your copy. The page is rendered outside the application: no layout, no blocks, no database, so keep it static and inline its CSS. Point the load balancer health check at a path you are happy to see fail, or expect the node to be pulled out of rotation for the whole window.
# from an address that is not on the exempt list
curl -s -o /dev/null -w '%{http_code}\n' -H 'Host: www.example.com' https://www.example.com/
# 503
# the body is pub/errors/503.phtml - edit that file to brand the page
curl -s -H 'Host: www.example.com' https://www.example.com/ | head -5Clear a stuck flag
The flag is the whole mechanism, so removing the file is a legitimate recovery and not a hack. This is the usual ending to a release script that aborted between setup:upgrade and maintenance:disable. Note the opposite failure too: deploy:mode:set enables and disables maintenance itself, so a crash in the middle of a mode switch can leave the site up with an empty pub/static.
bin/magento maintenance:status
# Status: maintenance mode is enabled
bin/magento maintenance:disable
# when the CLI itself will not start - a broken env.php, a missing compile
ls -l var/.maintenance.flag
rm -f var/.maintenance.flag
Discussion