Fix Nginx "connect() to unix:/run/gunicorn.sock Failed (2: No Such File or Directory)"
Fix the Nginx 502 error connect() to unix:/run/gunicorn.sock failed (2: No such file or directory): start the Gunicorn socket or service, match the socket path in Nginx and systemd, and stop PrivateTmp and RuntimeDirectory from hiding the file.
Problem statement
The site returns 502 Bad Gateway, and /var/log/nginx/error.log says:
connect() to unix:/run/gunicorn.sock failed (2: No such file or directory)
while connecting to upstream, client: 203.0.113.9, server: example.com,
request: "GET / HTTP/1.1", upstream: "http://unix:/run/gunicorn.sock:/"
Nginx is configured to talk to Gunicorn through a Unix socket file, and that file does not exist at the path Nginx uses. Either Gunicorn is not running, it created the socket somewhere else, or the socket is inside a private directory Nginx cannot see. This is different from (13: Permission denied), where the file exists but Nginx may not use it.
- Check the file:
ls -l /run/gunicorn.sock. - Check the services:
systemctl status gunicorn.socket gunicorn.service. - Start or enable them:
sudo systemctl enable --now gunicorn.socket. - Make the path identical in three places: the systemd socket unit (or Gunicorn
--bind), Nginxproxy_pass, and anyRuntimeDirectory. - Do not put the socket in
/tmpif the service usesPrivateTmp=true; use/run/<name>/.
Step-by-step solution
1. See whether the socket exists
ls -l /run/gunicorn.sock
sudo ss -xlp | grep gunicorn
No file and no listening Unix socket means nothing created it. If ss shows Gunicorn listening on a different path, you have a path mismatch.
2. Start Gunicorn through systemd
With socket activation, systemd creates the socket and starts Gunicorn on the first request:
# /etc/systemd/system/gunicorn.socket
[Unit]
Description=gunicorn socket
[Socket]
ListenStream=/run/gunicorn.sock
SocketUser=www-data
SocketMode=0660
[Install]
WantedBy=sockets.target
sudo systemctl daemon-reload
sudo systemctl enable --now gunicorn.socket
curl --unix-socket /run/gunicorn.sock http://localhost/
The curl call triggers gunicorn.service; check it with systemctl status gunicorn. If the service fails, its journal shows why: journalctl -u gunicorn -n 50.
3. Align the paths
The same path must appear in the socket unit or Gunicorn command and in Nginx:
upstream app {
server unix:/run/gunicorn.sock fail_timeout=0;
}
server {
location / {
proxy_pass http://app;
}
}
Without socket activation, Gunicorn creates the file itself from --bind unix:/run/gunicorn/gunicorn.sock. In that case, the directory must exist and be writable by the Gunicorn user, which brings us to /run.
4. Use RuntimeDirectory instead of /tmp
/run is a tmpfs, cleared on boot, and only root can create entries in it. Let systemd create a directory owned by the service user:
[Service]
User=deploy
Group=www-data
RuntimeDirectory=gunicorn
ExecStart=/srv/app/.venv/bin/gunicorn --bind unix:/run/gunicorn/gunicorn.sock config.wsgi
Avoid /tmp/gunicorn.sock when either unit uses PrivateTmp=true: each service then has its own private /tmp, and Nginx looks in a different one than Gunicorn wrote to.
5. Survive reboots
After a reboot, everything in /run is gone. Units that are not enabled do not recreate it. Make sure both are enabled:
systemctl is-enabled gunicorn.socket nginx
Explanation
A Unix domain socket is a file-system object that a server process creates and listens on. Nginx connects to it by path, and the kernel returns ENOENT (errno 2) if no such file exists. Because /run is cleared at boot and Gunicorn removes its socket on shutdown, the file only exists while something is listening. Systemd socket activation makes the file independent of Gunicorn's lifetime, which is why it is the most robust setup.
Edge cases / notes
- Docker. Unix sockets between containers need a shared volume; TCP on the Compose network is usually simpler.
- Multiple apps. Give each app its own socket name and directory, such as
/run/shop/gunicorn.sock. - SELinux. On RHEL-family systems, Nginx may need the
httpd_can_network_connectboolean or a socket context, which surfaces as permission denied, not errno 2.
Next steps
- If the file exists but access is denied, see Fix Gunicorn Socket Permission Denied.
- Set up the units correctly with Set Up systemd for Gunicorn and Django.
- For other 502 causes, read Debug Django 502 Bad Gateway.
FAQ
What does errno 2 mean in this message?
"No such file or directory": the socket file does not exist at the configured path.
Why did it break after a reboot?
/run is emptied at boot. If the socket unit or service is not enabled, nothing recreates the socket.
Should I use a Unix socket or TCP?
On one server, a Unix socket is slightly faster and not exposed to the network. TCP is simpler across containers or hosts.
Is it bad to put the socket in /tmp?
With PrivateTmp=true, each service sees a different /tmp, so Nginx cannot find it. Use /run with RuntimeDirectory.