How I Squashed a Laravel 10 Queue Worker Crash on a cPanel VPS: 3 Hidden Permission Bugs & FPM Misconfig That Slowed My Site Overnight
It felt like the whole API went silent at 2 am. My Laravel‑10 queue workers were crashing every few minutes, Redis was spiking, and the WordPress front‑end was crawling at a snail’s pace. After a frantic 45‑minute debug session I discovered three permission quirks and one PHP‑FPM setting that were silently throttling my entire stack. Below is the exact forensic walk‑through I used to bring the system back to life, plus a handful of production‑grade tweaks you can copy‑paste today.
Why This Matters
When a queue worker dies, Laravel’s queue:work process automatically restarts – but each restart spawns a fresh PHP‑FPM child. On a cPanel VPS with default limits, that can quickly exhaust available workers, balloon MySQL connections, and choke the Nginx ↔ Apache bridge that powers your WordPress site. The result? 5‑second page loads, missed API SLA, and a sudden spike in bounce rate.
Common Causes of Queue Crashes on a cPanel VPS
- Incorrect file ownership after a
composer installon the web user. - Missing execute bits on
artisanor supervisor scripts. - PHP‑FPM pools sharing the same
listen.owner/listen.groupas the Apache user, causing race conditions. - Out‑of‑memory (OOM) kills triggered by a low
pm.max_childrensetting.
Step‑By‑Step Fix Tutorial
1️⃣ Verify Ownership & Permissions
- All Laravel files should be owned by the cPanel user (e.g.,
exampleuser). - Directories:
0755, Files:0644. storageandbootstrap/cacheneed0775so the webserver can write.
# Replace exampleuser with your cPanel username
sudo chown -R exampleuser:exampleuser /home/exampleuser/public_html/laravel
find /home/exampleuser/public_html/laravel -type d -exec chmod 0755 {} \;
find /home/exampleuser/public_html/laravel -type f -exec chmod 0644 {} \;
chmod -R 0775 /home/exampleuser/public_html/laravel/storage
chmod -R 0775 /home/exampleuser/public_html/laravel/bootstrap/cache
2️⃣ Fix the artisan Execute Bit
artisan binary can be executed by the supervisor script.
chmod +x /home/exampleuser/public_html/laravel/artisan
3️⃣ Adjust PHP‑FPM Pool Settings
# /opt/cpanel/ea-php82/root/etc/php-fpm.d/www.conf
pm = dynamic
pm.max_children = 12 ; adjust to ~70% of total RAM / avg PHP process
pm.start_servers = 3
pm.min_spare_servers = 2
pm.max_spare_servers = 6
listen.owner = exampleuser
listen.group = exampleuser
listen.mode = 0660
; Reduce idle timeout to free workers faster
request_terminate_timeout = 300
After editing, restart PHP‑FPM:
sudo systemctl restart ea-php82-php-fpm
4️⃣ Configure Supervisor for Laravel Queues
# /etc/supervisor/conf.d/laravel-queue.conf
[program:laravel-queue]
process_name=%(program_name)s_%(process_num)02d
command=php /home/exampleuser/public_html/laravel/artisan queue:work redis --sleep=3 --tries=3 --timeout=60
autostart=true
autorestart=true
user=exampleuser
numprocs=4
redirect_stderr=true
stdout_logfile=/home/exampleuser/logs/laravel-queue.log
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl status laravel-queue:*
VPS or Shared Hosting Optimization Tips
- Swap space: Add a 1 GB swap file to prevent OOM kills on burst traffic.
- Opcode cache: Enable
opcache.enable=1and setopcache.max_accelerated_files=10000inphp.ini. - Redis persistence: Use
appendonly yesandsave 900 1for durability without high latency. - MySQL tuning: Set
innodb_buffer_pool_sizeto 70% of RAM; enablequery_cache_type=0for InnoDB‑only workloads. - Cloudflare page rules: Cache static assets for 1 day and enable “Always Online” to reduce load during queue spikes.
Real World Production Example
On a 4‑core Ubuntu 22.04 cPanel VPS I was running a Laravel API that processed webhook events from Stripe and a WordPress blog serving 10 k monthly visitors. After the fix:
# Before
Queue worker exits: "Failed to open stream: Permission denied"
Avg CPU: 95%
Redis: 0/1024 connections used
# After
Queue worker stable, 0 crashes in 48 h
Avg CPU: 32%
Redis: 125/1024 connections, p99 latency 2ms
WordPress TTFB: 0.42 s (down from 1.8 s)
Before vs After Results
Security Considerations
- Never set
chmod 777onstorage. Use group‑write permissions with a dedicatedwww-data(or cPanel user) group. - Lock down Supervisor:
chmod 640 /etc/supervisor/conf.d/laravel-queue.confand ensure onlyrootcan edit. - Enable
open_basedirrestriction for each PHP‑FPM pool to prevent accidental directory traversal. - Rotate Redis passwords every 90 days and set
requirepassin/etc/redis/redis.conf.
Bonus Performance Tips
- Use
php artisan route:cacheandconfig:cacheafter every deployment. - Leverage
Laravel OctanewithSwooleon a dedicated port for high‑throughput API calls. - Offload image processing to
spatie/laravel-image-optimizerand store results on Cloudflare R2. - Set
session.driver=redisandcache.driver=redisfor both Laravel and WordPress (viawp-config.phpplugin). - Enable HTTP/2 on Nginx:
listen 443 ssl http2;
FAQ
Q: My queue still dies after fixing permissions – what else can cause it?
A: Check the Laravel .env for QUEUE_CONNECTION=redis and verify the Redis service is reachable from the VPS. A firewall rule blocking 127.0.0.1:6379 will cause silent failures.
Q: Can I run the same setup on a shared cPanel host?
A: Shared hosts usually restrict FPM pool editing and Supervisor. In that case, use php artisan queue:listen with a cron entry (* * * * * php /path/artisan queue:work --daemon) and ask the host to increase max_children for you.
Q: Do I need to restart Nginx after changing FPM?
No, restarting PHP‑FPM is enough. However, if you modify fastcgi_buffers in Nginx, a reload (nginx -s reload) is required.
Final Thoughts
Server‑side bugs hide in plain sight: a missing chmod, a mis‑set FPM user, or a too‑low pm.max_children. The moment you bring the OS‑level hygiene back to parity with your Laravel codebase, the queue stabilizes, Redis stays happy, and your WordPress front‑end finally feels fast again. Treat your VPS like a production codebase—version‑control your php-fpm and supervisor configs, run composer install --no-dev on the server, and automate the permission steps in your CI/CD pipeline.
Monetize the Knowledge
If you run a SaaS monitoring service, consider offering a Laravel Queue Health Check add‑on that automatically scans for the four bugs covered here. Pair it with a WordPress‑Laravel Bridge plugin that syncs Redis cache keys across both platforms, and you have a ready‑to‑sell upsell for any agency managing mixed stacks.
No comments:
Post a Comment