Nginx configureren als reverse proxy

11 min leestijd·Matthieu|

Configureer Nginx als reverse proxy voor Node.js, Ollama en andere backends. Behandelt proxy_pass, header forwarding, WebSocket-ondersteuning, upstream load balancing en productie-timeouts met verificatie bij elke stap.

Een reverse proxy staat tussen clients en je backend-applicatie. Nginx ontvangt binnenkomende verzoeken, stuurt ze door naar een backend-server (Node.js, Python, Go, Ollama) en geeft het antwoord terug aan de client. Hiermee kun je TLS-terminatie, load balancing, caching en toegangscontrole toevoegen zonder je applicatie aan te passen.

Deze tutorial behandelt Nginx reverse proxy configuratie, van een eenvoudige proxy_pass tot WebSocket proxying, upstream load balancing en een productieklare Ollama-setup.

Vereisten

Voordat je begint, heb je nodig:

Controleer of Nginx draait:

sudo systemctl status nginx

Je zou active (running) in de output moeten zien.

Hoe configureer je proxy_pass in Nginx?

De proxy_pass directive vertelt Nginx waar verzoeken naartoe gestuurd moeten worden. Plaats het in een location-blok binnen een server-blok. Nginx stuurt het verzoek van de client naar de opgegeven backend-URL en streamt het antwoord terug. De directive accepteert HTTP- en HTTPS-URL's en kan verwijzen naar een IP-adres, domeinnaam of Unix-socket.

Maak een nieuw server block-bestand aan:

sudo nano /etc/nginx/sites-available/app.conf

Voeg een minimale reverse proxy configuratie toe:

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

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Activeer de site en test de configuratie:

sudo ln -s /etc/nginx/sites-available/app.conf /etc/nginx/sites-enabled/
sudo nginx -t

Als nginx -t teruggeeft syntax is ok en test is successful, herlaad dan:

sudo systemctl reload nginx

Controleer of de proxy werkt:

curl -I http://app.example.com

De response headers moeten afkomstig zijn van je backend-applicatie. Als je een 502 Bad Gateway ziet, draait je backend niet op poort 3000.

Wat gebeurt er met een trailing slash in proxy_pass?

De trailing slash in proxy_pass bepaalt hoe URI's herschreven worden. Dit is een van de meest voorkomende configuratiefouten.

Configuratie Verzoek Doorgestuurd naar backend
proxy_pass http://127.0.0.1:3000 /app/users http://127.0.0.1:3000/app/users
proxy_pass http://127.0.0.1:3000/ /app/users http://127.0.0.1:3000/users
proxy_pass http://127.0.0.1:3000/v2/ /app/users http://127.0.0.1:3000/v2/users
proxy_pass http://127.0.0.1:3000/v2 /app/users http://127.0.0.1:3000/v2users

De regel: wanneer proxy_pass een URI bevat (alles na host:port, zelfs alleen /), verwijdert Nginx het overeenkomende location-prefix uit de verzoek-URI en voegt de rest toe aan de proxy_pass-URI. Wanneer proxy_pass geen URI heeft, wordt het oorspronkelijke pad ongewijzigd doorgestuurd.

Voor een location /app/-blok gelden bovenstaande voorbeelden. Let op de vierde rij: zonder trailing slash na /v2 wordt het pad /v2users in plaats van /v2/users. Voeg altijd een trailing slash toe wanneer je een pad specificeert.

Welke headers moet je doorsturen naar de backend?

Zonder expliciete headerconfiguratie kan je backend-applicatie het echte IP-adres van de client, het oorspronkelijke protocol of de gevraagde hostnaam niet zien. Nginx vervangt deze standaard. Stuur ze handmatig door.

Header Waarde Doel
Host $host Behoudt de originele Host-header zodat de backend weet welk domein is opgevraagd
X-Real-IP $remote_addr Geeft het IP-adres van de client door aan de backend
X-Forwarded-For $proxy_add_x_forwarded_for Voegt het client-IP toe aan de keten van proxy's
X-Forwarded-Proto $scheme Vertelt de backend of het oorspronkelijke verzoek HTTP of HTTPS gebruikte

Voeg deze headers toe aan je location-blok:

location / {
    proxy_pass http://127.0.0.1:3000;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

Na het herladen van Nginx, controleer of de headers de backend bereiken. Als je app binnenkomende headers logt, bekijk ze:

sudo systemctl reload nginx
curl -s http://app.example.com/headers

Je backend zou X-Real-IP moeten tonen met het IP van de client, niet 127.0.0.1. Als het 127.0.0.1 toont, ontbreken de proxy_set_header directives of staan ze in de verkeerde context.

Beveiligingsopmerking: gebruik $proxy_add_x_forwarded_for in plaats van $remote_addr voor X-Forwarded-For. Het voegt het client-IP toe aan een bestaande X-Forwarded-For header. Als je alleen $remote_addr instelt, verlies je de proxy-keten, wat IP-tracking achter meerdere proxy's verbreekt. Als Nginx je enige proxy is, zijn ze gelijkwaardig.

Hoe proxy je een Node.js-applicatie met een reverse proxy?

Hier is een volledig server block voor het proxyen van een Node.js-applicatie op poort 3000. Dit voorbeeld bevat header forwarding, WebSocket-ondersteuning en het verbergen van de versie.

Maak het server block aan:

sudo nano /etc/nginx/sites-available/nodeapp.conf
server {
    listen 80;
    server_name nodeapp.example.com;

    # Hide Nginx version in responses
    server_tokens off;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;

        # Header forwarding
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # WebSocket support
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        # Timeouts
        proxy_connect_timeout 60s;
        proxy_read_timeout 60s;
        proxy_send_timeout 60s;
    }
}

Activeer, test en herlaad:

sudo ln -s /etc/nginx/sites-available/nodeapp.conf /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

Controleer of de proxy werkt:

curl -I http://nodeapp.example.com

Let op: de response zou geen Server: nginx/1.x.x regel mogen bevatten. De server_tokens off directive verbergt het versienummer. Versie-informatie helpt aanvallers bekende kwetsbaarheden te targeten.

Zie Nginx SSL/TLS met Let's Encrypt voor TLS-terminatie met Let's Encrypt.

Hoe proxy je WebSocket-verbindingen met Nginx?

WebSocket-verbindingen beginnen als een HTTP-verzoek met een Upgrade header en schakelen dan over naar een persistente bidirectionele verbinding. Nginx gebruikt standaard HTTP/1.0 voor upstream-verbindingen, wat het Upgrade-mechanisme niet ondersteunt. Je hebt drie directives nodig om WebSocket te laten werken: stel proxy_http_version in op 1.1, stuur de Upgrade header door en zet de Connection header op "upgrade".

Voor locations die zowel regulier HTTP- als WebSocket-verkeer afhandelen, gebruik de map directive om de Connection header conditioneel in te stellen. Voeg dit toe aan het http-blok in /etc/nginx/nginx.conf:

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

Verwijs vervolgens naar $connection_upgrade in je server block:

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

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        # Prevent idle timeout killing WebSocket connections
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
    }
}

De standaard proxy_read_timeout is 60 seconden. Als er in dat venster geen data over de verbinding gaat, sluit Nginx deze. Stel een hogere waarde in voor WebSocket-verbindingen. Je applicatie moet WebSocket ping frames sturen met een interval korter dan deze timeout.

Test de configuratie:

sudo nginx -t && sudo systemctl reload nginx

Om WebSocket-connectiviteit te verifiëren, installeer wscat en maak verbinding:

npm install -g wscat
wscat -c ws://ws.example.com/

Als de verbinding opent, werkt WebSocket proxying. Als je unexpected server response (200) krijgt, worden de Upgrade headers niet doorgestuurd. Controleer of de map directive in het http-blok staat, niet in een server-blok.

Hoe maak je een reverse proxy voor Ollama voor self-hosted AI?

Ollama serveert LLM-inferentie standaard op poort 11434 en bindt aan 127.0.0.1. Het proxyen via Nginx laat je TLS, authenticatie en toegangscontrole toevoegen zonder de Ollama-configuratie aan te passen. Het belangrijkste verschil met standaard proxying: LLM-inferentie kan minuten duren en streaming responses vereisen dat buffering uitgeschakeld is.

Maak het server block aan:

sudo nano /etc/nginx/sites-available/ollama.conf
server {
    listen 80;
    server_name ollama.example.com;

    server_tokens off;

    # Restrict access to specific IPs
    allow 192.168.1.0/24;
    allow 10.0.0.0/8;
    deny all;

    location / {
        proxy_pass http://127.0.0.1:11434;
        proxy_http_version 1.1;

        # Header forwarding
        proxy_set_header Host localhost:11434;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Connection '';

        # Disable buffering for streaming responses
        proxy_buffering off;
        proxy_cache off;
        chunked_transfer_encoding on;

        # Extended timeouts for LLM inference
        proxy_connect_timeout 300s;
        proxy_read_timeout 600s;
        proxy_send_timeout 600s;
    }
}

Activeer en test:

sudo ln -s /etc/nginx/sites-available/ollama.conf /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

Controleer of Ollama reageert via de proxy:

curl http://ollama.example.com/api/tags

Je zou een JSON-response moeten zien met beschikbare modellen. Als je een 403 Forbidden krijgt, staat het IP van je client niet in de allow-lijst. Als je een 502 Bad Gateway krijgt, draait Ollama niet:

sudo systemctl status ollama

Test een streaming completion:

curl -N http://ollama.example.com/api/generate -d '{
  "model": "llama3.2",
  "prompt": "Hello",
  "stream": true
}'

Let op: de -N flag schakelt curl's output buffering uit. Je zou tokens een voor een moeten zien binnenkomen. Als de volledige response in een keer aankomt, is proxy_buffering off niet ingesteld of wordt het overschreven.

Waarom deze instellingen afwijken van een standaard proxy:

  • proxy_buffering off: Nginx buffert normaal backend-responses en verstuurt ze als batch. Voor LLM streaming wil je dat elke token direct naar de client wordt gestuurd.
  • proxy_read_timeout 600s: LLM-inferentie op grote modellen kan enkele minuten duren. De standaard timeout van 60s zou de verbinding halverwege de generatie verbreken.
  • proxy_set_header Host localhost:11434: Ollama controleert de Host header en weigert verzoeken die niet overeenkomen met het geconfigureerde bind-adres.
  • proxy_set_header Connection '': Wist de Connection header om keep-alive problemen met chunked streaming te voorkomen.

Zie Nginx SSL/TLS met Let's Encrypt voor TLS-terminatie om Ollama veilig via het internet beschikbaar te maken. Stel Ollama nooit bloot zonder toegangscontrole. Combineer IP-restricties met HTTP Basic Auth of API-key validatie voor productiegebruik.

Om HTTP Basic Auth toe te voegen bovenop IP-restricties:

sudo apt install apache2-utils
sudo htpasswd -c /etc/nginx/.ollama_htpasswd apiuser
sudo chmod 640 /etc/nginx/.ollama_htpasswd
sudo chown root:www-data /etc/nginx/.ollama_htpasswd

Voeg vervolgens toe aan het location-blok in ollama.conf:

    auth_basic "Ollama API";
    auth_basic_user_file /etc/nginx/.ollama_htpasswd;

Controleer of de bestandspermissies correct zijn:

ls -la /etc/nginx/.ollama_htpasswd

Het bestand moet -rw-r----- tonen met root als eigenaar en www-data als groep. Het beperken van permissies voorkomt dat andere gebruikers op de server de wachtwoordhashes kunnen lezen.

Hoe configureer je upstream load balancing?

Het upstream-blok definieert een groep backend-servers waarover Nginx verzoeken verdeelt. Standaard gebruikt Nginx gewogen round-robin. Elke server krijgt een deel van de verzoeken proportioneel aan zijn gewicht (standaardgewicht: 1).

Voeg een upstream-blok toe voor je server-blok:

upstream app_backends {
    server 127.0.0.1:3000;
    server 127.0.0.1:3001;
    server 127.0.0.1:3002;
}

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

    location / {
        proxy_pass http://app_backends;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Load balancing methoden

Round-robin (standaard): verzoeken worden gelijkmatig over servers verdeeld. Geen directive nodig.

Least connections (minste verbindingen): stuurt verzoeken naar de server met de minste actieve verbindingen. Beter voor backends met wisselende responstijden:

upstream app_backends {
    least_conn;
    server 127.0.0.1:3000;
    server 127.0.0.1:3001;
}

IP hash: koppelt elk client-IP aan een specifieke backend. Handig voor sessiepersistentie zonder sticky cookies:

upstream app_backends {
    ip_hash;
    server 127.0.0.1:3000;
    server 127.0.0.1:3001;
}

Health checks met max_fails en fail_timeout

Nginx monitort passief de gezondheid van backends. Als een server niet reageert, markeert Nginx deze als onbeschikbaar en stopt met het doorsturen van verzoeken voor een bepaalde periode.

upstream app_backends {
    server 127.0.0.1:3000 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:3001 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:3002 backup;
}
Parameter Standaard Beschrijving
max_fails 1 Aantal mislukte pogingen binnen fail_timeout voordat de server als onbeschikbaar wordt gemarkeerd
fail_timeout 10s Venster voor het tellen van fouten, en hoe lang de server onbeschikbaar blijft
backup - Server ontvangt alleen verzoeken wanneer alle primaire servers uitgevallen zijn
weight 1 Relatief aandeel van verzoeken bij round-robin

Na het configureren van upstream, test en herlaad:

sudo nginx -t && sudo systemctl reload nginx

Controleer of load balancing werkt door meerdere verzoeken te sturen en te kijken welke backend reageert:

for i in $(seq 1 6); do curl -s http://app.example.com/health; echo; done

Als je backends een identifier in hun response meegeven, zou je verzoeken verdeeld over de backends moeten zien.

Hoe stem je proxy buffering en timeouts af?

Nginx buffert standaard backend-responses. Het leest de volledige response van de backend in het geheugen (of op schijf als het de buffer overschrijdt) en stuurt het daarna naar de client. Dit is efficiënt voor de meeste applicaties, maar verkeerd voor streaming, Server-Sent Events (SSE) of long-polling.

Timeout directives

Directive Standaard Aanbevolen Doel
proxy_connect_timeout 60s 5-10s Tijd om verbinding met de backend op te bouwen. Houd kort om snel te falen.
proxy_read_timeout 60s 60-300s Tijd om op de backend-response te wachten. Verhoog voor trage API's.
proxy_send_timeout 60s 60s Tijd om de request body naar de backend te sturen. Verhoog voor grote uploads.
location / {
    proxy_pass http://127.0.0.1:3000;

    proxy_connect_timeout 10s;
    proxy_read_timeout 120s;
    proxy_send_timeout 60s;
}

Deze timeouts gelden tussen twee opeenvolgende lees-/schrijfbewerkingen, niet voor het volledige verzoek. Een response die elke 30 seconden data stuurt, triggert nooit een proxy_read_timeout van 60 seconden.

Bufferinginstellingen

Directive Standaard Beschrijving
proxy_buffering on Buffer de volledige backend-response voordat deze naar de client wordt gestuurd
proxy_buffer_size 4k of 8k Buffer voor het eerste deel van de response (headers)
proxy_buffers 8 4k of 8 8k Aantal en grootte van buffers voor de response body
proxy_busy_buffers_size 8k of 16k Maximale grootte van buffers die bezig zijn met verzenden naar de client

Wanneer moet je proxy buffering uitschakelen?

Schakel buffering uit wanneer de backend data streamt: LLM-inferentie (Ollama, vLLM), Server-Sent Events, WebSocket-achtige lange responses, of elke API die chunked data incrementeel verstuurt.

location /stream/ {
    proxy_pass http://127.0.0.1:8080;
    proxy_buffering off;
}

Houd buffering ingeschakeld voor standaard request/response API's. Buffering beschermt je backend tegen trage clients: Nginx absorbeert de response snel en stuurt het naar de client op het tempo van de client. Zonder buffering houdt een trage client een backend-verbinding open.

Zie voor geavanceerde performance-tuning.

Hoe los je 502- en 504-fouten op?

502 Bad Gateway betekent dat Nginx geen verbinding kon maken met de backend of dat de backend een ongeldig antwoord stuurde. 504 Gateway Timeout betekent dat de backend niet binnen proxy_read_timeout reageerde.

502 Bad Gateway checklist

  1. Draait de backend?
ss -tlnp | grep 3000

Als er geen output is, luistert je backend niet op poort 3000. Start deze op.

  1. Is de proxy_pass URL correct? Controleer op typfouten in het poortnummer of IP-adres. Veelgemaakte fout: https:// gebruiken voor een backend die alleen HTTP spreekt.

  2. Blokkeert SELinux de verbinding? (RHEL/CentOS)

sudo setsebool -P httpd_can_network_connect 1
  1. Controleer het Nginx error log:
sudo tail -20 /var/log/nginx/error.log

Zoek naar connect() failed (111: Connection refused) of no live upstreams.

504 Gateway Timeout checklist

  1. Verhoog proxy_read_timeout:
proxy_read_timeout 300s;
  1. Controleer of de backend traag is:
time curl http://127.0.0.1:3000/slow-endpoint

Als dit langer duurt dan je proxy_read_timeout, verhoog de timeout of optimaliseer de backend.

  1. Controleer de upstream-status: als je upstream blocks gebruikt, kunnen alle servers als gefaald zijn gemarkeerd. Controleer het error log op no live upstreams while connecting to upstream.

Nginx logs lezen

Nginx schrijft foutdetails naar /var/log/nginx/error.log. Voor real-time monitoring:

sudo journalctl -u nginx -f

Of bekijk het error log direct:

sudo tail -f /var/log/nginx/error.log

Voeg voor per-site logs de directives access_log en error_log toe aan je server block:

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

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

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

Dit scheidt logs per applicatie, waardoor het makkelijker wordt om problemen met een specifieke backend te debuggen.

Veelvoorkomende headerproblemen

Als je backend 127.0.0.1 ontvangt als client-IP in plaats van het echte adres, ontbreekt de proxy_set_header X-Real-IP $remote_addr directive. Als je applicatie HTTP-links genereert met http:// terwijl het https:// zou moeten zijn, wordt de X-Forwarded-Proto header niet doorgestuurd. Sommige frameworks (Express, Django, Rails) vereisen expliciete configuratie om proxy headers te vertrouwen. In Express:

app.set('trust proxy', 1);

In Django, stel SECURE_PROXY_SSL_HEADER in:

SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

Zonder deze instellingen negeert je applicatie de doorgestuurde headers, zelfs wanneer Nginx ze correct verstuurt.

Volledige referentie: proxy directives

Ter referentie, hier is de minimale set directives voor verschillende proxy-scenario's:

# Standard HTTP proxy
location / {
    proxy_pass http://127.0.0.1:3000;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

# WebSocket proxy
location /ws/ {
    proxy_pass http://127.0.0.1:8080;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
    proxy_read_timeout 3600s;
}

# Streaming proxy (SSE, LLM)
location /stream/ {
    proxy_pass http://127.0.0.1:11434;
    proxy_http_version 1.1;
    proxy_buffering off;
    proxy_cache off;
    proxy_read_timeout 600s;
}

Zie Nginx server blocks voor server blocks die meerdere domeinen beheren. Zie voor beveiligingshardening inclusief rate limiting en toegangscontrole.


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
Nginx als reverse proxy configureren (2026)