Technology

Nginx without magic: how the server knows which site to show

Ports 80 and 443, server_name, web root, redirects and several services on one machine — explained step by step.

Once DNS has done its job, the browser knows the server’s IP address. It may seem that everything after that is simple: the request reached the machine, so the machine shows the site. But one server can host several sites, APIs, control panels and other services at the same time. Sometimes they all use the same IP address.

So how does the server know which site the visitor actually wants? Very often, the answer is Nginx. It accepts the incoming request, looks at where it arrived and which domain it is meant for, chooses the matching configuration and decides what to do next: return a ready file, redirect the visitor, or pass the request to another application.

An Nginx dispatcher cat routes example.com, api.example.com and shop.example.com to different services

The request has already reached the server

In the previous article we stopped around the chain domain → DNS → IP address. The browser now knows which machine it needs to contact.

A new part of the route begins:

IPportNginxright siteresponse

The IP alone still does not tell the server which page to show. It identifies only the machine, and that machine may host the main site, a subdomain, a shop, an API and an admin panel.

First comes the port

When a browser connects to a server, it connects not only to an IP address but to a specific port. For the web, two ports are used most often: 80 for HTTP and 443 for HTTPS.

You can imagine a server as a large building with many doors. The IP address brings us to the building. The port determines the door.

Connection address
203.0.113.10:80
203.0.113.10:443

These numbers are rarely visible in a normal browser address bar because HTTP and HTTPS have standard defaults. When we enter https://example.com, the browser normally assumes port 443.

What listen means

One of the simplest Nginx server blocks can look like this:

Nginx
server {
    listen 80;
}

This says: accept HTTP requests that arrive on port 80. HTTPS commonly uses listen 443 ssl;.

But a port is not enough. If several sites live on port 80 or 443, Nginx still has to understand which one the user wants. That is where server_name appears.

server_name — the site name this block expects

Minimal configuration
server {
    listen 80;
    server_name example.com www.example.com;

    root /var/www/example;
    index index.html;
}

listen 80 says where to accept requests. server_name says which domain names this configuration is for. root shows where the site files live. index says which file should be treated as the directory’s main page.

How Nginx knows the domain

DNS has already turned the domain name into an IP, but the name does not disappear. When the browser sends an HTTP request, it tells the server which site it wants. In simplified form:

HTTP request
GET / HTTP/1.1
Host: example.com

Nginx sees Host: example.com and compares that name with its server_name values. If it finds a matching block, it uses it. That is why one IP can easily serve many domains.

One server, one IP, many sites

Imagine two sites on one machine:

Two virtual hosts
server {
    listen 80;
    server_name cats.example;
    root /var/www/cats;
}

server {
    listen 80;
    server_name dogs.example;
    root /var/www/dogs;
}

Both sites may have the same IP. But the browser sends the site name. For cats.example, Nginx chooses the first block; for dogs.example, the second.

What root means

Once Nginx has chosen the right site, it has to know where its files are. The root directive is often used for this.

Site directory
root /var/www/example;

If the browser asks for https://example.com/about.html, a simple configuration may make Nginx look for /var/www/example/about.html. For /images/cat.jpg, it looks in /var/www/example/images/cat.jpg.

Why index.html opens

When a user enters only https://example.com/, no specific file is named. The server still has to show something.

Directory home page
index index.html;

If a directory is requested, Nginx tries to find index.html inside it. This is one of the web’s oldest conventions: a site’s home page often lives in that file.

What if the file is missing?

If the browser asks for /photo.jpg and the file does not exist, Nginx cannot invent it. In a simple setup, the server responds with 404 Not Found.

But Nginx can behave more flexibly: show a custom error page, redirect the request, pass it to an application, or serve several URLs with one handler.

Nginx may not store the site at all

Not every site consists of ready-made HTML files. A modern application may run on Node.js, Python, Go, PHP or another platform. For example, the application may listen on the internal address 127.0.0.1:3000.

Reverse proxy
location / {
    proxy_pass http://127.0.0.1:3000;
}

The chain becomes:

browserNginxapplicationNginxbrowser

The application creates the response, Nginx receives it and returns it to the browser. This mode is called a reverse proxy. The name sounds much scarier than the principle itself.

Why put Nginx in front of an application?

An application can sometimes accept external requests directly. But a separate web server provides a useful division of responsibilities.

🔒HTTPSaccepts TLS and works with certificates
↪️Redirectssends requests to another address or protocol
📁Filesserves HTML, CSS, JS and images efficiently
🧭Routessends domains and paths to the right services
🛡️Boundaryhides internal application ports
⚖️Load balancingcan distribute traffic between applications

Why location exists

Requests inside one site can be divided too. Images can come from disk while the API is passed to an application.

Different paths, different actions
location /images/ {
    root /var/www/example;
}

location /api/ {
    proxy_pass http://127.0.0.1:3000;
}

Nginx gradually narrows the route: which port the request reached → which domain it is for → which path it has → what should be done with it.

Why ports 80 and 443 exist together

For most modern sites, the final destination is HTTPS. But port 80 often remains open: it accepts an ordinary HTTP request and sends the user to the secure version.

HTTP → HTTPS
server {
    listen 80;
    server_name example.com;

    return 301 https://example.com$request_uri;
}

The browser receives the new address and makes the next request through port 443.

What happens on port 443?

HTTPS adds another layer. Before the normal HTTP request, a secure connection must be established and the server must present a certificate for the right domain.

HTTPS server
server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate /path/to/certificate.pem;
    ssl_certificate_key /path/to/private-key.pem;

    root /var/www/example;
}

That is why “DNS works, but the site shows a certificate error” is a perfectly normal diagnostic state. DNS has already completed its part. The error appeared at the next layer.

How HTTPS chooses the site before the HTTP request

HTTPS has an interesting detail: the certificate must be chosen and the secure channel established before the Host header appears inside the HTTP request. Modern browsers therefore send the desired site name during the TLS connection itself. The mechanism is called SNI — Server Name Indication.

In simplified terms, the browser says: “I am connecting to this IP, but I want example.com.” Nginx receives the name early enough to choose the appropriate HTTPS configuration and certificate.

What if there is no matching server_name?

If Nginx cannot find a matching configuration, it still has to choose some server block. Usually it uses the default configuration for that address and port.

Default server
listen 80 default_server;

That is why opening an IP directly may show another site, an Nginx placeholder or an error. It does not necessarily mean something is broken: the site may be configured only for a specific domain.

Why the wrong site can still open after DNS is configured

Imagine that DNS already returns the new IP, the request definitely reaches the right server, but the user sees another project or the standard Nginx page. The problem is now almost certainly not DNS.

Check server_name, whether the required configuration is active, the port, root, and whether another default_server is intercepting the request.

Do not start fixing DNS again

If the domain already reaches the correct server but an Nginx page appears instead of the site, the previous layer works. Move forward through the chain instead of going backward.

DNS ✓IP ✓portTLSNginxsite

How to test configuration before applying it

Nginx has a useful habit: configuration can be checked before it is applied.

Test
nginx -t

If the test succeeds, the configuration can be reloaded:

Apply without a full restart
systemctl reload nginx

reload asks the running Nginx process to adopt the new configuration. For ordinary site changes, this is often better than a full restart.

editsavenginx -treloadcheckdone

Where the configuration usually lives

Exact paths depend on the system and installation method. On Linux, the main file is often /etc/nginx/nginx.conf, while site configurations live in /etc/nginx/sites-available/, /etc/nginx/sites-enabled/ or /etc/nginx/conf.d/.

The important thing is not memorizing a directory but understanding the structure: there is a main configuration, it includes additional files, and those files contain individual server blocks.

Why a configuration file can exist but still do nothing

A file can sit on the server, look perfect and still not participate in operation at all. For example, it may be in the directory of available configurations but not linked into the active set.

So “does the file exist?” is not the same question as “is Nginx actually reading it?” Diagnostics should check the active configuration.

A redirect is not moving a file

When Nginx executes return 301, it does not fetch a page from another address and relay it itself. It tells the browser: “go to this other address.” The browser receives a new URL and makes a new request.

This is fundamentally different from proxying.

browserNginxnew addressbrowsernew request
browserNginxserviceNginxbrowser

Several services on one machine

Now we can build a diagram like the cover. The main site, API and shop live on one server. DNS for all three names points to one IP, while Nginx separates the requests.

example.comSITE
api.example.comAPI :3000
shop.example.comSHOP :4000

For the user these are three different services. For Nginx they are three routing rules. That is one of its core jobs.

Nginx does not know what you “meant”

The server works literally. If DNS contains one domain while server_name contains another, it will not guess that they are almost the same. If an application runs on port 3000 while proxy_pass points to 3001, that is where the request will go.

This strictness can be annoying during setup, but it is exactly what makes server behavior predictable. The computer is not being difficult — it is very consistently doing not what you wanted, but what you wrote.

Good diagnostics follow the chain

When a site does not open, it is more useful to follow the full request path than to change settings at random.

DNSIPportTLSNginxrouteapplication

Every successfully checked stage rules out an entire class of problems. If DNS returns the right IP, move on. If TLS connects, do not go back to DNS. If Nginx chose the correct block, check the file or application.

What a complete ordinary site looks like

Putting it together
server {
    listen 80;
    server_name example.com;
    return 301 https://example.com$request_uri;
}

server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate /path/to/certificate.pem;
    ssl_certificate_key /path/to/private-key.pem;

    root /var/www/example;
    index index.html;

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

The first part accepts HTTP and redirects it to HTTPS. The second accepts the secure connection. server_name defines the domain, the certificate handles TLS, root points to the site directory, and location defines how a path is processed.

Nginx is good precisely because it is boring

At first, Nginx can look like a collection of obscure directives. At heart, however, it performs mechanical work: accept a connection, identify the site, inspect the path, apply a rule, return a response.

That is a good thing. Infrastructure is especially pleasant when it is predictable. The fewer surprises between a user’s request and the site’s page, the better.