Laravel Queue Worker Crashes on VPS: 5 Hidden File‑Permission Pitfalls Causing Stuck Jobs and 0‑Second Uptime in 30 Minutes Fix Guide
Ever watched a queue worker die silently while your users stare at a blank page? You’re not alone. The frustration of “jobs stuck forever” and “artisan queue:work keeps exiting with code 0” is a pain point for every Laravel engineer running on a VPS. In the next few minutes you’ll discover the five permission traps that sabotage your queues, and a step‑by‑step rescue plan that restores 100 % uptime.
Why This Matters
Queue workers are the heartbeat of modern SaaS, handling email delivery, webhook retries, PDF generation, and more. When a worker crashes:
- Customer experience drops → revenue loss.
- Retry back‑off floods MySQL, hurting API speed.
- Server CPU spikes as supervisor respawns dead processes.
Fixing the underlying permission issue not only stabilises your Laravel app but also reduces the load on PHP‑FPM, Redis, and MySQL—key metrics that SEO tools like Google PageSpeed love.
Common Causes of Queue Worker Crashes
- Incorrect ownership of
storageandbootstrap/cachedirectories. - Missing execute flag on
artisanbinary. - Supervisor configuration pointing to a non‑executable PHP binary.
- Redis persistence files owned by
rootcausingERR Permission denied. - Composer autoload files with restrictive
chmodset during CI/CD.
www-data user must own all runtime paths. Anything else will silently kill queue:work after the first job finishes.
Step‑By‑Step Fix Tutorial
1️⃣ Verify Current Permissions
# Check ownership
ls -ld storage bootstrap/cache
# Sample output should be:
drwxr-xr-x 5 www-data www-data 4096 Sep 12 12:34 storage
drwxr-xr-x 5 www-data www-data 4096 Sep 12 12:34 bootstrap/cache
2️⃣ Correct Ownership Across the Project
# Replace /var/www/laravel with your app root
sudo chown -R www-data:www-data /var/www/laravel
sudo find /var/www/laravel -type d -exec chmod 2755 {} \;
sudo find /var/www/laravel -type f -exec chmod 0644 {} \;
storage to inherit the www-data group automatically.
3️⃣ Make artisan Executable
sudo chmod +x /var/www/laravel/artisan
4️⃣ Adjust Supervisor Configuration
[program:laravel-queue]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/laravel/artisan queue:work redis --sleep=3 --tries=3 --timeout=90
autostart=true
autorestart=true
user=www-data
numprocs=3
redirect_stderr=true
stdout_logfile=/var/www/laravel/storage/logs/worker.log
root. It will bypass permission checks and later fail when writing to storage/framework/cache.
5️⃣ Fix Redis Persistence Permissions
# Typical Redis path on Ubuntu
sudo chown redis:redis /var/lib/redis/dump.rdb
sudo chmod 660 /var/lib/redis/dump.rdb
6️⃣ Restart Services
sudo systemctl restart php8.2-fpm
sudo systemctl restart nginx
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl restart laravel-queue:*
VPS or Shared Hosting Optimization Tips
- Swap Management: Allocate at least 1 GB swap on low‑memory VPS to avoid OOM kills.
- PHP‑FPM Pools: Create a dedicated pool named
laravelwithpm.max_children=30for high‑throughput queues. - OPcache Settings:
opcache.memory_consumption=256andopcache.validate_timestamps=0inphp.iniboost API speed. - MySQL Tuning: Set
innodb_buffer_pool_size=70% of RAMand enableslow_query_logfor queue‑related queries. - Cloudflare Cache‑Purge Hook: Use Laravel webhook to purge CDN after jobs finish (e.g., image optimization).
Real World Production Example
Acme SaaS runs 12 k queued emails per hour on a 2‑vCPU Ubuntu 20.04 VPS. After applying the permission fix, the queue:work logs stopped restarting, CPU dropped from 95 % to 32 %, and email delivery latency fell from 45 s to 7 s.
Before vs After Results
| Metric | Before | After |
|---|---|---|
| CPU Avg | 95 % | 32 % |
| Queue Restarts | 12/hr | 0 |
| Job Latency | 45 s | 7 s |
Security Considerations
- Never give
www-datawrite access outsidestorageandbootstrap/cache. - Enable
open_basedirto restrict PHP file system access. - Use Laravel’s
queue:restartcommand instead of killing processes manually. - Keep Composer dependencies up‑to‑date:
composer auditandcomposer update --with-all-dependencies.
Bonus Performance Tips
- Switch Redis to
appendonly noin production for faster writes. - Drop
--sleepto1and use--daemonflag on high‑rate queues. - Leverage Laravel Horizon for real‑time queue monitoring and auto‑scaling.
- Compress large JSON payloads with
gzencodebefore pushing to the queue.
FAQ
Q: My supervisor still reports “EXITED (0)” after the fix.
A: Verify theuserdirective matches the owner ofstorage. Restart supervisor and checkworker.logfor permission errors.
Q: Can I run the queue on a shared hosting plan?
A: Yes, but you must usephp artisan queue:work --stop-when-emptyvia cron every minute, and ensure the host allowsexecfor the php binary.
Final Thoughts
File‑permission mishaps are the silent killers of Laravel queue reliability. By normalising ownership, tightening supervisor configs, and giving Redis the proper rights, you eliminate the “0‑second uptime” syndrome in under half an hour. The payoff? Faster APIs, happier customers, and a cleaner server‑side stack that scales without screaming for more RAM.
Ready to future‑proof your Laravel deployment? Pair this fix with a low‑cost, high‑performance VPS from Hostinger and you’ll have the resources you need without breaking the bank.
No comments:
Post a Comment