Set up HTTPS for n8n by placing it behind a reverse proxy like Nginx or Caddy that handles SSL/TLS termination. Caddy provides automatic HTTPS with Let's Encrypt certificates. Alternatively, set N8N_PROTOCOL=https with N8N_SSL_KEY and N8N_SSL_CERT environment variables for direct SSL, though a reverse proxy is the recommended production approach.
Why Set Up HTTPS for n8n
Running n8n over HTTP means all traffic between your browser and the server, including login credentials, API keys, and workflow data, is transmitted in plaintext. Anyone on the network can intercept this data. HTTPS encrypts all traffic with TLS, protecting sensitive information. HTTPS is also required for secure cookies, webhook reliability with external services, and browser security features. Most external APIs and webhook providers require HTTPS endpoints. The easiest way to add HTTPS to n8n is with a reverse proxy that handles certificate management automatically.
Prerequisites
- A self-hosted n8n instance running on a server with a public IP address
- A domain name pointed to your server (e.g., n8n.example.com)
- Ports 80 and 443 open in your firewall
- Docker and docker-compose installed (for the Docker approach)
- DNS A record configured for your domain pointing to your server IP
Step-by-step guide
Set up Caddy as a reverse proxy (easiest method)
Set up Caddy as a reverse proxy (easiest method)
Caddy is the simplest way to add HTTPS to n8n because it automatically obtains and renews Let's Encrypt SSL certificates. You only need a two-line Caddyfile. Caddy listens on ports 80 and 443, handles the ACME challenge for certificate issuance, and proxies requests to n8n running on an internal port. This is the recommended approach for most self-hosted n8n deployments.
1# Caddyfile — save this as Caddyfile in your project directory2n8n.example.com {3 reverse_proxy localhost:56784}Expected result: Caddy starts, obtains an SSL certificate from Let's Encrypt, and proxies HTTPS traffic to n8n on port 5678.
Deploy Caddy with n8n using Docker Compose
Deploy Caddy with n8n using Docker Compose
For Docker deployments, run both Caddy and n8n in the same docker-compose.yml file. Caddy handles HTTPS on ports 80 and 443 while n8n runs internally without exposing port 5678 to the public. Mount the Caddyfile and persistent volumes for certificates. Set N8N_PROTOCOL=https and WEBHOOK_URL in the n8n environment so n8n generates correct URLs for webhooks and the editor.
1# docker-compose.yml — n8n with Caddy reverse proxy2version: '3.8'34services:5 caddy:6 image: caddy:27 restart: unless-stopped8 ports:9 - '80:80'10 - '443:443'11 volumes:12 - ./Caddyfile:/etc/caddy/Caddyfile13 - caddy_data:/data14 - caddy_config:/config15 depends_on:16 - n8n1718 n8n:19 image: docker.n8n.io/n8nio/n8n20 restart: unless-stopped21 expose:22 - '5678'23 environment:24 - N8N_HOST=n8n.example.com25 - N8N_PORT=567826 - N8N_PROTOCOL=https27 - WEBHOOK_URL=https://n8n.example.com/28 - N8N_SECURE_COOKIE=true29 - GENERIC_TIMEZONE=America/New_York30 volumes:31 - n8n_data:/home/node/.n8n3233volumes:34 n8n_data:35 caddy_data:36 caddy_config:Expected result: Both containers start. Caddy automatically obtains an SSL certificate and proxies HTTPS requests to n8n. Accessing https://n8n.example.com shows the n8n editor.
Set up Nginx with Let's Encrypt (alternative)
Set up Nginx with Let's Encrypt (alternative)
If you prefer Nginx, install it alongside Certbot for Let's Encrypt certificate management. First obtain a certificate with Certbot, then configure Nginx to terminate SSL and proxy requests to n8n. This approach requires more configuration than Caddy but gives you fine-grained control over headers, caching, and rate limiting. Remember to include WebSocket upgrade headers for the n8n editor's real-time features.
1# Step 1: Install Certbot and obtain a certificate2sudo apt install certbot python3-certbot-nginx3sudo certbot certonly --nginx -d n8n.example.com45# Step 2: Nginx configuration — /etc/nginx/sites-available/n8n6server {7 listen 80;8 server_name n8n.example.com;9 return 301 https://$server_name$request_uri;10}1112server {13 listen 443 ssl http2;14 server_name n8n.example.com;1516 ssl_certificate /etc/letsencrypt/live/n8n.example.com/fullchain.pem;17 ssl_certificate_key /etc/letsencrypt/live/n8n.example.com/privkey.pem;18 ssl_protocols TLSv1.2 TLSv1.3;19 ssl_ciphers HIGH:!aNULL:!MD5;2021 location / {22 proxy_pass http://localhost:5678;23 proxy_set_header Host $host;24 proxy_set_header X-Real-IP $remote_addr;25 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;26 proxy_set_header X-Forwarded-Proto $scheme;27 proxy_http_version 1.1;28 proxy_set_header Upgrade $http_upgrade;29 proxy_set_header Connection "upgrade";30 proxy_buffering off;31 proxy_cache off;32 }33}3435# Step 3: Enable and reload36sudo ln -s /etc/nginx/sites-available/n8n /etc/nginx/sites-enabled/37sudo nginx -t38sudo systemctl reload nginxExpected result: Nginx proxies HTTPS traffic to n8n. The SSL certificate is valid and auto-renews via Certbot.
Configure n8n environment variables for HTTPS
Configure n8n environment variables for HTTPS
Regardless of which reverse proxy you use, n8n needs to know it is running behind HTTPS. Set N8N_PROTOCOL=https so n8n generates correct URLs in the editor and for webhooks. Set WEBHOOK_URL to your full HTTPS domain so webhook URLs sent to external services use HTTPS. Enable N8N_SECURE_COOKIE=true to ensure session cookies are only sent over encrypted connections.
1# Required environment variables for HTTPS2export N8N_PROTOCOL=https3export N8N_HOST=n8n.example.com4export WEBHOOK_URL=https://n8n.example.com/5export N8N_SECURE_COOKIE=true67# Optional: trust the reverse proxy headers8export N8N_PROXY_HOPS=1Expected result: n8n generates all URLs with https:// prefix. Webhook URLs copied from the editor use HTTPS. Session cookies are secure.
Set up direct SSL without a reverse proxy (alternative)
Set up direct SSL without a reverse proxy (alternative)
n8n can terminate SSL directly using N8N_SSL_KEY and N8N_SSL_CERT environment variables. Point these to your private key and certificate files. This approach is simpler but less flexible than a reverse proxy — you lose features like HTTP-to-HTTPS redirect, caching, and rate limiting. It is suitable for development or small deployments where you want to avoid running an additional service.
1# Direct SSL on n8n (no reverse proxy needed)2export N8N_PROTOCOL=https3export N8N_SSL_KEY=/path/to/privkey.pem4export N8N_SSL_CERT=/path/to/fullchain.pem5export N8N_PORT=44367n8n start89# In Docker:10# Mount the certificate files into the container11# docker run -d \12# -v /etc/letsencrypt:/etc/letsencrypt:ro \13# -e N8N_PROTOCOL=https \14# -e N8N_SSL_KEY=/etc/letsencrypt/live/n8n.example.com/privkey.pem \15# -e N8N_SSL_CERT=/etc/letsencrypt/live/n8n.example.com/fullchain.pem \16# -p 443:443 \17# docker.n8n.io/n8nio/n8nExpected result: n8n starts with SSL enabled on port 443. Accessing https://n8n.example.com:443 shows the n8n editor with a valid certificate.
Complete working example
1# docker-compose.yml — Production n8n with Caddy HTTPS2version: '3.8'34services:5 caddy:6 image: caddy:27 restart: unless-stopped8 ports:9 - '80:80'10 - '443:443'11 volumes:12 - ./Caddyfile:/etc/caddy/Caddyfile:ro13 - caddy_data:/data14 - caddy_config:/config15 depends_on:16 - n8n1718 n8n:19 image: docker.n8n.io/n8nio/n8n20 restart: unless-stopped21 expose:22 - '5678'23 environment:24 - N8N_HOST=n8n.example.com25 - N8N_PORT=567826 - N8N_PROTOCOL=https27 - N8N_EDITOR_BASE_URL=https://n8n.example.com/28 - WEBHOOK_URL=https://n8n.example.com/29 - N8N_SECURE_COOKIE=true30 - N8N_PROXY_HOPS=131 - GENERIC_TIMEZONE=America/New_York32 - N8N_LOG_LEVEL=info33 - EXECUTIONS_DATA_SAVE_ON_ERROR=all34 - EXECUTIONS_DATA_PRUNE=true35 - EXECUTIONS_DATA_MAX_AGE=16836 volumes:37 - n8n_data:/home/node/.n8n38 healthcheck:39 test: ['CMD', 'wget', '--spider', '-q', 'http://localhost:5678/healthz']40 interval: 30s41 timeout: 5s42 retries: 34344volumes:45 n8n_data:46 caddy_data:47 caddy_config:4849# Caddyfile (save as ./Caddyfile next to docker-compose.yml):50# n8n.example.com {51# reverse_proxy n8n:567852# }Common mistakes when setting up HTTPS for n8n
Why it's a problem: Forgetting to set N8N_PROTOCOL=https, causing n8n to generate HTTP webhook URLs
How to avoid: Set N8N_PROTOCOL=https and WEBHOOK_URL=https://your-domain.com/ in environment variables so n8n knows it is behind HTTPS.
Why it's a problem: Exposing port 5678 publicly alongside the reverse proxy
How to avoid: In Docker, use expose: ['5678'] instead of ports: ['5678:5678']. This makes the port accessible only to other containers, not the public internet.
Why it's a problem: Not including WebSocket headers in Nginx proxy configuration
How to avoid: Add proxy_set_header Upgrade $http_upgrade and proxy_set_header Connection 'upgrade' to your Nginx location block.
Why it's a problem: SSL certificate expires because auto-renewal is not configured
How to avoid: Caddy renews automatically. For Nginx with Certbot, verify the renewal timer with: sudo systemctl status certbot.timer.
Best practices
- Use a reverse proxy like Caddy or Nginx instead of direct SSL on n8n for production deployments
- Choose Caddy for automatic certificate management with zero configuration
- Always set N8N_PROTOCOL=https and WEBHOOK_URL with your HTTPS domain when behind a reverse proxy
- Enable N8N_SECURE_COOKIE=true to prevent session hijacking over unencrypted connections
- Do not expose n8n's port (5678) directly to the internet when using a reverse proxy — use expose instead of ports in Docker
- Set up automatic certificate renewal with Certbot or let Caddy handle it automatically
- Include WebSocket upgrade headers in Nginx configuration for the n8n editor's real-time features
- Test your SSL configuration at ssllabs.com to verify proper certificate chain and cipher selection
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I have n8n running in Docker on a VPS with a domain name. How do I set up HTTPS using Caddy as a reverse proxy with automatic Let's Encrypt certificates? Show me the docker-compose.yml and Caddyfile.
Help me configure HTTPS for my self-hosted n8n instance. I want to use Caddy for automatic SSL and make sure n8n generates HTTPS webhook URLs.
Frequently asked questions
Do I need a paid SSL certificate for n8n?
No. Let's Encrypt provides free SSL certificates that are trusted by all major browsers. Both Caddy and Certbot can obtain and renew Let's Encrypt certificates automatically.
Can I use a self-signed certificate?
Yes, but browsers will show security warnings. Self-signed certificates are acceptable for internal or development use. For production, use a trusted certificate from Let's Encrypt.
Should I use Caddy or Nginx?
Caddy is simpler because it handles HTTPS automatically with just two lines of configuration. Nginx offers more control over caching, rate limiting, and advanced proxy settings. For most n8n deployments, Caddy is the better choice.
Do webhooks require HTTPS?
Many external services require HTTPS webhook URLs. Slack, GitHub, Stripe, and most modern APIs reject HTTP webhook endpoints. Setting up HTTPS ensures compatibility with these services.
Can I use HTTPS on n8n Cloud?
Yes. n8n Cloud includes HTTPS by default with no configuration needed. Custom domains on n8n Cloud also receive automatic SSL certificates.
What ports do I need to open for HTTPS?
Open port 443 for HTTPS traffic and port 80 for the Let's Encrypt ACME challenge and HTTP-to-HTTPS redirect. Close port 5678 to the public if using a reverse proxy.
Can RapidDev help me set up a secure n8n deployment?
Yes. RapidDev can configure a production-hardened n8n deployment with HTTPS, reverse proxy, authentication, and monitoring. Contact RapidDev for a free consultation.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation