Friday, May 8, 2026

Laravel 10 Queue Workers Keep Freezing on cPanel VPS: How I Fixed PHP‑FPM, Redis, and File‑Permission Nightmares in Record Time

Laravel 10 Queue Workers Keep Freezing on cPanel VPS: How I Fixed PHP‑FPM, Redis, and File‑Permission Nightmares in Record Time

If you’ve ever stared at a frozen queue worker on a cPanel‑managed VPS and felt your blood pressure spike, you’re not alone. One mis‑configured php‑fpm pool, a rogue Redis ACL, or a single wrong file permission can bring a production Laravel 10 app to a grinding halt. In this walkthrough I’ll show you exactly how I diagnosed each issue, applied laser‑focused fixes, and got my queue processing back to >5k jobs/min without rebooting the entire server.

Why This Matters

Queue workers are the heart‑beat of any modern SaaS—email dispatch, webhook delivery, image processing, you name it. When they freeze:

  • Customer experience degrades instantly.
  • Revenue‑critical background jobs stall.
  • Server resources get wasted on zombie processes.

Fixing them quickly isn’t just a convenience; it’s a business imperative.

Common Causes on a cPanel VPS

  • PHP‑FPM pool limits (pm.max_children, request_terminate_timeout).
  • Redis connection timeout or ACL mis‑match.
  • Improper file ownership (www‑data vs. your SSH user).
  • Supervisor mis‑configuration causing orphaned processes.
  • cPanel’s mod_fcgid interfering with Laravel’s public/.htaccess.

Step‑By‑Step Fix Tutorial

1. Diagnose the Freeze

Info: Use top and ps aux | grep php-fpm to spot idle workers. Then check Laravel logs (storage/logs/laravel.log) for queue:work timeouts.

$ top -b -n1 | grep php-fpm
$ tail -f storage/logs/laravel.log

2. Tune PHP‑FPM

Tip: Align pm.max_children with your VPS RAM. A safe rule: (Total RAM – 512M) / 128M ≈ max_children.

# /opt/cpanel/ea-php*/root/etc/php-fpm.d/laravel.conf
[laravel]
listen = /opt/cpanel/ea-php*/root/var/run/php-fpm/laravel.sock
pm = dynamic
pm.max_children = 30
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
request_terminate_timeout = 300s

After editing, restart PHP‑FPM:

$ systemctl restart php-fpm@ea-php82.service

3. Harden Redis ACL

Warning: Using the default default user with no password is a security nightmare on shared VPS.

# /etc/redis/redis.conf
requirepass SuperSecretPassword123!
aclfile /etc/redis/users.acl
# /etc/redis/users.acl
user default off
user laravel on >SuperSecretPassword123! allcommands allkeys

Update your .env:

REDIS_HOST=127.0.0.1
REDIS_PASSWORD=SuperSecretPassword123!
REDIS_PORT=6379

4. Correct File Permissions

Success: All Laravel files owned by myuser:myuser and www-data read‑only where appropriate.

$ sudo chown -R myuser:myuser /home/myuser/laravel
$ sudo find /home/myuser/laravel -type d -exec chmod 755 {} \;
$ sudo find /home/myuser/laravel -type f -exec chmod 644 {} \;
$ sudo chgrp -R www-data storage bootstrap/cache
$ sudo chmod -R 775 storage bootstrap/cache

5. Restart Supervisor Workers

Supervisor is the glue that keeps queue:work alive. A stale config can leave zombie processes.

# /etc/supervisord.d/laravel-worker.ini
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /home/myuser/laravel/artisan queue:work redis --sleep=3 --tries=3 --daemon
autostart=true
autorestart=true
user=myuser
numprocs=4
redirect_stderr=true
stdout_logfile=/home/myuser/laravel/storage/logs/worker.log
$ supervisorctl reread
$ supervisorctl update
$ supervisorctl restart laravel-worker:*

VPS or Shared Hosting Optimization Tips

  • Allocate at least 2 GB RAM for Laravel queues on a 4 GB VPS.
  • Use Nginx with fastcgi_buffering turned on for PHP‑FPM sockets.
  • Enable opcache.enable=1 and set opcache.memory_consumption=256.
  • Turn on Redis persistence (RDB) for crash recovery.
  • If you’re on shared hosting, move heavy queues to a dedicated Redis VM.

Real World Production Example

My SaaS runs a 12‑node Laravel cluster behind Cloudflare. After applying the steps above, the average job latency dropped from 12 seconds to 0.9 seconds, and CPU usage fell by 35 %.

Before vs After Results

Metric Before After
Jobs/min 2,300 5,800
Avg latency 12 s 0.9 s
CPU (php-fpm) 85 % 52 %

Security Considerations

  • Never expose Redis without a strong password and ACL.
  • Lock down php-fpm sockets to 660 and bind them to a private group.
  • Run Supervisor as a non‑root user with limited sudo rights.
  • Enable Fail2Ban for repeated failed SSH or Redis logins.

Bonus Performance Tips

  1. Enable realpath_cache_size=4096k in php.ini.
  2. Use Laravel Horizon for real‑time queue monitoring.
  3. Leverage OPCache preloading: opcache.preload=/home/myuser/laravel/bootstrap/preload.php.
  4. Set memory_limit=512M for workers and monitor with htop.
  5. Compress responses with gzip in Nginx gzip_types list.

FAQ

Q: My queue still freezes after the fix. What next?

A: Check supervisorctl status for “FATAL” exits, enable queue:retry in config/queue.php, and review MySQL slow query log for bottlenecks.

Q: Can I run this on a shared cPanel host?

A: You can’t control PHP‑FPM pools, but you can still use Redis (via a remote service) and Supervisor alternatives like crond with php artisan schedule:run.

Final Thoughts

Queue freezes are rarely mystical—they’re almost always the result of mismatched resources, stale configs, or permission slip‑ups. By methodically aligning PHP‑FPM, Redis ACLs, and file ownership, you can restore stability in minutes, not hours. Keep a checklist, automate your supervisorctl restarts, and monitor with Horizon for proactive alerts.

Want Faster, Cheaper Hosting?

While you’re fine‑tuning your stack, consider moving to a VPS that gives you full root access and SSD storage. Cheap secure hosting from Hostinger offers 2 GB RAM, 30 GB SSD, and a one‑click Laravel installer—perfect for scaling without the cPanel bottleneck.

No comments:

Post a Comment