🔐 SSL & Domain Setup
HTTPS không còn optional - browsers cảnh báo HTTP sites và nhiều APIs require HTTPS. Bài này shows how to secure n8n properly.
Why SSL is Critical
Without SSL:
Text
1❌ Browsers show "Not Secure" warning2❌ Credentials sent in plain text3❌ Webhooks may not work (APIs require HTTPS)4❌ No trust from users/clients5❌ SEO penalty6❌ Many integrations refuse HTTPWith SSL:
Text
1✅ Encrypted communication2✅ No browser warnings3✅ All webhooks work4✅ Professional appearance5✅ API integrations work6✅ Required for OAuth callbacksDomain Setup
DNS Configuration:
Text
1RECORD TYPE HOST VALUE2───────────────────────────────────────────3A n8n YOUR_SERVER_IP4CNAME n8n your-app.railway.app5 (for PaaS)Verify DNS:
Bash
1# Check A record2dig n8n.yourdomain.com A3 4# Check propagation5nslookup n8n.yourdomain.com6 7# Or use online tool8# https://dnschecker.orgMethod 1: Let's Encrypt + Certbot
With Nginx (Manual):
Bash
1# Install certbot2sudo apt install certbot python3-certbot-nginx3 4# Get certificate5sudo certbot --nginx -d n8n.yourdomain.com6 7# Auto-renewal is configured automatically8# Test with:9sudo certbot renew --dry-runWith Docker Nginx:
yaml
1# docker-compose.yml2services:3 nginx:4 image: nginx:alpine5 ports:6 - "80:80"7 - "443:443"8 volumes:9 - ./nginx.conf:/etc/nginx/nginx.conf:ro10 - ./certbot/conf:/etc/letsencrypt:ro11 - ./certbot/www:/var/www/certbot:ro12 depends_on:13 - n8n14 15 certbot:16 image: certbot/certbot17 volumes:18 - ./certbot/conf:/etc/letsencrypt19 - ./certbot/www:/var/www/certbotInitial Certificate Request:
Bash
1# Create directories2mkdir -p certbot/conf certbot/www3 4# Start nginx first (for challenge)5docker compose up -d nginx6 7# Request certificate8docker compose run --rm certbot certonly \9 --webroot \10 --webroot-path=/var/www/certbot \11 --email your@email.com \12 --agree-tos \13 --no-eff-email \14 -d n8n.yourdomain.com15 16# Restart nginx with SSL config17docker compose restart nginxNginx Configuration:
nginx
1# nginx.conf2 3events {4 worker_connections 1024;5}6 7http {8 # HTTP - Redirect to HTTPS9 server {10 listen 80;11 server_name n8n.yourdomain.com;12 13 # Let's Encrypt challenge14 location /.well-known/acme-challenge/ {15 root /var/www/certbot;16 }17 18 # Redirect all other traffic19 location / {20 return 301 https://$host$request_uri;21 }22 }23 24 # HTTPS25 server {26 listen 443 ssl http2;27 server_name n8n.yourdomain.com;28 29 # SSL certificates30 ssl_certificate /etc/letsencrypt/live/n8n.yourdomain.com/fullchain.pem;31 ssl_certificate_key /etc/letsencrypt/live/n8n.yourdomain.com/privkey.pem;32 33 # SSL settings34 ssl_protocols TLSv1.2 TLSv1.3;35 ssl_prefer_server_ciphers off;36 ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;37 38 # HSTS39 add_header Strict-Transport-Security "max-age=63072000" always;40 41 # Proxy to n8n42 location / {43 proxy_pass http://n8n:5678;44 proxy_http_version 1.1;45 46 # WebSocket support47 proxy_set_header Upgrade $http_upgrade;48 proxy_set_header Connection "upgrade";49 50 # Headers51 proxy_set_header Host $host;52 proxy_set_header X-Real-IP $remote_addr;53 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;54 proxy_set_header X-Forwarded-Proto $scheme;55 56 # Timeouts57 proxy_connect_timeout 300;58 proxy_send_timeout 300;59 proxy_read_timeout 300;60 61 # Buffer settings62 proxy_buffering off;63 proxy_request_buffering off;64 }65 }66}Auto-Renewal:
Bash
1# Add to crontab20 0 1,15 * * docker compose run --rm certbot renew && docker compose restart nginxMethod 2: Traefik (Automatic SSL)
docker-compose.yml:
yaml
1version: "3.8"2 3services:4 traefik:5 image: traefik:v2.106 container_name: traefik7 restart: unless-stopped8 command:9 - "--api.dashboard=false"10 - "--providers.docker=true"11 - "--providers.docker.exposedbydefault=false"12 - "--entrypoints.web.address=:80"13 - "--entrypoints.websecure.address=:443"14 - "--entrypoints.web.http.redirections.entrypoint.to=websecure"15 - "--entrypoints.web.http.redirections.entrypoint.scheme=https"16 - "--certificatesresolvers.letsencrypt.acme.httpchallenge=true"17 - "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"18 - "--certificatesresolvers.letsencrypt.acme.email=your@email.com"19 - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"20 ports:21 - "80:80"22 - "443:443"23 volumes:24 - /var/run/docker.sock:/var/run/docker.sock:ro25 - traefik_letsencrypt:/letsencrypt26 networks:27 - web28 29 n8n:30 image: n8nio/n8n31 container_name: n8n32 restart: unless-stopped33 labels:34 - "traefik.enable=true"35 - "traefik.http.routers.n8n.rule=Host(`n8n.yourdomain.com`)"36 - "traefik.http.routers.n8n.entrypoints=websecure"37 - "traefik.http.routers.n8n.tls.certresolver=letsencrypt"38 - "traefik.http.services.n8n.loadbalancer.server.port=5678"39 environment:40 - N8N_HOST=n8n.yourdomain.com41 - N8N_PROTOCOL=https42 - WEBHOOK_URL=https://n8n.yourdomain.com/43 # ... other env vars44 volumes:45 - n8n_data:/home/node/.n8n46 networks:47 - web48 - internal49 50volumes:51 traefik_letsencrypt:52 n8n_data:53 54networks:55 web:56 external: true57 internal:Create External Network:
Bash
1docker network create webMethod 3: Cloudflare (Easiest)
Setup Steps:
Text
11. Add domain to Cloudflare22. Update nameservers at registrar33. Wait for DNS propagation (up to 24h)44. Enable SSL/TLS: Full (strict)55. Add A record: n8n → your_server_ip66. Enable proxy (orange cloud)Cloudflare Settings:
Text
1SSL/TLS MODE: Full (strict)2 3Edge Certificates:4├── Always Use HTTPS: ON5├── Minimum TLS Version: 1.26├── Opportunistic Encryption: ON7└── TLS 1.3: ON8 9Origin Certificates:10└── Generate for your serverWith Cloudflare Origin Certificate:
Bash
1# 1. Generate origin certificate in Cloudflare dashboard2# 2. Download cert.pem and key.pem3# 3. Place in ./ssl/ directory4 5# nginx.conf6ssl_certificate /etc/nginx/ssl/cert.pem;7ssl_certificate_key /etc/nginx/ssl/key.pem;Cloudflare + n8n Headers:
nginx
1# Trust Cloudflare IPs2set_real_ip_from 103.21.244.0/22;3set_real_ip_from 103.22.200.0/22;4# ... add all Cloudflare IPs5real_ip_header CF-Connecting-IP;n8n Configuration for SSL
Environment Variables:
Bash
1# Required for HTTPS2N8N_HOST=n8n.yourdomain.com3N8N_PORT=56784N8N_PROTOCOL=https5 6# Critical for webhooks!7WEBHOOK_URL=https://n8n.yourdomain.com/8 9# Editor URL10N8N_EDITOR_BASE_URL=https://n8n.yourdomain.com/11 12# If behind proxy13N8N_TRUST_PROXY=trueCommon Mistake
If webhooks return wrong URL, check WEBHOOK_URL environment variable!
Testing SSL
Online Tools:
Text
1SSL Labs: https://www.ssllabs.com/ssltest/2Security Headers: https://securityheaders.comCommand Line:
Bash
1# Check certificate2openssl s_client -connect n8n.yourdomain.com:443 -servername n8n.yourdomain.com3 4# Check expiry5echo | openssl s_client -connect n8n.yourdomain.com:443 2>/dev/null | openssl x509 -noout -dates6 7# Test with curl8curl -vI https://n8n.yourdomain.comn8n Webhook Test:
Bash
1# Test webhook endpoint2curl -X POST https://n8n.yourdomain.com/webhook-test/your-webhook-path \3 -H "Content-Type: application/json" \4 -d '{"test": "data"}'Troubleshooting
Certificate Not Working:
Bash
1# Check nginx logs2docker logs n8n-nginx3 4# Common issues:5# 1. Certificate path wrong6# 2. Certificate not yet issued7# 3. DNS not propagated8# 4. Port 80/443 blockedMixed Content Warnings:
Text
1Problem: Page loads but shows warnings2Cause: Some resources loaded over HTTP3 4Fix:51. Ensure N8N_PROTOCOL=https62. Check WEBHOOK_URL starts with https://73. Clear browser cacheWebhooks Return HTTP URL:
Bash
1# Check environment2docker exec n8n env | grep -E "WEBHOOK|N8N"3 4# Ensure these are set:5WEBHOOK_URL=https://n8n.yourdomain.com/6N8N_PROTOCOL=httpsCertificate Renewal Failed:
Bash
1# Manual renewal2docker compose run --rm certbot renew --force-renewal3 4# Check certbot logs5docker compose logs certbot6 7# Verify port 80 is accessible8curl http://n8n.yourdomain.com/.well-known/acme-challenge/testSecurity Best Practices
Headers to Add:
nginx
1# Security headers2add_header X-Frame-Options "SAMEORIGIN" always;3add_header X-Content-Type-Options "nosniff" always;4add_header X-XSS-Protection "1; mode=block" always;5add_header Referrer-Policy "strict-origin-when-cross-origin" always;6add_header Content-Security-Policy "default-src 'self' https:; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';" always;Rate Limiting:
nginx
1# Add to nginx http block2limit_req_zone $binary_remote_addr zone=n8n_limit:10m rate=10r/s;3 4# In server block5location / {6 limit_req zone=n8n_limit burst=20 nodelay;7 # ... proxy config8}Bài Tập Thực Hành
SSL Challenge
Secure your n8n instance:
- Register domain or use subdomain
- Configure DNS A record
- Choose SSL method (Certbot/Traefik/Cloudflare)
- Deploy SSL configuration
- Test with SSL Labs (aim for A+)
- Verify webhooks work over HTTPS
Share your SSL Labs score! 🔒
Key Takeaways
Remember
- 🔐 HTTPS is required - Not optional in 2024
- 🌐 WEBHOOK_URL - Must match your public URL
- ♻️ Auto-renew - Certificates expire in 90 days
- 🛡️ Security headers - Add them all
- 🧪 Test regularly - SSL Labs, curl, webhooks
Tiếp Theo
Bài tiếp theo: Backup & Restore - Comprehensive backup strategies cho workflows, credentials, và database.
