What's Actually Happening
Nginx fails to start because it cannot bind to port 80 or 443. These are privileged ports (below 1024) that require root privileges or special capabilities. When Nginx is configured to run as a non-root user or lacks the necessary permissions, you'll see permission denied errors during startup.
The Error You'll See
```bash $ systemctl start nginx Job for nginx.service failed because the control process exited with error code. See "systemctl status nginx" and "journalctl -xe" for details.
$ journalctl -xe | grep nginx nginx: [emerg] bind() to 0.0.0.0:80 failed (13: Permission denied) nginx: [emerg] bind() to 0.0.0.0:443 failed (13: Permission denied)
$ nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: [emerg] bind() to 0.0.0.0:80 failed (13: Permission denied) nginx: configuration file /etc/nginx/nginx.conf test failed
$ /usr/sbin/nginx nginx: [emerg] bind() to 0.0.0.0:80 failed (13: Permission denied) ```
Why This Happens
- 1.Running as non-root user: Nginx configured to run as non-root cannot bind privileged ports
- 2.Missing CAP_NET_BIND_SERVICE: Linux capability to bind privileged ports not granted
- 3.SELinux blocking: Security policy preventing port binding
- 4.AppArmor restrictions: Security module blocking access
- 5.Port already occupied: Another process has the port, causing permission conflict
- 6.Incorrect systemd service configuration: Service not granted necessary capabilities
- 7.Wrong file permissions: Nginx binary or config files inaccessible
Step 1: Verify the Error and Check Port Status
Confirm the exact issue:
```bash # Check Nginx error logs cat /var/log/nginx/error.log journalctl -u nginx -n 50
# Check if port is already in use sudo netstat -tulpn | grep :80 sudo ss -tulpn | grep :80
# Check what process might be using the port sudo lsof -i :80
# Check Nginx user configuration grep -r "user" /etc/nginx/nginx.conf
# Check systemd service configuration systemctl cat nginx ```
Step 2: Run Nginx as Root or Grant Capabilities
The simplest solution is to grant proper privileges:
Option A: Run Nginx as root (traditional approach) ```bash # Edit nginx.conf to remove user directive or set to root sudo nano /etc/nginx/nginx.conf
# Remove or change: # user nginx; # to: # user root; # Or simply remove the line (defaults to root)
# Or ensure systemd service runs as root sudo systemctl restart nginx ```
Option B: Grant CAP_NET_BIND_SERVICE capability ```bash # Grant capability to Nginx binary sudo setcap cap_net_bind_service=+ep /usr/sbin/nginx
# Verify capability is set getcap /usr/sbin/nginx # Output: /usr/sbin/nginx = cap_net_bind_service+ep
# Now Nginx can bind privileged ports as non-root sudo systemctl restart nginx ```
Option C: Configure systemd to grant capabilities
``bash
# Create systemd override
sudo systemctl edit nginx
Add:
``ini
[Service]
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE
# Reload systemd and restart
sudo systemctl daemon-reload
sudo systemctl restart nginxStep 3: Use Non-Privileged Ports
Run Nginx on ports above 1024:
# Edit Nginx configuration
sudo nano /etc/nginx/nginx.confChange port configuration: ```nginx # In server block server { listen 8080; # Non-privileged port # Or for SSL listen 8443 ssl;
# Rest of configuration... } ```
```bash # Test configuration sudo nginx -t
# Restart Nginx sudo systemctl restart nginx
# Use reverse proxy or firewall redirect for port 80 # Option 1: Use iptables to redirect sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
# Option 2: Use firewalld sudo firewall-cmd --add-forward-port=port=80:proto=tcp:toport=8080 --permanent sudo firewall-cmd --reload ```
Step 4: Fix SELinux Issues
SELinux can prevent binding to privileged ports:
```bash # Check SELinux status getenforce sestatus
# Check SELinux denials sudo ausearch -m avc -ts recent | grep nginx sudo grep nginx /var/log/audit/audit.log
# Allow Nginx to bind network ports sudo setsebool -P httpd_can_network_connect 1
# Check Nginx SELinux context ls -Z /usr/sbin/nginx ps -Z | grep nginx
# If SELinux is blocking, add policy sudo semanage port -a -t http_port_t -p tcp 80 sudo semanage port -a -t http_port_t -p tcp 443
# Or temporarily set to permissive (not for production) sudo setenforce 0 sudo systemctl restart nginx # After testing, re-enable sudo setenforce 1 ```
Step 5: Fix AppArmor Issues
On systems using AppArmor:
```bash # Check AppArmor status sudo aa-status
# Check Nginx profile sudo aa-status | grep nginx
# If profile is enforcing, temporarily disable sudo aa-disable /etc/apparmor.d/usr.sbin.nginx
# Or set to complain mode (logs but allows) sudo aa-complain /etc/apparmor.d/usr.sbin.nginx
# Restart Nginx sudo systemctl restart nginx
# Create custom profile if needed sudo aa-genprof /usr/sbin/nginx ```
Step 6: Fix systemd Service Configuration
Properly configure the Nginx systemd service:
```bash # View current service configuration systemctl cat nginx
# Create override file sudo systemctl edit nginx ```
Add proper configuration: ```ini [Service] # Run as root for privileged ports User=root Group=root
# Or grant capabilities for non-root CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_NET_ADMIN AmbientCapabilities=CAP_NET_BIND_SERVICE
# Ensure proper permissions ExecStartPre=/usr/sbin/nginx -t ExecStart=/usr/sbin/nginx
# Auto-restart on failure Restart=on-failure RestartSec=5s ```
```bash # Reload systemd sudo systemctl daemon-reload
# Restart Nginx sudo systemctl restart nginx
# Verify running sudo systemctl status nginx ```
Step 7: Check File Permissions
Verify Nginx binary and configuration permissions:
```bash # Check Nginx binary permissions ls -la /usr/sbin/nginx # Should be executable by proper user
# Check configuration file permissions ls -la /etc/nginx/nginx.conf ls -la /etc/nginx/sites-available/ ls -la /etc/nginx/sites-enabled/
# Fix permissions if needed sudo chmod 755 /usr/sbin/nginx sudo chmod 644 /etc/nginx/nginx.conf sudo chown -R root:root /etc/nginx/
# Check directory permissions ls -la /var/log/nginx/ sudo chown nginx:nginx /var/log/nginx/ sudo chmod 755 /var/log/nginx/ ```
Step 8: Use authbind for Privileged Ports
Alternative to capabilities using authbind:
```bash # Install authbind sudo apt-get install authbind # Debian/Ubuntu sudo yum install authbind # CentOS/RHEL
# Grant permission for port 80 sudo touch /etc/authbind/byport/80 sudo chmod 500 /etc/authbind/byport/80 sudo chown nginx:nginx /etc/authbind/byport/80
# Grant permission for port 443 sudo touch /etc/authbind/byport/443 sudo chmod 500 /etc/authbind/byport/443 sudo chown nginx:nginx /etc/authbind/byport/443
# Modify Nginx startup to use authbind sudo nano /etc/systemd/system/nginx.service ```
Change ExecStart:
``ini
ExecStart=/usr/bin/authbind --deep /usr/sbin/nginx -g daemon off;
# Reload and restart
sudo systemctl daemon-reload
sudo systemctl restart nginxStep 9: Verify Nginx User Configuration
Check and fix the user directive:
```bash # Check current user setting grep "user" /etc/nginx/nginx.conf
# Edit configuration sudo nano /etc/nginx/nginx.conf ```
Fix user directive: ```nginx # For root privileges user root;
# Or for non-root with capabilities user nginx;
# Make sure master process runs correctly # worker_processes auto; # master_process on; ```
```bash # Test configuration sudo nginx -t
# If test passes, restart sudo systemctl restart nginx ```
Step 10: Debug with Strace
If the issue persists, debug the startup:
```bash # Trace Nginx startup sudo strace -f /usr/sbin/nginx 2>&1 | grep -i bind
# Look for bind() calls and their results # Output should show: # bind(3, {sa_family=AF_INET, sin_port=htons(80), ...}, 16) = 0 # If = -1 EACCES, permission denied
# Check capabilities at runtime sudo capsh --print | grep Cap
# Check if SELinux context matches sudo matchpathcon /usr/sbin/nginx ```
Verify the Fix
Confirm Nginx starts and binds to port 80:
```bash # Check Nginx status sudo systemctl status nginx # Should show active (running)
# Test configuration sudo nginx -t # Should show: syntax is ok, test is successful
# Verify port binding sudo ss -tulpn | grep :80 # Should show nginx listening
# Test HTTP connection curl -I http://localhost # Should return HTTP response headers
# Check Nginx process ps aux | grep nginx # Should show master and worker processes
# Check ports are open sudo netstat -tulpn | grep nginx ```
Nginx should now successfully bind to port 80 and serve requests.