Skip to content
DevOps devops webservers 5 min read

Nginx Configuration Structure

Nginx (pronounced “engine-x”) is a web server: a program that listens for incoming requests from browsers and sends back web pages, files, or responses from your app. Before you can confidently change how Nginx behaves, you need a clear mental map of where its configuration lives and how the pieces fit together. On Ubuntu, all of this sits under one directory: /etc/nginx. This page walks through that directory, explains the sites-available / sites-enabled symlink pattern, and shows the block hierarchy that every Nginx config follows.

The /etc/nginx directory layout

When you install Nginx on Ubuntu with apt, it creates a tidy directory structure under /etc/nginx. Let’s look at it.

ls -l /etc/nginx

Output:

drwxr-xr-x 2 root root 4096 Jun 15 09:12 conf.d
drwxr-xr-x 2 root root 4096 Jun 15 09:12 sites-available
drwxr-xr-x 2 root root 4096 Jun 15 09:12 sites-enabled
-rw-r--r-- 1 root root 1447 Jun 15 09:12 nginx.conf
-rw-r--r-- 1 root root 2837 Jun 15 09:12 mime.types
-rw-r--r-- 1 root root  664 Jun 15 09:12 fastcgi_params

Here is what each piece does:

PathWhat it isWhen you touch it
/etc/nginx/nginx.confThe main, top-level config. The starting point Nginx reads first.Rarely — only for global settings (worker counts, logging).
/etc/nginx/conf.d/A folder for extra global config snippets. Every *.conf file here is loaded.For settings that apply site-wide (e.g. gzip, rate limits).
/etc/nginx/sites-available/Storage for your per-website config files. Files here are NOT active by default.Every time you add or edit a website.
/etc/nginx/sites-enabled/Active websites. Contains symlinks (shortcuts) pointing back to sites-available.To switch a site on or off.
/etc/nginx/mime.typesA lookup table mapping file extensions to content types.Almost never.

Editing nginx.conf directly is tempting, but resist it for per-site changes. Keeping each website in its own file under sites-available makes configs far easier to read, version, and disable without losing your work.

nginx.conf — the entry point

nginx.conf is the first file Nginx reads on startup. It sets global behaviour and then includes the other config files so they get loaded too. A trimmed Ubuntu default looks like this:

user www-data;
worker_processes auto;
pid /run/nginx.pid;

events {
    worker_connections 768;
}

http {
    sendfile on;
    keepalive_timeout 65;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

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

    gzip on;

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

The two include lines at the bottom are the magic. They tell Nginx: “also read every file in conf.d/ and every enabled site.” That is how your per-site files get pulled in without ever editing nginx.conf again.

This pair of directories is the most important Ubuntu-specific convention to understand.

  • sites-available is a library of every site config you have written, whether it’s live or not.
  • sites-enabled holds only the sites that are currently active. But instead of copying files here, you create a symlink (a symbolic link — a pointer that acts like a shortcut to the real file).

This separation means you can write and store a config without activating it, and you can switch a site off by deleting one symlink — your real config stays safe in sites-available.

When to use this: always, for any real website or app. It is the standard Ubuntu workflow.

Here is how you enable a site. Suppose you’ve written /etc/nginx/sites-available/myapp:

sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
ls -l /etc/nginx/sites-enabled/

Output:

lrwxrwxrwx 1 root root 34 Jun 15 10:02 myapp -> /etc/nginx/sites-available/myapp

The -> arrow confirms it’s a symlink, not a copy. To disable the site, just remove the symlink (the source file is untouched):

sudo rm /etc/nginx/sites-enabled/myapp

Ubuntu ships with a default site already enabled. To turn it off:

sudo rm /etc/nginx/sites-enabled/default

The block hierarchy: http → server → location

Every Nginx config is built from nested blocks — sections wrapped in { } braces. There are three you must know, and they nest from broadest to narrowest.

  1. http block — wraps all web (HTTP/HTTPS) settings. Defined once in nginx.conf. Settings here apply to every site.
  2. server block — defines one website (one domain). This is what you write in sites-available. Often called a “virtual host.”
  3. location block — matches specific URL paths within a site (e.g. /, /images/, /api/) and decides how to handle them.

Think of it as: the building (http), the apartments inside it (server), and the rooms inside each apartment (location).

A typical per-site file in sites-available contains a server block with location blocks inside:

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

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

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

    location /images/ {
        expires 30d;
    }
}
  • listen 80 — wait for requests on port 80 (standard HTTP).
  • server_name — which domain(s) this block answers for.
  • root — the folder on disk where the site’s files live.
  • location / — the catch-all rule for every URL.
  • location /images/ — a more specific rule, here caching images for 30 days.

Nginx always picks the most specific matching location for each request.

Testing and reloading config

Nginx will not pick up your edits automatically. After changing any file, the rule is: test, then reload. First, validate the syntax — this catches typos before they take your site down:

sudo nginx -t

Output:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

If it reports syntax is ok and test is successful, apply the change with a reload. A reload re-reads the config gracefully, without dropping any in-flight connections:

sudo systemctl reload nginx

Always run sudo nginx -t before reloading. If the config has an error, reload will refuse to apply it and your old (working) config keeps running — but only the -t test tells you clearly what is broken and on which line.

Use reload (not restart) for config changes — restart fully stops and starts Nginx, briefly dropping connections. Reserve restart for upgrades or when Nginx is in a stuck state.

Best Practices

  • Keep one server block per website in its own file under sites-available; never bundle unrelated sites together.
  • Activate sites only via symlinks in sites-enabled — disabling a site should never mean deleting your real config.
  • Put truly global settings (gzip, rate limits, logging) in conf.d/, and leave nginx.conf close to its Ubuntu default.
  • Always run sudo nginx -t after every edit and before every reload — make it a reflex.
  • Prefer systemctl reload nginx over restart so live visitors are never disconnected.
  • Remove the default default site once you have your own configured, to avoid serving the placeholder page by accident.
Last updated June 15, 2026
Was this helpful?