Troubleshooting Nginx 502 Bad Gateway with PHP-FPM Unix Socket on Alpine Linux
Fix Nginx 502 Bad Gateway errors on Alpine Linux when using PHP-FPM via a Unix socket. Diagnose common issues like permissions, socket path, and PHP-FPM configuration.
Fix Nginx 502 Bad Gateway errors on Alpine Linux when using PHP-FPM via a Unix socket. Diagnose common issues like permissions, socket path, and PHP-FPM configuration.
A "502 Bad Gateway" error indicates that Nginx, acting as a reverse proxy, failed to receive a valid response from an upstream server. In the context of a PHP application served by Nginx on Alpine Linux, this almost universally means Nginx was unable to communicate correctly with the PHP-FPM (FastCGI Process Manager) service. When configured to use a Unix domain socket, this communication breakdown is frequently due to misconfigurations related to the socket path, file permissions, or the PHP-FPM service itself. This guide will walk you through diagnosing and resolving these common issues.
Symptom & Error Signature
When encountering this issue, users will typically see a generic "502 Bad Gateway" page in their web browser. On the server side, the critical information is found in the Nginx error logs.
Browser Output:
502 Bad Gateway
nginx/1.24.0
Nginx Error Log (/var/log/nginx/error.log or Docker container logs):
You'll typically find one of these entries, providing a clue to the root cause:
- Socket not found/PHP-FPM not running:
2023/10/26 10:30:05 [crit] 1#1: *1 connect() to unix:/var/run/php/php7.4-fpm.sock failed (2: No such file or directory) while connecting to upstream, client: 192.168.1.100, server: example.com, request: "GET /index.php HTTP/1.1", upstream: "fastcgi://unix:/var/run/php/php7.4-fpm.sock:", host: "example.com" - Permission denied:
2023/10/26 10:30:05 [crit] 1#1: *1 connect() to unix:/var/run/php/php7.4-fpm.sock failed (13: Permission denied) while connecting to upstream, client: 192.168.1.100, server: example.com, request: "GET /index.php HTTP/1.1", upstream: "fastcgi://unix:/var/run/php/php7.4-fpm.sock:", host: "example.com" - PHP-FPM process prematurely closed connection (often due to crashes or timeouts):
2023/10/26 10:30:05 [error] 1#1: *1 upstream prematurely closed connection while reading response header from upstream, client: 192.168.1.100, server: example.com, request: "GET /index.php HTTP/1.1", upstream: "fastcgi://unix:/var/run/php/php7.4-fpm.sock:", host: "example.com"
Root Cause Analysis
The "502 Bad Gateway" error with Nginx and PHP-FPM via a Unix socket on Alpine Linux usually boils down to one or more of these underlying issues:
- PHP-FPM Service Not Running: The most straightforward cause. If PHP-FPM isn't active, the Unix socket won't exist, and Nginx has nowhere to connect.
- Incorrect Unix Socket Path: A mismatch between the socket path Nginx is configured to use (
fastcgi_pass) and the path PHP-FPM is configured to listen on (listen). - Socket Permissions: Nginx runs under a specific user (e.g.,
nginx). This user must have read and write permissions to the PHP-FPM Unix socket file, and execute permissions on all parent directories leading to the socket. Alpine Linux often uses thenginxuser by default for Nginx, andwww-dataor a similar user for PHP-FPM. - PHP-FPM Pool Configuration Issues: The
listen.owner,listen.group, andlisten.modedirectives in the PHP-FPM pool configuration file (www.confor similar) are crucial for setting correct socket permissions. - Resource Exhaustion or PHP Errors: PHP-FPM processes might be crashing due to memory limits, fatal PHP errors, or script timeouts (
request_terminate_timeout), causing PHP-FPM to close the connection before Nginx receives a full response. This often manifests as "upstream prematurely closed connection". - Nginx User Mismatch: The user Nginx is running as does not belong to the group that owns the PHP-FPM socket, or vice-versa, preventing proper access.
- Docker-specific Issues: In a Dockerized environment, bind mounts for the socket might be misconfigured, or processes inside the container might not be starting correctly.
Step-by-Step Resolution
Follow these steps to diagnose and resolve the 502 Bad Gateway error. Remember to check Nginx and PHP-FPM logs after each change.
1. Verify PHP-FPM Service Status
First, ensure PHP-FPM is actually running and listening for connections. Alpine Linux often runs in containers or uses OpenRC as an init system.
For Docker Containers:
docker ps | grep php-fpm docker logs <php-fpm-container-id-or-name>If
php-fpmis not listed indocker ps, or logs show startup failures, restart the container:docker restart <php-fpm-container-id-or-name>For Alpine with OpenRC (bare metal or VM):
rc-service php-fpm status rc-service php-fpm startGeneral process check (works everywhere):
ps aux | grep php-fpmYou should see several
php-fpm: pool wwwprocesses running. If not, PHP-FPM isn't active.If PHP-FPM isn't running, check its startup configuration and logs (e.g.,
/var/log/php-fpm.logor container logs) for specific errors preventing it from starting.
2. Confirm Socket Path Consistency
A common mistake is having Nginx configured to use one socket path while PHP-FPM is configured to listen on another.
- Check Nginx configuration:
Locate your Nginx server block configuration for the site (e.g.,
/etc/nginx/conf.d/default.confor/etc/nginx/http.d/default.conf). Find thefastcgi_passdirective:# /etc/nginx/conf.d/default.conf server { # ... location ~ .php$ { fastcgi_pass unix:/var/run/php/php7.4-fpm.sock; # <-- Note this path fastcgi_index index.php; include fastcgi.conf; } # ... } - Check PHP-FPM pool configuration:
Locate your PHP-FPM pool configuration file (e.g.,
/etc/php8/php-fpm.d/www.confon Alpine, replacephp8with your PHP version). Find thelistendirective:; /etc/php8/php-fpm.d/www.conf [www] listen = /var/run/php/php7.4-fpm.sock ; <-- This path must match NginxEnsure both paths are identical, including the exact PHP version in the socket name if specified.
3. Inspect Socket Permissions
This is a frequent culprit for (13: Permission denied) errors. Nginx needs appropriate permissions to access the socket file.
Check the socket file and its parent directory:
ls -l /var/run/php/php7.4-fpm.sock ls -ld /var/run/php/Expected output might look like:
srw-rw---- 1 www-data www-data 0 Oct 26 10:45 /var/run/php/php7.4-fpm.sock drwxr-xr-x 2 root root 60 Oct 26 10:45 /var/run/php/Here, the socket is owned by
www-data:www-data. Nginx, typically running as thenginxuser, would need to be part of thewww-datagroup or have appropriatelisten.modesettings.Check Nginx user: Inspect your main Nginx configuration file (
/etc/nginx/nginx.conf) for theuserdirective:# /etc/nginx/nginx.conf user nginx; # <-- Nginx runs as this user worker_processes auto; # ...Adjust PHP-FPM
listendirectives: In your PHP-FPM pool configuration (/etc/php8/php-fpm.d/www.conf), modify thelisten.owner,listen.group, andlisten.modedirectives to grant Nginx access.Option A: Add Nginx user to PHP-FPM group (Recommended): Ensure the
nginxuser is a member of the group that owns the PHP-FPM socket (e.g.,www-data).# On Alpine with OpenRC adduser nginx www-data # Or in Dockerfile: # RUN addgroup -S www-data && adduser -S nginx www-dataThen, configure PHP-FPM to create the socket with the group ownership and mode:
; /etc/php8/php-fpm.d/www.conf listen = /var/run/php/php7.4-fpm.sock listen.owner = www-data listen.group = www-data listen.mode = 0660 ; Allows owner and group to read/writeOption B: Grant broader permissions (less secure, but sometimes necessary in constrained environments):
; /etc/php8/php-fpm.d/www.conf listen = /var/run/php/php7.4-fpm.sock ; listen.owner = www-data ; Optional, if not needed to be explicitly www-data ; listen.group = www-data ; Optional listen.mode = 0666 ; Allows anyone to read/write (use with caution!)After changing PHP-FPM configuration, you must restart PHP-FPM for changes to take effect. If you're modifying users/groups, a full restart of both Nginx and PHP-FPM is recommended.
4. Review Nginx & PHP-FPM Configuration Files
Incorrect or insufficient settings can lead to premature connection closure.
Nginx Configuration (
/etc/nginx/nginx.confor site-specific conf): Ensurefastcgi_buffer_size,fastcgi_buffers, andfastcgi_read_timeoutare adequate, especially for larger PHP scripts or slower operations.# In your Nginx http or server block http { # ... fastcgi_buffers 16 16k; # Increase buffer size fastcgi_buffer_size 32k; fastcgi_connect_timeout 5s; # How long Nginx waits to connect to FPM fastcgi_send_timeout 120s; # How long Nginx waits for FPM to send data fastcgi_read_timeout 120s; # How long Nginx waits for FPM to send a response # ... }PHP-FPM Pool Configuration (
/etc/php8/php-fpm.d/www.conf): Review resource limits. "Upstream prematurely closed connection" can be a symptom of PHP-FPM processes dying.; /etc/php8/php-fpm.d/www.conf request_terminate_timeout = 60s ; How long a single PHP script can run ; If set to 0, it means 'Off'. Set to a reasonable value. catch_workers_output = yes ; Important for debugging, sends PHP errors to PHP-FPM logs ; Process Manager settings (adjust based on server resources) pm = dynamic ; or ondemand, static pm.max_children = 50 ; Max number of FPM child processes pm.start_servers = 5 pm.min_spare_servers = 5 pm.max_spare_servers = 35Also, check
php.ini(/etc/php8/php.ini) formemory_limitandmax_execution_time. If scripts exceed these, PHP processes can crash.
5. Examine PHP-FPM Logs for Errors
PHP-FPM logs are invaluable for understanding why processes might be failing.
tail -f /var/log/php-fpm.log
# Or for Docker:
docker logs -f <php-fpm-container-id-or-name>
Look for FATAL, ERROR, or WARNING messages, especially those related to memory_limit, max_execution_time, or uncaught exceptions in your PHP applications.
If catch_workers_output = yes is set in www.conf, PHP stderr (including errors) will be redirected to the PHP-FPM logs, which is very helpful for debugging.
6. Restart Services
After making any configuration changes, you must restart Nginx and PHP-FPM for the changes to take effect.
- Nginx:
nginx -t # Test Nginx configuration syntax nginx -s reload # Reload Nginx configuration (without dropping connections) # If a full restart is needed: # rc-service nginx restart # On Alpine with OpenRC # docker restart <nginx-container-id> # In Docker - PHP-FPM:
# On Alpine with OpenRC rc-service php-fpm restart # In Docker (if PHP-FPM is PID 1 or managed by supervisord) # docker restart <php-fpm-container-id-or-name> # or for supervisord inside container: # docker exec <php-fpm-container-id-or-name> supervisorctl restart php-fpmAlways test Nginx configuration with
nginx -tbefore reloading or restarting to avoid syntax errors that could take your web server offline.
7. Docker-Specific Considerations
If you're running Nginx and PHP-FPM in separate Docker containers, ensure the Unix socket is properly shared.
- Shared Volume for Socket:
The most robust way to share a Unix socket between containers is using a shared volume.
Ensure that the# docker-compose.yml example version: '3.8' services: nginx: image: nginx:alpine volumes: - ./nginx/conf.d:/etc/nginx/conf.d:ro - php-fpm-sock:/var/run/php # Mount the shared volume depends_on: - php-fpm # ... other nginx settings php-fpm: image: php:8.2-fpm-alpine # or similar volumes: - ./app:/var/www/html:rw - php-fpm-sock:/var/run/php # Mount the shared volume # ... other php-fpm settings volumes: php-fpm-sock: # Define the named volumelistendirective in PHP-FPM'swww.confandfastcgi_passin Nginx's config point to the same path within the respective containers that the shared volume is mounted to (e.g.,/var/run/php/php7.4-fpm.sock).
By systematically working through these steps, you should be able to identify and resolve the root cause of your Nginx 502 Bad Gateway error on Alpine Linux.