n8n beveiligen met Nginx reverse proxy, TLS en beveiligingsheaders
Plaats je zelfgehoste n8n-instantie achter Nginx met Let's Encrypt TLS, beveiligingsheaders, rate limiting, firewallregels en webhookbescherming. Elke stap bevat een verificatiecommando.
Deze tutorial plaatst je zelfgehoste n8n-instantie achter Nginx met TLS, beveiligingsheaders, rate limiting en firewallregels. Je gaat van een blootgestelde n8n op poort 5678 naar een productieklare configuratie waarbij alleen HTTPS-verkeer de editor en webhooks bereikt.
Vereisten:
- n8n draaiend via Docker Compose op een VPS (n8n installeren met Docker Compose op een VPS)
- Een domeinnaam (bijv.
n8n.example.com) met een A-record dat naar het IP-adres van je server wijst - SSH-toegang tot je server als niet-rootgebruiker met
sudo - Poorten 80 en 443 open in de firewall van je hostingprovider (Virtua Cloud opent deze standaard)
Deze handleiding gaat uit van Ubuntu 24.04 LTS. De commando's werken op Debian 12 met kleine aanpassingen. Overal wordt n8n versie 2.x gebruikt.
Hoe configureer ik Nginx als reverse proxy voor n8n met WebSocket-ondersteuning?
Nginx staat tussen het internet en n8n en stuurt verzoeken door naar localhost:5678. De n8n-editor is afhankelijk van WebSocket-verbindingen voor realtime updates. Zonder correcte WebSocket-proxying bevriest de editor-UI en toont "Connection lost." Je hebt proxy_pass naar localhost:5678 nodig, HTTP/1.1 upgrade-headers voor WebSocket, en de omgevingsvariabele N8N_PROXY_HOPS=1 zodat n8n het echte client-IP uit X-Forwarded-For leest.
Nginx installeren
sudo apt update && sudo apt install -y nginx
Controleer of Nginx draait:
sudo systemctl status nginx
Je zou active (running) in het groen moeten zien. Zo niet, start en activeer het:
sudo systemctl enable --now nginx
De enable --now-vlag doet twee dingen: enable zorgt dat Nginx automatisch start na een herstart, en --now start het meteen.
Het Nginx-serverblok aanmaken
Maak een nieuw configuratiebestand aan voor je n8n-domein:
sudo nano /etc/nginx/sites-available/n8n.example.com
Plak deze configuratie. Vervang n8n.example.com door je eigen domein:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
listen [::]:80;
server_name n8n.example.com;
# Will be replaced by Certbot later
location / {
proxy_pass http://127.0.0.1:5678;
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;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_cache off;
chunked_transfer_encoding off;
}
}
Het map-blok bovenaan regelt WebSocket-upgrades. Wanneer een browser een Upgrade: websocket-header stuurt, laat Nginx deze door. Voor gewone HTTP-verzoeken stuurt het close. Dit houdt de n8n-editor responsief.
proxy_buffering off en proxy_cache off voorkomen dat Nginx de server-sent events van n8n buffert, wat vertraging in de editor zou veroorzaken.
Activeer de site en test de configuratie:
sudo ln -s /etc/nginx/sites-available/n8n.example.com /etc/nginx/sites-enabled/
sudo nginx -t
Je zou het volgende moeten zien:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
Als de test slaagt, herlaad:
sudo systemctl reload nginx
Controleer of n8n bereikbaar is via Nginx:
curl -s -o /dev/null -w "%{http_code}" http://n8n.example.com
Een 200-respons betekent dat Nginx verkeer doorstuurt naar n8n. Een 502 betekent dat n8n niet draait op poort 5678. Controleer het met docker ps.
n8n-omgevingsvariabelen bijwerken
Open je n8n .env-bestand (in dezelfde map als je docker-compose.yml):
nano ~/n8n-docker/.env
Voeg deze variabelen toe of werk ze bij:
N8N_HOST=n8n.example.com
N8N_PROTOCOL=https
N8N_PROXY_HOPS=1
WEBHOOK_URL=https://n8n.example.com/
N8N_EDITOR_BASE_URL=https://n8n.example.com/
N8N_SECURE_COOKIE=true
Wat elke variabele doet:
| Variabele | Waarde | Doel |
|---|---|---|
N8N_HOST |
Je domein | Vertelt n8n welke hostnaam te gebruiken in webhook-URL's |
N8N_PROTOCOL |
https |
n8n genereert HTTPS webhook-URL's in plaats van HTTP |
N8N_PROXY_HOPS |
1 |
n8n vertrouwt één laag van X-Forwarded-For voor het echte client-IP |
WEBHOOK_URL |
Volledige URL | Overschrijft de automatisch gegenereerde webhook-basis-URL |
N8N_EDITOR_BASE_URL |
Volledige URL | URL gebruikt in e-mailnotificaties en SAML-redirects |
N8N_SECURE_COOKIE |
true |
Cookies worden alleen via HTTPS verstuurd. Voorkomt sessiekaping via onversleuteld HTTP |
Herstart n8n om de wijzigingen toe te passen:
cd ~/n8n-docker && docker compose down && docker compose up -d
Controleer of n8n de nieuwe omgevingsvariabelen heeft geladen:
docker compose logs --tail=20 n8n | grep -i "editor\|webhook\|proxy"
Je zou logregels moeten zien die verwijzen naar je domein en het HTTPS-protocol.
Hoe voeg ik Let's Encrypt TLS toe aan mijn n8n reverse proxy?
Certbot automatiseert de uitgifte van Let's Encrypt-certificaten en configureert Nginx automatisch voor TLS. Na het uitvoeren van Certbot wordt al het HTTP-verkeer omgeleid naar HTTPS, en zijn je n8n-editor en webhooks versleuteld tijdens transport.
Certbot installeren
sudo apt install -y certbot python3-certbot-nginx
Het certificaat verkrijgen
sudo certbot --nginx -d n8n.example.com
Certbot zal:
- Verifiëren dat je eigenaar bent van het domein via een HTTP-01-challenge
- Een certificaat verkrijgen van Let's Encrypt
- Je Nginx-configuratie aanpassen met TLS-instellingen en een HTTP-naar-HTTPS-redirect
Wanneer er om een e-mailadres wordt gevraagd, voer een echt adres in. Je ontvangt daar waarschuwingen bij mislukte verlengingen.
Controleren of TLS werkt
curl -I https://n8n.example.com
Zoek naar HTTP/2 200 in de respons. Als je een certificaatfout ziet, wacht dan een paar minuten voor DNS-propagatie.
Test de certificaatketen vanaf je lokale machine (niet de server):
openssl s_client -connect n8n.example.com:443 -servername n8n.example.com </dev/null 2>/dev/null | head -20
Zoek naar Verify return code: 0 (ok).
Automatische verlenging verifiëren
Certbot installeert een systemd-timer die certificaten verlengt voordat ze verlopen. Bevestig dat deze actief is:
sudo systemctl status certbot.timer
Je zou active (waiting) moeten zien. Test het verlengingsproces zonder daadwerkelijk te verlengen:
sudo certbot renew --dry-run
Een geslaagde dry run betekent dat je certificaten automatisch elke 60-90 dagen worden verlengd.
Welke beveiligingsheaders heeft n8n nodig in productie?
Beveiligingsheaders vertellen browsers hoe ze de inhoud van je site moeten behandelen. Zonder deze headers is je n8n-editor kwetsbaar voor clickjacking, MIME-type sniffing-aanvallen en cross-site scripting. Voeg zes headers toe aan je Nginx-configuratie om deze gaten te dichten.
Open de Nginx-configuratie die Certbot heeft aangepast:
sudo nano /etc/nginx/sites-available/n8n.example.com
Voeg binnen het server-blok dat luistert op poort 443 (het blok dat Certbot heeft aangemaakt) deze headers toe boven het location /-blok:
# Security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' wss://n8n.example.com; frame-ancestors 'none'" always;
Vervang n8n.example.com in de CSP connect-src-directive door je eigen domein. De wss://-vermelding staat WebSocket-verbindingen naar de editor toe.
Wat elke header doet:
| Header | Waarde | Wat het voorkomt |
|---|---|---|
Strict-Transport-Security |
1 jaar, subdomeinen | Browser gebruikt altijd HTTPS. Stopt SSL stripping-aanvallen |
X-Frame-Options |
DENY | Niemand kan je n8n-editor in een iframe plaatsen. Stopt clickjacking |
X-Content-Type-Options |
nosniff | Browser vertrouwt het opgegeven MIME-type. Stopt MIME-verwarringsaanvallen |
Referrer-Policy |
strict-origin-when-cross-origin | Beperkt referrer-informatie die naar externe sites lekt |
Permissions-Policy |
Weiger camera, microfoon, geo | Browser blokkeert toegang tot hardware-API's die n8n niet nodig heeft |
Content-Security-Policy |
Zie boven | Bepaalt welke scripts, stijlen en verbindingen de browser toestaat |
De CSP-header is het meest complex. De n8n-editor gebruikt inline scripts en eval() voor de workflowbouwer, dus 'unsafe-inline' en 'unsafe-eval' zijn vereist voor script-src. Dit is een bekend compromis. De overige directives zijn restrictief: alleen same-origin bronnen en WebSocket-verbindingen naar je domein.
Test en herlaad:
sudo nginx -t && sudo systemctl reload nginx
Controleer of de headers aanwezig zijn:
curl -sI https://n8n.example.com | grep -iE "strict-transport|x-frame|x-content|referrer|permissions|content-security"
Je zou alle zes headers in de output moeten zien. Als er een ontbreekt, controleer op typefouten in het configuratiebestand.
Hoe configureer ik de firewall voor n8n op een VPS?
UFW blokkeert al het verkeer behalve wat je expliciet toestaat. Voor n8n achter Nginx hoeven maar drie poorten open te zijn: 22 (SSH), 80 (HTTP, voor Certbot-verlenging en redirects) en 443 (HTTPS). Poort 5678, waar n8n rechtstreeks op luistert, moet van buitenaf geblokkeerd zijn. Veel handleidingen slaan deze stap over, waardoor n8n zonder TLS bereikbaar blijft.
Voor meer informatie over UFW, zie [-> linux-firewall-ufw-nftables-vps].
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp comment 'SSH'
sudo ufw allow 80/tcp comment 'HTTP - Certbot renewal'
sudo ufw allow 443/tcp comment 'HTTPS - n8n via Nginx'
sudo ufw enable
Typ y wanneer om bevestiging wordt gevraagd. Controleer de regels:
sudo ufw status verbose
Je zou drie ALLOW-regels moeten zien voor poorten 22, 80 en 443. Verder niets. Poort 5678 staat niet in de lijst, wat betekent dat deze geblokkeerd is.
Bevestig dat n8n niet direct bereikbaar is. Vanaf je lokale machine:
curl -s --connect-timeout 3 http://n8n.example.com:5678 || echo "Connection refused - correct!"
Als je "Connection refused" of een timeout krijgt, werkt de firewall. Als je een n8n-respons krijgt, omzeilt Docker waarschijnlijk UFW. Docker wijzigt iptables rechtstreeks en kan UFW-regels overschrijven.
n8n binden aan localhost en voorkomen dat Docker UFW omzeilt
De eenvoudigste oplossing is n8n alleen aan localhost binden. Wijzig in je docker-compose.yml de poortmapping:
ports:
- "127.0.0.1:5678:5678"
Dit zorgt ervoor dat n8n alleen verbindingen van dezelfde machine accepteert. Nginx op dezelfde server kan het bereiken, maar extern verkeer niet.
Herstart n8n:
cd ~/n8n-docker && docker compose down && docker compose up -d
Als dit alleen niet voldoende is (test opnieuw met curl vanaf je lokale machine), kun je ook het iptables-beheer van Docker uitschakelen. Bewerk /etc/docker/daemon.json:
sudo nano /etc/docker/daemon.json
Voeg toe:
{
"iptables": false
}
Herstart vervolgens Docker:
sudo systemctl restart docker
cd ~/n8n-docker && docker compose up -d
Waarschuwing: Het instellen van "iptables": false voorkomt dat Docker NAT- en forwardingregels aanmaakt. Dit kan de communicatie tussen containers en uitgaande internettoegang vanuit containers verbreken. Als je n8n-workflows HTTP-verzoeken naar externe API's doen (de meeste doen dat), test dan de uitgaande connectiviteit na deze wijziging. De localhost-binding alleen is meestal voldoende.
Controleer opnieuw vanaf je lokale machine dat poort 5678 niet bereikbaar is.
Hoe beperk ik het aantal verzoeken op n8n webhook-endpoints in Nginx?
Rate limiting beschermt je webhook-endpoints tegen misbruik en denial-of-service-pogingen. Je definieert een verzoeksnelheid per IP-adres. Legitieme integraties (GitHub, Stripe) sturen webhooks met een voorspelbaar tempo. Een aanvaller die je webhook-URL bombardeert krijgt een 429 Too Many Requests-respons in plaats van workflows te activeren.
Voor meer over rate limiting-strategieën, zie Nginx Rate Limiting en DDoS-bescherming.
Voeg een limit_req_zone-directive toe bovenaan je Nginx-configuratiebestand, buiten elk server-blok, naast de bestaande map-directive:
limit_req_zone $binary_remote_addr zone=webhooks:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=editor:10m rate=30r/s;
Dit maakt twee zones aan:
webhooks: 10 verzoeken per seconde per IP. Verwerkt callbacks van externe diensten.editor: 30 verzoeken per seconde per IP. De editor maakt veel kleine API-aanroepen en heeft daarom een hogere limiet nodig.
Voeg binnen het server-blok dat op 443 luistert een apart location-blok toe voor webhookpaden vóór het hoofd-location /:
# Rate limit webhook endpoints
location /webhook/ {
limit_req zone=webhooks burst=20 nodelay;
limit_req_status 429;
proxy_pass http://127.0.0.1:5678;
proxy_http_version 1.1;
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;
# Generous timeout for long-running webhook workflows
proxy_read_timeout 300s;
proxy_send_timeout 300s;
}
location /webhook-test/ {
limit_req zone=webhooks burst=5 nodelay;
limit_req_status 429;
proxy_pass http://127.0.0.1:5678;
proxy_http_version 1.1;
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;
}
De parameter burst=20 staat korte pieken tot 20 verzoeken toe voordat rate limiting actief wordt. Dit vangt gevallen op zoals GitHub die meerdere webhook-events stuurt vanuit een enkele push. nodelay verwerkt burst-verzoeken direct in plaats van ze in de wachtrij te plaatsen.
Voeg in het hoofd-location /-blok de rate limit voor de editor toe:
location / {
limit_req zone=editor burst=50 nodelay;
limit_req_status 429;
# ... existing proxy settings ...
}
Test en herlaad:
sudo nginx -t && sudo systemctl reload nginx
Controleer of rate limiting werkt door een reeks verzoeken naar een testwebhook te sturen:
for i in $(seq 1 30); do
curl -s -o /dev/null -w "%{http_code} " https://n8n.example.com/webhook/test-rate-limit
done
echo
Je zou een mix van 404-responsen (het webhookpad bestaat niet, wat normaal is) en 429-responsen moeten zien zodra de rate limit actief wordt.
Hoe beperk ik de n8n-editor tot specifieke IP-adressen?
Standaard kan iedereen die je n8n-URL kent de inlogpagina bereiken. IP-whitelisting op Nginx-niveau voegt een laag toe vóór n8n's eigen authenticatie. Alleen verzoeken vanaf jouw IP-adres (of je VPN) bereiken de editor. Webhook-endpoints blijven open voor het internet zodat externe diensten ze kunnen aanroepen.
Voeg een nieuw location-blok toe voor de editorpaden. Plaats het na de webhooklocaties en vóór het hoofd-location /:
# Restrict editor/API access to specific IPs
location /rest/ {
allow 203.0.113.50; # Your office/home IP
allow 10.0.0.0/8; # Your VPN range
deny all;
limit_req zone=editor burst=50 nodelay;
proxy_pass http://127.0.0.1:5678;
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;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
}
Vervang 203.0.113.50 door je eigen IP. Vind het met:
curl -4 ifconfig.me
Het /rest/-pad verwerkt de API-aanroepen van de n8n-editor. Het hoofd-location / bedient nog steeds de editor-frontend en webhooks. Voor een strengere afscherming kun je ook het rootpad beperken en aparte open locaties toevoegen voor alleen /webhook/ en /webhook-test/.
Test en herlaad:
sudo nginx -t && sudo systemctl reload nginx
Controleer vanaf je toegestane IP:
curl -s -o /dev/null -w "%{http_code}" https://n8n.example.com/rest/settings
Een 200 betekent dat je toegang hebt. Vanaf een ander IP (gebruik een telefoon die niet op je wifi zit), open https://n8n.example.com/rest/settings in een browser. Je zou een 403 Forbidden moeten krijgen.
Hoe beveilig ik n8n-webhooks tegen ongeautoriseerde toegang?
Webhook-URL's zijn standaard openbaar. Iedereen die de URL ontdekt of raadt kan je workflows activeren. Twee strategieën beschermen hiertegen: webhookpaden onvoorspelbaar houden en HMAC-handtekeningen valideren binnen je workflows.
Productiewebhooks met unieke ID's gebruiken
n8n genereert twee webhookpaden voor elk Webhook-node:
- Test-URL:
/webhook-test/<id>(alleen actief als de editor open is) - Productie-URL:
/webhook/<id>(actief wanneer de workflow is geactiveerd)
De <id> is standaard een UUID. Verander deze niet in iets raadbaars zoals /webhook/github of /webhook/stripe. De willekeurige UUID is je eerste verdedigingslinie.
HMAC-handtekeningen valideren in workflows
Diensten als GitHub en Stripe ondertekenen hun webhookpayloads met een gedeeld geheim. Je n8n-workflow moet deze handtekening verifiëren voordat de data wordt verwerkt.
Voor een GitHub-webhook, voeg een IF-node toe na het Webhook-node met deze voorwaarde:
- Stel in de instellingen van je GitHub-repository een webhookgeheim in (genereer er een met
openssl rand -base64 32) - Voeg in je n8n-workflow een Code-node toe na het Webhook-node:
const crypto = require('crypto');
const secret = $env.GITHUB_WEBHOOK_SECRET;
const signature = $input.first().headers['x-hub-signature-256'];
const body = JSON.stringify($input.first().json);
const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(body).digest('hex');
if (signature !== expected) {
throw new Error('Invalid webhook signature');
}
return $input.all();
- Sla het geheim op in de n8n-omgeving, niet hardgecodeerd in de workflow. Voeg het toe aan je
.env-bestand:
GITHUB_WEBHOOK_SECRET=your-generated-secret-here
En stel het beschikbaar voor n8n in docker-compose.yml:
environment:
- GITHUB_WEBHOOK_SECRET=${GITHUB_WEBHOOK_SECRET}
Voor Stripe-webhooks is het patroon vergelijkbaar maar met een andere header (stripe-signature) en een timing-safe vergelijking. Raadpleeg de Stripe webhook-handtekeningendocumentatie voor het huidige ondertekeningsschema.
n8n-versie-informatie verbergen
Standaard bevat n8n versie-informatie in API-responsen. Schakel versie-openbaarmaking uit om verkenning moeilijker te maken:
In je .env-bestand:
N8N_VERSION_NOTIFICATIONS_ENABLED=false
Voeg in je Nginx-configuratie binnen het server-blok toe:
server_tokens off;
Versie-openbaarmaking helpt aanvallers om bekende kwetsbaarheden in specifieke n8n-releases te targeten. Het verbergen ervan dwingt ze om blind te scannen.
Hoe stel ik timeouts en uploadlimieten in voor n8n?
Sommige n8n-workflows draaien minutenlang en verwerken grote datasets of wachten op externe API's. De standaard timeout van 60 seconden van Nginx zal deze verzoeken afbreken. Workflows voor bestandsuploads falen als de payload de standaard body-limiet van 1 MB van Nginx overschrijdt.
Voeg in het hoofd-location /-blok van je HTTPS-server het volgende toe of werk het bij:
# Timeout tuning for long-running workflows
proxy_connect_timeout 60s;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
# Allow file uploads up to 50 MB
client_max_body_size 50m;
proxy_read_timeout 300s geeft workflows tot 5 minuten om te reageren. Pas dit aan op basis van de uitvoeringstijd van je langstlopende workflow. Het webhook-location-blok heeft al eigen timeout-instellingen uit de rate limiting-sectie.
client_max_body_size 50m staat bestandsuploads tot 50 MB toe via webhook- en editor-endpoints. n8n-workflows die CSV-imports, afbeeldingsuploads of documentconversies verwerken hebben dit nodig.
Test en herlaad:
sudo nginx -t && sudo systemctl reload nginx
Volledige Nginx-configuratiereferentie
De volledige configuratie na alle wijzigingen. Vergelijk het met je bestand:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
limit_req_zone $binary_remote_addr zone=webhooks:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=editor:10m rate=30r/s;
server {
listen 80;
listen [::]:80;
server_name n8n.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name n8n.example.com;
ssl_certificate /etc/letsencrypt/live/n8n.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/n8n.example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
server_tokens off;
# Security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' wss://n8n.example.com; frame-ancestors 'none'" always;
client_max_body_size 50m;
# Rate limit webhook endpoints
location /webhook/ {
limit_req zone=webhooks burst=20 nodelay;
limit_req_status 429;
proxy_pass http://127.0.0.1:5678;
proxy_http_version 1.1;
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;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
}
location /webhook-test/ {
limit_req zone=webhooks burst=5 nodelay;
limit_req_status 429;
proxy_pass http://127.0.0.1:5678;
proxy_http_version 1.1;
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;
}
# Restrict editor API to specific IPs
location /rest/ {
allow 203.0.113.50;
allow 10.0.0.0/8;
deny all;
limit_req zone=editor burst=50 nodelay;
proxy_pass http://127.0.0.1:5678;
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;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
}
# Main location - editor frontend and fallback
location / {
limit_req zone=editor burst=50 nodelay;
limit_req_status 429;
proxy_pass http://127.0.0.1:5678;
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;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_cache off;
chunked_transfer_encoding off;
proxy_connect_timeout 60s;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
}
}
Hoe controleer ik of WebSocket-verbindingen werken in de n8n-editor?
De n8n-editor gebruikt een WebSocket-verbinding op /rest/push om realtime updates over workflowuitvoering te ontvangen. Als deze verbinding mislukt, zie je "Connection lost"-banners en wordt de editor niet bijgewerkt na workflowuitvoeringen.
Open de n8n-editor in je browser. Open de ontwikkelaarstools (F12), ga naar het tabblad Network en filter op "WS" (WebSocket). Je zou een verbinding naar wss://n8n.example.com/rest/push moeten zien met status 101 (Switching Protocols).
Vanaf de opdrachtregel, test de WebSocket-upgrade:
curl -sI -H "Upgrade: websocket" -H "Connection: Upgrade" -H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" -H "Sec-WebSocket-Version: 13" https://n8n.example.com/rest/push
Een 101 Switching Protocols-respons bevestigt dat WebSocket-proxying werkt. Een 200 of 400 betekent dat de upgrade-headers n8n niet bereiken. Ga terug en controleer de map-directive en de Upgrade/Connection proxy-headers.
Gaat er iets mis?
n8n-editor toont "Connection lost"
WebSocket-proxying werkt niet. Controleer dat:
- Het
map $http_upgrade $connection_upgrade-blok bovenaan de configuratie bestaat proxy_set_header Upgrade $http_upgradeenproxy_set_header Connection $connection_upgradein hetlocation /-blok staanproxy_http_version 1.1is ingesteld (WebSocket vereist HTTP/1.1)
Controleer de Nginx-logs:
sudo journalctl -u nginx -f
"502 Bad Gateway" na herstart
De n8n-container draait niet of luistert niet op poort 5678:
docker ps | grep n8n
docker compose logs --tail=50 n8n
Certbot-verlenging mislukt
Controleer of de timer draait en test handmatig:
sudo systemctl status certbot.timer
sudo certbot renew --dry-run
Als de verlenging mislukt, controleer of poort 80 open is in UFW en of het HTTP-serverblok nog aanwezig is (Certbot heeft het nodig voor de HTTP-01-challenge).
"403 Forbidden" vanaf toegestaan IP
Je IP is mogelijk veranderd. Controleer je huidige IP met curl -4 ifconfig.me en werk de allow-directive in de Nginx-configuratie bij.
Rate limiting te agressief
Als legitieme webhookverzenders 429-fouten krijgen, verhoog de rate- en burst-waarden in je limit_req_zone- en limit_req-directives. Monitor eerst het tempo van inkomende verzoeken:
sudo tail -f /var/log/nginx/access.log | grep webhook
Volgende stappen
- Automatische back-ups en updates instellen voor je n8n-instantie (n8n in productie back-uppen en updaten (Docker Compose + PostgreSQL))
- Meer leren over Nginx reverse proxy-patronen (Nginx configureren als reverse proxy)
- TLS-configuratie uitgebreider verkennen (Let's Encrypt SSL/TLS instellen voor Nginx op Debian 12 en Ubuntu 24.04)
- Terug naar het overzicht workflowautomatisering (Workflow-automatisering zelf hosten op een VPS met n8n)
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