toshy/maintenance-bundle
A PHP maintenance-mode bundle that lets you temporarily disable your application, display a maintenance page, and configure bypass access for admins or authorized users during deployments and updates.
Architecture fit — the headline finding is a framework mismatch. Despite being catalogued as a "Laravel/PHP package," toshy/maintenance-bundle is a Symfony 2 bundle (a fork of LexikMaintenanceBundle). It integrates via mechanisms that do not exist in Laravel: registration in AppKernel::registerBundles(), DI container service definitions, a kernel.request event listener, YAML configuration under a lexik_maintenance key, and two Symfony Console commands (maintenance:enable / maintenance:disable). There is no service provider, no HTTP kernel middleware, and no Artisan command surface. Any Laravel adoption would be a from-scratch reimplementation, not an integration.
Even within Symfony, the fit is weak. Symfony 2 is end-of-life since 2018. Modern Symfony (5.4/6.x/7.x) does not use bundles for this concern; a kernel event subscriber, a 503 response via a feature flag, or edge-level maintenance is the idiomatic pattern. The two-command workflow is conceptually sound but trivially reproducible.
Functional scope is narrow. The bundle toggles a 503 response and permits an IP allowlist from configuration. It does not appear to provide: centralised state across nodes, a pre-rendered/static maintenance page, Retry-After header control, scheduled maintenance windows, or bypass via signed cookie/token. Laravel has offered all of these natively since 5.x (artisan down), with --secret, --render, --retry, and --redirect added in 8.x/9.x. The package is functionally redundant on Laravel.
Integration feasibility: low. Expected composer.json constraints (php, symfony/symfony ~2.x) will conflict with any Laravel 9/10/11 dependency graph. Symfony 2-era code frequently fails on PHP 8.x (removed constructs, deprecated container access patterns, Twig 1.x templating). Installation is likely to require --ignore-platform-reqs at best, which is not a defensible production posture.
Technical risk: high. Three compounding factors:
lexik/maintenance-bundle.X-Forwarded-For handling is a bypass vector.Key questions to resolve before any decision:
Retry-After, scheduled window, multi-node consistency?Stack fit. Laravel: incompatible, not recommended. Modern Symfony (4.4+): not idiomatically correct; a ~100-line event subscriber plus a config flag replaces it. Legacy Symfony 2.x/3.x: the only context where this bundle is a genuine drop-in.
Migration / adoption path.
php artisan down --secret="<token>" --retry=60 --render=errors::503. IP allowlisting becomes a lightweight middleware that short-circuits to a 503 view unless the client IP matches a configured CIDR list. Estimated 50–150 LOC.kernel.request subscriber (priority before routing) reading an env var or feature flag, returning a 503 Response, with an allowlist check and a bypass token. Roughly a half-day of work and fully owned.repositories entry with type: vcs) since Packagist presence is unverified, register the bundle in AppKernel, publish the YAML config, and validate.Compatibility checklist before adoption.
composer.json: PHP constraint, symfony/symfony constraint, Twig constraint, any sensio/* coupling.ContainerAware, getContainer(), $this->container, Twig 1.x syntax, each(), curly-brace string offsets, dynamic property assignment on PHP 8.2.cache:clear may be required to flip it — unacceptable in an incident.Sequencing.
Retry-After.Maintenance burden: you own it. A 0-star personal fork with no dependents means no upstream patches, no security advisories, and no issue triage. If adopted, vendor it, pin the commit, and assign a named owner. Budget a recurring review each time the PHP runtime or framework is upgraded.
Support posture. No vendor, no SLA, no community. The escalation path is "read the source, patch in-house." This is acceptable for legacy Symfony 2 where the alternative is a bespoke build of equivalent size; it is not acceptable as a new dependency in a modern stack.
Scaling constraints — the most significant operational issue.
Failure modes to design against.
X-Forwarded-For if trusted proxies are misconfigured — validate that the app only sees proxy-injected headers.Cache-Control: no-store on the maintenance response.Retry-After, causing aggressive client retry storms or search-engine index degradation.Ramp-up. Low conceptual complexity but non-trivial toolchain cost. A Laravel developer needs roughly a half-day to learn Symfony bundle conventions; the real time sink is resolving a Symfony 2 dependency graph on a modern PHP runtime. Estimate 1–2 dev-days for the evaluation spike and 3–5 dev-days if replicating the behaviour natively in Laravel — still cheaper than owning an unmaintained fork.
Recommendation: do not adopt. On Laravel the package is architecturally incompatible and functionally redundant. On modern Symfony it is non-idiomatic and unmaintained. The only defensible case is an existing Symfony 2.x estate with a documented requirement, and even then, edge-level maintenance with a static 503 page is the lower-risk control.
How can I help you explore Laravel packages today?