KVM VPS from Rs 149/mo. Mumbai, Noida and Jaipur nodes.

24×7 infrastructure operations Sales +91 98297 14343
vpswala.in
VPSWala 3 min read

Multi-Domain Hosting on a Linux VPS: Nginx Blocks & PHP-FPM Pools

Complete tutorial on configuring multiple isolated websites on a single Linux VPS using Nginx server blocks and dedicated user-level PHP-FPM pools.

Hosting multiple websites on a single Linux VPS is a cost-effective strategy for web development agencies and businesses managing multiple web properties. However, running multiple domains under a single shared web server user introduces severe security vulnerabilities and performance bottlenecks. Implementing isolated Nginx server blocks and dedicated PHP-FPM pools ensures complete security sandboxing and resource control across all hosted domains.

Security Risks of Default Shared-User Hosting

By default, standard LEMP (Linux, Nginx, MySQL, PHP) installations execute all PHP scripts under a single shared system user (typically www-data or nginx). In this flat configuration, every website shares identical file read and write permissions.

If an attacker exploits an unpatched WordPress plugin on one secondary website, they instantly gain file read access to every other site sharing the www-data user. They can read configuration files (such as wp-config.php or .env), extract database credentials, and compromise all hosted domains. Creating separate system users and dedicated PHP-FPM execution pools isolates each website into an independent security container.

Step 1: Creating Isolated System Users and Document Roots

For each website, create a dedicated system user without an interactive login shell. This ensures that even if a PHP script is compromised, the attacker cannot execute shell logins or traverse outside the assigned document root.

# Create dedicated system users
sudo useradd -r -s /bin/false site1_user
sudo useradd -r -s /bin/false site2_user

# Create separate web root directories
sudo mkdir -p /var/www/site1.com/public
sudo mkdir -p /var/www/site2.com/public

# Assign strict ownership and permissions
sudo chown -R site1_user:site1_user /var/www/site1.com
sudo chown -R site2_user:site2_user /var/www/site2.com
sudo chmod 750 /var/www/site1.com
sudo chmod 750 /var/www/site2.com

Add the Nginx runtime user (www-data) to each site group so Nginx can read static assets (images, CSS, JS) directly:

sudo usermod -aG site1_user www-data
sudo usermod -aG site2_user www-data

Step 2: Configuring Dedicated PHP-FPM Pools

PHP-FPM allows you to create independent worker pools. Each pool listens on its own distinct Unix domain socket and runs under its designated system user.

Create the pool configuration file for the first domain at /etc/php/8.2/fpm/pool.d/site1.conf:

[site1]
user = site1_user
group = site1_user

listen = /run/php/php8.2-fpm-site1.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

pm = dynamic
pm.max_children = 10
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
pm.max_requests = 500

chdir = /var/www/site1.com/public
php_admin_value[open_basedir] = /var/www/site1.com/public:/tmp

Notice the open_basedir directive: it restricts PHP file access strictly to the website's document root and the system temporary directory. Create a matching configuration for site2.conf with site2_user and its respective socket path.

Test the PHP-FPM configuration syntax and restart the service:

sudo php-fpm8.2 -t
sudo systemctl restart php8.2-fpm

Step 3: Configuring Nginx Server Blocks

Next, configure Nginx to route domain traffic to its corresponding document root and isolated PHP-FPM Unix socket.

Create the configuration for the first site at /etc/nginx/sites-available/site1.com.conf:

server {
    listen 80;
    listen [::]:80;
    server_name site1.com www.site1.com;

    root /var/www/site1.com/public;
    index index.php index.html;

    access_log /var/log/nginx/site1.access.log;
    error_log /var/log/nginx/site1.error.log;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.2-fpm-site1.sock;
    }

    location ~ /\.ht {
        deny all;
    }
}

Enable the site by symlinking to sites-enabled, test the syntax, and reload Nginx:

sudo ln -s /etc/nginx/sites-available/site1.com.conf /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Step 4: Automated SSL Certificates and Validation

Automate SSL provisioning across all hosted domains using Certbot and the Nginx plugin:

sudo certbot --nginx -d site1.com -d www.site1.com
sudo certbot --nginx -d site2.com -d www.site2.com

Certbot automatically updates the Nginx server blocks with HTTPS listen directives, SSL certificate paths, and HTTP-to-HTTPS redirect rules.

Step 5: Log Rotation and Subdomain Management per Isolated User

When running multiple websites, access and error logs can rapidly consume NVMe disk space if left unmanaged. Configure logrotate to automatically compress and retain logs on a weekly schedule.

Create /etc/logrotate.d/nginx-multi-domain:

/var/log/nginx/*.access.log /var/log/nginx/*.error.log {
    weekly
    missingok
    rotate 12
    compress
    delaycompress
    notifempty
    create 0640 www-data adm
    sharedscripts
    postrotate
        [ -f /var/run/nginx.pid ] && kill -USR1 $(cat /var/run/nginx.pid)
    endscript
}

For staging subdomains (e.g., staging.site1.com), create a subfolder under /var/www/site1.com/staging owned by the same site1_user, allowing safe pre-production testing within the exact same security boundaries.

Multi-Domain VPS Resource Sizing Matrix

Hosted Websites Traffic Tier Recommended VPS Plan Resource Allocation Strategy
2–3 Brochure Websites Low (< 10k visits/mo each) VPS 2: 2 vCPU, 2 GB RAM pm.max_children = 5 per pool, OPcache enabled
5–8 Dynamic WordPress Sites Medium (10k–50k visits/mo each) VPS 8: 4 vCPU, 8 GB RAM pm.max_children = 10 per pool, Redis object cache
10+ High-Traffic Domains / WooCommerce Heavy (100k+ visits/mo) 9950X High-Frequency VPS (16–32 GB RAM) pm.max_children = 25+, FastCGI microcaching

VPSWala provides high-performance KVM Cloud VPS hosting built on enterprise RAID NVMe arrays with complete root access, allowing developers to configure custom multi-domain architectures without artificial hosting restrictions. Explore our Cloud VPS Plans or evaluate high-frequency single-thread power with our AMD Ryzen 9 9950X VPS.


Sources

Not sure which size?

Send the stack, get a size.

Tell us the operating system, application stack, current traffic, database size and where it hurts today. You get a sizing recommendation, the matching plan and a price.

Related

More on this.

Get sizing help See VPS plans