How to Run Nginx as a Non-Root User on Ubuntu: Solving Permission Denied Errors


2 views

When attempting to run Nginx without root privileges, the most common errors involve permission denials for log files (error.log and access.log). These occur because:

1. Nginx master process requires root to bind to privileged ports (<80/443)
2. Worker processes need proper file system permissions
3. Log directories often inherit restrictive permissions

First, create a dedicated system user (if not existing):

sudo adduser --system --no-create-home --group --disabled-login nginx

Then modify your nginx.conf (typically at /etc/nginx/nginx.conf):

user nginx;
worker_processes auto;

events {
    worker_connections 1024;
}

http {
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;
    ...
}

For proper log file handling:

sudo mkdir -p /var/log/nginx
sudo chown -R nginx:nginx /var/log/nginx
sudo chmod -R 755 /var/log/nginx

For development environments, run on high ports:

server {
    listen 8080;
    server_name localhost;
    ...
}

Then forward using iptables:

sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080

For Ubuntu 16.04+ using systemd:

[Service]
User=nginx
Group=nginx
AmbientCapabilities=CAP_NET_BIND_SERVICE
ExecStart=/usr/sbin/nginx -g 'daemon on; master_process on;'
ExecReload=/usr/sbin/nginx -s reload
...

If you still encounter permission issues:

# Check process ownership
ps aux | grep nginx

# Verify directory permissions
namei -l /var/log/nginx/error.log

# Test configuration
sudo -u nginx nginx -t

When attempting to run Nginx without root privileges, the main obstacles are file ownership and process permissions. The error messages clearly indicate the core issue:

nginx: [alert] could not open error log file: open() "/opt/nginx/logs/error.log" failed (13: Permission denied)
2012/03/16 18:17:27 [emerg] 859#0: open() "/opt/nginx/logs/access.log" failed (13: Permission denied)

First, ensure your Nginx user has proper access to required directories:

sudo mkdir -p /opt/nginx/logs
sudo chown -R nginx:nginx /opt/nginx
sudo chmod -R 750 /opt/nginx
sudo chmod 640 /opt/nginx/conf/*

For the log directory specifically:

sudo touch /opt/nginx/logs/{access,error}.log
sudo chown nginx:nginx /opt/nginx/logs/*.log
sudo chmod 640 /opt/nginx/logs/*.log

Create or modify your systemd service file (/etc/systemd/system/nginx.service):

[Unit]
Description=NGINX Web Server
After=syslog.target network.target

[Service]
User=nginx
Group=nginx
Type=forking
PIDFile=/opt/nginx/logs/nginx.pid
ExecStartPre=/opt/nginx/sbin/nginx -t
ExecStart=/opt/nginx/sbin/nginx
ExecReload=/opt/nginx/sbin/nginx -s reload
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
CapabilityBoundingSet=CAP_NET_BIND_SERVICE

[Install]
WantedBy=multi-user.target

Use Linux capabilities to allow binding to privileged ports without full root access:

sudo setcap 'cap_net_bind_service=+ep' /opt/nginx/sbin/nginx

Verify the capabilities:

getcap /opt/nginx/sbin/nginx

If capabilities aren't suitable, use iptables to forward ports:

sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
sudo iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 8443

After implementing these changes, test your setup:

sudo -u nginx /opt/nginx/sbin/nginx -t
systemctl start nginx
systemctl status nginx
ps aux | grep nginx

The process list should show Nginx running under the nginx user:

nginx     1234  0.0  0.1  24532  1234 ?        S    14:30   0:00 nginx: worker process
  • Never run Nginx as root in production
  • Regularly audit file permissions
  • Consider using AppArmor or SELinux for additional protection
  • Monitor log files for permission-related warnings