Recently while setting up multiple Node.js applications behind Nginx on CentOS 7, I encountered a puzzling scenario where some ports worked perfectly while others threw 502 Bad Gateway errors. The Nginx error logs revealed:
[crit] 12807#0: *13 connect() to 127.0.0.1:7777 failed (13: Permission denied)
Strangely, the same application worked flawlessly when configured to use port 8008.
The root cause lies in SELinux's port restrictions. On CentOS/RHEL systems, SELinux by default only allows certain ports for HTTP communication. You can check the allowed ports with:
semanage port -l | grep http
http_port_t tcp 80, 81, 443, 488, 8008, 8009, 8443, 9000
Notice how 7777 isn't in this list while 8008 is? That explains our different behavior.
Option 1: Add Your Port to http_port_t
The most secure approach is to formally add your port to SELinux's allowed set:
sudo semanage port -a -t http_port_t -p tcp 7777
Option 2: Temporarily Disable SELinux Enforcement
For development environments only (not recommended for production):
sudo setenforce 0
Option 3: Modify Your Node.js Application
Simply switch to a standard HTTP port that SELinux already allows:
const port = process.env.PORT || 8008;
server.listen(port, () => {
console.log(Server running on port ${port});
});
After applying any solution, verify Nginx can connect to your upstream:
curl -I http://localhost:7777
sudo ausearch -m avc -ts recent
For production environments, I recommend:
- Always use Option 1 (adding ports properly)
- Keep SELinux in enforcing mode
- Consider using reverse proxy headers in your Node app:
app.enable('trust proxy');
app.use((req, res, next) => {
req.headers['x-forwarded-proto'] === 'https'
? next()
: res.redirect('https://' + req.headers.host + req.url);
});
Here's a complete Nginx configuration that works with SELinux:
server {
listen 80;
server_name myapp.com;
location / {
proxy_pass http://127.0.0.1:8008;
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;
}
}
When configuring Nginx as a reverse proxy for Node.js applications on CentOS 7, you might encounter this frustrating situation where certain ports work perfectly (like 8008) while others (like 7777) throw 13: Permission denied
errors in the Nginx error logs.
In CentOS/RHEL systems, SELinux enforces strict security policies. By default, non-standard ports (anything outside common web ports like 80, 443, 8000-9000) are blocked from network communication unless explicitly permitted.
Check SELinux status with:
sestatus
getenforce
To see if your problematic port (7777) has the correct context:
semanage port -l | grep http
You'll likely see output showing allowed ports like:
http_port_t tcp 80, 81, 443, 488, 8008, 8009, 8443
Add your custom port to SELinux's allowed list:
sudo semanage port -a -t http_port_t -p tcp 7777
For multiple ports:
sudo semanage port -a -t http_port_t -p tcp 7777,8888,9999
If you prefer not to modify SELinux policies (not recommended for production):
Temporarily set SELinux to permissive mode:
sudo setenforce 0
Or disable SELinux enforcement (strongly discouraged):
sudo sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
Ensure your Nginx config includes proper proxy settings:
location / {
proxy_pass http://127.0.0.1:7777;
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;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
After making changes, always:
- Restart Nginx:
sudo systemctl restart nginx
- Check SELinux logs:
sudo ausearch -m avc -ts recent
- Test connectivity:
curl -v http://localhost:7777
Don't forget about firewalld on CentOS 7:
sudo firewall-cmd --zone=public --add-port=7777/tcp --permanent
sudo firewall-cmd --reload