Tuesday, May 12, 2026

Laravel Queue Workers Stop Crashing on Shared cPanel VPS: Diagnose and Fix Failed Jobs, Permission Errors, and PHP‑FPM Timeouts with Real‑World Logs and One‑Minute Hotfixes This Week 🚨

Laravel Queue Workers Stop Crashing on Shared cPanel VPS: Diagnose and Fix Failed Jobs, Permission Errors, and PHP‑FPM Timeouts with Real‑World Logs and One‑Minute Hotfixes This Week 🚨

If you’ve ever stared at a blinking php artisan queue:work that immediately dies, felt the sting of “Failed job” emails at 3 am, and wondered whether you’re about to abandon Laravel for a static site, you’re not alone. On shared cPanel VPSes the problem is maddeningly common: workers explode, jobs disappear, and the whole API ground to a halt.

What you’ll learn:
  • Why queue workers fail on shared cPanel VPS.
  • How to read the exact log lines that point to permission vs PHP‑FPM timeout issues.
  • One‑minute hotfixes you can apply via SSH or cPanel Terminal.
  • Long‑term VPS and shared‑hosting optimizations that keep your Laravel‑WordPress hybrid humming.

Why This Matters

Queue workers are the backbone of any modern Laravel application—email notifications, image processing, webhook dispatches, and every API‑heavy background task rely on them. When they crash:

  • Your users experience delayed emails or missing push notifications.
  • Retry loops consume CPU and RAM, driving up VPS costs.
  • Failed‑job tables fill up, causing MySQL bloat and slower queries.
  • WordPress plugins that depend on Laravel services (e.g., custom API gateways) start to timeout, hurting SEO and conversion rates.

Common Causes on Shared cPanel VPS

Below are the top three culprits you’ll see in /var/log/php-fpm/error.log and storage/logs/laravel.log on a typical shared VPS.

1. PHP‑FPM “request timed out”

2024-05-10 02:15:32 [error] [pool www] child 2459 said into stderr: 
[2024-05-10 02:15:32] FastCGI sent in stderr: "PHP Fatal error:  Uncaught Symfony\Component\Process\Exception\RuntimeException: The process has been terminated due to timeout."

2. File permission errors on storage and bootstrap/cache

2024-05-10 02:18:07 [error] Illuminate\Contracts\Filesystem\FileNotFoundException: 
Failed to open stream: Permission denied (storage/framework/sessions/...)

3. Supervisor not respecting cPanel limits

2024-05-10 02:20:44 [error] supervisor[laravel-worker-00] exited with status 2
Warning: Ignoring these errors will eventually cause a “Too many open files” fatal and bring down every PHP site on the server.

Step‑By‑Step Fix Tutorial

Step 1 – Increase PHP‑FPM Timeout

Log into cPanel → “Select PHP Version” → “Options”. Set max_execution_time to 300 and request_terminate_timeout to 300. If you have SSH access, edit the pool file directly:

# SSH into your VPS
sudo vim /opt/cpanel/ea-php81/root/etc/php-fpm.d/www.conf

; Add or edit these lines
request_terminate_timeout = 300
php_admin_value[max_execution_time] = 300
Tip: After editing, reload PHP‑FPM with systemctl reload php-fpm (or use cPanel “Restart PHP-FPM” button).

Step 2 – Fix Storage Permissions

Laravel expects the storage and bootstrap/cache directories to be writable by the web user (nobody on cPanel). Run:

# From your project root
sudo chown -R $USER:nobody storage bootstrap/cache
sudo find storage bootstrap/cache -type d -exec chmod 775 {} \;
sudo find storage bootstrap/cache -type f -exec chmod 664 {} \;

Step 3 – Configure Supervisor for cPanel Limits

Many shared hosts block systemctl, so use a simple supervisord.conf that respects the cPanel ulimit values.

# /home/username/supervisord.conf
[supervisord]
logfile=/home/username/supervisor.log
loglevel=info
pidfile=/home/username/supervisord.pid
nodaemon=true

[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /home/username/public_html/artisan queue:work redis --sleep=3 --tries=3
autostart=true
autorestart=true
user=username
numprocs=2
stopwaitsecs=360
stdout_logfile=/home/username/worker_stdout.log
stderr_logfile=/home/username/worker_stderr.log

Start it via cPanel’s “Cron Jobs” (run once at reboot):

@reboot /usr/local/bin/supervisord -c /home/username/supervisord.conf
Success: Workers now survive the typical 30‑second cPanel idle timeout.

VPS or Shared Hosting Optimization Tips

  • Swap file: For low‑RAM VPSes, create a 1 GB swap to prevent OOM kills.
    sudo fallocate -l 1G /swapfile
    sudo chmod 600 /swapfile
    sudo mkswap /swapfile
    sudo swapon /swapfile
  • Redis persistence: Enable appendonly yes in /etc/redis/redis.conf to avoid lost jobs after restarts.
  • MySQL tuning: Set innodb_buffer_pool_size = 256M (or 50 % of RAM) for faster queue table reads.
  • Opcode cache: Enable OPcache in php.ini (opcache.enable=1) to shave 30 % off job boot time.
  • Cloudflare page rules: Bypass caching for /api/* endpoints that trigger queues.

Real World Production Example

Company Acme SaaS ran a Laravel + WordPress hybrid on a 2 CPU, 4 GB shared cPanel VPS. After the first week, the failed_jobs table grew to 12 K rows and the queue worker kept exiting with “request timed out”. Below is the exact log snippet:

2024-05-06 07:42:15 local.ERROR: RuntimeException: The process has been terminated due to timeout. {"exception":"[object] (Symfony\\Component\\Process\\Exception\\RuntimeException(code: 0): The process has been terminated due to timeout. at /home/acme/vendor/symfony/process/Process.php:332)"} 
2024-05-06 07:42:15 local.ERROR: Failed to write file: Permission denied | /home/acme/storage/framework/cache/data/...
2024-05-06 07:42:17 local.INFO: Worker stopped due to signal 15

Fixes applied:

  1. PHP‑FPM timeout raised to 300 s.
  2. Directory ownership switched to acme:nobody.
  3. Supervisor config updated with numprocs=4 and stopwaitsecs=360.
  4. Redis append‑only enabled.

Before vs After Results

Metric Before Fix After Fix
Failed jobs per day 1,250 12
Average queue latency 8.4 s 0.9 s
CPU spikes (max %) 95% 45%

Security Considerations

When you broaden permissions or add swap files, make sure you’re not opening a new attack vector.

  • Never set chmod 777 on storage. Use 775/664 as shown.
  • Limit Supervisor to run as the specific user, not root.
  • Keep Redis bound to 127.0.0.1 and use a strong password in .env (REDIS_PASSWORD).
  • Enable disable_functions for exec, shell_exec in shared hosting if not needed.

Bonus Performance Tips

  • Batch email jobs (max 50 per queue) to reduce PHP‑FPM start‑up cost.
  • Use --daemon mode only with php artisan queue:work --daemon when you have a process manager that guarantees zero‑timeout.
  • Leverage Laravel Horizon on VPS (requires Redis) for visual queue metrics and auto‑scaling.
  • Compress large payloads before pushing to the queue (base64 + gzencode).
  • Set QUEUE_CONNECTION=redis in .env and disable sync for production.

FAQ

Q: My queue still restarts after the hotfix. What else can I check?

A: Verify the max_children setting in /etc/php-fpm.d/www.conf. If it’s lower than the number of Supervisor processes, PHP‑FPM will kill workers.

Q: Can I use Supervisor on a pure shared hosting plan without SSH?

A: Yes. Many hosts let you run “Cron Jobs” every minute that invoke php artisan queue:work --once. It’s less efficient but avoids daemon limits.

Q: Do I need to clear Laravel cache after changing permissions?

A: Run php artisan config:clear && php artisan cache:clear to avoid stale path references.

Final Thoughts

Queue workers crashing on a shared cPanel VPS is not a “Laravel bug” – it’s a classic mismatch between Laravel’s expectations and the restrictive environment of shared hosting. By extending PHP‑FPM timeouts, securing proper file ownership, and using a lightweight Supervisor configuration, you can restore stability within minutes and prevent costly downtime for both Laravel and WordPress components.

Remember: the real power of a hybrid Laravel‑WordPress stack lies in the ability to run background jobs reliably. Once the workers stay alive, your API response times, email deliverability, and user experience will all climb, giving you more room to monetize, upsell SaaS features, or simply scale without panic.

Quick One‑Minute Hotfix Recap:
  1. Increase PHP‑FPM request_terminate_timeout to 300 s.
  2. Set chmod 775/664 on storage and bootstrap/cache, chown to youruser:nobody.
  3. Deploy a minimal supervisord.conf and start it via a cron @reboot line.

Apply the steps now, watch the failed_jobs table shrink, and enjoy a smooth, production‑grade queue system—even on a modest shared VPS.

Looking for cheap, secure hosting that plays well with Laravel, Redis, and WordPress? Check out Hostinger’s VPS plans – they give you full root access, ready‑to‑go PHP‑FPM, and a 30‑day money‑back guarantee.

No comments:

Post a Comment