Enable HTTPS for n8n with Let’s Encrypt
I’ve secured multiple self-hosted n8n deployments where one missing proxy header quietly broke webhooks and login sessions days later.
Enable HTTPS for n8n with Let’s Encrypt and keep your editor, credentials, and webhooks protected with a renewal-safe setup.
What you need before you touch TLS
Lock these in first so the HTTPS rollout is clean and predictable:
- A real domain (or subdomain) you control, pointing to your server’s public IP (A/AAAA record).
- Ports 80 and 443 reachable from the public internet (security group/firewall allows inbound).
- n8n already running (Docker or systemd) on an internal port (commonly 5678).
- A reverse proxy you control (Nginx is the most common for U.S. VPS setups).
Set the n8n variables that prevent “localhost webhooks”
When n8n sits behind a reverse proxy, the editor can display or register the wrong webhook URL unless you explicitly set it. n8n’s docs recommend defining WEBHOOK_URL and setting N8N_PROXY_HOPS so forwarded headers are trusted. (n8n reverse proxy webhook configuration)
Use this baseline (adjust the domain):
Real-world pitfall: WEBHOOK_URL is often the difference between working production webhooks and “http://localhost:5678” showing up in external services. If webhooks still look wrong, re-check your domain, trailing slash, and whether you’re hitting the correct public hostname. (n8n endpoints variables)
Nginx reverse proxy config that works with n8n (including WebSockets)
n8n’s editor uses WebSockets, so your Nginx config needs Upgrade headers and consistent forwarding. This server block is a solid starting point:
Challenge you’ll actually hit: If you forget X-Forwarded-Proto or proxy hops are miscounted, you can see login/session weirdness or “connection lost”-style behavior behind certain proxy chains. Treat forwarded headers and N8N_PROXY_HOPS as a correctness requirement, not a nice-to-have. (n8n reverse proxy headers guidance)
Get a Let’s Encrypt certificate with Certbot (the renewal-safe way)
Let’s Encrypt recommends Certbot for most self-managed servers, which is the typical pattern on U.S. VPS providers. (Let’s Encrypt getting started)
On Ubuntu with Nginx, use Certbot’s Nginx plugin (it can install and wire TLS automatically):
Why this is production-friendly: Let’s Encrypt certificates are short-lived by design (default 90 days), so you want automation from day one. (Let’s Encrypt certificate lifetime FAQ)
Verify auto-renewal so you don’t lose HTTPS on a weekend
Certbot packages typically install a systemd timer or cron that renews automatically; you still want a dry-run test and a quick sanity check. (Certbot EFF renewal guidance)
Common weakness: Renewal succeeds but Nginx never reloads, so the new certificate doesn’t get served. If you see that pattern, add a deploy hook that reloads Nginx only when renewal happens (reload is usually cleaner than restart). (Let’s Encrypt community renewal hook discussion)
Harden the HTTPS edge without slowing down your instance
- Redirect HTTP to HTTPS after validation works (Certbot can do this automatically for Nginx installs).
- Keep TLS termination at the proxy and run n8n internally on plain HTTP.
- Prefer a single public hostname for editor + webhooks unless you have a strong reason to split them.
- Don’t expose 5678 publicly; keep it bound to localhost or a private network and only allow 80/443 in.
Alternative HTTPS approaches (when Nginx + Certbot isn’t your best fit)
| Approach | Best when | Strength | Real drawback |
|---|---|---|---|
| Nginx + Certbot | You want maximum control on a typical VPS | Widely supported, transparent configs | More moving parts; renewal hooks and headers can be misconfigured |
| Traefik (ACME) | You run many Docker services and want auto-routing | Automatic certificates and routing via labels | Label complexity and resolver mistakes can silently break HTTPS |
| Caddy | You want the simplest “HTTPS by default” proxy | Very fast to set up, minimal config | Less explicit than Nginx; debugging can feel opaque under pressure |
| Nginx Proxy Manager | You prefer a UI-driven proxy workflow | Easy for quick deployments | UI convenience can hide critical details (headers/websockets) if you don’t verify |
Traefik (ACME) in one sentence
Traefik’s ACME support is well-documented and can issue/renew certificates automatically, but you need disciplined label management so HTTPS routing stays correct as you add services. (Traefik ACME documentation)
Challenge you’ll face: One wrong router rule can make Traefik serve the default certificate or route to the wrong container, and you may not notice until a webhook call fails. Keep your routers minimal, name them clearly, and validate with a real external request after every change.
Caddy as a simpler TLS edge
If you want “set it and forget it” HTTPS, Caddy is a strong option for English-speaking markets because it automates certificate management with a clean config model. (Caddy official site)
Challenge you’ll face: Because it “just works,” teams sometimes skip learning the details—then struggle when they need custom headers, rate limits, or unusual proxy behavior. Keep a small checklist: WebSockets, forwarded proto, and the public base URL for n8n.
Nginx Proxy Manager (UI-based)
If you want a web UI to manage hosts and certificates, Nginx Proxy Manager can be convenient in a homelab or lightweight VPS setup. (Nginx Proxy Manager official site)
Challenge you’ll face: UI defaults don’t always match n8n’s needs (especially WebSockets and forwarded headers). After enabling SSL in the UI, still verify the headers and confirm webhooks show the correct HTTPS URL inside the editor.
Troubleshooting: the failures that waste the most time
1) Webhooks show localhost or http instead of https
- Set
WEBHOOK_URLto your public HTTPS base and restart n8n. - Set
N8N_PROXY_HOPS=1when there is one proxy in front of n8n. - Ensure Nginx sends
X-Forwarded-ProtoandX-Forwarded-Host.
These steps align with n8n’s official reverse proxy guidance. (n8n reverse proxy webhook configuration)
2) “Connection lost” in the editor after enabling HTTPS
- Confirm WebSockets are enabled (
Upgrade/Connectionheaders and HTTP/1.1). - Increase proxy read timeout if your network is slow or you use long-lived connections.
- Re-check forwarded headers and proxy hops so n8n trusts the proxy chain.
3) Certbot succeeds but HTTPS still serves the old certificate
- Run
sudo certbot renew --dry-runto confirm renewal logic. - Reload Nginx after renewal (a deploy hook can enforce this when needed).
- Verify you’re testing the correct hostname (no stale DNS / wrong subdomain).
Certbot’s renewal test is the quickest way to prove the automation path is healthy. (Certbot EFF renewal guidance)
Advanced FAQ
Should n8n run on HTTPS internally too?
No—TLS termination at the reverse proxy is the standard production pattern. Run n8n internally on HTTP and enforce HTTPS at the edge, then set n8n’s public URLs (like WEBHOOK_URL) to your external HTTPS domain.
Do you need WEBHOOK_URL if you already set N8N_HOST and N8N_PROTOCOL?
Behind a reverse proxy, WEBHOOK_URL is the reliable way to force correct production webhook URLs in the editor and when registering with external services. n8n explicitly calls this out for reverse proxy setups. (n8n reverse proxy webhook configuration)
How often should you expect certificates to renew?
Let’s Encrypt defaults to short-lived certificates (90 days), and the recommended practice is automated renewal well before expiry. If you’re doing this manually, you’re taking unnecessary risk. (Let’s Encrypt certificate lifetime FAQ)
What’s the cleanest way to handle multiple n8n instances (dev/staging/prod) in the U.S.?
Use separate subdomains (for example, n8n-dev, n8n-staging, n8n-prod), issue separate certificates, and give each instance its own WEBHOOK_URL and editor base URL so webhooks never cross-wire. This keeps integrations predictable when you connect to U.S.-based SaaS tools that cache callback URLs.
Can you split the editor and webhook domains?
Yes, but it increases the chances of mixed-host issues if you don’t set the variables carefully. If you do split them, keep WEBHOOK_URL pointed to the webhook hostname and set N8N_EDITOR_BASE_URL to the editor hostname (n8n notes editor base URL impacts emails and auth redirects). (n8n deployment variables)
What’s the #1 mistake after HTTPS is enabled?
Assuming “the lock icon” means webhooks are correct. Always create a fresh webhook node, confirm the URL is the public HTTPS domain, and trigger it from an external request before you trust the deployment.
Conclusion
Once your proxy headers, WEBHOOK_URL, and renewal path are correct, you get the best kind of security: the kind you stop thinking about. Treat HTTPS as part of your n8n reliability stack, validate it with a real webhook call, and you’ll avoid the most painful production surprises.

