Host multiple sites with Nginx
One VPS can serve several domain names without an extra container or machine. Nginx separates sites using the request's Host header: each domain gets its own server block, document root and logs. This guide sets up two sites, then shows the checks that prevent the wrong content from being served.
One server block per site
Create a separate root for each site. Static files are enough here; a PHP or Node.js application plugs into the same root or sits behind a proxy.
sudo mkdir -p /var/www/site-a.fr /var/www/site-b.fr
sudo chown -R deploy:www-data /var/www/site-a.fr /var/www/site-b.fr
sudo chmod 750 /var/www/site-a.fr /var/www/site-b.frPut an index.html in each folder, then create /etc/nginx/sites-available/site-a.fr.conf:
server {
listen 80;
listen [::]:80;
server_name site-a.fr www.site-a.fr;
root /var/www/site-a.fr;
index index.html;
location / {
try_files $uri $uri/ =404;
}
access_log /var/log/nginx/site-a.fr.access.log;
error_log /var/log/nginx/site-a.fr.error.log;
}listen [::]:80 is required to answer over IPv6; without it, Nginx only listens on IPv4. server_name accepts several names, but the first matching block wins. try_files returns a clean 404 instead of listing the directory.
Enable the site and reload
The Debian package reads sites-enabled, not sites-available. A symbolic link activates the site without duplicating the file.
sudo ln -s /etc/nginx/sites-available/site-a.fr.conf /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginxnginx -t validates syntax and paths before any reload; do not skip it. reload applies the configuration without dropping active connections. Repeat for the second site.
To stop an unknown domain from landing on the first site, remove the package's /etc/nginx/sites-enabled/default link, then keep an explicit default block:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
return 444;
}Code 444 closes the connection without a response. If you prefer to keep the default site, adapt it instead of adding a second default_server, which Nginx would reject.
Verify before going public
Test locally with a Host header, then over IPv6 and from outside:
curl -H "Host: site-a.fr" http://127.0.0.1/
curl -6 -H "Host: site-a.fr" http://[::1]/
dig +short AAAA site-a.frCompare the responses and read /var/log/nginx/site-a.fr.access.log. A 403 almost always means permissions or a missing index; a 404 means a misspelled root. Check that www-data can traverse every parent directory with namei -l /var/www/site-a.fr/index.html.
Common mistakes
- Two
default_serverblocks on the same port: Nginx refuses to start. - A
server_namecontaininghttps://or a slash: that is not a URL, only the name. - DNS still points elsewhere: test with
curl --resolve site-a.fr:80:YOUR_IPV6. - After an edit,
systemctl restarthides a syntax error; usenginx -tthenreload.
Once both domains return their own content over IPv4 and IPv6, add HTTPS site by site. Keep a copy of /etc/nginx before the next change.
Advertisement
Was this article helpful?
Read next
- Configure Nginx as a reverse proxyForward a local application with proxy_pass, pass the right headers and handle WebSocket and timeouts.
- Apache or Nginx: which one?Compare Apache and Nginx on architecture, .htaccess, PHP-FPM and practical selection criteria.
- Install Nginx on DebianInstall Nginx, check the service, test locally, open the firewall and inspect the logs.