How to Host Multiple Websites on One VPS: Nginx Virtual Hosts Guide

How to Host Multiple Websites on One VPS: Nginx Virtual Hosts Guide

One of the biggest advantages of running your own VPS is the ability to host as many websites as you want — all on a single server, without paying for separate hosting accounts. With Nginx virtual hosts (also called server blocks), you can serve dozens of domains from one VPS, each with its own configuration, SSL certificate, and document root.

In this guide, you’ll learn exactly how to set up Nginx virtual hosts on Ubuntu to host multiple websites on one VPS — from installing Nginx to configuring HTTPS with free Let’s Encrypt SSL certificates.

Why Host Multiple Websites on One VPS?

  • Cost efficiency — One $20/month VPS can replace five or more separate shared hosting accounts.
  • Full control — Set custom PHP versions, cache headers, redirects, and server rules per domain.
  • Better performance — No noisy neighbors. Your VPS resources are dedicated to your sites only.
  • Simplified management — One server, one SSH login, one place to manage everything.
  • Easy scaling — When traffic grows, upgrade the VPS instead of migrating dozens of sites.

What Are Nginx Virtual Hosts (Server Blocks)?

An Nginx server block is a configuration section that tells Nginx how to handle requests for a specific domain. When a visitor loads site-a.com, Nginx reads the matching server block and serves files from that domain’s folder. For site-b.com, it reads a different block and serves a completely separate set of files — all happening on the same server, at the same IP address.

This is similar to Apache’s VirtualHost directive, but Nginx is faster and more resource-efficient, making it the preferred choice for modern VPS setups.

Requirements

  • A KVM VPS running Ubuntu 22.04 or 24.04 LTS
  • Root or sudo access via SSH
  • Two or more domain names with DNS pointed to your VPS IP
  • Basic Linux terminal familiarity

💡 VPS.DO Tip: All VPS.DO plans include full root access, KVM virtualization, and SSD storage — everything you need to run a multi-site Nginx setup. View USA VPS plans →

In this tutorial we’ll use two example domains: site1.com and site2.com. Replace these with your actual domain names throughout.


Step 1: Update Your VPS

sudo apt update && sudo apt upgrade -y

Step 2: Install Nginx

sudo apt install nginx -y

Start and enable Nginx so it runs on boot:

sudo systemctl start nginx
sudo systemctl enable nginx

Verify it’s running:

sudo systemctl status nginx

You should see active (running). If you visit your VPS IP in a browser, you’ll see the default Nginx welcome page — that confirms it’s working.

Step 3: Open the Firewall

Allow HTTP and HTTPS traffic through UFW:

sudo ufw allow 'Nginx Full'
sudo ufw allow OpenSSH
sudo ufw enable

Step 4: Create Directory Structure for Each Website

Create a separate web root directory for each domain:

sudo mkdir -p /var/www/site1.com/html
sudo mkdir -p /var/www/site2.com/html

Set correct ownership (replace your_user with your actual sudo username):

sudo chown -R $USER:$USER /var/www/site1.com/html
sudo chown -R $USER:$USER /var/www/site2.com/html

Set proper permissions:

sudo chmod -R 755 /var/www/site1.com
sudo chmod -R 755 /var/www/site2.com

Step 5: Create Test HTML Pages

Create a simple test page for each site so you can verify each domain loads correctly:

nano /var/www/site1.com/html/index.html

Paste:

<html>
  <head><title>Site 1</title></head>
  <body><h1>Welcome to site1.com — hosted on VPS.DO!</h1></body>
</html>

Repeat for site2:

nano /var/www/site2.com/html/index.html
<html>
  <head><title>Site 2</title></head>
  <body><h1>Welcome to site2.com — hosted on VPS.DO!</h1></body>
</html>

Step 6: Create Nginx Server Block for site1.com

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

Paste the following configuration:

server {
    listen 80;
    listen [::]:80;

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

    server_name site1.com www.site1.com;

    location / {
        try_files $uri $uri/ =404;
    }

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

Step 7: Create Nginx Server Block for site2.com

sudo nano /etc/nginx/sites-available/site2.com
server {
    listen 80;
    listen [::]:80;

    root /var/www/site2.com/html;
    index index.html index.htm index.php;

    server_name site2.com www.site2.com;

    location / {
        try_files $uri $uri/ =404;
    }

    access_log /var/log/nginx/site2.com.access.log;
    error_log /var/log/nginx/site2.com.error.log;
}

Step 8: Enable the Server Blocks

Nginx reads active configs from sites-enabled. Create symbolic links to activate each site:

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/

Step 9: Avoid the “server_names_hash_bucket_size” Error

When hosting multiple domains, Nginx may throw a hash bucket size error if domain names are long. Prevent this proactively:

sudo nano /etc/nginx/nginx.conf

Find the http block and uncomment (or add) this line:

server_names_hash_bucket_size 64;

Step 10: Test and Reload Nginx

Always test the configuration before reloading to avoid taking your server down with a syntax error:

sudo nginx -t

You should see:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Then reload:

sudo systemctl reload nginx

Now visit http://site1.com and http://site2.com in your browser. Each should display its own test page. ✅


Step 11: Add Free SSL (HTTPS) with Let’s Encrypt

Running sites over HTTP in 2025 is a security risk and an SEO penalty. Add free SSL certificates using Certbot:

sudo apt install certbot python3-certbot-nginx -y

Issue certificates for both domains:

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

Certbot will automatically update your Nginx server blocks to add HTTPS configuration and redirect HTTP to HTTPS. Follow the on-screen prompts to complete the process.

Test auto-renewal (certificates expire every 90 days, but this is handled automatically):

sudo certbot renew --dry-run

✅ Both sites are now running on HTTPS with auto-renewing certificates.


Step 12: Adding a WordPress Site to the Mix

If one of your sites is a WordPress installation, the server block needs a few additions. Here’s a production-ready WordPress Nginx config:

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

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

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

    location ~ /\.ht {
        deny all;
    }

    location = /favicon.ico { log_not_found off; access_log off; }
    location = /robots.txt  { log_not_found off; access_log off; allow all; }
    location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ {
        expires max;
        log_not_found off;
    }
}

Make sure PHP-FPM is installed and the socket path matches your PHP version (php8.1-fpm.sock, php8.3-fpm.sock, etc.).


Managing Multiple Sites: Best Practices

Keep configs organized

Follow the sites-available / sites-enabled pattern for every domain. Never edit the default config file directly.

Separate log files

Always define unique access_log and error_log paths per domain. This makes debugging much easier when issues arise on specific sites.

Monitor disk usage

Multiple sites can consume disk space quickly. Keep an eye on usage:

df -h
du -sh /var/www/*

Use a process manager for Node.js apps

If one of your sites is a Node.js app, use PM2 alongside Nginx as a reverse proxy. Nginx handles the incoming requests and forwards them to your Node app running on an internal port.

Automate certificate renewal

Certbot sets up a cron job automatically, but confirm it:

sudo systemctl status certbot.timer

Troubleshooting Common Issues

403 Forbidden error

Usually a permissions issue. Check that the web root and its files are readable by Nginx:

sudo chmod -R 755 /var/www/site1.com
sudo chown -R www-data:www-data /var/www/site1.com

Wrong site loading for a domain

Check that your server_name values are correct and unique per config file. Also confirm DNS has propagated (can take up to 48 hours for new domains).

Nginx fails to reload after config change

Run sudo nginx -t first to pinpoint the syntax error before applying any changes.

SSL certificate not issuing

Ensure ports 80 and 443 are open, DNS is pointing to your VPS, and no other process is listening on port 80 when Certbot runs.


How Many Websites Can One VPS Handle?

This depends on traffic, not just site count. A general rule of thumb:

VPS Plan RAM Suitable for
Entry (1–2 vCPU / 2 GB RAM) 2 GB 5–15 low-traffic static or WordPress sites
Mid-tier (2 vCPU / 4 GB RAM) 4 GB 15–40 sites, including moderate-traffic WordPress
Power (4 vCPU / 8 GB RAM) 8 GB 40+ sites, e-commerce, high-traffic applications

VPS.DO’s USA VPS 500SSD plan (2 cores, 4 GB RAM, 500 GB SSD) is a strong starting point for hosting 10–30 WordPress sites comfortably. When you need more headroom, upgrading takes minutes — not a server migration.

Final Thoughts

Nginx virtual hosts make it simple to consolidate all your websites onto a single VPS — cutting hosting costs while gaining far more control than shared hosting ever offered. With the setup in this guide, you can add new domains in minutes: create a directory, write a server block, enable it, run Certbot, and you’re live.

The real power comes from combining this with other server optimizations — caching, PHP-FPM tuning, and a CDN — but that’s a topic for a future post. For now, you have a solid, production-ready multi-site Nginx setup running on your VPS.

Need help getting started? VPS.DO’s support team is online 24/7. Open a ticket anytime →


Related articles you might find useful:

Fast • Reliable • Affordable VPS - DO It Now!

Get top VPS hosting with VPS.DO’s fast, low-cost plans. Try risk-free with our 7-day no-questions-asked refund and start today!