Laravel Production Crash: How One Mis‑configured .htaccess on cPanel Dragged Hours‑Long Queue Workers Offline – Quick Fixes for PHP‑FPM, Opcache, and MySQL Blocking 🚀
If you’ve ever stared at a blinking terminal while your Laravel queue workers silently died, you know the gut‑wrenching feeling of a production outage that could have been prevented. One tiny line in .htaccess turned a stable VPS into a parking lot for 1000+ pending jobs, costing the client hours of lost revenue and endless Slack panic‑messages.
Why This Matters
Queue workers are the heartbeat of any SaaS‑style Laravel app—order processing, email dispatch, webhook retries. When they stall, every API call backs up, Redis fills, and MySQL sees a flood of lock waits. The ripple effect shows up in WordPress sites sharing the same server, WordPress plugins lag, and API speed drops dramatically.
Common Causes of Queue Collapse
- Incorrect
RewriteRulethat forces every request throughindex.phpcausing an infinite loop. - PHP‑FPM pool limits (
pm.max_children) set too low for high‑traffic queues. - Opcache disabled for CLI, making Artisan commands reload the entire framework each run.
- MySQL
innodb_lock_wait_timeouthitting default 50 seconds due to long‑running jobs. - Redis persistence mis‑configuration that blocks write‑through under heavy load.
Step‑by‑Step Fix Tutorial
1. Verify the .htaccess culprit
# Problematic block that rewrites everything to index.php
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [L,QSA]
On a Laravel app behind Apache, this rule is fine for web routes but it also intercepts php artisan queue:work calls when run via cron or Supervisor. The fix is to add an exclusion for queue scripts.
2. Add safe exclusions
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/artisan$ [NC]
RewriteRule ^ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [L,QSA]
This tells Apache to serve artisan directly, letting Supervisor launch workers without looping.
.htaccess file in public/ for web routes only. Deploy it via Git or your CI pipeline to avoid manual edits on production.
3. Tune PHP‑FPM for queue workers
# /etc/php/8.2/fpm/pool.d/laravel.conf
[laravel]
user = www-data
group = www-data
listen = /run/php-fpm-laravel.sock
pm = dynamic
pm.max_children = 40
pm.start_servers = 8
pm.min_spare_servers = 6
pm.max_spare_servers = 12
catch_workers_output = yes
php_admin_value[error_log] = /var/log/php-fpm/laravel-error.log
php_admin_flag[log_errors] = on
Match pm.max_children to the number of Supervisor processes you plan to run. A common pattern: max_children = workers * 2 to handle occasional spikes.
4. Enable Opcache for CLI
# /etc/php/8.2/cli/conf.d/10-opcache.ini
opcache.enable=1
opcache.validate_timestamps=1
opcache.max_accelerated_files=20000
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
Without Opcache, each php artisan queue:work reloads the full framework, adding ~200ms latency per job.
5. Reduce MySQL lock wait time
# /etc/mysql/mysql.conf.d/mysqld.cnf
[mysqld]
innodb_lock_wait_timeout = 10
innodb_flush_log_at_trx_commit = 2
max_connections = 500
Lowering the timeout prevents a single hung job from blocking the entire table.
6. Restart services
sudo systemctl restart php8.2-fpm
sudo systemctl restart nginx # or httpd for Apache
sudo systemctl restart mysql
VPS or Shared Hosting Optimization Tips
- Use a dedicated queue worker VM on a lightweight Ubuntu 22.04 droplet. Isolate Redis, MySQL, and PHP‑FPM to avoid noisy neighbor issues.
- Leverage Cloudflare Page Rules to cache static assets and reduce Apache load.
- Enable HTTP/2 or HTTP/3 on Nginx for better multiplexing of API calls.
- Monitor with Netdata or New Relic to spot sudden spikes in
php-fpm: active processes. - For shared cPanel hosts, keep your .htaccess minimal and use
php_valuedirectives sparingly.
Real World Production Example
Acme SaaS runs 12 Laravel queue workers on a 4‑core VPS. After a weekend deployment, a junior dev added the following line to .htaccess:
RewriteRule ^ - [F]
The rule returned 403 for every request, including internal artisan calls. Supervisor kept restarting workers, MySQL lock tables, and Redis queues filled up. The outage lasted 3 hours before the dev reverted the file.
Before vs After Results
| Metric | Before Fix | After Fix |
|---|---|---|
| Avg. job latency | 12 s | 0.18 s |
| PHP‑FPM CPU usage | 85 % | 30 % |
| MySQL lock wait time | 45 s | <5 s |
| Redis memory | 1.2 GB | 0.8 GB |
Security Considerations
When editing .htaccess, never expose internal paths or environment files. Add these directives:
# Prevent access to .env and config files
Require all denied
# Disable directory listing
Options -Indexes
Also lock down Supervisor config (/etc/supervisor/conf.d/laravel-queue.conf) so only root can edit.
Bonus Performance Tips
- Use
php artisan queue:restartafter each code push to clear compiled jobs. - Enable
redis-cli --bigkeysmonitoring to prune stale keys. - Run
composer install --optimize-autoloader --no-devon production builds. - Set
APP_DEBUG=falseandLOG_LEVEL=errorto avoid IO overhead. - Deploy with Docker and use
--restart unless-stoppedfor containerized workers.
FAQ
Q: Does the .htaccess fix work on Nginx?
No. Nginx uses location blocks. The equivalent is to add a location = /artisan { fastcgi_pass ... } directive.
Q: Can I run Laravel queues on shared hosting?
It’s possible with cron, but you’ll lose real‑time processing. Consider cheap secure hosting that offers at least 2 CPU cores and SSH access.
Q: How many workers should I run per CPU core?
Start with 1.5 workers per core and adjust based on php-fpm: idle processes metrics.
Q: Will disabling Opcache for CLI affect production?
Only CLI commands; web requests continue to benefit from Opcache.
Final Thoughts
Production stability is rarely about a single technology—it’s the interaction between Apache, PHP‑FPM, Opcache, MySQL, and your queue manager. A mis‑configured .htaccess can cascade into a full‑scale outage, but with the systematic checklist above you can lock down the environment, keep queue workers alive, and protect your revenue stream.
Take a moment now to audit your .htaccess, verify PHP‑FPM pools, and enable Opcache for CLI. The next time you push a release, the only thing you’ll worry about is new features, not a mysterious queue freeze.
No comments:
Post a Comment