[GH-ISSUE #5895] Internal Reverse Proxy #11880

Open
opened 2026-08-05 01:31:26 -04:00 by saavagebueno · 18 comments
Owner

Originally created by @ITCMD on GitHub (Apr 15, 2026).
Original GitHub issue: https://github.com/netbirdio/netbird/issues/5895

Is your feature request related to a problem? Please describe.
We've got numerous devices and services at customer locations we'd love to access via a direct dns query. IE device 192.168.1.40 on network b. We'd love to create a dns zone device.customerxyz.com and have it forward to that device, including port options. We can do this on the public internet using the reverse proxy setup, but we're using nginx and do not have any proxy clusters setup. However, that should not be needed if we want to only expose it internally. We can expose devices as resources, but this is only IP so it doesn't help with non-standard ports and does not work if the IPs conflict with another resource.

Describe the solution you'd like
Add an internal reverse proxy where you could setup something like:

  • doman: printer.greenstreet.company.com
  • Device: 192.168.1.21 port 8080
  • Via peer: (select a peer or peer group)

Then when I visit printer.greenstreet.company.com while connected to netbird, it routes with a valid https and without needing to enter in port 8080. It would need to have its own generated IP on the netbird network or a similar one for the DNS to work, I am guessing.

Describe alternatives you've considered
I have considered using the existing remote proxy service, but I do not want to setup proxy clusters as there is nothing we would want to expose to the public internet. We've also considered just exposing the service, but then we still have to manually type in the port and manage ip conflicts.

Originally created by @ITCMD on GitHub (Apr 15, 2026). Original GitHub issue: https://github.com/netbirdio/netbird/issues/5895 **Is your feature request related to a problem? Please describe.** We've got numerous devices and services at customer locations we'd love to access via a direct dns query. IE device 192.168.1.40 on network b. We'd love to create a dns zone device.customerxyz.com and have it forward to that device, including port options. We can do this on the public internet using the reverse proxy setup, but we're using nginx and do not have any proxy clusters setup. However, that should not be needed if we want to only expose it internally. We can expose devices as resources, but this is only IP so it doesn't help with non-standard ports and does not work if the IPs conflict with another resource. **Describe the solution you'd like** Add an internal reverse proxy where you could setup something like: - doman: printer.greenstreet.company.com - Device: 192.168.1.21 port 8080 - Via peer: (select a peer or peer group) Then when I visit printer.greenstreet.company.com while connected to netbird, it routes with a valid https and without needing to enter in port 8080. It would need to have its own generated IP on the netbird network or a similar one for the DNS to work, I am guessing. **Describe alternatives you've considered** I have considered using the existing remote proxy service, but I do not want to setup proxy clusters as there is nothing we would want to expose to the public internet. We've also considered just exposing the service, but then we still have to manually type in the port and manage ip conflicts.
saavagebueno added the feature-request label 2026-08-05 01:31:26 -04:00
Author
Owner

@NoNaccc commented on GitHub (Apr 18, 2026):

+1 on this.

To simplify the ask: right now the reverse proxy is designed to expose services to the public internet. But many of us need the same functionality — nice DNS names, automatic TLS, port abstraction — purely internally, only for clients connected to the NetBird mesh.

This is closely related to #5556 , which I opened a while back. My request there was about allowing auth bypass based on source IP/CIDR (e.g. 100.64.0.0/10) so that VPN-connected clients don't have to go through SSO again. Both issues boil down to the same underlying gap: there's no clean way to use the reverse proxy for internal-only services.

Right now there's a clear gap between Networks (internal, but IP-only, no TLS, no port mapping) and the Reverse Proxy (DNS + TLS + port mapping, but public-facing). The missing piece is an internal reverse proxy that combines the convenience of the reverse proxy with the scope of Networks — only reachable for connected peers, with proper DNS and TLS, without needing proxy clusters or public certificate validation.

<!-- gh-comment-id:4274540903 --> @NoNaccc commented on GitHub (Apr 18, 2026): +1 on this. To simplify the ask: right now the reverse proxy is designed to expose services to the public internet. But many of us need the same functionality — nice DNS names, automatic TLS, port abstraction — purely internally, only for clients connected to the NetBird mesh. This is closely related to #5556 , which I opened a while back. My request there was about allowing auth bypass based on source IP/CIDR (e.g. 100.64.0.0/10) so that VPN-connected clients don't have to go through SSO again. Both issues boil down to the same underlying gap: there's no clean way to use the reverse proxy for internal-only services. Right now there's a clear gap between Networks (internal, but IP-only, no TLS, no port mapping) and the Reverse Proxy (DNS + TLS + port mapping, but public-facing). The missing piece is an internal reverse proxy that combines the convenience of the reverse proxy with the scope of Networks — only reachable for connected peers, with proper DNS and TLS, without needing proxy clusters or public certificate validation.
Author
Owner

@elia2904 commented on GitHub (Apr 20, 2026):

+1 on this.
That's a feature I would find very helpfull.

<!-- gh-comment-id:4284469972 --> @elia2904 commented on GitHub (Apr 20, 2026): +1 on this. That's a feature I would find very helpfull.
Author
Owner

@Minimalist-2211 commented on GitHub (Apr 20, 2026):

We need this, pls NetBird! 🙏

<!-- gh-comment-id:4285070735 --> @Minimalist-2211 commented on GitHub (Apr 20, 2026): We need this, pls NetBird! 🙏
Author
Owner

@Silvani-In-The-Net commented on GitHub (Apr 20, 2026):

I also second this, I use an external domain that I allow family to use through Pangolin-Reverse proxy for things like Jellyfin. This feature would allow me to completely swap over to this for both my external and internal services for which I still rely on Caddy (with Self Signed Certs).

<!-- gh-comment-id:4285437376 --> @Silvani-In-The-Net commented on GitHub (Apr 20, 2026): I also second this, I use an external domain that I allow family to use through Pangolin-Reverse proxy for things like Jellyfin. This feature would allow me to completely swap over to this for both my external and internal services for which I still rely on Caddy (with Self Signed Certs).
Author
Owner

@Minimalist-2211 commented on GitHub (Apr 21, 2026):

I also second this, I use an external domain that I allow family to use through another proxy service for things like Jellyfin. This feature would allow me to completely swap over to this for both my external and internal services for which I still rely on Caddy (with Self Signed Certs).

Same!

<!-- gh-comment-id:4287063406 --> @Minimalist-2211 commented on GitHub (Apr 21, 2026): > I also second this, I use an external domain that I allow family to use through another proxy service for things like Jellyfin. This feature would allow me to completely swap over to this for both my external and internal services for which I still rely on Caddy (with Self Signed Certs). Same!
Author
Owner

@dasunsrule32 commented on GitHub (Apr 30, 2026):

As @NoNaccc said earlier, with the internal proxy, it would be nice to deploy the proxy on-premise to handle TLS negotiation, have a local IP and can connect to the backend services there. Then policies can define access over the Netbird client.

It would also be nice to have flexibility to access those same services locally via the on-premise proxy. I think it should work similarly to how the public services work where you don't need to be connected to the client and can still hit those services.

Pangolin has added internal proxy support, however, there implementation will still go out to their server for services on the same network, which I don't want.

Currently, I deploy Caddy on prem and point Pangolin to it. Netbird doesn't handle TLS SNI Server Names currently, so I can't use that connection without a bunch of janky changes in Caddy. Pangolin lets you set that feature directly in the proxy settings.

<!-- gh-comment-id:4353614757 --> @dasunsrule32 commented on GitHub (Apr 30, 2026): As @NoNaccc said earlier, with the internal proxy, it would be nice to deploy the proxy on-premise to handle TLS negotiation, have a local IP and can connect to the backend services there. Then policies can define access over the Netbird client. It would also be nice to have flexibility to access those same services locally via the on-premise proxy. I think it should work similarly to how the public services work where you don't need to be connected to the client and can still hit those services. Pangolin has added internal proxy support, however, there implementation will still go out to their server for services on the same network, which I don't want. Currently, I deploy Caddy on prem and point Pangolin to it. Netbird doesn't handle TLS SNI Server Names currently, so I can't use that connection without a bunch of janky changes in Caddy. Pangolin lets you set that feature directly in the proxy settings.
Author
Owner

@WirtsLegs commented on GitHub (May 6, 2026):

Big +1 from me, probably the single most significant missing feature for me. I have a limited but distributed user-base and need to be able to cleanly control access to services for them, without making those services available to the open internet

<!-- gh-comment-id:4391402790 --> @WirtsLegs commented on GitHub (May 6, 2026): Big +1 from me, probably the single most significant missing feature for me. I have a limited but distributed user-base and need to be able to cleanly control access to services for them, without making those services available to the open internet
Author
Owner

@timthelion commented on GitHub (May 16, 2026):

I would love this too. Even better if it supported wildcards.

<!-- gh-comment-id:4466474090 --> @timthelion commented on GitHub (May 16, 2026): I would love this too. Even better if it supported wildcards.
Author
Owner

@chadillac commented on GitHub (May 20, 2026):

Another +1 for this... spent some time thinking about it, and I think if network route peers could also serve as revproxy service exposures with the DNS zones, you could achieve something like this...

internal DNS: .lan
network: 192.168.10.0/24
route peer: server.lan (192.168.10.0/24)
peer service:
  |- mything.lan -> server.lan:8080
  |- otherthing.lan -> server.lan:1111
  |- gateway.lan -> 192.168.10.1:8443

So with this setup, check the zone, if no resource exists at the name, check the service, as the route peer is routed the traffic, it can either masquerade it along, or it can redirect it into it's native revproxy which then routes in through to the expected port mapping on the peer.

So visiting gateway.lan on the nb peer would result in traffic routing to the server.lan peer, and then acting as a revproxy to 192.168.10.1:8443 to get to the LAN gateway admin login page.

Just my $0.02

To get around this lack of feature, I was planning to deploy an internal revproxy myself that will do something like this for being able to easily expose services to netbird peers using a similar pattern.

<!-- gh-comment-id:4500983019 --> @chadillac commented on GitHub (May 20, 2026): Another +1 for this... spent some time thinking about it, and I think if network route peers could also serve as revproxy service exposures with the DNS zones, you could achieve something like this... ``` internal DNS: .lan network: 192.168.10.0/24 route peer: server.lan (192.168.10.0/24) peer service: |- mything.lan -> server.lan:8080 |- otherthing.lan -> server.lan:1111 |- gateway.lan -> 192.168.10.1:8443 ``` So with this setup, check the zone, if no resource exists at the name, check the service, as the route peer is routed the traffic, it can either masquerade it along, or it can redirect it into it's native revproxy which then routes in through to the expected port mapping on the peer. So visiting `gateway.lan` on the nb peer would result in traffic routing to the `server.lan` peer, and then acting as a revproxy to `192.168.10.1:8443` to get to the LAN gateway admin login page. Just my $0.02 To get around this lack of feature, I was planning to deploy an internal revproxy myself that will do something like this for being able to easily expose services to netbird peers using a similar pattern.
Author
Owner

@SneakyTurt1e commented on GitHub (May 28, 2026):

+1 on this.
I think it's quite useful within our docker lab... even we can setup custom DNS domain for netbird network, but it's pain to remember all ports we using with docker container.

<!-- gh-comment-id:4562229209 --> @SneakyTurt1e commented on GitHub (May 28, 2026): +1 on this. I think it's quite useful within our docker lab... even we can setup custom DNS domain for netbird network, but it's pain to remember all ports we using with docker container.
Author
Owner

@erdelmaero commented on GitHub (Jun 2, 2026):

+1 on this — would let us collapse a duplicated piece of our stack.

We currently do use netbird-proxy for public service exposure and it's been
great there. The gap is on the internal side: any service that should only be
reachable from inside the mesh still goes through a separate Traefik instance
we maintain ourselves. The pattern is:

  • service runs in our k8s cluster, no public DNS A record, no public IP
  • internal Traefik handles TLS termination (wildcard LE cert via DNS-01,
    managed by cert-manager), forward-auth via oauth2-proxy, host-based routing
  • the NetBird DNS we serve to mesh peers points to that Traefik's LB IP
  • peer hits e.g. argocd.contoso.com → Traefik → backend pod

It works, but we're effectively maintaining two reverse proxies for what is
conceptually one capability — "give peers a friendly hostname, terminate TLS,
optionally gate with SSO". The reverse-proxy already does all that for public
services. For internal-only services, all we want is for it to:

  • not require a public DNS A record / publicly resolvable hostname for each
    service (DNS-01 wildcard already covers TLS; the per-host A record only
    exists today to satisfy the public-exposure assumption)
  • run on a peer inside the mesh rather than the public exposure VM

I think the underlying need — NetBird as ZTN + an internal reverse proxy in
front of mesh-only services — is a very common architecture. Today users
either do what we do (separate reverse proxy + NetBird DNS pointing at it),
or fall back to bare IPs + remembering port numbers. Both are worse than
having this in one product.

@chadillac's sketch a few comments up matches our case almost exactly. The
one thing we'd most want layered on top is the same per-service group ACLs
the public reverse proxy already has, so we can keep the SSO / per-group
access model unified across public and internal services.

Happy to help test prereleases.

<!-- gh-comment-id:4607332069 --> @erdelmaero commented on GitHub (Jun 2, 2026): +1 on this — would let us collapse a duplicated piece of our stack. We currently *do* use netbird-proxy for public service exposure and it's been great there. The gap is on the internal side: any service that should only be reachable from inside the mesh still goes through a separate Traefik instance we maintain ourselves. The pattern is: - service runs in our k8s cluster, no public DNS A record, no public IP - internal Traefik handles TLS termination (wildcard LE cert via DNS-01, managed by cert-manager), forward-auth via oauth2-proxy, host-based routing - the NetBird DNS we serve to mesh peers points to that Traefik's LB IP - peer hits e.g. `argocd.contoso.com` → Traefik → backend pod It works, but we're effectively maintaining two reverse proxies for what is conceptually one capability — "give peers a friendly hostname, terminate TLS, optionally gate with SSO". The reverse-proxy already does all that for public services. For internal-only services, all we want is for it to: - not require a public DNS A record / publicly resolvable hostname for each service (DNS-01 wildcard already covers TLS; the per-host A record only exists today to satisfy the public-exposure assumption) - run on a peer inside the mesh rather than the public exposure VM I think the underlying need — NetBird as ZTN + an internal reverse proxy in front of mesh-only services — is a very common architecture. Today users either do what we do (separate reverse proxy + NetBird DNS pointing at it), or fall back to bare IPs + remembering port numbers. Both are worse than having this in one product. @chadillac's sketch a few comments up matches our case almost exactly. The one thing we'd most want layered on top is the same per-service group ACLs the public reverse proxy already has, so we can keep the SSO / per-group access model unified across public and internal services. Happy to help test prereleases.
Author
Owner

@kgrotel commented on GitHub (Jul 18, 2026):

Why not just use BYOP (Bring your own proxy) deploy it on a Netbird Node, let it use a Netbird DNS Zone and you are done .. i even created a Netbird Operator for Kubernetes to deploy that Proxy .. works like a charm

@erdelmaero you seem to have similar setup we have just we use ciliumLB thus checkout -> https://github.com/ccbash/netbird-operator
would be great to get some feedback on it anyway

<!-- gh-comment-id:5010355396 --> @kgrotel commented on GitHub (Jul 18, 2026): Why not just use BYOP (Bring your own proxy) deploy it on a Netbird Node, let it use a Netbird DNS Zone and you are done .. i even created a Netbird Operator for Kubernetes to deploy that Proxy .. works like a charm @erdelmaero you seem to have similar setup we have just we use ciliumLB thus checkout -> https://github.com/ccbash/netbird-operator would be great to get some feedback on it anyway
Author
Owner

@timthelion commented on GitHub (Jul 18, 2026):

@kgrotel that only gets you half way to what we want. That lets you expose a service on a URL. It wouldn't let you use netbird for fine grained access to services. Imagine you have five services on one server and you want separate ACLs for each one.

<!-- gh-comment-id:5010450673 --> @timthelion commented on GitHub (Jul 18, 2026): @kgrotel that only gets you half way to what we want. That lets you expose a service on a URL. It wouldn't let you use netbird for fine grained access to services. Imagine you have five services on one server and you want separate ACLs for each one.
Author
Owner

@kgrotel commented on GitHub (Jul 19, 2026):

@timthelion it actually does .. using NetBird reverse proxy it registers in the control plane and supports policies assigned via groups for each exposed service it even shows access logs

<!-- gh-comment-id:5014890958 --> @kgrotel commented on GitHub (Jul 19, 2026): @timthelion it actually does .. using NetBird reverse proxy it registers in the control plane and supports policies assigned via groups for each exposed service it even shows access logs
Author
Owner

@timthelion commented on GitHub (Jul 19, 2026):

@kgrotel um 😅. Take another look at the title of this issue. It says "internal". What I think everyone here wants, is to be able to do just that without creating an externally exposed URL.

<!-- gh-comment-id:5014943965 --> @timthelion commented on GitHub (Jul 19, 2026): @kgrotel um 😅. Take another look at the title of this issue. It says "internal". What I think everyone here wants, is to be able to do just that without creating an externally exposed URL.
Author
Owner

@DjSni commented on GitHub (Jul 19, 2026):

@timthelion it actually does .. using NetBird reverse proxy it registers in the control plane and supports policies assigned via groups for each exposed service it even shows access logs

@kgrotel um 😅. Take another look at the title of this issue. It says "internal". What I think everyone here wants, is to be able to do just that without creating an externally exposed URL.

Well, to put it simply, we want it to be possible to use internal domains like myhome.lab, and for them to be accessible only through the Netbird reverse proxy, with all ACLs in place.
That way, I can just go to app.myhome.lab and see my app.

<!-- gh-comment-id:5014968490 --> @DjSni commented on GitHub (Jul 19, 2026): > [@timthelion](https://github.com/timthelion) it actually does .. using NetBird reverse proxy it registers in the control plane and supports policies assigned via groups for each exposed service it even shows access logs > [@kgrotel](https://github.com/kgrotel) um 😅. Take another look at the title of this issue. It says "internal". What I think everyone here wants, is to be able to do just that without creating an externally exposed URL. Well, to put it simply, we want it to be possible to use internal domains like myhome.lab, and for them to be accessible only through the Netbird reverse proxy, with all ACLs in place. That way, I can just go to app.myhome.lab and see my app.
Author
Owner

@syorito-hatsuki commented on GitHub (Jul 19, 2026):

@timthelion it actually does .. using NetBird reverse proxy it registers in the control plane and supports policies assigned via groups for each exposed service it even shows access logs

@kgrotel um 😅. Take another look at the title of this issue. It says "internal". What I think everyone here wants, is to be able to do just that without creating an externally exposed URL.

Well, to put it simply, we want it to be possible to use internal domains like myhome.lab, and for them to be accessible only through the Netbird reverse proxy, with all ACLs in place. That way, I can just go to app.myhome.lab and see my app.

And it no need to exact be .lan, it can be normal domain with wildcard CA but subdomains goes first to NetBird DNS + Internal Proxy instead of public DNS and then to Proxy (at least that how I build it on Kubernates 👀)

<!-- gh-comment-id:5014988612 --> @syorito-hatsuki commented on GitHub (Jul 19, 2026): > > [@timthelion](https://github.com/timthelion) it actually does .. using NetBird reverse proxy it registers in the control plane and supports policies assigned via groups for each exposed service it even shows access logs > > > [@kgrotel](https://github.com/kgrotel) um 😅. Take another look at the title of this issue. It says "internal". What I think everyone here wants, is to be able to do just that without creating an externally exposed URL. > > Well, to put it simply, we want it to be possible to use internal domains like myhome.lab, and for them to be accessible only through the Netbird reverse proxy, with all ACLs in place. That way, I can just go to app.myhome.lab and see my app. And it no need to exact be .lan, it can be normal domain with wildcard CA but subdomains goes first to NetBird DNS + Internal Proxy instead of public DNS and then to Proxy (at least that how I build it on Kubernates 👀)
Author
Owner

@WirtsLegs commented on GitHub (Jul 23, 2026):

yeah in my case what I'm hoping for is the ability to do a split basically, this would be the ideal but

Say I own example.com
I have 5 services, a.example.com, b.example.com, c.example.com, d.example.com, e.example.com

I want a.example.com and b.example.com to be accessible from the open internet (current reverse proxy feature), but also from within the netbird mesh, so clients connected aren't having their requests routed out onto the internet to the reverse proxy that's handling external requests. In both public and internal access cases I want to be able to optionally do auth and have fine grained control on who can access what and optionally include header values based on that auth. In this case the DNS would be split brain and ideally someone connected to the mesh is served a mesh address when they do a request for a.example.com and not the public record.

Then I want c.example.com, d.example.com, and e.example.com to ONLY be accessible to people that are connected to the mesh, not allowing public access. Further I want to be able to apply all the same fine grained control and adding header values etc for these services based on netbird groups/users etc.

<!-- gh-comment-id:5059013291 --> @WirtsLegs commented on GitHub (Jul 23, 2026): yeah in my case what I'm hoping for is the ability to do a split basically, this would be the ideal but Say I own example.com I have 5 services, a.example.com, b.example.com, c.example.com, d.example.com, e.example.com I want a.example.com and b.example.com to be accessible from the open internet (current reverse proxy feature), but also from within the netbird mesh, so clients connected aren't having their requests routed out onto the internet to the reverse proxy that's handling external requests. In both public and internal access cases I want to be able to optionally do auth and have fine grained control on who can access what and optionally include header values based on that auth. In this case the DNS would be split brain and ideally someone connected to the mesh is served a mesh address when they do a request for a.example.com and not the public record. Then I want c.example.com, d.example.com, and e.example.com to ONLY be accessible to people that are connected to the mesh, not allowing public access. Further I want to be able to apply all the same fine grained control and adding header values etc for these services based on netbird groups/users etc.
Sign in to join this conversation.
No Label feature-request
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: DYNR/netbird#11880