How to Fix a 500 Internal Server Error Caused by Redis Mis‑configuration on a Docker Nginx Stack in Production Laravel Applications
You’ve just pushed a fresh Laravel release to production, the CI/CD pipeline told you “All good!” and then you open the site—boom, a generic “500 Internal Server Error”. Your heart races, the client is already on Slack, and you suspect nothing more than a typo. In reality the culprit is often hidden deep inside Docker, Nginx, or Redis. This guide walks you through the exact steps to locate, diagnose, and permanently squash that Redis‑related 500 error, with a focus on real‑world Docker‑Nginx‑Laravel stacks running on VPS or shared hosting.
Why This Matters
Every second of downtime costs money, reputation, and developer morale. A mis‑configured Redis instance can bring down your entire queue system, session driver, and cache layer, turning a high‑traffic Laravel app into a black hole. Fixing it quickly not only restores API speed and WordPress performance (if you share the same Redis server) but also prevents future cascading failures across PHP‑FPM, MySQL, and Composer autoloaders.
Common Causes
- Wrong
REDIS_HOSTorREDIS_PORTin.envafter Docker network changes. - Redis container not exposing the expected port (default 6379) to the host.
- Insufficient
maxmemorypolicy causing Redis to abort connections. - Missing
phpredisextension in the PHP‑FPM image. - Supervisor workers crashing because they can’t connect to Redis.
Step‑by‑Step Fix Tutorial
1️⃣ Verify Docker Network Connectivity
Enter the Laravel container and ping the Redis service.
# Inside Laravel container
docker exec -it laravel_app bash
ping redis
# If ping fails, inspect your docker‑compose.yml
2️⃣ Check .env Values
Make sure the Redis variables match the Docker service name and exposed port.
# .env
REDIS_HOST=redis
REDIS_PASSWORD=null
REDIS_PORT=6379
CACHE_DRIVER=redis
SESSION_DRIVER=redis
QUEUE_CONNECTION=redis
3️⃣ Confirm Redis Is Listening
# From host
docker exec -it redis redis-cli ping
# Expected output: PONG
4️⃣ Adjust Nginx FastCGI Params
If you’re using Nginx as a reverse proxy, ensure PHP‑FPM points to the correct socket and that fastcgi_param SCRIPT_FILENAME is set.
# /etc/nginx/conf.d/laravel.conf
server {
listen 80;
server_name example.com;
root /var/www/html/public;
index index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass php-fpm:9000;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param DOCUMENT_ROOT $realpath_root;
}
}
docker compose exec php-fpm php artisan config:clear after any .env change.
5️⃣ Rebuild PHP‑FPM Image with phpredis
# Dockerfile for php-fpm
FROM php:8.2-fpm-alpine
RUN apk add --no-cache \
libzip-dev \
zlib-dev \
&& docker-php-ext-install zip pdo_mysql \
&& pecl install redis \
&& docker-php-ext-enable redis
WORKDIR /var/www/html
COPY . .
6️⃣ Restart the Stack
# From project root
docker compose down
docker compose up -d --build
7️⃣ Verify Laravel Logs
Tail the Laravel log to confirm the 500 error is gone.
# Inside Laravel container
tail -f storage/logs/laravel.log
VPS or Shared Hosting Optimization Tips
- Use a dedicated Redis instance: On cheap VPS, allocate a separate RAM slice (e.g.,
maxmemory 256mb) to avoid swapping. - Enable TCP keepalive: Add
tcp_keepalive 60;inredis.confto keep long‑running queue workers stable. - Leverage Cloudflare cache‑purge API: Reduces hit‑rate on Redis for static assets.
- Set proper
php-fpmworkers: For 2‑core VPS, start withpm.max_children = 20and adjust based ontopoutput.
Real World Production Example
Acme SaaS runs a 12‑container Docker stack on a 4 vCPU, 8 GB Ubuntu 22.04 VPS. After a major feature release, their users reported “502 Bad Gateway” that later turned into “500”. The root cause was a Redis maxmemory-policy allkeys-lru hitting the 1 GB cap and evicting session keys, causing PHP‑FPM to throw RedisException: Connection refused.
The fix involved:
- Increasing Redis memory limit to 2 GB.
- Changing the eviction policy to
volatile-lruto keep session keys safe. - Adding a Supervisor config that restarts the queue workers on Redis disconnect.
Supervisor Config
# /etc/supervisor/conf.d/laravel-queue.conf
[program:laravel-queue]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/html/artisan queue:work redis --sleep=3 --tries=3
autostart=true
autorestart=true
stopwaitsecs=3600
user=www-data
stdout_logfile=/var/log/laravel/queue.log
stderr_logfile=/var/log/laravel/queue_error.log
Before vs After Results
| Metric | Before Fix | After Fix |
|---|---|---|
| 5‑minute error rate | 27 % | 0 % |
| Average API response | 850 ms | 320 ms |
| Redis memory usage | 1 GB (full) | 1.2 GB (headroom) |
Security Considerations
- Never expose Redis port 6379 to the public internet; bind to
127.0.0.1or Docker internal network only. - Use a strong
requirepassinredis.confand reference it viaREDIS_PASSWORDin Laravel. - Enable TLS termination in Nginx if you forward Redis traffic over a VPN.
- Set proper file permissions on
.env(600) and Docker secrets.
protected-mode without a firewall opens the server to remote exploitation. Always keep the firewall active.
Bonus Performance Tips
- Cache warm‑up scripts: Run
php artisan cache:clear && php artisan view:cacheafter deployments. - Use Redis pipeline for bulk writes: Improves queue throughput by up to 30%.
- Enable OPcache and JIT in
php.ini:opcache.enable=1andopcache.jit_buffer_size=100M. - Configure MySQL query cache (or use Percona): Reduces DB load that often spikes when Redis is down.
FAQ
Q: My Laravel logs still show “Redis connection timed out” after the fix.
A: Verify the Docker network DNS resolution. Rundocker compose exec php-fpm getent hosts redisand ensure the IP matches the Redis container.
Q: Can I run Redis on the same VPS as my Laravel app?
A: Yes, but allocate at least 25% of RAM to Redis and monitorredis-cli info memorydaily.
Q: Does Cloudflare interfere with Redis?
A: Only if you proxy API endpoints that rely on Redis for auth. Bypass Cloudflare for those routes or use “Cache‑Level: Bypass”.
Final Thoughts
Redis is a powerful accelerator for Laravel, but it also becomes a single point of failure when mis‑configured. By systematically checking Docker networking, .env values, Nginx fastcgi params, and PHP‑FPM extensions, you can turn a dreaded 500 error into a quick “fix and deploy” routine. Keep the security boxes locked, monitor memory usage, and automate restarts with Supervisor—your production stack will stay fast, resilient, and ready for the next traffic surge.
No comments:
Post a Comment