How to Configure Different Users per Virtual Host in Nginx for Enhanced Security and Isolation


2 views

When deploying multiple applications on a single Nginx server, a common security requirement is to run each virtual host under different user permissions. This provides process isolation and minimizes the impact if one application gets compromised.

Nginx itself runs as a master process (typically as root or nginx user) with worker processes that handle requests. The configuration directive:

user www-data www-data;

in the main nginx.conf file sets the default user for all worker processes globally.

For PHP applications, you can achieve per-virtual-host user separation using PHP-FPM pools:

server {
    listen 80;
    server_name site1.example.com;
    
    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php7.4-fpm-site1.sock;
        include fastcgi_params;
    }
}

Then configure separate PHP-FPM pools:

[site1]
user = site1user
group = site1group
listen = /var/run/php/php7.4-fpm-site1.sock

For non-PHP applications, you can run separate application servers (like Gunicorn for Python) as different users and proxy through Nginx:

server {
    listen 80;
    server_name app2.example.com;
    
    location / {
        proxy_pass http://unix:/tmp/app2.sock;
    }
}

Then run your application server as the desired user:

sudo -u app2user gunicorn -b unix:/tmp/app2.sock app:app

When implementing this approach:

  • Ensure proper file permissions for each application's files
  • Use separate temporary directories
  • Consider SELinux/AppArmor contexts if enabled
  • Monitor process ownership regularly

Running multiple application instances with different users may:

  • Slightly increase memory usage
  • Require more system resources for process management
  • Need careful tuning of worker processes

Nginx operates with a master process that spawns worker processes. By default, these workers run under the user specified in the main nginx.conf file with the user directive. The limitation is that this user applies globally to all virtual hosts.


# Default in nginx.conf
user www-data;
worker_processes auto;

When hosting multiple applications with different security requirements, running all worker processes under the same system user creates potential security risks. A compromised virtual host could affect others on the same server.

1. Separate Nginx Instances

For true process isolation, you can run multiple Nginx instances with different configurations:


sudo -u user1 nginx -c /etc/nginx/user1.conf
sudo -u user2 nginx -c /etc/nginx/user2.conf

2. PHP-FPM Process Separation

When using PHP, configure different pools in php-fpm:


[site1]
user = user1
group = group1

[site2]
user = user2
group = group2

3. Docker Containers

For modern deployments, containerization provides the cleanest isolation:


docker run --user user1 nginx

If implementing multiple instances or containers:

  • Ensure proper filesystem permissions
  • Use separate log directories
  • Consider SELinux/AppArmor policies
  • Monitor resource usage

Here's how to set up two Nginx instances with different users:


# First instance
useradd -r nginx_user1
cp /etc/nginx/nginx.conf /etc/nginx/nginx_user1.conf
sed -i 's/user www-data;/user nginx_user1;/' /etc/nginx/nginx_user1.conf

# Second instance
useradd -r nginx_user2
cp /etc/nginx/nginx.conf /etc/nginx/nginx_user2.conf
sed -i 's/user www-data;/user nginx_user2;/' /etc/nginx/nginx_user2.conf

# Start instances
sudo -u nginx_user1 nginx -c /etc/nginx/nginx_user1.conf
sudo -u nginx_user2 nginx -c /etc/nginx/nginx_user2.conf