Proteggere n8n con reverse proxy Nginx, TLS e header di sicurezza

14 min di lettura·Matthieu·webhookssecuritylets-encryptreverse-proxynginxn8n|

Posiziona la tua istanza n8n self-hosted dietro Nginx con TLS Let's Encrypt, header di sicurezza, rate limiting, regole firewall e protezione webhook. Ogni passaggio include un comando di verifica.

Questo tutorial posiziona la tua istanza n8n self-hosted dietro Nginx con TLS, header di sicurezza, rate limiting e regole firewall. Passerai da un n8n esposto sulla porta 5678 a una configurazione pronta per la produzione in cui solo il traffico HTTPS raggiunge l'editor e i webhook.

Prerequisiti:

  • n8n in esecuzione tramite Docker Compose su un VPS ()
  • Un nome di dominio (es. n8n.example.com) con un record A che punta all'IP del tuo server
  • Accesso SSH al server come utente non root con sudo
  • Porte 80 e 443 aperte nel firewall del tuo provider di hosting (Virtua Cloud le apre di default)

Questa guida presuppone Ubuntu 24.04 LTS. I comandi funzionano su Debian 12 con piccoli aggiustamenti. Si utilizza n8n versione 2.x in tutto il tutorial.

Come configuro Nginx come reverse proxy per n8n con supporto WebSocket?

Nginx si posiziona tra internet e n8n, inoltrando le richieste a localhost:5678. L'editor di n8n si basa su connessioni WebSocket per gli aggiornamenti in tempo reale. Senza un proxy WebSocket configurato correttamente, l'interfaccia dell'editor si blocca e mostra "Connection lost." Servono proxy_pass verso localhost:5678, header di upgrade HTTP/1.1 per WebSocket e la variabile d'ambiente N8N_PROXY_HOPS=1 affinché n8n legga l'IP reale del client da X-Forwarded-For.

Installare Nginx

sudo apt update && sudo apt install -y nginx

Verifica che Nginx sia in esecuzione:

sudo systemctl status nginx

Dovresti vedere active (running) in verde. In caso contrario, avvialo e abilitalo:

sudo systemctl enable --now nginx

Il flag enable --now fa due cose: enable fa partire Nginx automaticamente dopo un riavvio, e --now lo avvia immediatamente.

Creare il blocco server Nginx

Crea un nuovo file di configurazione per il tuo dominio n8n:

sudo nano /etc/nginx/sites-available/n8n.example.com

Incolla questa configurazione. Sostituisci n8n.example.com con il tuo dominio reale:

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;
    }
}

Il blocco map in cima gestisce gli upgrade WebSocket. Quando un browser invia un header Upgrade: websocket, Nginx lo lascia passare. Per le richieste HTTP normali, invia close. Questo mantiene l'editor di n8n reattivo.

proxy_buffering off e proxy_cache off impediscono a Nginx di bufferizzare i server-sent events di n8n, il che causerebbe ritardi nell'editor.

Abilita il sito e testa la configurazione:

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

Dovresti vedere:

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

Se il test passa, ricarica:

sudo systemctl reload nginx

Verifica che n8n sia raggiungibile tramite Nginx:

curl -s -o /dev/null -w "%{http_code}" http://n8n.example.com

Una risposta 200 significa che Nginx sta inoltrando il traffico a n8n. Un 502 significa che n8n non è in esecuzione sulla porta 5678. Controllalo con docker ps.

Aggiornare le variabili d'ambiente di n8n

Apri il file .env di n8n (nella stessa directory del docker-compose.yml):

nano ~/n8n-docker/.env

Aggiungi o aggiorna queste variabili:

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

Cosa fa ogni variabile:

Variabile Valore Scopo
N8N_HOST Il tuo dominio Indica a n8n quale hostname usare negli URL dei webhook
N8N_PROTOCOL https n8n genera URL webhook HTTPS invece di HTTP
N8N_PROXY_HOPS 1 n8n si fida di un livello di X-Forwarded-For per ottenere l'IP reale del client
WEBHOOK_URL URL completo Sovrascrive l'URL base dei webhook generato automaticamente
N8N_EDITOR_BASE_URL URL completo URL usato nelle notifiche email e nei redirect SAML
N8N_SECURE_COOKIE true I cookie vengono inviati solo via HTTPS. Previene il dirottamento di sessione su HTTP in chiaro

Riavvia n8n per applicare le modifiche:

cd ~/n8n-docker && docker compose down && docker compose up -d

Verifica che n8n abbia caricato le nuove variabili d'ambiente:

docker compose logs --tail=20 n8n | grep -i "editor\|webhook\|proxy"

Dovresti vedere righe di log che fanno riferimento al tuo dominio e al protocollo HTTPS.

Come aggiungo TLS Let's Encrypt al mio reverse proxy per n8n?

Certbot automatizza l'emissione dei certificati Let's Encrypt e configura automaticamente Nginx per TLS. Dopo aver eseguito Certbot, tutto il traffico HTTP viene reindirizzato su HTTPS, e l'editor di n8n e i webhook sono cifrati in transito.

Installare Certbot

sudo apt install -y certbot python3-certbot-nginx

Ottenere il certificato

sudo certbot --nginx -d n8n.example.com

Certbot farà:

  1. Verificare che sei il proprietario del dominio tramite una sfida HTTP-01
  2. Ottenere un certificato da Let's Encrypt
  3. Modificare la configurazione Nginx per aggiungere le impostazioni TLS e un redirect HTTP-a-HTTPS

Quando viene richiesto un indirizzo email, inseriscine uno reale. Riceverai lì gli avvisi di mancato rinnovo.

Verificare che TLS funzioni

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

Cerca HTTP/2 200 nella risposta. Se vedi un errore di certificato, attendi qualche minuto per la propagazione DNS.

Testa la catena di certificati dalla tua macchina locale (non dal server):

openssl s_client -connect n8n.example.com:443 -servername n8n.example.com </dev/null 2>/dev/null | head -20

Cerca Verify return code: 0 (ok).

Verificare il rinnovo automatico

Certbot installa un timer systemd che rinnova i certificati prima della scadenza. Conferma che sia attivo:

sudo systemctl status certbot.timer

Dovresti vedere active (waiting). Testa il processo di rinnovo senza rinnovare realmente:

sudo certbot renew --dry-run

Un dry run riuscito significa che i tuoi certificati si rinnoveranno automaticamente ogni 60-90 giorni.

Quali header di sicurezza servono a n8n in produzione?

Gli header di sicurezza indicano ai browser come gestire il contenuto del tuo sito. Senza di essi, il tuo editor n8n è vulnerabile a clickjacking, attacchi di MIME-type sniffing e cross-site scripting. Aggiungi sei header alla configurazione Nginx per colmare queste lacune.

Apri la configurazione Nginx modificata da Certbot:

sudo nano /etc/nginx/sites-available/n8n.example.com

All'interno del blocco server che ascolta sulla porta 443 (quello creato da Certbot), aggiungi questi header sopra il blocco location /:

    # 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;

Sostituisci n8n.example.com nella direttiva CSP connect-src con il tuo dominio reale. La voce wss:// consente le connessioni WebSocket all'editor.

Cosa fa ogni header:

Header Valore Cosa previene
Strict-Transport-Security 1 anno, sottodomini Il browser usa sempre HTTPS. Blocca attacchi di SSL stripping
X-Frame-Options DENY Nessuno può incorporare il tuo editor n8n in un iframe. Blocca il clickjacking
X-Content-Type-Options nosniff Il browser rispetta il tipo MIME dichiarato. Blocca attacchi di confusione MIME
Referrer-Policy strict-origin-when-cross-origin Limita le informazioni di referrer inviate a siti esterni
Permissions-Policy Nega fotocamera, microfono, geolocalizzazione Il browser blocca l'accesso ad API hardware non necessarie per n8n
Content-Security-Policy Vedi sopra Controlla quali script, stili e connessioni il browser consente

L'header CSP è il più complesso. L'editor di n8n usa script inline ed eval() per il costruttore di workflow, quindi 'unsafe-inline' e 'unsafe-eval' sono necessari per script-src. È un compromesso noto. Le altre direttive sono restrittive: solo risorse same-origin e connessioni WebSocket al tuo dominio.

Testa e ricarica:

sudo nginx -t && sudo systemctl reload nginx

Verifica che gli header siano presenti:

curl -sI https://n8n.example.com | grep -iE "strict-transport|x-frame|x-content|referrer|permissions|content-security"

Dovresti vedere tutti e sei gli header nell'output. Se ne manca qualcuno, controlla la presenza di errori di battitura nel file di configurazione.

Come configuro il firewall per n8n su un VPS?

UFW blocca tutto il traffico tranne ciò che consenti espressamente. Per n8n dietro Nginx, servono solo tre porte aperte: 22 (SSH), 80 (HTTP, per il rinnovo Certbot e i redirect) e 443 (HTTPS). La porta 5678, dove n8n ascolta direttamente, deve essere bloccata dall'esterno. Molte guide saltano questo passaggio, lasciando n8n accessibile senza TLS.

Per approfondire UFW, consulta .

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

Quando richiesto, digita y per confermare. Verifica le regole:

sudo ufw status verbose

Dovresti vedere tre regole ALLOW per le porte 22, 80 e 443. Nient'altro. La porta 5678 non è elencata, il che significa che è bloccata.

Conferma che n8n non è raggiungibile direttamente. Dalla tua macchina locale:

curl -s --connect-timeout 3 http://n8n.example.com:5678 || echo "Connection refused - correct!"

Se ottieni "Connection refused" o un timeout, il firewall funziona. Se ottieni una risposta da n8n, è probabile che Docker stia aggirando UFW. Docker modifica iptables direttamente e può sovrascrivere le regole UFW.

Associare n8n a localhost e impedire a Docker di aggirare UFW

La soluzione più semplice è associare n8n solo a localhost. Nel tuo docker-compose.yml, modifica il mapping delle porte:

    ports:
      - "127.0.0.1:5678:5678"

Questo assicura che n8n accetti connessioni solo dalla stessa macchina. Nginx sullo stesso server può raggiungerlo, ma il traffico esterno no.

Riavvia n8n:

cd ~/n8n-docker && docker compose down && docker compose up -d

Se questo da solo non risolve (testa di nuovo con curl dalla tua macchina locale), puoi anche disabilitare la gestione iptables di Docker. Modifica /etc/docker/daemon.json:

sudo nano /etc/docker/daemon.json

Aggiungi:

{
  "iptables": false
}

Poi riavvia Docker:

sudo systemctl restart docker
cd ~/n8n-docker && docker compose up -d

Attenzione: Impostare "iptables": false impedisce a Docker di creare regole NAT e di forwarding. Questo può interrompere la comunicazione tra container e l'accesso a internet in uscita dai container. Se i tuoi workflow n8n fanno richieste HTTP ad API esterne (la maggior parte lo fa), testa la connettività in uscita dopo questa modifica. Il binding a localhost da solo è di solito sufficiente.

Verifica nuovamente dalla tua macchina locale che la porta 5678 sia irraggiungibile.

Come limito le richieste sugli endpoint webhook di n8n in Nginx?

Il rate limiting protegge i tuoi endpoint webhook da abusi e tentativi di denial-of-service. Definisci una frequenza di richieste per indirizzo IP. Le integrazioni legittime (GitHub, Stripe) inviano webhook a una frequenza prevedibile. Un attaccante che bombarda il tuo URL webhook riceve una risposta 429 Too Many Requests invece di attivare workflow.

Per approfondire le strategie di rate limiting, consulta .

Aggiungi una direttiva limit_req_zone in cima al tuo file di configurazione Nginx, fuori da qualsiasi blocco server, accanto alla direttiva map esistente:

limit_req_zone $binary_remote_addr zone=webhooks:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=editor:10m rate=30r/s;

Questo crea due zone:

  • webhooks: 10 richieste al secondo per IP. Gestisce i callback dei servizi esterni.
  • editor: 30 richieste al secondo per IP. L'editor fa molte piccole chiamate API, quindi necessita di un limite più alto.

All'interno del blocco server in ascolto sulla 443, aggiungi un blocco location separato per i percorsi webhook prima del location / principale:

    # 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;
    }

Il parametro burst=20 consente brevi picchi fino a 20 richieste prima che il rate limiting si attivi. Questo gestisce casi come GitHub che invia più eventi webhook da un singolo push. nodelay elabora le richieste del burst immediatamente invece di metterle in coda.

Nel blocco location / principale, aggiungi il rate limit per l'editor:

    location / {
        limit_req zone=editor burst=50 nodelay;
        limit_req_status 429;

        # ... existing proxy settings ...
    }

Testa e ricarica:

sudo nginx -t && sudo systemctl reload nginx

Verifica che il rate limiting funzioni inviando una raffica di richieste a un webhook di test:

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

Dovresti vedere un mix di risposte 404 (il percorso webhook non esiste, il che è normale) e risposte 429 quando il rate limiting si attiva.

Come limito l'editor n8n a indirizzi IP specifici?

Di default, chiunque conosca il tuo URL n8n può accedere alla pagina di login. La whitelist IP a livello Nginx aggiunge un livello prima dell'autenticazione di n8n. Solo le richieste dal tuo indirizzo IP (o dalla tua VPN) raggiungono l'editor. Gli endpoint webhook restano aperti a internet per consentire ai servizi esterni di chiamarli.

Aggiungi un nuovo blocco location per i percorsi dell'editor. Posizionalo dopo le location dei webhook e prima del location / principale:

    # 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;
    }

Sostituisci 203.0.113.50 con il tuo IP reale. Trovalo con:

curl -4 ifconfig.me

Il percorso /rest/ gestisce le chiamate API dell'editor n8n. Il location / principale continua a servire il frontend dell'editor e i webhook. Per un blocco più restrittivo, puoi anche limitare il percorso root e aggiungere location aperte separate solo per /webhook/ e /webhook-test/.

Testa e ricarica:

sudo nginx -t && sudo systemctl reload nginx

Verifica dal tuo IP consentito:

curl -s -o /dev/null -w "%{http_code}" https://n8n.example.com/rest/settings

Un 200 significa che sei autorizzato. Da un IP diverso (usa un telefono non connesso al tuo Wi-Fi), accedi a https://n8n.example.com/rest/settings nel browser. Dovresti ricevere un 403 Forbidden.

Come proteggo i webhook di n8n da accessi non autorizzati?

Gli URL dei webhook sono pubblici di default. Chiunque scopra o indovini l'URL può attivare i tuoi workflow. Due strategie proteggono da questo: mantenere i percorsi webhook imprevedibili e validare le firme HMAC all'interno dei tuoi workflow.

Usare webhook di produzione con ID univoci

n8n genera due percorsi webhook per ogni nodo Webhook:

  • URL di test: /webhook-test/<id> (attivo solo quando l'editor è aperto)
  • URL di produzione: /webhook/<id> (attivo quando il workflow è attivato)

L'<id> è un UUID di default. Non cambiarlo con qualcosa di prevedibile come /webhook/github o /webhook/stripe. L'UUID casuale è il tuo primo livello di difesa.

Validare le firme HMAC nei workflow

Servizi come GitHub e Stripe firmano i payload dei webhook con un segreto condiviso. Il tuo workflow n8n dovrebbe verificare questa firma prima di elaborare i dati.

Per un webhook GitHub, aggiungi un nodo IF dopo il nodo Webhook con questa condizione:

  1. Nelle impostazioni del tuo repository GitHub, imposta un segreto per il webhook (generane uno con openssl rand -base64 32)
  2. Nel tuo workflow n8n, aggiungi un nodo Code dopo il nodo Webhook:
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();
  1. Memorizza il segreto nell'ambiente di n8n, non codificato nel workflow. Aggiungilo al tuo file .env:
GITHUB_WEBHOOK_SECRET=your-generated-secret-here

E rendilo disponibile a n8n nel docker-compose.yml:

    environment:
      - GITHUB_WEBHOOK_SECRET=${GITHUB_WEBHOOK_SECRET}

Per i webhook Stripe, il pattern è simile ma usa un header diverso (stripe-signature) e un confronto timing-safe. Consulta la documentazione sulle firme webhook di Stripe per lo schema di firma attuale.

Nascondere le informazioni sulla versione di n8n

Di default, n8n include informazioni sulla versione nelle risposte API. Disabilita la divulgazione della versione per rendere la ricognizione più difficile:

Nel tuo file .env:

N8N_VERSION_NOTIFICATIONS_ENABLED=false

Nella configurazione Nginx, aggiungi all'interno del blocco server:

    server_tokens off;

La divulgazione della versione aiuta gli attaccanti a prendere di mira vulnerabilità note in release specifiche di n8n. Nasconderla li costringe a sondare alla cieca.

Come regolo i timeout e i limiti di upload per n8n?

Alcuni workflow n8n funzionano per minuti, elaborando grandi dataset o attendendo API esterne. Il timeout predefinito di 60 secondi di Nginx interromperà queste richieste. I workflow di upload file falliscono se il payload supera il limite predefinito di 1 MB del body di Nginx.

Nel blocco location / principale del tuo server HTTPS, aggiungi o aggiorna:

    # 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 concede ai workflow fino a 5 minuti per rispondere. Regola questo valore in base al tempo di esecuzione del tuo workflow più lungo. Il blocco location dei webhook ha già le sue impostazioni di timeout dalla sezione rate limiting.

client_max_body_size 50m consente upload fino a 50 MB tramite gli endpoint webhook e dell'editor. I workflow n8n che elaborano importazioni CSV, upload di immagini o conversioni di documenti ne hanno bisogno.

Testa e ricarica:

sudo nginx -t && sudo systemctl reload nginx

Riferimento completo della configurazione Nginx

La configurazione completa dopo tutte le modifiche. Confrontala con il tuo file:

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;
    }
}

Come verifico che le connessioni WebSocket funzionino nell'editor n8n?

L'editor di n8n usa una connessione WebSocket su /rest/push per ricevere aggiornamenti in tempo reale sull'esecuzione dei workflow. Se questa connessione fallisce, vedrai banner "Connection lost" e l'editor non si aggiornerà dopo l'esecuzione dei workflow.

Apri l'editor n8n nel browser. Apri gli strumenti per sviluppatori (F12), vai alla scheda Network e filtra per "WS" (WebSocket). Dovresti vedere una connessione a wss://n8n.example.com/rest/push con stato 101 (Switching Protocols).

Dalla riga di comando, testa l'upgrade WebSocket:

curl -sI -H "Upgrade: websocket" -H "Connection: Upgrade" -H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" -H "Sec-WebSocket-Version: 13" https://n8n.example.com/rest/push

Una risposta 101 Switching Protocols conferma che il proxy WebSocket funziona. Un 200 o 400 significa che gli header di upgrade non stanno raggiungendo n8n. Torna indietro e controlla la direttiva map e gli header proxy Upgrade/Connection.

Qualcosa è andato storto?

L'editor n8n mostra "Connection lost"

Il proxy WebSocket non funziona. Controlla che:

  1. Il blocco map $http_upgrade $connection_upgrade esista in cima alla configurazione
  2. proxy_set_header Upgrade $http_upgrade e proxy_set_header Connection $connection_upgrade siano nel blocco location /
  3. proxy_http_version 1.1 sia impostato (WebSocket richiede HTTP/1.1)

Controlla i log di Nginx:

sudo journalctl -u nginx -f

"502 Bad Gateway" dopo il riavvio

Il container n8n non è in esecuzione o non è in ascolto sulla porta 5678:

docker ps | grep n8n
docker compose logs --tail=50 n8n

Il rinnovo di Certbot fallisce

Controlla che il timer sia in esecuzione e testa manualmente:

sudo systemctl status certbot.timer
sudo certbot renew --dry-run

Se il rinnovo fallisce, assicurati che la porta 80 sia aperta in UFW e che il blocco server HTTP sia ancora presente (Certbot ne ha bisogno per la sfida HTTP-01).

"403 Forbidden" dall'IP consentito

Il tuo IP potrebbe essere cambiato. Controlla il tuo IP attuale con curl -4 ifconfig.me e aggiorna la direttiva allow nella configurazione Nginx.

Rate limiting troppo aggressivo

Se i mittenti di webhook legittimi ricevono errori 429, aumenta i valori di rate e burst nelle direttive limit_req_zone e limit_req. Monitora prima la frequenza delle richieste in arrivo:

sudo tail -f /var/log/nginx/access.log | grep webhook

Prossimi passi

  • Configurare backup e aggiornamenti automatici per la tua istanza n8n ()
  • Approfondire i pattern di reverse proxy con Nginx ()
  • Esplorare la configurazione TLS in dettaglio ()
  • Tornare alla panoramica sull'automazione dei workflow (automazione workflow self-hosted)

Copyright 2026 Virtua.Cloud. Tutti i diritti riservati. Questo contenuto è un'opera originale del team Virtua.Cloud. La riproduzione, ripubblicazione o redistribuzione senza autorizzazione scritta è vietata.

Pronto a provare?

Distribuisci il tuo server in pochi secondi. Linux, Windows o FreeBSD.

Vedi piani VPS