You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I'm reaching out with a challenge that's been racking my brain, but I'm convinced that if a solution exists, I'll find it here.
My goal is to securely expose several self-hosted services (like Immich, Home Assistant, etc.) using the magic of Tailscale Funnel in combination with my own custom domain, while managing everything through Nginx Proxy Manager (NPM).
I know the obvious alternative might be Cloudflare Tunnels, but I really like the Tailscale ecosystem and its simplicity, and I would love to keep my setup as "Tailscale-native" as possible.
My Environment (The Setup 🤓)
Operating System: Windows 11 with WSL2.
Virtualization: Docker Desktop.
Key Services:
immich (Docker Container)
nginx-proxy-manager (Docker Container)
Network Condition: I'm behind a CGNAT, so I cannot open ports on my router. This is precisely why I love Tailscale!
Domain: I own a custom domain, let's call it example.top, which is managed through Cloudflare as my DNS provider.
The Ideal Architecture (The Dream ✨)
What I'm trying to achieve is the following traffic flow to access my photo service:
External User → https://photos.example.top → Cloudflare DNS → Tailscale Funnel Servers → My Windows 11 PC → Nginx Proxy Manager (Docker) → Immich (Docker)
And so on for other subdomains like drive.example.top, home.example.top, etc.
What I've Tried (Step-by-Step 🛠️)
I've followed a setup that, in theory, seems perfectly logical. Here are the detailed steps:
1. Docker and Services are Up and Running
I have my NPM and Immich containers running smoothly on the same Docker network. NPM is configured to expose ports 80, 443, and 81 on my host.
Proxy Status:DNS Only (Gray Cloud). My understanding is that this is crucial for traffic to go directly to Tailscale's servers without Cloudflare's interference.
3. Nginx Proxy Manager (NPM) Configuration
Inside NPM, I've set up a Proxy Host to handle the request:
Domain Names:photos.example.top
Scheme:http
Forward Hostname / IP:host.docker.internal (so NPM can find the Immich container)
Forward Port:2283 (the Immich port)
SSL Tab: I've successfully requested a Let's Encrypt SSL certificate using the DNS Challenge with my Cloudflare API. The certificate for photos.example.top is generated and installed correctly in NPM. ✅
4. Activating Tailscale Funnel
Finally, in my Windows terminal, I've enabled the Funnel to redirect incoming traffic to port 443, where NPM is listening for HTTPS connections.
tailscale funnel --bg 80 (I've tried many things with 80)tailscale funnel --bg 443 (recently try with 443 but i am not sure, it not work or i am idiot xD)
The Problem - The Brick Wall 🧱
When I try to access https://photos.example.top from an external network, the browser returns an ERR_CONNECTION_CLOSED error almost instantly.
Key Symptom:There are absolutely no logs in Nginx Proxy Manager. No access logs, no error logs. This leads me to believe the traffic isn't even reaching my machine.
Sanity Check: If I modify my hosts file on another PC on my local network to point photos.example.top to the IP of my Docker PC, it works perfectly! This confirms that the NPM -> Immich chain and the SSL certificate within NPM are correct.
My Hypothesis 🧐
After extensive testing, my theory is that the problem lies in an SSL certificate mismatch (SSL Handshake Failure) at the Tailscale server level.
My browser initiates the connection, requesting to see the site photos.example.top.
The request arrives at the Tailscale Funnel ingress server.
The Tailscale server presents its own certificate, which is valid only for *.ts.net, not for example.top.
Since the requested domain name (SNI) doesn't match the presented certificate, the SSL handshake fails, and Tailscale abruptly closes the connection before it can forward the traffic to my NPM instance.
The Big Question for the Community 🙋♂️
Is my hypothesis correct? Is this a fundamental, current limitation of Tailscale Funnel?
Is there any "trick," hidden flag, or advanced configuration that would allow Tailscale Funnel to work with custom domains? Perhaps a way to make it "ignore" SSL termination and just pass through the raw TCP traffic?
I've noticed that tailscale serve has more options. Could there be a combination with serve that might achieve this?
Has anyone successfully built a similar architecture without resorting to an intermediary VPS or Cloudflare Tunnels?
I truly believe in Funnel's potential to simplify self-hosting for everyone, and being able to use a custom domain would be the cherry on top.
I'm grateful in advance for any ideas, clues, or even a well-explained "it can't be done, and here's why." Thanks for reading this far!
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Guyys!!
I'm reaching out with a challenge that's been racking my brain, but I'm convinced that if a solution exists, I'll find it here.
My goal is to securely expose several self-hosted services (like Immich, Home Assistant, etc.) using the magic of Tailscale Funnel in combination with my own custom domain, while managing everything through Nginx Proxy Manager (NPM).
I know the obvious alternative might be Cloudflare Tunnels, but I really like the Tailscale ecosystem and its simplicity, and I would love to keep my setup as "Tailscale-native" as possible.
My Environment (The Setup 🤓)
immich
(Docker Container)nginx-proxy-manager
(Docker Container)example.top
, which is managed through Cloudflare as my DNS provider.The Ideal Architecture (The Dream ✨)
What I'm trying to achieve is the following traffic flow to access my photo service:
External User
→https://photos.example.top
→Cloudflare DNS
→Tailscale Funnel Servers
→My Windows 11 PC
→Nginx Proxy Manager (Docker)
→Immich (Docker)
And so on for other subdomains like
drive.example.top
,home.example.top
, etc.What I've Tried (Step-by-Step 🛠️)
I've followed a setup that, in theory, seems perfectly logical. Here are the detailed steps:
1. Docker and Services are Up and Running
I have my NPM and Immich containers running smoothly on the same Docker network. NPM is configured to expose ports
80
,443
, and81
on my host.2. DNS Configuration in Cloudflare
In my Cloudflare dashboard, I've created a CNAME record for my
photos
subdomain, pointing to the unique URL provided by Tailscale Funnel.CNAME
photos
desktop-dnvumg.example.top...ts.net
(my Funnel URL)3. Nginx Proxy Manager (NPM) Configuration
Inside NPM, I've set up a Proxy Host to handle the request:
photos.example.top
http
host.docker.internal
(so NPM can find the Immich container)2283
(the Immich port)photos.example.top
is generated and installed correctly in NPM. ✅4. Activating Tailscale Funnel
Finally, in my Windows terminal, I've enabled the Funnel to redirect incoming traffic to port 443, where NPM is listening for HTTPS connections.
The Problem - The Brick Wall 🧱
When I try to access
https://photos.example.top
from an external network, the browser returns anERR_CONNECTION_CLOSED
error almost instantly.hosts
file on another PC on my local network to pointphotos.example.top
to the IP of my Docker PC, it works perfectly! This confirms that theNPM -> Immich
chain and the SSL certificate within NPM are correct.My Hypothesis 🧐
After extensive testing, my theory is that the problem lies in an SSL certificate mismatch (SSL Handshake Failure) at the Tailscale server level.
photos.example.top
.*.ts.net
, not forexample.top
.The Big Question for the Community 🙋♂️
tailscale serve
has more options. Could there be a combination withserve
that might achieve this?I truly believe in Funnel's potential to simplify self-hosting for everyone, and being able to use a custom domain would be the cherry on top.
I'm grateful in advance for any ideas, clues, or even a well-explained "it can't be done, and here's why." Thanks for reading this far!
Cheers.
Beta Was this translation helpful? Give feedback.
All reactions