bolt Valebyte VPS from $4/mo — NVMe, 60s deploy.

Get a VPS arrow_forward
eco Beginner Tutorial/How-to

How to Host Multiple Websites on One Dedicated Nginx Server

calendar_month Oct 27, 2026 schedule 6 min read visibility 6 views
How to Host Multiple Websites on One Dedicated Nginx Server
info

Need a server for this guide? We offer dedicated servers and VPS in 50+ countries with instant setup.

A dedicated server with at least 4 vCPUs, 8 GB RAM, and 100 GB NVMe storage can reliably host multiple low-to-medium traffic websites with Nginx. This tutorial shows how to configure separate Nginx server blocks, PHP-FPM pools, DNS records, HTTPS certificates, permissions, and monitoring on Ubuntu 24.04.

Need a server for this guide?

Deploy a VPS or dedicated server in minutes.

What you need before configuring Nginx

This guide uses Ubuntu 24.04 LTS, Nginx, PHP-FPM, MariaDB, and two example domains: site1.com and site2.com. Replace these names with your actual domains. The design works for static sites, WordPress, Laravel, PHP applications, documentation sites, and small APIs.

Minimum production requirements

  • CPU: 4 vCPUs for several light websites; use dedicated physical cores for sustained traffic or CPU-heavy applications.
  • Memory: 8 GB RAM minimum. Allocate more if several sites use PHP, MariaDB, Redis, or search services.
  • Storage: 100 GB NVMe SSD minimum, with backups stored separately.
  • Operating system: Ubuntu 24.04 LTS with root or sudo access.
  • Network: A static public IPv4 address and correctly configured DNS.
  • Access: An SSH client and a local copy of each website.

A VPS is sufficient for a few low-traffic sites, but a dedicated or bare-metal server is preferable for sustained traffic, large databases, strict isolation, or predictable disk and CPU performance. One server also creates a single failure domain, so maintain off-server backups and have a recovery plan.

Production capacity planning

Use the table below as a starting point for production sizing; actual capacity depends on caching, application code, database queries, image sizes, and traffic patterns.

Scale: active sites and aggregate peak loadvCPURAMDiskMonthly bandwidth
5 sites, up to 20 dynamic requests/sec4 vCPU8 GB160 GB NVMe SSD5 TB
20 sites, up to 100 dynamic requests/sec8 vCPU32 GB480 GB NVMe SSD15 TB
50 sites, up to 300 dynamic requests/sec16 dedicated cores64 GB960 GB NVMe SSD with RAID130 TB

For sustained traffic, databases, or customers who require isolation, choose bare metal with dedicated cores and enterprise NVMe storage rather than oversubscribing a small VPS.

Step 1: Update Ubuntu and create an administrative user

Connect over SSH, update packages, and create a non-root account. Replace deploy with your preferred username.

ssh root@SERVER_IP
apt update && apt -y full-upgrade
apt install -y sudo
adduser deploy
usermod -aG sudo deploy

Copy your SSH key to the new account before disabling root login:

ssh-copy-id deploy@SERVER_IP
ssh deploy@SERVER_IP
sudo hostnamectl set-hostname web01.example.net

After confirming key-based login works, edit SSH settings:

sudo nano /etc/ssh/sshd_config

Set PermitRootLogin no and, if every administrator uses keys, set PasswordAuthentication no. Validate and reload:

sudo sshd -t && sudo systemctl reload ssh
Quick pick
Need a dedicated server?
Bare metal with NVMe in 70+ locations — configure and order in minutes.
Browse servers

Step 2: Install Nginx, PHP-FPM, MariaDB, and firewall tools

Install the web stack and common PHP extensions. Remove extensions that your applications do not need.

sudo apt install -y nginx mariadb-server php-fpm php-mysql php-curl php-gd php-mbstring php-xml php-zip php-intl unzip curl ufw fail2ban
sudo systemctl enable --now nginx mariadb php8.3-fpm fail2ban
sudo mariadb-secure-installation

Check the installed PHP-FPM socket because the version may differ on another Ubuntu release:

ls /run/php/php*-fpm.sock
systemctl status nginx --no-pager

Allow only required public services. SSH should be restricted to a trusted IP range where possible.

sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw --force enable
sudo ufw status verbose

Step 3: Create separate directories and permissions

Give every website its own document root. Keeping sites separate simplifies deployment, permissions, logs, and future migration.

sudo mkdir -p /var/www/site1.com/public
sudo mkdir -p /var/www/site2.com/public
sudo chown -R deploy:www-data /var/www/site1.com /var/www/site2.com
sudo find /var/www/site1.com /var/www/site2.com -type d -exec chmod 755 {} \;
sudo find /var/www/site1.com /var/www/site2.com -type f -exec chmod 644 {} \;

Create test files:

printf '%s\n' '<h1>site1.com works</h1>' | sudo tee /var/www/site1.com/public/index.html
printf '%s\n' '<h1>site2.com works</h1>' | sudo tee /var/www/site2.com/public/index.html

For WordPress or another PHP application, upload files into the matching public directory and ensure only directories that require uploads are writable by the web process.

Step 4: Configure Nginx server blocks

Nginx selects a server block from the requested hostname. Create one configuration file per site.

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

Use this configuration for a static or PHP site:

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?$query_string;
    }

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

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

Create the second block by changing the domain and path:

sudo cp /etc/nginx/sites-available/site1.com /etc/nginx/sites-available/site2.com
sudo sed -i 's/site1\.com/site2.com/g; s#/var/www/site1.com#/var/www/site2.com#g; s#site1#site2#g' /etc/nginx/sites-available/site2.com
sudo ln -s /etc/nginx/sites-available/site1.com /etc/nginx/sites-enabled/site1.com
sudo ln -s /etc/nginx/sites-available/site2.com /etc/nginx/sites-enabled/site2.com
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginx

The try_files rule is suitable for many front-controller applications. A purely static site can use try_files $uri $uri/ =404; instead, which avoids sending unknown paths to PHP.

Quick pick
Need a dedicated server?
Bare metal with NVMe in 70+ locations — configure and order in minutes.
Browse servers

Step 5: Point DNS records to the dedicated server

At your DNS provider, create these records:

  • An A record for site1.com pointing to the server IPv4 address.
  • An A record for www.site1.com pointing to the same address, or a CNAME to site1.com.
  • Equivalent records for site2.com and www.site2.com.
  • An AAAA record only if IPv6 is configured and tested on the server.

Verify DNS before requesting certificates:

sudo apt install -y dnsutils
 dig +short site1.com A
dig +short site2.com A
curl -I http://site1.com

DNS changes can be delayed by cached TTL values. The response from dig must contain the server address before continuing.

Step 6: Enable HTTPS with Let's Encrypt

Install Certbot and request one certificate covering both the apex and www hostname for each site.

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d site1.com -d www.site1.com
sudo certbot --nginx -d site2.com -d www.site2.com

Choose the redirect option when Certbot asks whether HTTP should redirect to HTTPS. Test renewal without changing live certificates:

sudo certbot renew --dry-run
sudo nginx -t
curl -I https://site1.com
curl -I https://site2.com

Keep ports 80 and 443 open because HTTP-01 certificate renewal needs port 80 unless you use DNS validation.

Step 7: Add PHP-FPM isolation and database users

For several independent PHP applications, separate PHP-FPM pools reduce cross-site access and make resource limits easier to apply. Create a pool for site1:

sudo nano /etc/php/8.3/fpm/pool.d/site1.conf
[site1]
user = site1
group = site1
listen = /run/php/site1.sock
listen.owner = www-data
listen.group = www-data
pm = dynamic
pm.max_children = 12
pm.start_servers = 2
pm.min_spare_servers = 2
pm.max_spare_servers = 4
php_admin_value[open_basedir] = /var/www/site1.com:/tmp

Create the system user and repeat the pool with site2-specific values:

sudo useradd --system --home /var/www/site1.com --shell /usr/sbin/nologin site1
sudo chown -R site1:site1 /var/www/site1.com
sudo systemctl restart php8.3-fpm
sudo systemctl status php8.3-fpm --no-pager

Change site1's Nginx PHP line to fastcgi_pass unix:/run/php/site1.sock;. Do not set pm.max_children too high: a practical starting point is 2 to 4 workers per GB of RAM available to PHP, then adjust after measuring worker memory use.

Create separate MariaDB credentials rather than using root:

sudo mariadb
CREATE DATABASE site1db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'site1user'@'localhost' IDENTIFIED BY 'CHANGE_THIS_LONG_PASSWORD';
GRANT ALL PRIVILEGES ON site1db.* TO 'site1user'@'localhost';
FLUSH PRIVILEGES;
EXIT;
Quick pick
Need a dedicated server?
Bare metal with NVMe in 70+ locations — configure and order in minutes.
Browse servers

Step 8: Test every website and monitor logs

Check configuration syntax, HTTP status, virtual-host routing, PHP execution, and certificate renewal:

sudo nginx -t
curl -I https://site1.com
curl -I https://site2.com
curl -s https://site1.com | head
sudo tail -f /var/log/nginx/site1.access.log /var/log/nginx/site1.error.log

Test hostname routing directly against the server address if DNS is not ready:

curl --resolve site1.com:80:SERVER_IP http://site1.com
curl --resolve site2.com:80:SERVER_IP http://site2.com

Monitor resource pressure with:

free -h
uptime
df -h
sudo systemctl --failed
sudo journalctl -u nginx -u php8.3-fpm --since '1 hour ago'

Set log rotation, collect metrics for CPU, RAM, disk latency, disk usage, HTTP status codes, and certificate expiry, and keep at least one backup outside the server. A database dump can be created with:

sudo mysqldump --single-transaction site1db | gzip | sudo tee /var/backups/site1db-$(date +%F).sql.gz > /dev/null

Troubleshooting common problems

Every domain displays the same website

Check that each server_name is correct, the site is enabled, and the default block is removed. Run sudo nginx -T and search for duplicate hostnames.

Nginx returns 403 Forbidden

Confirm that the document root exists, directories have execute permission, and the Nginx user can traverse the path:

namei -l /var/www/site1.com/public
sudo tail -n 50 /var/log/nginx/site1.error.log

PHP returns 502 Bad Gateway

The PHP-FPM socket may be wrong or the service may be stopped. Run:

ls -l /run/php/
sudo systemctl status php8.3-fpm
sudo journalctl -u php8.3-fpm -n 50 --no-pager

Certbot cannot validate a domain

Check that DNS resolves to this server, port 80 is reachable, and Nginx loads the correct server block. A proxy or CDN must also forward HTTP validation requests correctly.

One site consumes all resources

Inspect access logs and PHP-FPM workers, enable application caching, limit upload sizes, and lower that site's pool limits. For noisy neighbors or compliance requirements, move the application to a separate VPS or dedicated server.

Operational recommendations

  • Use version-controlled deployment files and test Nginx changes with nginx -t before every reload.
  • Keep applications, plugins, Ubuntu packages, and PHP updated.
  • Use separate Unix users, databases, logs, and deployment directories for each site.
  • Enable automated backups and periodically perform a full restore test.
  • Use a CDN or object storage for large static assets and video rather than consuming all server bandwidth.
  • For mail, use a separate mail-focused service or server when deliverability and reputation are business-critical.

table_chart Dedicated server sizes for multiple Nginx websites

Option vCPU RAM Storage Best for
Entry dedicated server 4 vCPU 8 GB 160 GB NVMe SSD 5 light sites and up to 20 dynamic requests/sec
Production dedicated server 8 vCPU 32 GB 480 GB NVMe SSD 20 sites and up to 100 dynamic requests/sec
High-capacity bare metal 16 dedicated cores 64 GB 960 GB NVMe SSD RAID1 50 sites and up to 300 dynamic requests/sec

check_circle Conclusion

Nginx server blocks let one dedicated server host many isolated domains with independent files, logs, PHP settings, databases, and TLS certificates. Start with the capacity table, test every change, and choose a Valebyte dedicated server when sustained traffic, database performance, or workload isolation requires predictable bare-metal resources.

help Frequently Asked Questions

Was this guide helpful?

Your feedback helps us improve our guides.

Share this post:

Send this guide to someone who may find it useful.

Telegram VKVK WhatsApp Facebook LinkedIn XX

multiple websites on one dedicated server Nginx virtual hosts host multiple domains Nginx dedicated server web hosting Nginx server blocks
support_agent
Valebyte Support
Usually replies within minutes
Hi there!
Send us a message and we'll reply as soon as possible.