Thursday, May 7, 2026

Why My Laravel Production App Is Crashing at 8 PM: Solving PHP‑FPM Timeouts on cPanel Shared Hosting with Docker‑Lite

Why My Laravel Production App Is Crashing at 8 PM: Solving PHP‑FPM Timeouts on cPanel Shared Hosting with Docker‑Lite

It’s 8 PM. Your monitoring dashboard flashes red, users can’t submit forms, and the error log is exploding with FastCGI: comm with server “unix:/opt/php-fpm.sock” aborted: timeout. You’re on a shared cPanel box, you’ve just added a Docker‑Lite environment for a queue worker, and the whole Laravel site collapses like a house of cards. Sound familiar? You’re not alone.

Why This Matters

Every lost request after hours means lost revenue, a bruised brand, and a frantic on‑call rotation. In the SaaS world, a single timeout can trigger a cascade: failed API calls, dead queue jobs, and a sudden spike in CPU that forces your host to throttle or even suspend the account. Understanding the root cause—and fixing it—keeps your Laravel app smooth, your WordPress integration fast, and your customers happy.

Common Causes of 8 PM Crashes

  • PHP‑FPM max_children hit during traffic spike.
  • Docker‑Lite container starving for CPU/memory on shared hosting.
  • Long‑running queue workers that never exit, exhausting FPM slots.
  • Mis‑configured Nginx/Apache fastcgi buffers.
  • MySQL lock contention caused by heavy reporting queries.
  • Redis cache miss flood when the TTL expires at the top of the hour.
  • Composer autoloader bloat after a recent composer update.
INFO: Most shared cPanel hosts limit CPU to ~30 % and memory to 1 GB per account. Docker‑Lite runs as a regular user, so it inherits those limits. When a Laravel scheduler fires at the top of the hour, it can easily exceed them.

Step‑By‑Step Fix Tutorial

1. Diagnose the Timeout

First, confirm the error source.

tail -f /home/username/logs/php-fpm/error.log | grep "timeout"

Look for lines that mention request_terminate_timeout or pm.max_children.

2. Increase PHP‑FPM Limits

Edit the PHP‑FPM pool file (usually /opt/php73/etc/php-fpm.d/www.conf on cPanel).

[www]
pm = dynamic
pm.max_children = 30            ; raise from default 12
pm.start_servers = 5
pm.min_spare_servers = 3
pm.max_spare_servers = 10
request_terminate_timeout = 120 ; seconds

After saving, restart PHP‑FPM:

/usr/local/bin/php-fpm -y /opt/php73/etc/php-fpm.conf --reload
TIP: Set pm.max_requests to 500 to force graceful worker recycling and avoid memory leaks.

3. Optimize Docker‑Lite Resource Limits

Add a docker-compose.yml snippet that caps CPU and memory:

services:
  queue-worker:
    image: yourrepo/laravel-queue
    deploy:
      resources:
        limits:
          cpus: '0.75'
          memory: 512M
    restart: unless-stopped

Deploy the changes:

docker compose up -d --no-deps --force-recreate queue-worker

4. Tune Nginx FastCGI Buffers (or Apache Proxy)

If you’re using Nginx as a reverse proxy, add these directives to your site block:

location ~ \.php$ {
    include fastcgi_params;
    fastcgi_pass unix:/opt/php73/var/run/www.sock;
    fastcgi_buffer_size 32k;
    fastcgi_buffers 8 64k;
    fastcgi_busy_buffers_size 128k;
    fastcgi_read_timeout 90;
}

For Apache with mod_proxy_fcgi:

ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://127.0.0.1:9000/home/username/public_html/$1

5. Offload Heavy Queries to Redis

Cache the hourly report data that kills MySQL.

// In a Laravel service provider
Cache::remember('hourly_report', 55, function () {
    return DB::table('orders')
        ->selectRaw('SUM(total) as total, DATE(created_at) as day')
        ->where('created_at', '>=', now()->subHour())
        ->groupBy('day')
        ->get();
});

6. Restart Supervisor Workers

Ensure Supervisor respects the new PHP‑FPM limits.

[program:laravel-queue]
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
numprocs=3
user=username
stopwaitsecs=360
stdout_logfile=/home/username/logs/queue.log
stderr_logfile=/home/username/logs/queue-error.log

Reload Supervisor:

supervisorctl reread && supervisorctl update && supervisorctl restart laravel-queue:*
WARNING: Do NOT set numprocs higher than your PHP‑FPM max_children or you’ll create a deadlock.

VPS or Shared Hosting Optimization Tips

  • Use OPcache. Add opcache.enable=1 and opcache.memory_consumption=192 to php.ini.
  • Limit Composer autoload. Run composer dump-autoload -o after each deploy.
  • Swap wisely. On VPS, enable a 1 GB swap file to avoid OOM kills.
  • Separate Redis. If possible, use a managed Redis instance to free local RAM.
  • Enable HTTP/2. Both Nginx and Apache support it; it reduces latency for API calls.

Real World Production Example

Company Acme SaaS ran a Laravel API on a 2 CPU cPanel shared plan. Their nightly email campaign triggered a queue:work container at 20:00. After applying the steps above they saw:

Metric Before After
CPU Avg 85 % 42 %
PHP‑FPM Timeouts 12/hr 0
Redis Cache Misses 8,320 1,210
SUCCESS: The site stayed up during the 20:00 spike, email delivery time dropped 37 %, and the client saved $120/mo by staying on shared hosting instead of upgrading.

Before vs After Results

# BEFORE
[20:00] PHP-FPM: request timeout (max 30s)
[20:00] Docker container OOM killed
[20:01] 502 Bad Gateway errors spike

# AFTER
[20:00] PHP-FPM: all workers healthy
[20:00] Docker container uses 0.6 CPU / 400M RAM
[20:01] 0 error responses, API latency 120ms

Security Considerations

  • Never expose Docker socket directly to the web; bind it to localhost.
  • Use --read-only flag for containers that only need to read the codebase.
  • Restrict php.ini disable_functions to block exec, shell_exec if not needed.
  • Enable mod_security on Apache or ngx_http_limit_req_module on Nginx to mitigate brute‑force API calls.

Bonus Performance Tips

  • Enable Laravel route cache: php artisan route:cache.
  • Cache config: php artisan config:cache.
  • Use php artisan view:cache for Blade templates.
  • Set SESSION_DRIVER=redis and CACHE_DRIVER=redis in .env.
  • Compress assets with laravel-mix --production and serve via Cloudflare CDN.

FAQ

Q: I’m on a cPanel host that doesn’t let me edit php-fpm.conf. What can I do?

A: Use a custom .user.ini to set request_terminate_timeout and max_execution_time. Also, push the heavy job to a separate Docker container that runs under its own user.

Q: My queue jobs still hang after the fix.

A: Add --timeout=120 to the queue:work command and ensure Supervisor’s stopwaitsecs is higher than that value.

Final Thoughts

Time‑outs at 8 PM are rarely a mystical bug; they’re a symptom of resource contention, mis‑configured FPM pools, and unchecked container consumption. By tightening PHP‑FPM, sandboxing Docker‑Lite, and leveraging Redis and OPcache, you can keep a Laravel app stable on even the most modest shared host. The same principles apply when you later migrate to a VPS or a dedicated cloud instance—just scale the numbers.

If you’re looking for an affordable, secure hosting platform that plays nicely with cPanel, Docker‑Lite, and Laravel, check out Hostinger’s cheap secure hosting. Their burstable CPU and built‑in Redis add‑on make the transition painless.

No comments:

Post a Comment