When encountering the "Permission denied" error (13) while Nginx tries to connect to upstream servers on non-standard ports (like 41002), this typically stems from Linux security mechanisms. Here's what's happening under the hood:
2015/01/28 16:04:49 [crit] 30571#0: *1 connect() to 123.123.123.1:41002 failed (13: Permission denied)
For RHEL/CentOS systems, you'll need to adjust SELinux policies:
# Temporary solution (not recommended for production)
setenforce 0
# Permanent solution (allows Nginx to connect to non-standard ports)
semanage port -a -t http_port_t -p tcp 41001
semanage port -a -t http_port_t -p tcp 41002
Here's the proper server block configuration that preserves both the port and URI:
server {
server_name uat.company.com;
listen 41001;
listen 41002;
listen 8080;
location / {
proxy_pass http://123.123.123.1:$server_port;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Handle redirects properly
proxy_redirect http://123.123.123.1:$server_port/ http://$host:$server_port/;
}
}
server {
server_name qa.company.com;
listen 41001;
listen 41002;
listen 8080;
location / {
proxy_pass http://123.123.123.2:$server_port;
proxy_set_header Host $host:$server_port;
# ... same headers as above
}
}
Key points to ensure port preservation works:
- Always include
$server_port
in bothproxy_pass
andHost
header - Configure proper
proxy_redirect
rules to handle backend redirects - Verify DNS records point to your Nginx server
Ensure your firewall allows traffic on these ports:
# For UFW (Ubuntu)
ufw allow 41001/tcp
ufw allow 41002/tcp
# For firewalld (RHEL/CentOS)
firewall-cmd --permanent --add-port=41001/tcp
firewall-cmd --permanent --add-port=41002/tcp
firewall-cmd --reload
When troubleshooting, check these logs:
# Nginx error log
tail -f /var/log/nginx/error.log
# SELinux audit logs
ausearch -m avc -ts recent
# Network connectivity
nc -zv 123.123.123.1 41002
tcpdump -i any port 41002
When implementing a reverse proxy solution for multiple environments (DEV/QA/UAT) with port preservation requirements, we often encounter permission and routing issues. The key requirements are:
- Maintaining original port numbers in proxied requests
- Preserving URI paths during redirection
- Handling multiple ports (41001, 41002, 8080)
- SELinux context considerations
Here's the proper server block configuration that handles both port preservation and URI routing:
# /etc/nginx/conf.d/multi_env_proxy.conf
server {
server_name uat.company.com;
listen 41001;
listen 41002;
listen 8080;
location / {
proxy_pass http://123.123.123.1:$server_port;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
server {
server_name qa.company.com;
listen 41001;
listen 41002;
listen 8080;
location / {
proxy_pass http://123.123.123.2:$server_port;
proxy_set_header Host $host:$server_port;
# Additional headers same as above
}
}
For systems with SELinux enabled, you must configure proper context for network connections:
# Check current SELinux boolean for HTTPD
getsebool -a | grep httpd
# Allow nginx to make network connections
setsebool -P httpd_can_network_connect 1
# Alternative: Temporarily set permissive mode for testing
setenforce 0
The magic happens through these key components:
$server_port
captures the original request port- Host header modification maintains the original host:port combination
- X-Forwarded headers ensure backends receive correct client information
Use curl to verify the proxy behavior:
curl -v http://uat.company.com:41002/webapp/
curl -v http://qa.company.com:8080/static/home.html
Check nginx logs for troubleshooting:
tail -f /var/log/nginx/error.log
journalctl -u nginx -f
For complex routing scenarios, consider these additional parameters:
proxy_redirect off;
proxy_buffering off;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_read_timeout 300;
proxy_connect_timeout 300;