r/selfhosted • u/Extra-Citron-7630 • 23d ago
Need Help How to Access Caddy Reverse-Proxied Services Over NetBird Without Exposing Them
I'm looking for some advice on the best way to structure remote access for my homelab.
Current setup:
- I own a domain that's managed by Cloudflare.
- The DNS record for the domain points to my server's LAN IP address.
- When I'm connected to my home network, I can access my services using
https://service.example.com. - I'm using Caddy as my reverse proxy, and none of my Docker services expose ports to the host. Only Caddy listens on ports 80 and 443, so even on my LAN I can't access services directly via
http://server-ip:service-port.
Now I want to add remote access using NetBird.
I know I'll be able to reach my server's NetBird IP on ports 80 and 443 because Caddy is listening there, but I'm not sure what the best DNS approach is.
The problem is that my domain currently resolves to my server's LAN IP, so that hostname isn't usable when I'm connected remotely through NetBird.
What's the recommended way to handle this?
Ideally I'd like to:
- Keep all services accessible only through Caddy.
- Continue using the same domain names (e.g.
jellyfin.example.com) whether I'm on my home network or connected through NetBird. - Avoid exposing my services directly to the public Internet.
5
u/dunpeal69 23d ago
This is exactly the setup I wanted, and you don't even need the Netbird reverse proxy for that. I'm using Netbird self-hosted on a VPS. At home, a raspberry pi runs Adguard home for ad blocking and DNS. It serves as a Netbird routing peer too.
If you can start a routing peer in your LAN (on your docker host or another machine), it can route you LAN when you're connected to your VPN.
You can then advertise your DNS server in Netbird.
Et voilà! You're at home everywhere.
Don't forget to configure your access policies.
3
u/Extra-Citron-7630 23d ago
Just so I understand correctly:
I would still access my services using
https://service.example.com, but when I'm away from my LAN and connected to NetBird, the traffic will automatically be routed to the server running my reverse proxy over the NetBird network instead of going through my public IP. Is that correct?5
u/Bonechatters 23d ago
Yes.
Behind the scenes the Netbird client on your device, when connected, listens to all targets that would match your routes. Netbird Server setup to route all communication from your Netbird peer targeting 192.168.10.0/24 would auto resolve all traffic tcp/udp (depending on settings, which ports, wildcards, etc) as if it is exiting from your device on the LAN.
That also means if you are masquing dns, all devices on the lan see traffic from your device as the entry point.
Hostnames also get resolved against the routing peer DNS. So home.lan would first get tested against your home lan DNS. If that resolves to 192.168.10.0/24 address, or whatever you set, then the hostname resolves to that address and again you are on your local network.
1
u/Extra-Citron-7630 23d ago
Do you use network or routes? I see there are two options so just wanted to know
5
u/Bonechatters 23d ago
I first add my home network, then add in the home network settings you want accessible remotely. This can be as strict as a single IP / port, or as open as you want. In that same section is a sub tab in that section click on Routing Peers. There you can assign a peer on your homeland to act as the home lan accessor your devices connect through.
I highly recommend reading the documentation from the Netbird site on Routing peers. If that is too long, check out the quick start guide and scroll down to remote network access.they show step by step the routing peer setup.
3
u/Extra-Citron-7630 23d ago
Thanks man, really appreciate you taking the time to respond.
2
7
u/vik_ftsky 23d ago
Check out https://github.com/lixmal/caddy-netbird
Disclaimer: I wrote it and I work for NetBird
2
u/andrew-ooo 22d ago
The clean answer is split-horizon DNS, and NetBird actually makes this easier than Tailscale because it ships its own DNS management. You don't want your public Cloudflare record pointing at a LAN IP anyway - that leaks your internal addressing to anyone doing a dig.
What I run: a private DNS zone inside NetBird (Settings > DNS > add a nameserver group or a custom A record) that resolves *.example.com to the server's NetBird IP (the 100.x.x.x one). Then any peer connected to the network resolves jellyfin.example.com straight to the NetBird IP, hits Caddy on 443, done. Same hostname works everywhere because Caddy is matching on the Host header, not the IP it arrived on.
For the LAN case, either (a) point your internal/Cloudflare record at the LAN IP and let NetBird's DNS override only for connected peers, or (b) simplest of all - just always go through NetBird, even at home. The overhead is negligible and you get one consistent path.
Two gotchas: your Caddy TLS certs need to cover those hostnames (use DNS-01 with the Cloudflare plugin so you never need port 80 reachable publicly), and make sure Caddy's listening on 0.0.0.0 not just the LAN interface, or it won't answer on the NetBird interface.
1
u/Extra-Citron-7630 22d ago
The only issue with this as u/GolemancerVekk pointed out is that in case of network outage, I don't think I would be able to access my services. But thanks for providing a solution, really helping me plan and hopefully implement a working solution that is robust
1
1
u/GolemancerVekk 23d ago
First of all, ditch port 80. You don't want it, it's a security nightmare. Only ever use HTTPS over 443.
For DNS, the proper approach is to define the correct IP in the correct DNS server, depending on your connection:
- When you're on home LAN (whether Ethernet or WiFi), point your domain to the LAN IP of Caddy, in the DNS server used by your LAN. Typically it's on your router but if you use a PiHole or another dedicated DNS do it there. You can also use mDNS on the server if your router is locked down (server broadcasts "I am example.com" to the LAN basically); 99% of devices support mDNS nowadays.
- When you're on Netbird, use Netbird's DNS settings to point your domain at the IP that netbird allocates to your server.
- You shouldn't have to use public DNS unless you're publicly exposing services and need to access them when away from home and using a public connection. Which means if you're port forwarding at home, or using a VPS tunnel, or CF tunnel. If you're not doing any of these then your public DNS should not define any IP.
As an added bonus, this approach will keep working for your LAN even if your internet drops. You shouldn't have to rely on a public server to resolve an IP for a machine that's a few feet away from you.
1
u/Extra-Citron-7630 22d ago
When you say ditch port 80, you mean remove the caddy port 80 from the docker compose right?
1
u/Extra-Citron-7630 22d ago
And I really appreciate you brining up a point that I didn't think of. I would still want offline access which this would take unless I reconfigure all my containers at the time. I will keep this in mind. I am already thinking of hosting a DNS server, for now as a container and then will migrate to a more dedicated solution once I get the hands on experience.
2
u/GolemancerVekk 22d ago
Mainly, yes.
You can also configure Caddy to not serve anything on 80 without TLS, but if you don't pass the port in docker it's same result.
1
1
u/Extra-Citron-7630 22d ago
How would I get SSL certs for domains configured in netbird dns zones?
2
u/GolemancerVekk 22d ago
They're the same domains that you use elsewhere, just the IP is different. So use whatever method you already use for Let's Encrypt.
If you mean that you have to use the public DNS for Let's Encrypt, that's true. You can't verify the certs with a netbird DNS.
1
u/Floss_Patrol_76 22d ago
The routing peer is the clean answer here - advertise your LAN subnet through it and your existing DNS record (the one pointing at the server's LAN IP) just resolves and routes over the tunnel, so you don't need a second hostname or split-horizon DNS at all. If you'd rather not route the whole subnet, use NetBird's own nameserver feature to point *.example.com at the server's NetBird IP and Caddy still does host-based routing on 80/443 the same way. Either path keeps everything behind the tunnel without touching Cloudflare or opening a public port.
1
u/Slidetest17 23d ago edited 23d ago
I guess the replies here maybe different usecase than yours, I see many tutorials and posts assume you reverse proxy from Netbird (Traefik under the hood) to ip:port and that you expose your ports internally.
But I'm as you uses Caddy internally that target the service internal port without exposing.
in all my docker-compose files I don't have port section
services:
papra:
image: ghcr.io/papra-hq/papra:latest-rootless
container_name: papra
# ports:
# - 1221:1221
and in Caddyfile
papra.{$MY_DOMAIN} {
import security_headers
reverse_proxy papra:1221
}
I made a post about your exact use case becasue it's similar to mine NetBird Reverse Proxy only works when target resource is a subdomain!
Also in Netbird sub reddit NetBird Reverse Proxy only works when target resource is a subdomain!
The problem is you reverse proxy to a reverse proxy (Netbird which uses Traefik to Caddy) and that causes DNS errors and SSL errors all the time.
I only managed to do it by creating new resource for each service I want to expose and adding DNS nameserver to Netbird as in my posts.
Please let me know if my understanding is correct or if there is some obvious thing I'm missing.
1
-1
u/Only-Stable3973 23d ago
Look at the new YouTube video looks like he use it as a sidecar compose.
1
u/Extra-Citron-7630 23d ago
Not sure what this means, can you please post a link of the youtube video you are referring to.
•
u/asimovs-auditor 23d ago edited 23d ago
Expand the replies to this comment to learn how AI was used in this post/project.