Setting up n8n to run locally with SSL sounds like it should be straightforward. After all, it’s just a matter of pointing to some certificate files and changing a port, right? Well, what I thought would be a quick 10-minute task turned into an hours-long debugging session that taught me some valuable lessons about n8n’s configuration quirks.
I needed this setup specifically for Telegram bot webhooks, which have strict requirements: HTTPS only, and the webhook URL must use one of Telegram’s supported ports: 80, 88, 443, or 8443. N8n’s default port 5678 simply won’t work for Telegram webhooks, making this SSL configuration a necessity, not just a nice-to-have. The challenge was further complicated by running this in my homelab with a dynamic IP from my ISP, requiring me to use a subdomain from my hosting provider to make the service accessible from the internet.
In this post, I’ll walk you through my experience, the mistakes I made, and the eventual solution that got everything working smoothly using proper HTTPS that satisfies Telegram’s webhook requirements in a homelab environment.
The Goal: Telegram API Webhook Requirements
My objective wasn’t just about having a “nice” SSL setup—it was a hard requirement. I needed to set up a Telegram bot webhook, and Telegram’s API has specific requirements for webhook URLs:
– Must use HTTPS (not HTTP
– Must use one of the supported ports: 80, 88, 443, or 8443 (other ports won’t work)
– Must have a valid SSL certificate
– Must be accessible from the internet (no localhost URLs)
This meant n8n’s default port 5678 was completely unusable for my use case. Adding to the complexity, my server runs in my homelab with a dynamic IP issued by my ISP, so I needed to use a subdomain from my hosting provider that points to my home network.
I needed to run n8n on my local server using HTTPS with a valid domain name, accessible via:
Must be accessible from the internet (no localhost URLs)
https://example.yourdomain.net:443
or
https://example.yourdomain.net:8443
I set this up inside a Proxmox LXC container and wanted to run n8n directly with SSL enabled, no reverse proxy, no complicated routing, just clean and simple HTTPS that would satisfy Telegram’s webhook requirements while working with my dynamic IP homelab setup.
First Attempt: The Port 443 Disaster
Before diving into the SSL configuration, I had to solve the dynamic IP challenge. Since my homelab runs on a dynamic IP from my ISP, I set up a subdomain (example.yourdomain.net) through my hosting provider that points to my home network. This involved configuring dynamic DNS updates to keep the subdomain pointing to my current IP address.
With the DNS sorted, I started by obtaining an SSL certificate using certbot in manual mode via DNS challenge. After updating the TXT record and getting the certificates, I had the familiar files:
/etc/letsencrypt/live/example.yourdomain.net/fullchain.pem
/etc/letsencrypt/live/example.yourdomain.net/privkey.pem
Confident this would work, I configured my systemd service like this:
[Service]
Environment="N8N_PORT=443"
Environment="N8N_SSL_CERT=/etc/letsencrypt/live/example.yourdomain.net/fullchain.pem"
Environment="N8N_SSL_KEY=/etc/letsencrypt/live/example.yourdomain.net/privkey.pem"
ExecStart=n8n start
Everything looked perfect on paper. But when I tried to access the URL, I was greeted with frustrating SSL errors:
- Chrome:
ERR_CERT_AUTHORITY_INVALID - curl:
(35) SSL routines:ssl3_get_record:wrong version number
I spent way too much time rechecking DNS records, reissuing certificates, and even considering falling back to plain HTTP on port 80. Nothing worked.
The Eureka Moment: The Missing Protocol
After hours of troubleshooting, I discovered the real culprit. Despite providing certificates and configuring SSL, n8n wasn’t actually serving HTTPS at all. The missing piece was this single environment variable:
ini
Environment="N8N_PROTOCOL=https"
Here’s the key insight: Without explicitly setting N8N_PROTOCOL, n8n defaults to HTTP, regardless of what port or certificates you configure. The SSL certificate files were essentially being ignored.
Switching to Port 8443: Telegram-Compatible Alternative
Since I’d already spent considerable time wrestling with port 443 and wanted to avoid conflicts with other services that might need that port, I decided to use port 8443 instead. Fortunately, Telegram’s webhook API accepts both 443 and 8443, making this a perfect alternative.
Here’s my final working systemd service configuration:
ini
[Service]
Environment="N8N_PORT=8443"
Environment="N8N_PROTOCOL=https"
Environment="N8N_SSL_CERT=/etc/letsencrypt/live/example.yourdomain.net/fullchain.pem"
Environment="N8N_SSL_KEY=/etc/letsencrypt/live/example.yourdomain.net/privkey.pem"
ExecStart=n8n start
After reloading and restarting the service:
bash
sudo systemctl daemon-reload
sudo systemctl restart n8n
Finally, accessing https://example.yourdomain.net:8443 worked flawlessly. The SSL handshake succeeded, browsers were happy, and curl returned actual data instead of cryptic errors.
Key Lessons Learned
Through this experience, I learned several important things:
1. Always Set the Protocol Explicitly If you’re serving over HTTPS, you must define N8N_PROTOCOL=https. This isn’t optional or implied—it’s required.
2. Telegram Webhook Requirements Are Strict If you’re setting up Telegram bot webhooks, you must use HTTPS on one of the supported ports: 80, 88, 443, or 8443. No other ports will work, and HTTP is not accepted. This makes proper SSL configuration mandatory, not optional.
3. Homelab Dynamic IP Solutions Work Well Running webhooks from a homelab with dynamic IP is totally feasible using a subdomain from your hosting provider. The key is ensuring your dynamic DNS updates are reliable and your port forwarding is correctly configured.
4. Port 443 Requires Extra Considerations Running on port 443 may require additional steps:
- Ensuring the port is free from other services
- Dealing with potential conflicts with web servers
5. DNS-01 Challenge Works Great for Homelab The DNS-01 challenge with Certbot is particularly good for homelab setups since you don’t need to expose port 80 for validation. Just remember that certificates issued this way won’t automatically renew without proper hooks.
6. Error Messages Can Be Misleading If you see “wrong version number” errors from curl or SSL-related browser errors, suspect a protocol mismatch between what you think you’re serving and what’s actually being served.
Final Thoughts
While it’s technically possible to serve n8n on port 443 with valid SSL, using an alternative port like 8443 is often more practical, especially in development environments where you might have multiple services running.
The real lesson here is that n8n’s SSL configuration requires both the certificate files and the explicit protocol setting. Miss either one, and you’ll find yourself debugging SSL errors that don’t actually indicate SSL problems.
Hopefully, this saves someone else from spending hours debugging what turned out to be a single missing environment variable. Sometimes the simplest solutions are the ones that elude us the longest!
Have you run into similar configuration gotchas with n8n or other self-hosted tools? Share your experiences in the comments below.