How to Fix Nginx Permission Denied Upstream Socket Errors
When using Nginx as a reverse proxy, web requests are often forwarded to backend applications (like Gunicorn, Node.js, or PHP-FPM) using Unix sockets instead of local TCP ports. Unix sockets are faster and require less CPU overhead, but they introduce strict Linux file permission requirements.
If your permissions are misconfigured, Nginx will return an HTTP 502 Bad Gateway to your users. When you check /var/log/nginx/error.log, you will find this entry:
connect() to unix:/run/myapp/myapp.sock failed (13: Permission denied)
The error code 13 indicates that the user running the Nginx worker process cannot read or write to the socket file, or is blocked from traversing the socket's parent directories.
1. Checking Nginx Worker and Socket Owners
To resolve this issue, you must identify which user is running your Nginx worker processes. By default on Ubuntu and Debian systems, Nginx runs as www-data. On CentOS or RHEL, it runs as nginx.
Identify the active worker user with this command:
ps aux | grep nginx
Once you know the Nginx worker user, check the permissions and ownership of your Unix socket file:
ls -la /run/myapp/myapp.sock
If the socket file is owned by your deployment user and group (e.g., myapp:myapp) and has permission settings of 660 (srw-rw----), Nginx will not have permission to access it.
2. Common Socket Error Patterns
Understanding the exact error message in the Nginx logs simplifies the troubleshooting process. The table below lists the three common socket connection errors:
| Nginx Log Error Message | Primary Cause | Recommended Action |
|---|---|---|
13: Permission denied | The Nginx worker user lacks read/write permissions on the socket or cannot traverse the parent folders. | Audit the socket permissions (660) and parent directory access (755). |
2: No such file or directory | The socket file does not exist, or Nginx is pointed to an incorrect directory path. | Verify that the backend process is running and generating the socket file in the correct directory. |
111: Connection refused | The backend application process has stopped listening or has crashed. | Restart your backend service (Gunicorn, PHP-FPM, uWSGI). |
3. Resolving Traversal Blocks with Namei
A common mistake is fixing the permissions of the socket file while ignoring the parent directories. Even if the socket file has 777 permissions, Nginx cannot connect if it cannot traverse the folders leading to it.
Use the namei tool to trace path permissions from the root down to the socket file:
namei -l /run/myapp/myapp.sock
The output displays permissions for each segment:
f: /run/myapp/myapp.sock
drwxr-xr-x root root /
drwxr-xr-x root root run
drwx------ myapp myapp myapp
s????????? ? ? myapp.sock
In the output above, the directory /run/myapp is restricted to the myapp user (drwx------). Since Nginx runs as www-data, it cannot access the folder. Fix this by allowing traversal access to group members:
sudo chmod 755 /run/myapp
4. Persisting Permissions with Systemd
If you manually run chmod 660 on the socket file, the permissions will reset the next time your application restarts. To persist these configurations, update your systemd service file (e.g., /etc/systemd/system/myapp.service):
[Service]
User=myapp
Group=www-data
UMask=0007
RuntimeDirectory=myapp
RuntimeDirectoryMode=0755
ExecStart=/path/to/gunicorn --bind unix:/run/myapp/myapp.sock myapp.wsgi:application
Group=www-data: Runs the process under a group that Nginx can access.UMask=0007: Ensures the Unix socket is created with660permissions, allowing thewww-datagroup read/write access.RuntimeDirectory=myapp: Creates/run/myapp/automatically upon service start.RuntimeDirectoryMode=0755: Sets directory permissions to allow Nginx traversal.
Reload and restart the services to apply changes:
sudo systemctl daemon-reload
sudo systemctl restart myapp
sudo systemctl restart nginx
5. Auditing AppArmor Restrictions
If Unix permissions are configured correctly but Nginx still logs a permission denied error, AppArmor or SELinux might be blocking the access. AppArmor profiles on Ubuntu can prevent Nginx from reading files outside of specific directories.
Run this command to check for AppArmor denials:
sudo dmesg | grep -i apparmor
If you find active denials relating to your socket path, edit the Nginx AppArmor profile configuration to allow read/write access to /run/myapp/*.
6. Proactive Outage Monitoring with Pingzo
Upstream socket permission failures are common during automated deployments. When permission blocks occur, your backend returns a 502 Bad Gateway, but local server checkers might report that the process is running.
Pingzo helps prevent these silent failures by verifying your endpoints from external global validation nodes:
- Real User Simulation: Pingzo attempts to load your application pages, verifying that the Nginx proxy and Unix sockets are working.
- Instant Alerts: If a permission error triggers a 502 error, Pingzo routes a critical alert to your team via WhatsApp.
- Response Telemetry: Identify latency spikes and connection drops caused by queue congestion on the Unix socket before they affect your users.