drawik/symfony-maintenance-mode-bundle
Installation:
composer require drawik/symfony-maintenance-mode-bundle
Ensure your project uses Symfony 6 or 7.
Enable Maintenance Mode:
php bin/console maintenance:enable
This immediately locks the application (default lock file: /tmp/maintenance_mode.lock).
First Use Case:
config/packages/maintenance_mode.yaml:
maintenance_mode:
maintenance_config:
allowed_ips: ['127.0.0.1', '::1']
Deployment Integration:
post-deploy hook (e.g., GitHub Actions, Deployer):
php bin/console maintenance:enable
# Run migrations/deployments...
php bin/console maintenance:disable
Environment-Specific Config:
maintenance_mode.yaml per environment (e.g., config/packages/dev/maintenance_mode.yaml):
# config/packages/prod/maintenance_mode.yaml
maintenance_mode:
maintenance_config:
enabled: 0 # Disabled in production by default
allowed_ips: ['192.168.1.100'] # Only allow staging server
Dynamic IP Whitelisting:
Custom Lock File:
var/maintenance.lock) for better portability:
maintenance_mode:
maintenance_config:
lock_file_path: '%kernel.project_dir%/var/maintenance.lock'
bundles.php changes are needed.MaintenanceModeListener to Symfony’s event dispatcher. Override its logic (e.g., MaintenanceModeListener::onKernelRequest) if you need custom logic (e.g., API vs. web maintenance).$kernel->getContainer()->get('maintenance_mode.listener')->setEnabled(true);
Lock File Permissions:
/tmp/maintenance_mode.lock by default) is writable by the web server user (e.g., www-data).chmod 666 /tmp/maintenance_mode.lock
var/maintenance.lock) with chmod 644.Caching Issues:
HttpCache), clear it after disabling maintenance:
php bin/console cache:clear
IP Whitelisting Quirks:
allowed_ips config supports both IPv4 and IPv6, but subnet masks (e.g., 192.168.1.0/24) are not supported.192.168.1.*) or extend the bundle to parse CIDR notation.Symfony Debug Mode:
APP_DEBUG setting. Debug mode does not bypass maintenance.Console Commands in Maintenance:
maintenance:enable/disable commands themselves are not blocked by maintenance mode. Use this to your advantage for emergency fixes:
php bin/console maintenance:disable --env=prod # Works even if maintenance is on
Check Lock File:
1 (enabled) or 0 (disabled):
cat /tmp/maintenance_mode.lock
Log Listener Errors:
MaintenanceModeListener throws exceptions:
APP_ENV=dev APP_DEBUG=1 php bin/console server:run
Test IP Whitelisting:
curl to test if your IP is allowed:
curl -I http://localhost
503 Service Unavailable (unless whitelisted).Custom Maintenance Page:
503 page by creating a custom twig template at templates/bundles/MaintenanceMode/error503.html.twig.onKernelException event.Dynamic IP Allowlist:
MaintenanceModeListener to fetch IPs from a database:
// src/EventListener/CustomMaintenanceListener.php
use Drawik\MaintenanceModeBundle\EventListener\MaintenanceModeListener;
class CustomMaintenanceListener extends MaintenanceModeListener {
public function isIpAllowed(string $ip): bool {
// Fetch from DB or API
return in_array($ip, $this->fetchAllowedIps());
}
}
config/services.yaml:
services:
App\EventListener\CustomMaintenanceListener:
tags: ['kernel.event_listener', { event: 'kernel.request', method: 'onKernelRequest' }]
Multi-Tenant Maintenance:
lock_file_path config to create tenant-specific lock files:
lock_file_path: '%kernel.project_dir%/var/maintenance_%tenant_id%.lock'
echo "1" > var/maintenance_tenant1.lock
API vs. Web Maintenance:
REQUEST_URI in the listener:
if (str_starts_with($request->getUri(), '/api')) {
return; // Skip maintenance for API
}
How can I help you explore Laravel packages today?