Tips > Ops & Security

Use a Reverse Proxy With SSL Termination

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

TipIntermediate2 min read

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.


# /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";
    }
}
```text
Alternatively, Caddy provides automatic TLS with zero configuration:

```text
# Caddyfile

n8n.example.com {
    reverse_proxy localhost:5678 {
        header_up X-Forwarded-Proto {scheme}
    }
}
```text
Set the corresponding n8n environment variables so it knows it is behind a proxy:

```bash
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/
```text

**Related:** [Use Docker Compose with Health Checks for n8n and PostgreSQL](../self-hosting-operations/01-use-docker-compose-with-health-checks-for-n8n-and-postgresql.md) | [Use Path Parameters in Webhook URLs for Dynamic Routing](../webhook-mastery/01-use-path-parameters-in-webhook-urls-for-dynamic-routing.md)

Want this running in your stack?

I build production n8n and Cloudflare automation for teams — the same engineering behind HarperFlow. Fixed-price, escrow-protected, US-based.