If you are managing more than one WordPress site, paying for separate shared hosting plans for each one is wasteful. A single VPS can comfortably host five, ten, or even twenty WordPress sites, depending on their traffic. You get better performance, full control over your server stack, and a significantly lower cost per site.

This guide walks you through setting up a LEMP stack (Linux, Nginx, MariaDB, PHP) on Ubuntu 24.04 LTS, then configuring Nginx server blocks (virtual hosts) to serve multiple WordPress installations from the same server. Each site gets its own domain, database, and isolated directory.

Why Use a VPS Instead of Shared Hosting?

Shared hosting puts hundreds of websites on a single server. Your sites compete for CPU, RAM, and disk I/O with every other customer on that machine. The results are predictable: slow load times during peak hours, restrictive resource limits, and no ability to tune your server configuration.

A VPS gives you dedicated resources and full root access. Here is what that means in practice:

Prerequisites

Step 1: Install the LEMP Stack

Start by updating your system and installing Nginx, MariaDB, and PHP:

sudo apt update && sudo apt upgrade -y

# Install Nginx
sudo apt install nginx -y

# Install MariaDB
sudo apt install mariadb-server -y

# Install PHP 8.3 and required WordPress extensions
sudo apt install php8.3-fpm php8.3-mysql php8.3-curl php8.3-gd \
  php8.3-intl php8.3-mbstring php8.3-soap php8.3-xml \
  php8.3-zip php8.3-imagick php8.3-redis -y

Secure MariaDB by running the interactive setup script:

sudo mysql_secure_installation

Answer "Yes" to all prompts: set a root password, remove anonymous users, disallow remote root login, remove the test database, and reload privileges.

Step 2: Create Databases for Each Site

Each WordPress installation needs its own database and database user. Log into MariaDB and create them:

sudo mysql -u root -p

Then run the following SQL for each site (replace the names and passwords):

CREATE DATABASE site1_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'site1_user'@'localhost' IDENTIFIED BY 'strong_password_here';
GRANT ALL PRIVILEGES ON site1_db.* TO 'site1_user'@'localhost';

CREATE DATABASE site2_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'site2_user'@'localhost' IDENTIFIED BY 'another_strong_password';
GRANT ALL PRIVILEGES ON site2_db.* TO 'site2_user'@'localhost';

FLUSH PRIVILEGES;
EXIT;

Use unique, strong passwords for each database user. A password manager can help you track them.

Step 3: Download and Install WordPress

Create a directory structure for each site and download WordPress:

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

# Download and extract WordPress for site 1
cd /tmp
wget https://wordpress.org/latest.tar.gz
tar -xzf latest.tar.gz
sudo cp -r wordpress/* /var/www/site1.com/public/

# Repeat for site 2
sudo cp -r wordpress/* /var/www/site2.com/public/

# Set proper ownership
sudo chown -R www-data:www-data /var/www/site1.com/public
sudo chown -R www-data:www-data /var/www/site2.com/public

Now configure each WordPress installation. For site 1:

cd /var/www/site1.com/public
sudo cp wp-config-sample.php wp-config.php
sudo nano wp-config.php

Update the database settings to match what you created in Step 2:

define( 'DB_NAME', 'site1_db' );
define( 'DB_USER', 'site1_user' );
define( 'DB_PASSWORD', 'strong_password_here' );
define( 'DB_HOST', 'localhost' );

Also replace the placeholder authentication keys and salts with unique values from the WordPress secret key generator. Repeat this process for each additional site.

Step 4: Configure Nginx Server Blocks

This is where the multi-site magic happens. Create an Nginx server block configuration for each domain. Start with site 1:

sudo nano /etc/nginx/sites-available/site1.com

Add the following configuration:

server {
    listen 80;
    server_name site1.com www.site1.com;
    root /var/www/site1.com/public;
    index index.php index.html;

    client_max_body_size 64M;

    # Security headers
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;

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

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    # Deny access to sensitive files
    location ~ /\.ht {
        deny all;
    }

    location = /wp-config.php {
        deny all;
    }

    # Cache static assets
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
        expires 30d;
        add_header Cache-Control "public, immutable";
    }
}

Create an identical configuration for site 2, changing the server_name and root path:

sudo nano /etc/nginx/sites-available/site2.com

Enable both sites and test the configuration:

sudo ln -s /etc/nginx/sites-available/site1.com /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/site2.com /etc/nginx/sites-enabled/

# Remove the default site
sudo rm /etc/nginx/sites-enabled/default

# Test the configuration
sudo nginx -t

# Reload Nginx
sudo systemctl reload nginx

Step 5: Install SSL Certificates

Install Certbot and generate free SSL certificates for all your domains in a single command:

sudo apt install certbot python3-certbot-nginx -y

# Generate certificates for all sites
sudo certbot --nginx -d site1.com -d www.site1.com -d site2.com -d www.site2.com

Certbot will automatically modify your Nginx configurations to redirect HTTP to HTTPS and configure the SSL certificate paths. Verify auto-renewal is working:

sudo certbot renew --dry-run

Step 6: Optimize PHP-FPM for Multiple Sites

The default PHP-FPM pool works fine for a single site, but for multiple WordPress installations, you should tune the worker settings. Edit the pool configuration:

sudo nano /etc/php/8.3/fpm/pool.d/www.conf

Adjust these values based on your available RAM:

pm = dynamic
pm.max_children = 20
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 6
pm.max_requests = 500

A rough guideline: each PHP-FPM worker uses about 30-50 MB of memory with WordPress. On a 4 GB VPS, setting pm.max_children to 20 allows for comfortable headroom alongside Nginx, MariaDB, and the operating system.

sudo systemctl restart php8.3-fpm

Step 7: Install Redis for Object Caching

Redis stores frequently accessed database queries in memory, dramatically reducing load times and database pressure when running multiple sites:

sudo apt install redis-server -y
sudo systemctl enable redis-server

In each WordPress installation, install the "Redis Object Cache" plugin by Till Kruss. Then add this line to each site's wp-config.php (before the "That's all, stop editing!" comment):

define( 'WP_REDIS_DATABASE', 0 );  // Use 0 for site1, 1 for site2, etc.

Using different Redis database numbers prevents cache collisions between sites. Activate the plugin in each WordPress admin panel and verify it connects to Redis successfully.

Step 8: Set Up Automated Backups

Create a simple backup script that dumps each database and archives each site directory:

sudo nano /usr/local/bin/backup-sites.sh
#!/bin/bash
BACKUP_DIR="/var/backups/wordpress"
DATE=$(date +%Y-%m-%d)
mkdir -p $BACKUP_DIR/$DATE

# Backup each site's database
mysqldump -u root site1_db | gzip > $BACKUP_DIR/$DATE/site1_db.sql.gz
mysqldump -u root site2_db | gzip > $BACKUP_DIR/$DATE/site2_db.sql.gz

# Backup each site's files
tar -czf $BACKUP_DIR/$DATE/site1_files.tar.gz -C /var/www/site1.com public
tar -czf $BACKUP_DIR/$DATE/site2_files.tar.gz -C /var/www/site2.com public

# Delete backups older than 14 days
find $BACKUP_DIR -type d -mtime +14 -exec rm -rf {} +
sudo chmod +x /usr/local/bin/backup-sites.sh

# Schedule daily backups at 3 AM
echo "0 3 * * * root /usr/local/bin/backup-sites.sh" | sudo tee /etc/cron.d/wordpress-backup

How Many Sites Can One VPS Handle?

This depends on your traffic levels and how well each site is optimized. Here are some practical guidelines:

VPS Specs Low-Traffic Sites Medium-Traffic Sites
2 vCPU / 2 GB RAM 3-5 sites 1-2 sites
2 vCPU / 4 GB RAM 5-10 sites 3-5 sites
4 vCPU / 8 GB RAM 10-20 sites 5-10 sites

"Low-traffic" means under 1,000 daily visitors per site. "Medium-traffic" means 1,000 to 10,000 daily visitors per site. With Redis caching and properly configured Nginx, these numbers are conservative. The bottleneck is almost always RAM, not CPU.

Host Your WordPress Sites on Reliable Infrastructure

Running multiple WordPress sites on a VPS is straightforward once the stack is in place. The key to doing it well is starting with reliable infrastructure. MassiveGRID's Cloud VPS plans start at $1.99/month and run on Proxmox HA clusters with Ceph distributed storage, so your data is replicated across multiple physical drives and your server automatically migrates to healthy hardware in the event of a failure. With data centers in New York, London, Frankfurt, and Singapore, you can place your server close to your audience for the best possible load times. Configure your VPS to match the needs of your site portfolio and deploy in minutes.