Tips > Ops & Security

Use a Reverse Proxy With SSL Termination

n8n's built-in HTTP server does not support TLS.

n8n's built-in HTTP server does not support TLS, so running it directly sends login credentials, API keys in webhook payloads, and OAuth tokens in plaintext. Put n8n behind a reverse proxy -- Nginx or Caddy -- that terminates TLS and forwards the right headers, then set n8n's environment variables so it knows it is behind a proxy.

Why put n8n behind a reverse proxy?

n8n's built-in HTTP server does not support TLS. Running it without a reverse proxy means all traffic -- including login credentials, API keys in webhook payloads, and OAuth tokens -- travels in plaintext. Additionally, a reverse proxy provides connection limits, request buffering, and an additional layer of access control.

Real-world example: An n8n instance exposed directly on port 5678 without TLS. A network sniffer on the same subnet captures webhook payloads containing customer PII and API credentials in plaintext.

How do you configure Nginx as an SSL-terminating proxy for n8n?

# /etc/nginx/sites-available/n8n.conf

server {
    listen 80;
    server_name n8n.example.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    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;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    # Security headers

    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header X-Content-Type-Options nosniff always;
    add_header X-Frame-Options DENY always;

    # Request size limit (match N8N_PAYLOAD_SIZE_MAX)

    client_max_body_size 256m;

    # Timeouts for long-running webhook responses

    proxy_read_timeout 300s;
    proxy_send_timeout 300s;

    location / {
        proxy_pass http://127.0.0.1:5678;
        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 (required for n8n UI)

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

How do you use Caddy for automatic TLS instead?

Alternatively, Caddy provides automatic TLS with zero configuration:

# Caddyfile

n8n.example.com {
    reverse_proxy localhost:5678 {
        header_up X-Forwarded-Proto {scheme}
    }
}

What environment variables tell n8n it is behind a proxy?

Set the corresponding n8n environment variables so it knows it is behind a proxy:

N8N_HOST=n8n.example.com
N8N_PROTOCOL=https
N8N_PORT=5678
WEBHOOK_URL=https://n8n.example.com/
N8N_EDITOR_BASE_URL=https://n8n.example.com/

Related: Use Docker Compose with Health Checks for n8n and PostgreSQL · Use Path Parameters in Webhook URLs for Dynamic Routing

Showcase builds

19 complete workflows from my own projects, each with its n8n workflow JSON to import. Showcase entries link the file at the end of the article.

See the showcase builds

Keep reading

190 entries grouped by topic, from first workflow to queue mode. Free, no signup.

Browse the encyclopedia

Need it built?

I design, build and run n8n systems for clients. Every engagement starts with a $1,500 diagnostic audit, credited toward the build.

Book an introductory call