This guide walks you through hosting multiple WordPress sites on a single VPS with strong isolation between them. You’ll set up separate users, PHP-FPM pools, and databases per site, so a compromise or resource spike on one site won’t take down or expose the others. You’ll need root access to a Linux VPS (Ubuntu 22.04/24.04 recommended) and basic comfort with the command line.
What You’ll Need
- A VPS with at least 2 GB RAM (more if you expect heavy traffic)
- Ubuntu 22.04 or 24.04 installed (other distros work but commands differ)
- A domain name (or subdomain) for each WordPress site
- SSH access with root or sudo privileges
- About 45 minutes of time
Step-by-Step
- Update the system and install required packages. Log in via SSH and run:
sudo apt update && sudo apt upgrade -y sudo apt install nginx mariadb-server php-fpm php-mysql php-curl php-gd php-mbstring php-xml php-zip php-imagick certbot python3-certbot-nginx
- Create a system user for each site. Replace
site1with your first site’s short name. Repeat for each site.sudo adduser --system --home /var/www/site1 --group site1
This user will own the site’s files and run its PHP processes, isolating it from other sites.
- Create the web root and set permissions.
sudo mkdir -p /var/www/site1/public_html sudo chown -R site1:site1 /var/www/site1
- Create a separate database and database user for each site. Log into MariaDB:
sudo mysql
Then run (replace
site1db,site1user, andStrongPassword1with your own):CREATE DATABASE site1db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER 'site1user'@'localhost' IDENTIFIED BY 'StrongPassword1'; GRANT ALL PRIVILEGES ON site1db.* TO 'site1user'@'localhost'; FLUSH PRIVILEGES; EXIT;
- Create a PHP-FPM pool for each site. Copy the default pool config:
sudo cp /etc/php/8.3/fpm/pool.d/www.conf /etc/php/8.3/fpm/pool.d/site1.conf
Edit the file (adjust PHP version if needed):
sudo nano /etc/php/8.3/fpm/pool.d/site1.conf
Change these lines:
[site1] user = site1 group = site1 listen = /run/php/site1.sock listen.owner = www-data listen.group = www-data listen.mode = 0660
Remove or comment out the original
user,group, andlistenlines. Save and exit. - Restart PHP-FPM.
sudo systemctl restart php8.3-fpm
- Create an Nginx server block for each site. Create a new config file:
sudo nano /etc/nginx/sites-available/site1
Paste a basic WordPress config (replace
example.comwith your domain):server { listen 80; server_name example.com www.example.com; root /var/www/site1/public_html; index index.php index.html index.htm; location / { try_files $uri $uri/ /index.php?$args; } location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/run/php/site1.sock; } location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { expires max; log_not_found off; } location ~ /\. { deny all; } }Save and exit. Enable the site:
sudo ln -s /etc/nginx/sites-available/site1 /etc/nginx/sites-enabled/
- Test Nginx config and reload.
sudo nginx -t sudo systemctl reload nginx
- Install WordPress for the first site. Download and extract WordPress into the site’s directory:
cd /tmp wget https://wordpress.org/latest.tar.gz tar -xzf latest.tar.gz sudo rsync -av wordpress/ /var/www/site1/public_html/ sudo chown -R site1:site1 /var/www/site1/public_html
- Run the WordPress installer. Visit
http://example.comin your browser. Fill in the database name, user, and password you created. For the database host, uselocalhost. Complete the installation. - Repeat steps 2–10 for each additional site. Use a different user, database, PHP-FPM pool, and Nginx config for each.
- Enable HTTPS with Let’s Encrypt. For each domain, run:
sudo certbot --nginx -d example.com -d www.example.com
Follow the prompts. Certbot will automatically configure Nginx to use the SSL certificate.
- Set up a firewall (if not already). Allow only SSH, HTTP, and HTTPS:
sudo ufw allow OpenSSH sudo ufw allow 'Nginx Full' sudo ufw enable
- Harden each site’s file permissions. After installing WordPress, set stricter permissions:
sudo find /var/www/site1/public_html -type d -exec chmod 755 {} \; sudo find /var/www/site1/public_html -type f -exec chmod 644 {} \; sudo chown -R site1:site1 /var/www/site1/public_html
Common Mistakes
- Using the same PHP-FPM pool for all sites – this defeats isolation.
- Putting all sites in the same directory with the same user – a compromise affects everything.
- Forgetting to set
listen.ownerandlisten.grouptowww-data, causing 502 errors. - Using the same database user for multiple sites – if one site is hacked, all databases are accessible.
- Not enabling a firewall – leaving other ports open can expose your server.
- Ignoring file permissions – leaving files writable by the web server can allow code injection.
Tips
- Use a separate domain or subdomain per site to avoid cookie conflicts.
- Set PHP memory limits per pool (e.g.,
php_admin_value[memory_limit] = 256M) to prevent one site from exhausting RAM. - Enable OPcache per pool to improve performance.
- Use a plugin like Wordfence on each site, but note that isolation is your primary defense.
- Regularly update WordPress core, themes, and plugins on each site.
- Consider using a staging copy of each site before major updates.
Troubleshooting
- 502 Bad Gateway: Check that the PHP-FPM pool exists and is running:
sudo systemctl status php8.3-fpm. Also verify the socket path in your Nginx config matches thelistenline in the pool config. - 404 errors on WordPress pages: Ensure the
try_filesline is exactly as shown. Reload Nginx after changes. - Permission denied when uploading files: Make sure the web root is owned by the site user and that the user has write permissions to
wp-content. - Database connection errors: Double-check the database name, user, and password in
wp-config.php. Verify the user has privileges on the correct database. - SSL certificate fails: Ensure your domain’s DNS points to your VPS IP before running Certbot. Also check that port 80 is open.
- One site goes down, others too: Check system resources with
free -handtop. If RAM is exhausted, increase VPS memory or reduce PHP-FPM workers.
Frequently Asked Questions
Can I host unlimited sites on one VPS?
Technically yes, but performance degrades as resources run out. Each site consumes RAM and CPU. Monitor usage and upgrade when needed.
Is this setup truly secure?
Isolation prevents one site from accessing another’s files or database. It’s a strong baseline, but you still need to keep WordPress and plugins updated, use strong passwords, and follow security best practices.
What if I already have WordPress installed on the VPS?
You can migrate each existing site to its own pool and user. The process involves moving files and exporting/importing the database, then updating wp-config.php.
Do I need a separate IP for each site?
No, Nginx uses domain names to route requests. All sites can share the same IP.
Can I use Docker instead?
Yes, Docker offers even stronger isolation, but it adds complexity. This guide gives you a lightweight, native alternative that’s easier to manage for most users.
How do I back up a single site?
You can use a plugin like UpdraftPlus, or manually back up the site’s directory and database using mysqldump and tar.
Related
Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.
More cards in this drawer
- OLED TVs in Dark Rooms: Why They Look Better and When They Don’t
- Philips DST7060/20 7000 Series Iron: Specs & Fit
- Coal Fueled Jet Aircraft: Could It Work?675 L
- Remote Desktop on Raspberry Pi: How to Enable It
- Word Select Last Line in Paragraph?
- Google Assistant IFTTT Recipes: 7 Useful Automations