Skip to content

Nginx Configuration Explained: File Locations, Server Blocks and nginx -t

5 min read

Applies to: Nginx 1.26.3 on Debian 13, 1.24.0 on Ubuntu 24.04, 1.28.3 on Ubuntu 26.04 and 1.20.1 on AlmaLinux 9 (tested on all four)

Nginx reads one main file, /etc/nginx/nginx.conf, and that file includes the rest. Your website goes into its own small file with a server { } block. After every change you run nginx -t and reload.

Where the configuration files are

  • Debian and Ubuntu: sites live in /etc/nginx/sites-available/ and are switched on with a symlink in /etc/nginx/sites-enabled/. A fresh install has one site there, default. Extra snippets can go in /etc/nginx/conf.d/*.conf.
  • AlmaLinux, Rocky Linux and RHEL: there is no sites-available. Put each site in /etc/nginx/conf.d/; only files ending in .conf are read. The default server block sits inside nginx.conf itself.

These are the include lines from the Debian 13 nginx.conf (Ubuntu’s are the same):

include /etc/nginx/modules-enabled/*.conf;
    include /etc/nginx/mime.types;
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;

To see the full configuration Nginx actually loads, with every included file, run sudo nginx -T. Each file starts with a header line; in our test:

$ sudo nginx -T 2>/dev/null | grep '^# configuration file'
# configuration file /etc/nginx/nginx.conf:
# configuration file /etc/nginx/mime.types:
# configuration file /etc/nginx/sites-enabled/default:
# configuration file /etc/nginx/sites-enabled/example.com:

How the file is built

A simple directive is a name and values ending in a semicolon, for example worker_processes auto;. A block directive ends with braces. The blocks nest like this: the main part of the file holds user, worker_processes and error_log; inside it are events { } and http { }; each site is a server { } inside http, and a location { } sits inside a server. Nginx runs its workers as www-data on Debian and Ubuntu and as nginx on AlmaLinux.

1. Create the website folder

sudo mkdir -p /var/www/example.com/public
echo '<h1>example.com works</h1>' | sudo tee /var/www/example.com/public/index.html
sudo chown -R www-data:www-data /var/www/example.com

On AlmaLinux use nginx:nginx as the owner.

2. Write a server block

On Debian and Ubuntu create /etc/nginx/sites-available/example.com; on AlmaLinux create /etc/nginx/conf.d/example.com.conf:

server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;

    root /var/www/example.com/public;
    index index.html index.php;

    access_log /var/log/nginx/example.com.access.log;
    error_log  /var/log/nginx/example.com.error.log;

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

3. Enable the site (Debian and Ubuntu only)

sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/

To switch a site off later, delete the symlink; the file in sites-available stays.

4. Test, then reload

$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
$ sudo systemctl reload nginx

A reload doesn’t drop visitors. According to the Nginx documentation, the master process checks the new configuration first; if it can’t apply it, it rolls back and keeps working with the old one, and old workers finish their current requests before they exit.

5. Check that the site answers

Before DNS points to the server, you can test with a Host header:

$ curl -H 'Host: example.com' http://127.0.0.1/
<h1>example.com works</h1>

A name that no server_name matches goes to the default server for that port. In our test, a request for other.test still got a 200 from the Debian default site. Remove /etc/nginx/sites-enabled/default if you don’t want that page to answer.

Errors nginx -t shows, and what they mean

  • [emerg] unknown directive "tryfiles" in /etc/nginx/sites-enabled/example.com:13: a typo in a directive name. The file and line number are in the message.
  • [emerg] invalid number of arguments in "root" directive in /etc/nginx/sites-enabled/example.com:7: we removed the semicolon after root, so Nginx read the next line as part of it.
  • [emerg] unexpected end of file, expecting "}": a block is missing its closing brace.
  • [warn] conflicting server name "example.com" on 0.0.0.0:80, ignored: two enabled server blocks use the same name, often a copied file. The test still passes, but only one of them is used.

A missing semicolon doesn’t always fail the test. When we removed the one after index index.html index.php, nginx -t passed, because Nginx treated the next line’s words as more index file names. If a setting seems to be ignored, look at it in nginx -T.

Next steps

Add HTTPS and redirect HTTP to HTTPS, turn on gzip compression, or run several sites on separate IP addresses. Common errors after a change: 403 Forbidden after changing the root folder and 502 Bad Gateway.

Official documentation: Nginx beginner’s guide and how Nginx processes a request.

Related services

KVM VPS hosting

NVMe SSD and full root access, with Free Basic Managed Support.

Managed cPanel VPS

cPanel included; we handle updates, security and monitoring.

Server management

on-demand administration, hardening, migrations and monitoring.

Was this answer helpful?

Still stuck? Open a ticket