Nginx configuratiebestandsstructuur uitgelegd

9 min leestijd·Matthieu|

Een volledige uitleg van hoe Nginx configuratiebestanden op schijf zijn georganiseerd, hoe contexts in elkaar genest zijn, hoe include-directives bestanden inladen, en hoe directive-overerving werkt.

Nginx configuratiebestandsstructuur uitgelegd

Je hebt Nginx geinstalleerd. Je opende /etc/nginx/nginx.conf en vond een bestand dat andere bestanden includet, die weer meer bestanden includen. Sommige directives staan binnen accolades, andere zweven op het hoogste niveau. Voordat je server blocks, SSL of reverse proxies gaat configureren, heb je de plattegrond nodig.

Dit artikel geeft je die plattegrond. Geen recepten. Alleen het mentale model van hoe Nginx-configuratie werkt, zodat je elke config die je tegenkomt kunt lezen en aanpassen.

Waar worden Nginx configuratiebestanden opgeslagen?

Op Debian 12 en Ubuntu 24.04 installeert het apt-pakket alles onder /etc/nginx/. Zo ziet die directory eruit na een schone installatie:

/etc/nginx/
├── nginx.conf              # Main config entry point
├── mime.types              # Maps file extensions to MIME types
├── conf.d/                 # Drop-in config files (*.conf auto-included)
├── sites-available/        # All virtual host config files
│   └── default             # Default server block
├── sites-enabled/          # Symlinks to active virtual hosts
│   └── default -> ../sites-available/default
├── snippets/               # Reusable config fragments
│   └── fastcgi-php.conf
├── modules-available/      # Available dynamic module configs
├── modules-enabled/        # Symlinks to loaded modules
├── fastcgi.conf            # FastCGI directive defaults
├── fastcgi_params          # FastCGI parameter mappings
├── proxy_params            # Proxy header defaults
├── scgi_params             # SCGI parameter mappings
├── uwsgi_params            # uWSGI parameter mappings
├── koi-utf                 # Character set mapping files
├── koi-win
└── win-utf

Je kunt dit verifiëren op je eigen server:

ls -la /etc/nginx/

Het bestand dat je het vaakst bewerkt is niet nginx.conf zelf. Het is meestal een bestand in sites-available/ of conf.d/. Het hoofdbestand nginx.conf stelt globale standaardwaarden in en haalt die bestanden binnen via include-directives.

Hoe zijn Nginx configuratiebestanden georganiseerd?

Nginx-configuratie gebruikt een boomstructuur van geneste contexts. Elke context is een block directive omgeven door accolades. Directives die binnen een context staan, gelden alleen binnen dat bereik.

De hierarchie ziet er als volgt uit:

main (top level, outside any braces)
├── events { }
└── http { }
    └── server { }
        └── location { }

Elke directive in de config bevindt zich op een van deze niveaus. De main context is het bestand zelf. Al het andere is daarbinnen genest.

Wat regelt de main context?

De main context is alles buiten elke block directive in nginx.conf. Het regelt instellingen op procesniveau die de gehele Nginx-instantie beinvloeden.

Belangrijke directives op dit niveau:

Directive Doel Typische waarde
user OS-gebruiker waaronder de workerprocessen draaien www-data
worker_processes Aantal workerprocessen auto (komt overeen met CPU-cores)
pid Pad naar het PID-bestand /run/nginx.pid
error_log Globaal foutlogpad en -niveau /var/log/nginx/error.log
include Moduleconfiguraties laden /etc/nginx/modules-enabled/*.conf

Hier is de main context uit de standaard Debian 12 nginx.conf:

user www-data;
worker_processes auto;
pid /run/nginx.pid;
error_log /var/log/nginx/error.log;
include /etc/nginx/modules-enabled/*.conf;

Deze vijf regels worden als eerste uitgevoerd. Ze bepalen als welke gebruiker Nginx draait, hoeveel workers het start, en waar fouten worden weggeschreven.

Wat komt er in het events block?

Het events block configureert hoe Nginx verbindingen afhandelt op OS-niveau. Het bevindt zich in de main context.

events {
    worker_connections 768;
    # multi_accept on;
}

worker_connections stelt het maximaal aantal gelijktijdige verbindingen per workerproces in. Met worker_processes auto op een machine met 4 cores krijg je 4 x 768 = 3.072 gelijktijdige verbindingen. De standaard vanuit de Nginx-broncode is 512, maar Debian stelt het in op 768.

Waar dient de http context voor?

Het http block bevat alle configuratie die te maken heeft met HTTP-verkeer. Elk server block bevindt zich daarbinnen. Directives die je hier plaatst, gelden voor alle virtual hosts, tenzij een server of location block ze overschrijft.

http {
    sendfile on;
    tcp_nopush on;
    types_hash_max_size 2048;
    server_tokens off;

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

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

    gzip on;

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

Let op server_tokens off; bovenaan. Dit verbergt het Nginx-versienummer uit response headers. Versie-informatie helpt aanvallers bekende kwetsbaarheden te targeten. De Debian-standaard bevat deze regel niet. Voeg hem toe.

De twee include-regels onderaan zijn de manier waarop Nginx je daadwerkelijke siteconfiguraties binnenhaalt. We behandelen include hieronder in detail.

Hoe werken server blocks?

Een server block definieert een virtual host. Het bevindt zich in de http context. Elk server block luistert op een adres/poort-combinatie en matcht verzoeken aan de hand van de Host-header.

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

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

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

Wanneer een verzoek binnenkomt, kiest Nginx het server block door server_name te matchen met de Host-header. Als geen enkel block matcht, gebruikt Nginx de default_server:

listen 80 default_server;

Meestal maak je een bestand per domein aan in sites-available/, elk met een server block (of twee, als je zowel HTTP als HTTPS hebt).

Hoe matcht Nginx location blocks?

Een location block bepaalt hoe Nginx verzoeken voor specifieke URI-patronen afhandelt. Het bevindt zich in een server block (of in een ander location block).

Nginx evalueert location blocks in een specifieke volgorde:

Modifier Type Voorbeeld Gedrag
= Exacte match location = / Matcht alleen /. Stopt onmiddellijk met zoeken.
^~ Priority prefix location ^~ /images/ Matcht prefix. Slaat regex-controles over.
~ Regex (hoofdlettergevoelig) location ~ \.php$ Eerste regex-match wint.
~* Regex (niet hoofdlettergevoelig) location ~* \.(jpg|png)$ Eerste regex-match wint.
(geen) Prefix location /api/ Langste prefix wint, maar regex kan overschrijven.

Het matchingalgoritme:

  1. Nginx controleert alle prefix-locations en onthoudt de langste match.
  2. Als die match = of ^~ gebruikt, stop. Gebruik die.
  3. Anders worden regex-locations gecontroleerd in de volgorde waarin ze in het configuratiebestand staan.
  4. De eerste regex-match wint. Als geen regex matcht, gebruik de langste prefix uit stap 1.

Dit betekent dat de volgorde van prefix-locations in je configuratiebestand er niet toe doet. Maar de volgorde van regex wel.

Hoe werkt de include directive?

De include directive voegt de inhoud van een ander bestand (of bestanden die overeenkomen met een glob-patroon) in op de huidige positie in de config. Nginx lost het op bij het laden van de configuratie, voordat de config als geheel wordt geparsed.

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

De glob *.conf matcht alle bestanden die eindigen op .conf in die directory. De glob * matcht alles. Beide zijn gangbare patronen.

De include directive werkt in elke context. Je kunt het gebruiken binnen http, server of location blocks:

server {
    listen 443 ssl;
    include snippets/ssl-params.conf;
}

Zo werkt de snippets/-directory. Je schrijft een herbruikbaar fragment eenmalig en includet het waar nodig.

Let op: Nginx weigert te starten als een include zonder glob geen bestanden vindt. Als je include /etc/nginx/conf.d/*.conf; schrijft en de directory is leeg, start Nginx gewoon op (globs mogen niets matchen). Maar include /etc/nginx/ssl.conf; faalt als dat bestand niet bestaat.

Wat is het verschil tussen sites-available, sites-enabled en conf.d?

Deze drie directory's dienen verschillende doelen. Debian en Ubuntu gebruiken alle drie.

Directory Doel Hoe Nginx het leest Wanneer gebruiken
sites-available/ Slaat alle virtual host configs op Wordt niet direct gelezen Altijd. Een bestand per domein.
sites-enabled/ Bevat symlinks naar actieve configs Ingeladen via include /etc/nginx/sites-enabled/*; Maak hier een symlink om een site te activeren.
conf.d/ Drop-in configuratiefragmenten Ingeladen via include /etc/nginx/conf.d/*.conf; Globale http-niveau-instellingen, upstream blocks, maps.

Het sites-available / sites-enabled patroon laat je een site uitschakelen zonder de config te verwijderen. Om een site te activeren:

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

Om hem uit te schakelen:

rm /etc/nginx/sites-enabled/example.com

Herlaad daarna:

sudo nginx -t && sudo systemctl reload nginx

Draai altijd nginx -t voordat je herlaadt. Het valideert de config zonder lopend verkeer te beinvloeden.

De conf.d/-directory is eenvoudiger. Elk .conf-bestand erin wordt automatisch geladen. Geen symlinks nodig. Sommige beheerders geven de voorkeur aan conf.d/ vanwege de eenvoud en slaan sites-available/sites-enabled helemaal over. Beide aanpakken werken. Kies er een en blijf consistent.

Een valkuil: als je zowel conf.d/ als sites-enabled/ gebruikt, zorg er dan voor dat je geen tegenstrijdige server blocks op beide plekken definieert. Nginx laadt beide, en het resultaat hangt af van directive-mergingregels en server_name-matching.

Hoe werkt Nginx directive-overerving?

Nginx geeft directives van bovenliggende contexts door aan onderliggende contexts. Dit is het onderdeel waar de meeste mensen fouten maken, en de bron van subtiele productiebugs.

Er zijn drie typen directives, en elk erft anders over.

Normale directives

Normale directives bevatten een enkele waarde. Als een onderliggende context dezelfde directive definieert, vervangt deze de bovenliggende waarde volledig. Als het kind de directive niet definieert, wordt de waarde van de parent overgenomen.

Voorbeeld: root is een normale directive.

http {
    root /var/www/default;

    server {
        server_name example.com;
        # root is inherited: /var/www/default

        location /app {
            root /var/www/app;
            # root is overridden: /var/www/app
        }

        location /blog {
            # root is inherited: /var/www/default
        }
    }
}

Andere normale directives: index, access_log (bij enkelvoudig gebruik), error_log, client_max_body_size.

Array directives

Array directives kunnen meerdere keren voorkomen in dezelfde context om waarden te verzamelen. Maar wanneer een onderliggende context ook maar een instantie definieert, vervangt deze alle waarden van de parent. Niet samenvoegen. Vervangen.

add_header is de meest voorkomende array directive. Dit gedrag veroorzaakt een bekende productiebug.

Wat gebeurt er wanneer je headers toevoegt in zowel http als location blocks?

Als je add_header definieert in de http context en vervolgens een andere add_header in een location block, wist het location block alle headers uit de http context. Niet alleen degene die je overschrijft. Allemaal.

http {
    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-Content-Type-Options "nosniff";

    server {
        server_name example.com;

        location /api/ {
            add_header X-Custom "api-response";
            # X-Frame-Options is GONE
            # X-Content-Type-Options is GONE
            # Only X-Custom is sent
        }
    }
}

Om te verifieren dat dit op je server gebeurt:

curl -I https://example.com/api/

Controleer de response headers. Als je security headers ontbreken bij /api/-responses maar aanwezig zijn op andere paden, is dit de oorzaak.

De oplossing: herhaal alle headers in de onderliggende context.

location /api/ {
    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-Content-Type-Options "nosniff";
    add_header X-Custom "api-response";
}

Of gebruik een snippet:

# /etc/nginx/snippets/security-headers.conf
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Strict-Transport-Security "max-age=63072000" always;
location /api/ {
    include snippets/security-headers.conf;
    add_header X-Custom "api-response";
}

Let op: Nginx 1.29.3+ introduceerde add_header_inherit merge; dat dit gedrag verandert. Met merge voegen onderliggende contexts toe aan de headers van de parent in plaats van ze te vervangen. Als je Nginx 1.28.x draait (de huidige stabiele versie per maart 2026), heb je dit nog niet.

Hetzelfde wisgedrag geldt voor proxy_set_header. Als je een proxy_set_header definieert in een location block, gaan alle proxy_set_header-directives uit de server of http context verloren. De officiele documentatie stelt het expliciet: "These directives are inherited from the previous configuration level if and only if there are no proxy_set_header directives defined on the current level."

server {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    location /api/ {
        proxy_set_header X-Request-ID $request_id;
        # Host, X-Real-IP, X-Forwarded-For are all GONE
        proxy_pass http://backend;
    }
}

Los het op dezelfde manier op: herhaal alle headers in het location block, of gebruik een include snippet.

Action directives

Action directives zoals rewrite en return erven niet over naar geneste contexts. Ze worden alleen uitgevoerd in de context waar ze gedefinieerd zijn.

server {
    rewrite ^/old/(.*)$ /new/$1 permanent;

    location /app {
        # The rewrite above does NOT apply here
        # Requests matching /app are handled by this location
    }
}

De try_files directive heeft een verwante valkuil. Wanneer deze in de server context staat, maakt Nginx een impliciete pseudo-location aan met de laagst mogelijke prioriteit. Als een gewoon location block het verzoek matcht, wordt try_files op serverniveau nooit uitgevoerd:

server {
    try_files $uri /index.php;   # Never runs for /app/* requests
    location /app { }            # This catches them first
}

Plaats try_files altijd in een specifiek location block.

Hoe inspecteer je de effectieve Nginx-configuratie?

Twee commando's helpen je te begrijpen wat Nginx daadwerkelijk ziet na het oplossen van alle include-directives.

Test de config op syntaxfouten:

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

Draai dit altijd voordat je herlaadt. Als de test faalt, vertelt Nginx je het bestand en regelnummer.

Dump de volledig samengevoegde config:

sudo nginx -T

Dit geeft de volledige effectieve configuratie weer met alle includes opgelost en inline uitgebreid. Pipe het naar less voor leesbaarheid:

sudo nginx -T | less

Of zoek naar een specifieke directive:

sudo nginx -T | grep -n "add_header"

Dit toont elke add_header directive in alle geincludeerde bestanden, met regelnummers in de samengevoegde output. Gebruik dit bij het debuggen van overervingsproblemen. Als een header voorkomt in het http block maar niet in een location block, en je ziet geen add_header in die location, dan wordt de header overgenomen. Als je een andere add_header in de location ziet, zijn alle headers van de parent gewist.

Gebruik nginx -T wanneer configuratiewijzigingen zich niet gedragen zoals verwacht.

Snel overzicht: het complete plaatje

/etc/nginx/nginx.conf
│
├─ main context (process-level: user, worker_processes, pid)
│
├─ events { }  (connection handling: worker_connections)
│
└─ http { }    (all HTTP config)
   │
   ├─ include conf.d/*.conf      (global HTTP settings, upstreams, maps)
   ├─ include sites-enabled/*    (virtual host configs)
   │
   └─ server { }                 (one per domain/port)
      │
      ├─ listen, server_name     (routing)
      ├─ root, index             (defaults for this host)
      │
      └─ location { }           (URI pattern matching)
         ├─ try_files, root      (per-path behavior)
         └─ proxy_pass           (reverse proxy target)

Inheritance: parent -> child (down only)
Normal directives: child overrides parent
Array directives: child REPLACES ALL parent values
Action directives: no inheritance

Copyright 2026 Virtua.Cloud. Alle rechten voorbehouden. Deze inhoud is een origineel werk van het Virtua.Cloud-team. Reproductie, herpublicatie of herdistributie zonder schriftelijke toestemming is verboden.

Klaar om het zelf te proberen?

Deploy uw eigen server in seconden. Linux, Windows of FreeBSD.

Bekijk VPS-aanbod