Post

Project: Multi-Site Nginx — 3 Websites on One Server

Project: Multi-Site Nginx — 3 Websites on One Server

One of the most common tasks for a systems administrator is hosting multiple websites on a single server. This project configures 3 independent virtual hosts on one RHEL server — each with its own domain, files, and log files.

Repo: biroue10/multi-site-nginx


How Nginx Routes Traffic to the Right Site

When a browser sends a request, it includes the domain name in the HTTP header:

1
2
GET / HTTP/1.1
Host: site1.local

Nginx reads this Host header and matches it against all server_name directives across all config files. The matching block handles the request. This is called a Virtual Host.

1
2
3
Request: Host: site1.local  →  matches server_name site1.local  →  serves /var/www/site1
Request: Host: site2.local  →  matches server_name site2.local  →  serves /var/www/site2
Request: Host: site3.local  →  matches server_name site3.local  →  serves /var/www/site3

3 sites, 1 IP address, 1 Nginx process.


Configuration

Each site gets its own file in /etc/nginx/conf.d/. This keeps configurations isolated — disabling a site means removing one file, not editing a monolithic config.

site1.conf:

1
2
3
4
5
6
7
8
server {
    listen 80;
    server_name site1.local;
    root /var/www/site1;
    index index.html;
    access_log /var/log/nginx/site1-access.log;
    error_log  /var/log/nginx/site1-error.log;
}
DirectivePurpose
listen 80Accept HTTP traffic on port 80
server_nameDomain that triggers this block
rootDirectory where site files live
indexDefault file to serve
access_logRequests log — this site only
error_logErrors log — this site only

Local DNS with /etc/hosts

There is no real DNS server in this lab. /etc/hosts maps domain names to IPs locally — the system checks it before querying DNS.

1
sudo bash -c 'echo "127.0.0.1 site1.local site2.local site3.local" >> /etc/hosts'

Now site1.local resolves to 127.0.0.1 without any DNS server.


Testing

1
2
3
4
5
sudo nginx -t && sudo systemctl reload nginx

curl http://site1.local
curl http://site2.local
curl http://site3.local

Output:

1
2
3
<html><body><h1>Site 1</h1></body></html>
<html><body><h1>Site 2</h1></body></html>
<html><body><h1>Site 3</h1></body></html>

Each site responds correctly from its own directory.


Separate Logs

Each site writes to its own log:

1
2
3
/var/log/nginx/site1-access.log
/var/log/nginx/site2-access.log
/var/log/nginx/site3-access.log

Why it matters: When multiple sites share a single log file, troubleshooting requires filtering out all other sites’ traffic. Separate logs mean you go directly to the right file. In production with high traffic, this saves significant time during incidents.

Log entry after curl:

1
127.0.0.1 - - [13/Jun/2026:06:52:59 +0100] "GET / HTTP/1.1" 200 48 "-" "curl/8.12.1"
FieldValueMeaning
127.0.0.1Client IPRequest came from localhost
GET / HTTP/1.1RequestMethod, path, protocol
200StatusSuccess
48BytesResponse size
curl/8.12.1User-AgentTool that made the request

Key Concepts

  • Virtual Host — multiple sites on one IP, separated by domain name
  • server_name — the directive Nginx uses to match incoming requests
  • conf.d/ — each file is one site — clean, isolated, easy to manage
  • Separate logs — essential for troubleshooting in multi-site environments
  • /etc/hosts — local DNS override, no external server needed

What’s Next

  • HTTPS with Let’s Encrypt — automate certificate issuance for each domain
  • Custom error pages — branded 404/500 pages per site
  • Rate limiting — protect each site independently

Repo: github.com/biroue10/multi-site-nginx

This post is licensed under CC BY 4.0 by the author.