When setting up Nginx to proxy requests to a Node.js server via UNIX domain sockets, several configuration aspects need careful attention. The 502 Bad Gateway error typically indicates a connection failure between Nginx and your Node.js application.
Here's a working configuration that addresses both Nginx and Node.js setup:
// Node.js server setup
const http = require('http');
const fs = require('fs');
// Clean up existing socket if present
try { fs.unlinkSync('/tmp/app.socket'); } catch(e) {}
http.createServer((req, res) => {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello from Node.js via UNIX socket!\n');
}).listen('/tmp/app.socket', () => {
console.log('Node.js server listening on UNIX socket');
});
// Set appropriate permissions
fs.chmod('/tmp/app.socket', 0777, (err) => {
if (err) throw err;
});
The most reliable approach combines upstream declaration with proper permissions:
upstream nodejs_socket {
server unix:/tmp/app.socket;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://nodejs_socket;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Important for UNIX socket connections
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}
The permission denied error (13) suggests Nginx's worker process can't access the socket file. Solutions include:
- Ensure both processes run under the same user
- Set appropriate socket file permissions (0777 for testing)
- Check apparmor/selinux policies if enforced
When troubleshooting, verify these aspects:
# Check socket file existence and permissions
ls -la /tmp/app.socket
# Verify Nginx worker process user
ps aux | grep nginx
# Test direct socket connection
curl --unix-socket /tmp/app.socket http://localhost/
For newer Nginx versions, you can use this direct approach:
server {
listen 80;
location / {
proxy_pass http://unix:/tmp/app.socket:/;
proxy_set_header Host $http_host;
}
}
Remember that the trailing colon and slash in unix:/tmp/app.socket:/
are crucial for proper request URI handling.
Setting up Nginx to proxy requests to a Node.js application via UNIX domain sockets should be straightforward, but there are several common pitfalls that can lead to 502 Bad Gateway errors. Let's examine a working configuration that addresses both the Nginx setup and Node.js implementation.
Here's the correct way to configure Nginx for UNIX socket proxying:
upstream nodejs_unix {
server unix:/tmp/app.socket;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://nodejs_unix;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
The Node.js server needs proper socket handling and permissions:
const http = require('http');
const fs = require('fs');
const socketPath = '/tmp/app.socket';
// Clean up socket if it exists from previous runs
try { fs.unlinkSync(socketPath); } catch (e) {}
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello from UNIX socket!\n');
});
server.listen(socketPath, () => {
console.log(Server running at ${socketPath});
// Set appropriate permissions
fs.chmodSync(socketPath, '777');
});
The most common issue is permission errors between Nginx and the socket file. Consider these points:
- Nginx worker processes must have read/write permissions to the socket
- The directory (/tmp) must allow socket creation
- Best practice is to use a dedicated directory with proper ownership
When encountering issues, check these areas:
# Check socket permissions
ls -la /tmp/app.socket
# Verify Nginx error logs
tail -f /var/log/nginx/error.log
# Test socket connectivity directly
curl --unix-socket /tmp/app.socket http://localhost/
Using UNIX sockets instead of TCP offers several benefits:
- Lower latency (no TCP overhead)
- No port conflicts
- Better security (filesystem permissions)
- Higher throughput for local communications
For Express.js applications, the setup is similar but requires proper headers:
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('Express via UNIX socket');
});
app.listen('/tmp/express.socket', () => {
console.log('Express server listening on socket');
});