You've got one domain running fine on your VPS through Nginx, and now a second site needs a home — a client project, a side domain, a staging copy. The instinct is to just drop the new files somewhere and point DNS at the same server. That's where most people get stuck: the new domain either shows the first site's content, throws a 404, or lands on the plain "Welcome to nginx!" page. None of that is a DNS problem. It's almost always a missing or misconfigured server block.

Symptom: the new domain shows the wrong site (or no site at all)

You point newsite.com's A record at your VPS IP, wait out propagation, and open it in a browser. Instead of the site you uploaded, you get one of these:

  • The content from your first domain, even though the files are in a completely different folder
  • A bare Nginx default page reading "Welcome to nginx!"
  • A 404 Not Found from Nginx itself, not from your app
  • A 403 Forbidden even though file permissions look fine

All four point at the same root cause: Nginx doesn't know a domain called newsite.com exists. It's still routing every request to whichever server block matches first — usually your original site, because that one is marked (explicitly or by accident) as the default_server.

Cause: Nginx needs one server block per site, not one config for the whole box

Apache admins are used to VirtualHost entries. Nginx's equivalent is the server block — a server { } section that tells Nginx "if a request's Host header matches this domain, serve files from this directory." Without a server block for newsite.com, any request for that domain falls through to whichever block is marked default_server, which is why you see your first site's content instead of an error.

On a fresh Ubuntu/Debian VPS, Nginx ships with one config at /etc/nginx/sites-available/default, symlinked into /etc/nginx/sites-enabled/, and that block is set as the default. Every domain you add afterward needs its own file in sites-available, its own symlink in sites-enabled, and a server_name line that actually matches the domain. On AlmaLinux/Rocky, the same idea applies, just under /etc/nginx/conf.d/*.conf with no separate sites-available/enabled split.

Fix: create a server block for each domain

Here's the process for adding a second (or third, or tenth) domain to an existing Nginx VPS.

1. Create the site's directory and a test page

sudo mkdir -p /var/www/newsite.com/public_html
echo "newsite.com is live" | sudo tee /var/www/newsite.com/public_html/index.html
sudo chown -R www-data:www-data /var/www/newsite.com

Keep every domain in its own folder under /var/www/. Don't nest a second site inside your first domain's directory — that's how ownership and permission bugs sneak in later.

2. Write the server block

Create /etc/nginx/sites-available/newsite.com (Ubuntu/Debian) or /etc/nginx/conf.d/newsite.com.conf (AlmaLinux/Rocky):

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

    server_name newsite.com www.newsite.com;
    root /var/www/newsite.com/public_html;
    index index.html index.php;

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

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

Two lines matter most here. server_name must list every hostname this block should answer for — typos here are the single most common reason a new domain still shows the wrong site. And root must point at this domain's own folder, not the one your first site uses.

3. Enable the block and reload

On Ubuntu/Debian you need the symlink; on AlmaLinux/Rocky the conf.d file is picked up automatically:

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

nginx -t is not optional. It validates syntax before anything touches the live process, so a typo in one domain's block can't take down every site on the box. If it reports an error, fix it and re-run nginx -t before reloading — don't reload on a config that failed the test.

4. Point DNS and confirm which block answers

Add the A record for newsite.com (and the CNAME for www, or a matching A record) in your DNS zone, pointing at the VPS's public IP. While you wait for propagation, you can confirm the server block itself works by forcing the Host header directly:

curl -H "Host: newsite.com" http://YOUR_VPS_IP/

If that returns the right content, Nginx is configured correctly and any remaining issue is DNS propagation, not your server block.

5. Add SSL once the domain resolves

Once newsite.com is actually resolving to your VPS, get it a certificate the same way you did for your first domain:

sudo certbot --nginx -d newsite.com -d www.newsite.com

Certbot edits the same server block to add the listen 443 ssl directives and the HTTP-to-HTTPS redirect — you don't need to write that part by hand.

Prevention: keep one clean block per domain

HabitWhy it saves you a support ticket
One file per domain in sites-availableEasy to spot which config belongs to which site; nothing gets silently shared
Explicit default_server on a dummy blockPrevents new domains from accidentally inheriting your main site's content before DNS is set up
Always run nginx -t before reloadCatches a bad brace or missing semicolon before it breaks every site on the VPS, not just the new one
Match server_name exactly, including wwwThe most common reason a "configured" domain still shows the wrong content
sudo nginx -T to dump the full merged configLets you see every active server block at once when something's routing oddly

If you're going to be adding domains regularly, it's worth setting an explicit catch-all block once, so future domains fail loudly (404) instead of quietly serving someone else's site:

server {
    listen 80 default_server;
    server_name _;
    return 444;
}

return 444; just closes the connection with no response for any Host header that doesn't match a real block — a clean way to confirm a new domain truly isn't wired up yet, instead of it silently borrowing another site's content.

Frequently Asked Questions

Do I need a separate PHP-FPM pool for each domain?

Not necessarily. For a handful of low-traffic sites, sharing one PHP-FPM pool (as in the example above) is fine. If one site is much busier than the others, or you want strict resource isolation between clients, create a separate pool per domain in /etc/php/8.3/fpm/pool.d/ with its own listen socket, and point that domain's server block at it.

Can I run out of server blocks on one VPS?

There's no hard Nginx limit on the number of server blocks — people run dozens on a modest VPS. What runs out first is usually RAM or CPU under real traffic, not the config itself. Watch your resource usage as you add sites, not the block count.

Why does my new domain still show the old site after I added the block?

Almost always one of three things: the symlink into sites-enabled is missing, server_name doesn't exactly match the domain you're testing (check for a missing www variant), or you reloaded before running nginx -t and the new block never actually loaded because of a syntax error elsewhere in the file.

What's the difference between "reload" and "restart" here?

systemctl reload nginx re-reads the config without dropping active connections — use this every time. restart stops and starts the whole process, which briefly takes every site on the VPS offline for a second. Reserve restart for cases where reload genuinely doesn't pick up a change, which is rare.

Do I need Apache's .htaccess equivalent for Nginx?

Nginx doesn't read per-directory .htaccess files at all — every rewrite rule, redirect, and access restriction has to live directly in the server block and get reloaded. It's less flexible for quick one-off changes but faster, since Nginx isn't scanning the filesystem for override files on every request.