Traefik + pfSense + Cloudflare: Solving Hairpinning and Internal/External Access

I host Emby for myself via Cloudflare with a .nl domain. Additionally, I have an internal domain (.me) that Cloudflare resolves for me.

The problem starts when I try to watch something via Infuse while on my home network. My pfSense router crashes, which makes sense: the connection first goes through Cloudflare and then comes back to my network, creating an unnecessary detour because it’s configured to use the .nl domain.

To prevent this, I’ve been working on setting up Host Overrides. On my PC, this seems to work well: when I check with nslookup, I see that my domain correctly resolves to my internal network. But when I test with Packet Capture, it shows that traffic is still going through Cloudflare.

On my iPhone, the Host Override doesn’t work at all. When I enter my public domain there, the connection continues to go through Cloudflare instead of to my local server.

Why do I want to solve this? In Infuse, I can only enter one IP address: my host address. If I enter both the internal and external addresses, the libraries appear duplicated. My idea was that if I only use the external domain, Infuse would automatically choose the local route when I’m at home and the Cloudflare route when I’m away.

  • External domains (.nl) work through Cloudflare (orange cloud/proxied traffic)
  • Internal domains (.me) for local use resolved by Cloudflare (no cloud)
  • Goal: Automatically redirect from .nl to .me when at home

What I found out:

  • The biggest issue: Cloudflare proxy (orange cloud) changes client IPs to Cloudflare IPs
  • ClientIP matcher in Traefik doesn’t work because all requests that are from .nl domain come with Cloudflare IPs

Hopefully you guys have some idea’s. Thanks in advance!

I am hosting Nextcloud at home. I am using NPM as my proxy, not Traefik, but I don’t think that should make a difference. I too have an external domain (.com) and an internal domain (.cc), but I am only using the external domain, internally and externally. I have set the the NPM proxy to redirect my internal docker host IP on port 80 for nextcloud.mydomain.com. In pfSense, I have set the host override to point all requests for nextcloud.mydomain.com to the IP of my Docker host. I also have all pfSense doing all DNS resolving. pfSense only goes out to remote DNS servers as a fallback if the local DNS reslover can’t handle the request. My remote DNS servers are also cloudflare (not sure if that makes a difference)

The setup seems to work flawlessly. I have never checked to see how the traffic is being routed, but the responsiveness is great.

FWIW, I just went and ran traceroute from my desktop PC to my nextcloud.mydomain.com. On my internal network, it was one hop from my PC to the server, all IPv4 addressing. If I switch to a network which doesn’t go through pfSense, it was 8 hops, all IPv6 routing (which is disabled inside my home network). So I am confident that the set up I described doesn’t route traffic out to Cloudflare from within my regular home network, despite using my “external” domain.

While the Nextcloud setup using NPM and pfSense host overrides works flawlessly, my situation is different due to the way Cloudflare’s proxy is handling my traffic. I host Emby behind Cloudflare with a .nl domain for external access and also have an internal .me domain. I want internal clients (e.g., when using Infuse) to automatically connect via the internal domain (.me) to avoid the extra routing through Cloudflare, which in turn causes my pfSense router to crash.

However, in my setup—even though my host override makes nslookup return the correct internal IP (10.10.60.1)—all requests for the .nl domain are still proxied by Cloudflare. Because of Cloudflare’s orange cloud, every request (even from inside) is terminated at Cloudflare and forwarded with Cloudflare’s IP as the source. This means that any attempt to differentiate internal from external traffic based on client IP (or headers like CF-Connecting-IP) fails.

In essence, even though I want the external domain to redirect internally to my .me domain, the Cloudflare proxy masks the true client IP, forcing all traffic (internal and external alike) to appear as if it’s coming from Cloudflare. This prevents any reliable automatic redirection based on the client’s IP.

So, unlike the Nextcloud setup where internal DNS overrides and host overrides force a direct local connection, my traffic still takes the external route due to Cloudflare’s proxy.

I need a solution where internal traffic automatically bypasses Cloudflare (or is redirected to my internal domain) while still preserving Cloudflare’s protection for external access. Unfortunately, if split DNS (or an internal DNS override) isn’t working as intended, it’s very challenging to achieve this solely via Cloudflare-proxied domains, since the original client IP is lost.

BTW, I’m running traefik on my unraid server.

Maybe someone has an idea.

You are missing the point. You don’t need two domains. pfSense, if properly configured, can route your internal requests to your .nl domain without sending it out to cloudflare. Having two domains is messing you up.

Okay I have changed the dnsresolver to my local ip with the .nl, then I get DNS_PROBE_POSSIBLE. I changed my DHCP to the right DNS. I have watched the DNS resolver video. But I cant get my head around it…
What am I missing? The 10.10.60.1 is where my traefik container is. Or should I place my pfSense IP there?

Btw I’m kindda new to networking. AI has helped me massively, but I think I don’t see the full picture

OK, let me see if I can help.

First off, my NPM proxy hosts points my docker host IP to nextcloud.mydomain.com (which is my external domain). I obtained a certificate from Cloudflare using the DNS challenge and the certificate is tied to nextcloud.mydomain.com, so internally I have to go to https://nextcloud.mydomain.com to access Nextcloud.

Second, inside of pfsense, my host over ride points nextcloud.mydomain.com at my docker host IP, where NGINX picks up the request.

Third, inside of Cloudflare, under Zero Trust/Networks, I have my public host name for the tunnel configured as nextcloud. mydomain.com pointing to the service type of HTTPS: nextcloud.mydomain.com

Finally, under the DNS entry for mydomain.com, I have one CNAME entry for Nextcloud that was created by the tunnel. It shows the proxy status as “proxied”. Please note if you change your tunnel, you have to delete the associated DNS entry for the tunnel before you can change where the tunnel points.

Ah so you didn’t even opened a port. You are just using Cloudflare tunnels. Hmm interesting… I will try that setup thank you!

Yes, correct. No ports open on my firewall, and no DNS entries in Cloudlare pointing to my public IP address. Outside traffic to nextcloud.mydomain.com is routed by cloudflare and passed into my network via the tunnel. Inside my network, traffic for nextcloud.mydomain.com is routed by pfSense directly to my NPM proxy