Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Maintenance Bundle Laravel Package

prolix/maintenance-bundle

Prolix Maintenance Bundle is a Symfony bundle for putting your app into maintenance mode. It serves configurable 503 responses, supports IP whitelisting and custom maintenance templates, and helps manage planned downtime cleanly without exposing errors to visitors.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony bundle, not a Laravel package. If you're a Laravel developer, the closest day-to-day equivalent is php artisan down / php artisan up (with --secret, --render, --redirect). The mental model transfers 1:1, but everything below is Symfony wiring.

  1. Install the fork via Composer (note: repo is named LexikMaintenanceBundle, Packagist name is prolix/maintenance-bundle — confirm the constraint in composer.json matches your Symfony version):

    composer require prolix/maintenance-bundle
    
  2. Register the bundle in config/bundles.php (Flex usually does this automatically):

    return [
        // ...
        Lexik\Bundle\MaintenanceBundle\LexikMaintenanceBundle::class => ['all' => true],
    ];
    
  3. Configure it in config/packages/lexik_maintenance.yaml — start with the file driver, which is the simplest:

    lexik_maintenance:
        authorized:
            ips: ['127.0.0.1', '10.0.0.0/8']
            hosts: []
            paths: ['^/healthz$', '^/_ops']
        driver:
            ttl: 3600
            file:
                storage_dir: '%kernel.project_dir%/var/maintenance'
                key_name: maintenance
        template: '@LexikMaintenance/Maintenance/maintenance.html.twig'
    
  4. First use case: put the site into maintenance while you deploy, keep yourself in via the IP allowlist, and let it auto-expire after an hour in case you forget to unlock:

    php bin/console lexik:maintenance:lock --ttl=3600
    # deploy, migrate, warm cache...
    php bin/console lexik:maintenance:unlock
    
  5. Where to look first in the source: the bundle's MaintenanceListener (kernel.request listener that returns the 503 response), the Driver interface, and the three commands. That's 90% of the surface area.

Implementation Patterns

Deploy-script sandwich. The canonical pattern: lock → deploy → unlock, with a trap so a failed deploy doesn't leave the site locked forever.

#!/usr/bin/env bash
set -euo pipefail
php bin/console lexik:maintenance:lock --env=prod --ttl=1800
trap 'php bin/console lexik:maintenance:unlock --env=prod' EXIT
php bin/console doctrine:migrations:migrate --no-interaction
php bin/console cache:clear --env=prod
php bin/console cache:warmup --env=prod

Use lexik:maintenance:check for gating and monitoring. It exits non-zero/zero depending on lock state, so it's script-friendly — useful in a deploy wrapper to skip redundant locks, or as a smoke-test step that fails the build if maintenance is still on after a deploy.

Multi-server / containerized apps need a shared driver. The file driver writes to a local path, so with two app servers only one serves 503. Use the database, Redis, or Memcached driver so every node sees the same state:

# prod
lexik_maintenance:
    driver:
        redis:
            host: '%env(REDIS_HOST)%'
            port: 6379

The database driver needs its table created (check the bundle's Resources for the schema/SQL) — wire it into a migration.

Bypass rules are your most-used knob. Health checks, load balancers, webhooks (Stripe, GitHub), and your own admin routes must keep working during maintenance. Use authorized.paths (regexes on the pathinfo) and authorized.ips (CIDR supported). This is the Symfony analogue of Laravel's --secret cookie, but broader.

Custom 503 page. Override the template config to point at your Twig template. Keep the response status at 503 with a Retry-After header — that's what tells Google/browsers this is temporary, so you don't lose index position the way a 200 "we'll be back" page would.

Programmatic control. For admin-panel "maintenance mode" toggles, inject the driver service (lexik_maintenance.driver) or the factory and call lock() / unlock() / isLocked() from a controller or command instead of shelling out. This is the cleanest way to expose it to non-Symfony-savvy ops people.

CI/test wiring. Disable the bundle in config/packages/test/lexik_maintenance.yaml (or guard the listener) — a stale lock file in a shared build workspace will make every functional test return 503 and produce mystifying failures.

Gotchas and Tips

  • Package-name confusion. The repository says LexikMaintenanceBundle, the install name is prolix/maintenance-bundle. That's a fork of the original lexik/maintenance-bundle. Pin the version in composer.json and check whether the fork or the upstream is the one you actually want — with 6 stars and 0 dependents, neither has a large safety net.

  • The file driver lives inside var/cache by default. cache:clear / cache:warmup can wipe your lock state mid-deploy, or worse, write the lock into the new cache dir while the old one still serves. Point storage_dir outside var/cache (e.g. var/maintenance) or use Redis/DB in prod.

  • --env matters. Running lock without --env=prod writes state for the dev environment; your prod site is unaffected and you'll spend an hour debugging a "broken" command. Always pass it explicitly in scripts, and make sure the prod config actually defines the driver.

  • TTL is a footgun in both directions. A short TTL silently unlocks mid-migration; a missing TTL leaves the site down indefinitely. Set ttl to slightly longer than your worst-case deploy and also add a monitoring alert that fires when lexik:maintenance:check reports locked for more than N minutes.

  • HTTP caches and CDNs ignore it. The listener only returns 503 for requests that reach PHP. If Varnish/Cloudflare/Fastly is serving cached pages, users won't see maintenance mode until you purge. Add a CDN purge step to the deploy, or a CDN-level rule keyed on a /.maintenance marker.

  • Authorized paths are regexes against the pathinfo, not globs and not full URLs. ^/admin won't match if your app is in a subdirectory or the route is locale-prefixed (/en/admin). Test with bin/console debug:router and a real curl before relying on it during an incident.

  • Unlock before you clear cache. If something goes wrong with warmup, you want the site live while you debug rather than locked with a broken console app.

  • Debugging: php bin/console debug:container lexik_maintenance shows which driver is wired in the current env; php bin/console lexik:maintenance:check -v shows the current state. If the listener isn't firing, check event priority — another kernel.request listener (e.g. a security firewall or a redirect listener) registered earlier can preempt the 503.

  • Extension point: for custom backends (DynamoDB, Consul, etcd, S3) implement the bundle's driver interface and register it via the driver factory. Given how small this project is, that's often less risky than waiting for upstream support for a storage backend.

  • Security listener ordering: the maintenance listener should generally run before the firewall, otherwise unauthenticated users get redirected to /login during maintenance instead of a 503 — confusing for users and bad for SEO.

  • Zero dependents is a signal. Treat this as "small, single-maintainer, low-bus-factor." Read the listener and driver code (it's short) before relying on it in a production incident path; if you need it to be bulletproof, wrapping the driver interface yourself is a cheap insurance policy.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
alphabalex/messaging-made-easy
rawphp/warp
shootkiran/merobug
narakode/fineauth
numencode/wn-syncops-plugin
ibnnajjaar/mib-global-pay
ably/pubsub-server
mstfkhazaal/defender
mfonte/base62x
karnoweb/metapilot
tobya/bcsapiwrapper
swalker2/cpanel
vish4395/laravel-translation-manager
morningtrain/economic
teksite/systeminfo-laravel
atomcms/voting
run6/weather
siokas/laravelembeddirectives
adamlien/pkuuids
gilsonsouza/lara-doc-generator