Troubleshooting PHP-FPM Socket Permission Denied: Nginx User/Group Mismatch on Alpine Linux
Resolve 'PHP-FPM socket permission denied' errors on Alpine Linux caused by Nginx and PHP-FPM user/group mismatches. Fix your 502 Bad Gateway now!
Resolve 'PHP-FPM socket permission denied' errors on Alpine Linux caused by Nginx and PHP-FPM user/group mismatches. Fix your 502 Bad Gateway now!
When deploying web applications on Alpine Linux using Nginx and PHP-FPM, encountering a "PHP-FPM socket permission denied" error is a common hurdle. This issue typically manifests as a 502 Bad Gateway error in the browser and indicates that Nginx, acting as the web server, lacks the necessary permissions to communicate with the PHP-FPM service via its Unix socket. This guide will walk you through diagnosing and resolving this user/group mismatch.
Symptom & Error Signature
The most direct symptom you'll encounter is a 502 Bad Gateway error displayed in your web browser when trying to access PHP pages. On the server, the definitive error signature will be found in your Nginx error logs, typically located at /var/log/nginx/error.log.
Nginx Error Log Example:
2026/09/27 10:30:45 [crit] 1234#1234: *1 connect() to unix:/var/run/php-fpm/php-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-fpm/php-fpm.sock:", host: "example.com"
You might also see a similar error if you try to curl your application locally:
$ curl -I http://localhost/index.php
HTTP/1.1 502 Bad Gateway
Server: nginx/1.24.0
Date: Mon, 27 Sep 2026 10:30:45 GMT
Content-Type: text/html
Content-Length: 172
Connection: keep-alive
Root Cause Analysis
The "Permission denied" error indicates a fundamental access control problem. On Unix-like systems, processes run under specific user and group identities, and access to files, directories, and IPC mechanisms (like Unix domain sockets) is governed by these identities.
The root cause of this particular error is almost always a mismatch in the user and group permissions between the Nginx process and the PHP-FPM process (or more precisely, the permissions of the Unix socket created by PHP-FPM).
Here's a breakdown of the common contributing factors:
Default User/Group Mismatch:
- Nginx: On Alpine Linux (and many other distributions), Nginx typically runs as the
nginxuser andnginxgroup. - PHP-FPM: PHP-FPM, by default, often runs as the
php-fpmuser andphp-fpmgroup, or sometimesnobodyorwww-data(thoughphp-fpmis standard on Alpine for its daemon). - When PHP-FPM creates its Unix socket (e.g.,
/var/run/php-fpm/php-fpm.sock), it assigns ownership and permissions based on its configured user and group. If the Nginx user (nginx) is not part of the PHP-FPM's group (php-fpm) and the socket's permissions are restrictive (e.g.,0660), Nginx will be denied access.
- Nginx: On Alpine Linux (and many other distributions), Nginx typically runs as the
Incorrect
php-fpmPool Configuration (www.conf):- The
listen.owner,listen.group, andlisten.modedirectives within the PHP-FPM pool configuration (/etc/phpX/php-fpm.d/www.confon Alpine) directly control the ownership and permissions of the Unix socket. If these are not configured to allow the Nginx user access, the error will occur.
- The
Parent Directory Permissions:
- Less common for the socket itself, but sometimes the parent directory (
/var/run/php-fpm/in this case) might have incorrect permissions, preventing PHP-FPM from even creating the socket with the desired permissions, or preventing Nginx from traversing the directory.
- Less common for the socket itself, but sometimes the parent directory (
SELinux/AppArmor (Less likely on Alpine):
- While not standard on a default Alpine installation, if you're running a custom kernel or a more complex security setup, mandatory access control systems like SELinux or AppArmor could also enforce restrictions. However, for Alpine, the vast majority of "permission denied" issues are standard Unix discretionary access control problems.
Step-by-Step Resolution
The goal is to ensure that the Nginx user has read/write access to the PHP-FPM Unix socket. We'll achieve this by modifying the PHP-FPM pool configuration.
1. Identify Running Users and Configuration Paths
First, let's confirm the users under which Nginx and PHP-FPM are running, and locate their configuration files.
# Check Nginx user (usually 'nginx')
ps aux | grep -E '[n]ginx' | head -n 1 | awk '{print $1}'
# Check PHP-FPM user (e.g., 'php-fpm' or 'nobody')
ps aux | grep -E '[p]hp-fpm' | head -n 1 | awk '{print $1}'
# Locate PHP-FPM www.conf (replace 'X' with your PHP version, e.g., php81)
find /etc/php* -name www.conf
# Locate Nginx configuration file
find /etc/nginx -name nginx.conf
On Alpine Linux, PHP versions are typically installed in separate directories, e.g.,
/etc/php81/php-fpm.d/www.conffor PHP 8.1. Adjust commands accordingly.
2. Inspect Nginx Configuration for Socket Path
Confirm that Nginx is configured to use the correct Unix socket path. Open your Nginx site configuration (e.g., /etc/nginx/conf.d/default.conf or your specific virtual host file) and look for the fastcgi_pass directive.
# Example Nginx site configuration
server {
listen 80;
server_name example.com;
root /var/www/html;
index index.php index.html;
location ~ .php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+.php)(/.+)$;
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock; # <--- This is the socket path
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
Verify the fastcgi_pass directive points to the correct socket path. If it's different from /var/run/php-fpm/php-fpm.sock, make a note of it.
3. Modify PHP-FPM Pool Configuration (www.conf)
This is the core fix. We will adjust the php-fpm pool configuration to allow the Nginx user access to the socket.
Open the www.conf file for your PHP-FPM version (e.g., /etc/php81/php-fpm.d/www.conf).
# Example for PHP 8.1
apk add nano # if you don't have a text editor
nano /etc/php81/php-fpm.d/www.conf
Locate the listen directive and the listen.owner, listen.group, and listen.mode directives. They usually look something like this:
; php-fpm.d/www.conf (default on Alpine)
listen = /var/run/php-fpm/php-fpm.sock
listen.owner = php-fpm
listen.group = php-fpm
listen.mode = 0660
Here are the recommended solutions:
Option A: Add Nginx User to PHP-FPM Group (Recommended for Separation)
This is generally the most secure and recommended approach as it maintains separation of concerns. PHP-FPM still runs as its own user, but Nginx is granted access via group permissions.
Ensure
listen.ownerandlisten.groupare set correctly:listen.owner: Should be the user PHP-FPM is running as (e.g.,php-fpm).listen.group: Should be the group PHP-FPM is running as (e.g.,php-fpm).listen.mode: Crucially, set this to0660to allow read/write access for the owner and group.
; In /etc/phpX/php-fpm.d/www.conf listen = /var/run/php-fpm/php-fpm.sock listen.owner = php-fpm listen.group = php-fpm listen.mode = 0660Add the Nginx user to the PHP-FPM group:
- Find the actual group name PHP-FPM uses (e.g.,
php-fpm). - Find the actual user name Nginx uses (e.g.,
nginx).
# Add 'nginx' user to 'php-fpm' group # Note: 'adduser' is for adding new users. 'addgroup' is for adding existing users to a group. # On Alpine, 'addgroup' is usually used like this: addgroup nginx php-fpmIf the
php-fpmgroup doesn't exist, it might be that PHP-FPM runs asnobodyorwww-data. Adjustlisten.groupto the correct group (e.g.,www-data) and then addnginxto that group. However, on Alpine, a dedicatedphp-fpmuser and group are standard.- Find the actual group name PHP-FPM uses (e.g.,
Option B: Change PHP-FPM Socket Ownership to Nginx User/Group (Simpler, Less Secure)
This approach is simpler but ties the PHP-FPM socket directly to the Nginx user, which might be less ideal for strict permission separation.
Modify
www.confto setlisten.ownerandlisten.grouptonginx:; In /etc/phpX/php-fpm.d/www.conf listen = /var/run/php-fpm/php-fpm.sock listen.owner = nginx listen.group = nginx listen.mode = 0660While simpler, this means the PHP-FPM process (which typically runs as
php-fpmornobody) will need elevated privileges to create the socket asnginxif it's not already running asnginx. Ensure theuserandgroupdirectives withinwww.confalso matchnginxif you choose this option:user = nginx group = nginxThis would mean PHP-FPM processes run as
nginx, which grants them the same permissions as Nginx itself, potentially reducing security if the PHP application is compromised. Option A is generally preferred.
4. Verify Socket Directory Permissions (If Necessary)
Ensure the directory where the socket is created (/var/run/php-fpm/) has appropriate permissions. PHP-FPM should be able to create the socket there.
# Check permissions for the directory
ls -ld /var/run/php-fpm/
# Example output
# drwxr-xr-x 2 php-fpm php-fpm 60 Sep 27 10:45 /var/run/php-fpm/
# If the directory doesn't exist or has wrong permissions for php-fpm,
# you might need to create it and set permissions.
# This is usually handled by the php-fpm package, but can be useful for debugging.
# Example:
# mkdir -p /var/run/php-fpm/
# chown php-fpm:php-fpm /var/run/php-fpm/
# chmod 755 /var/run/php-fpm/
The php-fpm user/group needs write access to this directory to create the socket. drwxr-xr-x owned by php-fpm:php-fpm is usually sufficient.
5. Restart Services
After making changes to www.conf or user groups, you must restart both PHP-FPM and Nginx for the changes to take effect.
# Restart PHP-FPM
rc-service php-fpm restart
# Restart Nginx
rc-service nginx restart
On Alpine,
rc-serviceis the standard way to manage services. If you're running in a Docker container and process management is handled differently, you might need to stop/start the container or directly restart processes.
6. Verify the Fix
Check PHP-FPM socket permissions: After restarting PHP-FPM, verify the ownership and permissions of the created socket.
ls -l /var/run/php-fpm/php-fpm.sockExpected output for Option A:
srw-rw---- 1 php-fpm php-fpm 0 Sep 27 10:50 /var/run/php-fpm/php-fpm.sockThis shows the socket owned by
php-fpm:php-fpmwith0660permissions. Since thenginxuser is now part of thephp-fpmgroup, Nginx will have read/write access.Expected output for Option B (if you also changed
user=nginxinwww.conf):srw-rw---- 1 nginx nginx 0 Sep 27 10:50 /var/run/php-fpm/php-fpm.sockTest your website: Open your browser and navigate to your website. PHP pages should now load correctly without the 502 Bad Gateway error.
Check Nginx error logs: Confirm that no new
Permission deniederrors appear in/var/log/nginx/error.log.
By following these steps, you should successfully resolve the "PHP-FPM socket permission denied" error on your Alpine Linux system. Remember to prioritize Option A for better security and process separation.
Our Production Verification Guarantee
Encountering a bug not covered here or running a non-standard kernel configuration? Our solutions are continually refined against real production incidents. Submit an environment trace for our editorial team to replicate.