mirror of
https://github.com/juanfont/headscale.git
synced 2026-01-11 20:00:28 +01:00
Plans to implement Funnel? #387
Closed
opened 2025-12-29 01:28:03 +01:00 by adam
·
29 comments
No Branch/Tag Specified
main
update_flake_lock_action
gh-pages
kradalby/release-v0.27.2
dependabot/go_modules/golang.org/x/crypto-0.45.0
dependabot/go_modules/github.com/opencontainers/runc-1.3.3
copilot/investigate-headscale-issue-2788
copilot/investigate-visibility-issue-2788
copilot/investigate-issue-2833
copilot/debug-issue-2846
copilot/fix-issue-2847
dependabot/go_modules/github.com/go-viper/mapstructure/v2-2.4.0
dependabot/go_modules/github.com/docker/docker-28.3.3incompatible
kradalby/cli-experiement3
doc/0.26.1
doc/0.25.1
doc/0.25.0
doc/0.24.3
doc/0.24.2
doc/0.24.1
doc/0.24.0
kradalby/build-docker-on-pr
topic/docu-versioning
topic/docker-kos
juanfont/fix-crash-node-id
juanfont/better-disclaimer
update-contributors
topic/prettier
revert-1893-add-test-stage-to-docs
add-test-stage-to-docs
remove-node-check-interval
fix-empty-prefix
fix-ephemeral-reusable
bug_report-debuginfo
autogroups
logs-to-stderr
revert-1414-topic/fix_unix_socket
rename-machine-node
port-embedded-derp-tests-v2
port-derp-tests
duplicate-word-linter
update-tailscale-1.36
warn-against-apache
ko-fi-link
more-acl-tests
fix-typo-standalone
parallel-nolint
tparallel-fix
rerouting
ssh-changelog-docs
oidc-cleanup
web-auth-flow-tests
kradalby-gh-runner
fix-proto-lint
remove-funding-links
go-1.19
enable-1.30-in-tests
0.16.x
cosmetic-changes-integration
tmp-fix-integration-docker
fix-integration-docker
configurable-update-interval
show-nodes-online
hs2021
acl-syntax-fixes
ts2021-implementation
fix-spurious-updates
unstable-integration-tests
mandatory-stun
embedded-derp
prtemplate-fix
v0.28.0-beta.1
v0.27.2-rc.1
v0.27.1
v0.27.0
v0.27.0-beta.2
v0.27.0-beta.1
v0.26.1
v0.26.0
v0.26.0-beta.2
v0.26.0-beta.1
v0.25.1
v0.25.0
v0.25.0-beta.2
v0.24.3
v0.25.0-beta.1
v0.24.2
v0.24.1
v0.24.0
v0.24.0-beta.2
v0.24.0-beta.1
v0.23.0
v0.23.0-rc.1
v0.23.0-beta.5
v0.23.0-beta.4
v0.23.0-beta3
v0.23.0-beta2
v0.23.0-beta1
v0.23.0-alpha12
v0.23.0-alpha11
v0.23.0-alpha10
v0.23.0-alpha9
v0.23.0-alpha8
v0.23.0-alpha7
v0.23.0-alpha6
v0.23.0-alpha5
v0.23.0-alpha4
v0.23.0-alpha4-docker-ko-test9
v0.23.0-alpha4-docker-ko-test8
v0.23.0-alpha4-docker-ko-test7
v0.23.0-alpha4-docker-ko-test6
v0.23.0-alpha4-docker-ko-test5
v0.23.0-alpha-docker-release-test-debug2
v0.23.0-alpha-docker-release-test-debug
v0.23.0-alpha4-docker-ko-test4
v0.23.0-alpha4-docker-ko-test3
v0.23.0-alpha4-docker-ko-test2
v0.23.0-alpha4-docker-ko-test
v0.23.0-alpha3
v0.23.0-alpha2
v0.23.0-alpha1
v0.22.3
v0.22.2
v0.23.0-alpha-docker-release-test
v0.22.1
v0.22.0
v0.22.0-alpha3
v0.22.0-alpha2
v0.22.0-alpha1
v0.22.0-nfpmtest
v0.21.0
v0.20.0
v0.19.0
v0.19.0-beta2
v0.19.0-beta1
v0.18.0
v0.18.0-beta4
v0.18.0-beta3
v0.18.0-beta2
v0.18.0-beta1
v0.17.1
v0.17.0
v0.17.0-beta5
v0.17.0-beta4
v0.17.0-beta3
v0.17.0-beta2
v0.17.0-beta1
v0.17.0-alpha4
v0.17.0-alpha3
v0.17.0-alpha2
v0.17.0-alpha1
v0.16.4
v0.16.3
v0.16.2
v0.16.1
v0.16.0
v0.16.0-beta7
v0.16.0-beta6
v0.16.0-beta5
v0.16.0-beta4
v0.16.0-beta3
v0.16.0-beta2
v0.16.0-beta1
v0.15.0
v0.15.0-beta6
v0.15.0-beta5
v0.15.0-beta4
v0.15.0-beta3
v0.15.0-beta2
v0.15.0-beta1
v0.14.0
v0.14.0-beta2
v0.14.0-beta1
v0.13.0
v0.13.0-beta3
v0.13.0-beta2
v0.13.0-beta1
upstream/v0.12.4
v0.12.4
v0.12.3
v0.12.2
v0.12.2-beta1
v0.12.1
v0.12.0-beta2
v0.12.0-beta1
v0.11.0
v0.10.8
v0.10.7
v0.10.6
v0.10.5
v0.10.4
v0.10.3
v0.10.2
v0.10.1
v0.10.0
v0.9.3
v0.9.2
v0.9.1
v0.9.0
v0.8.1
v0.8.0
v0.7.1
v0.7.0
v0.6.1
v0.6.0
v0.5.2
v0.5.1
v0.5.0
v0.4.0
v0.3.6
v0.3.5
v0.3.4
v0.3.3
v0.3.2
v0.3.1
v0.3.0
v0.2.2
v0.2.1
v0.2.0
v0.1.1
v0.1.0
Labels
Clear labels
CLI
DERP
DNS
Nix
OIDC
SSH
bug
database
documentation
duplicate
enhancement
faq
good first issue
grants
help wanted
might-come
needs design doc
needs investigation
no-stale-bot
out of scope
performance
policy 📝
pull-request
question
regression
routes
stale
tags
tailscale-feature-gap
well described ❤️
wontfix
Mirrored from GitHub Pull Request
No Label
enhancement
Milestone
No items
No Milestone
Projects
Clear projects
No project
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: starred/headscale#387
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @julianfairfax on GitHub (Dec 3, 2022).
Feature request
Are there plans to implement support for tailscale's Funnel?
I can't actually use headscale, as the whole reason I'm using tailscale is that I can't do port forwarding, and thus, my running head scale server would be unreachable by all devices.
Using tailscale though, I find the Funnel useful, as I run a Nextcloud server, and want to share links to my files with people not on my tailnet.
It would thus be cool to have this feature in headscale, for those who can use it!
@kradalby commented on GitHub (Dec 7, 2022):
We cannot really implement Tailscale's Funnel per se as it is not a public infrastructure like DERP. The way it works is roughly by setting up a connection between your node and the Tailscale Funnel ingress via your tailnet. This means that the tailnet must be hosted on tailscale.com.
In theory we could run our own "Headscale Funnel" infrastructure, but we have no capacity to do that.
or empower users to set this up themselves, but that still requires you to have a server with a public IP etc. For the record, this can already be done with a couple of lines of config and https://github.com/samhocevar/rinetd.
@nikicat commented on GitHub (Aug 25, 2023):
If I understand correctly one of the main Funnel features is the automatic mapping of a subdomain to an exposed service with automatic certificate issuing (using letsencrypt for user-provided domain).
I would certainly use such a feature if Headscale implemented it.
@rallisf1 commented on GitHub (Aug 26, 2023):
I guess it could be implemented via 3rd party services like ngrok. My favorite is cloudflare tunnel. It is free, cloudflared is open source and all you really need is a domain on cloudflare.
@nikicat commented on GitHub (Aug 27, 2023):
Yes, I want something like you mentioned @rallisf1 , but hosted on my own server, not a third-party service, that's why I'm actually using headscale instead of tailscale.
@rallisf1 commented on GitHub (Aug 28, 2023):
This would require a reverse proxy and a dns server. Reverse proxy is easy, I already run headscale behind caddy. You'd need some form of integration with headscale though to generate the config for the Funnels. The DNS server must be public facing, be set as the designated nameserver for the domain you own (different than the magicDNS domain) and also integrated with headscale. Most registrars require at least 2 nameservers though, plus it's hell of a lot easier to just use a 3rd party DNS service that provides an API, like cloudflare...
@nikicat commented on GitHub (Aug 28, 2023):
Reverse proxy, dns server, and a certificate manager (for https support) - all this should ideally be integrated into a single application. btw, the domain used for forwarding could be a 2nd level domain (or even deeper) so it should not be a problem to have only one NS for that.
@rallisf1 commented on GitHub (Aug 28, 2023):
I am strongly against this. There are battle tested open source packages that will do a better job than any 1st party implementation, plus I bet there is no capacity to even consider that. Integration, docs and a
docker-compose.ymlfor the lazy is all that it takes.true but that means exposing your internal domains to the internet and frankly I'd never do that, even when they point to 100.x.x.x IPs.
@nikicat commented on GitHub (Aug 28, 2023):
I just partially understand and accept your opinion - using proven tools is a good way, but nevertheless, we need a manager program that will
It doesn't look like a trivial thing from my point of view.
@renne commented on GitHub (Dec 23, 2023):
I suggest to run Tailscale exit nodes on servers with public static IP-adresses.
For Funnel requests Headscale just needs to push the necessary DNAT rules for opening and forwarding ports to the Tailscale exit node.
Lego can be used by Headscale to configure the primary DNS-server of your domain provider.
That way one only needs to rent a small VPS (1 vCPU, 512 MB RAM, 1 GB storage) to run an "Funnel" gateway.
For security reasons I suggest to run the TLS-server on your application servers instead of the Tailscale exit node (in my opinion the Tailscale exit node is not a secure host because the server provider has access).
@hoijui commented on GitHub (Feb 21, 2024):
I am also interested in this feature.
While I am an IT person, I only have very basic networking knowledge (mostly just IPv4 basics).
We have a tech-related non-profit (NPO) - promoting/pushing Open Source Hardware - which rents a (virtual) server.
Personally I have a low-power-consumption mini server at home, behind a CGNAT. I need it to be publicly reachable, providing web-serving, SSH server, email-server and things like that, at some point. Most importantly though, I want to use it for "hosting" distributed services nodes, like Tor, IPFS and such. This same setup should then be used by others that are part of the NPO.
It would be nice to be able to host Headscale ourselfs, and allow all our members (for now me, for testing) to have their own public server at home, providing both fail-safety and backups within the organization in a distributed manner, as well as (probably most important) build consciousness amongst the members for what distributed means, what the benefits are, that it is possible to some extend already, and what is missing.
I understand maybe 50% of the conversation in this issue. I personally would like to have a section somewhere in the docu of Headscale, that deals with this topic, explaining that the exact feature "funnel" as it is in Tailscale does not exist, but ... "you can build something similar in different ways, for example ...".
What do you think?
I'd be happy to dummy-test such a section.
@rallisf1 commented on GitHub (Feb 21, 2024):
@hoijui it's not so much a technical problem as an economic one. For Funnels to work you either need a server with a public IP (2 of them if you want to host your own private nameservers) or 3rd party services (DNS + Proxy). Let's say you want to self-host everything. Although running a DNS and proxy is dirt cheap on resources, traffic is not and that's gonna be double than a normal web/application server because of tunelling remote connections. Economically it makes more sense to just host the damn thing you need in a VPS altogether and skip the VPN.
Tailscale (meaning the SaaS) makes money and can afford this service, most of us cannot.
Should there be a guide about it for those who don't care about the cost? Sure, but there are a gazzilion ways to accomplish this, thus there will still be people who want help with e.g. Apache and GoDaddy instead of Caddy and Cloudflare, and it will still not be an integration.
@hoijui commented on GitHub (Feb 21, 2024):
I understand that it is an economical problem, and thus Headscale can not provide it for its community. My NPO though, could provide it for its members, as we are a small community, and people accessing our servers would also be fairly limited, meaning: in total, I could imagine it would not be a huge load on our server(s), to establish the incoming connections for our NATed server from our hosted server with the static IP.
If you say it is not possible/makes no sense to document how to do it anyway, because too complex/too many options, then.. well.. it is so. :-)
@stratself commented on GitHub (Aug 1, 2024):
I propose an example "funnel" with my own stack (archive.org link), using Tailscale nodes and a TCP proxy to route traffic from a VPS towards a HTTPS reverse proxy on a Pi behind NAT. Traefik is said reverse proxy in both cases.
I also set the Pi to use the VPS as an exit node, so outgoing requests can also come from the VPS itself and not from my residential IP.
With the right DNS records and routings, this should allow you to host webservices. Automating this stack to spin up any service from any node in the tailnet is a harder story though... I'm not sure its aptness for the TOR/IPFS use case as @hoijui mentioned. Feel free to contact me for more discussions
Edit: 20102025, new website URL
@hoijui commented on GitHub (Aug 1, 2024):
ehh cool, thank you for the article, @skedastically !
@qm3ster commented on GitHub (Aug 2, 2024):
@skedastically FYI link times out for me right now.
@LeapGM commented on GitHub (Mar 9, 2025):
Hey folks! I just found headscale and I'm looking to test it out as a tailscale alternative :)
I've just implemented a funnel/tunnel solution using tailscale & NPM (Nginx Proxy Manager), so I can use my own secure domain for all services in my tailscale network, no matter what server they're running on. NPM handles Let's Encrypt certs, including renewals. I'm currently testing it out, and I'm adding a script, using Cloudflare Tunnel, to be able to easily toggle public access to any service.
Once I have it all working and stable enough, I'm thinking I'll post it as a repo. Then it's time to see if it works with headscale! Headscale looks like a great initiative, and I would love replacing tailscale with open source.
@hoijui commented on GitHub (Mar 10, 2025):
Nice @LeapGM ! :-)
... you'll post a script?
possibly also interesting for some folks here:
https://github.com/samyk/pwnat
@salemgolemugoo commented on GitHub (Apr 3, 2025):
Any updates? I would love to check your solution
@hkfuertes commented on GitHub (Apr 3, 2025):
Places I have seen with a solution, but I don't think I like that one... what I have seen is a node avaliable on the internet and connected to the network (tailscale or headscale, it does not matter) and NPM (or Caddy) just pointing to the ts's ip of the services.... so from the Web --> internet node with NPM -- {tailscale} --> service... but in the end all the traffic will go through the node... Is your script different? that would be awesome! headscale control just delegating the connection to direct link....
I have to test my own aproach to see how slow it feels...
@tgrushka commented on GitHub (May 4, 2025):
@hoijui I agree with you, this should be simpler. I think tailscale doesn't want their headscale maintainers to implement a feature that they think would hurt their profits. I do not agree with @rallisf1 that you need all this infrastructure to do it. See this project: https://github.com/anderspitman/SirTunnel
I'm trying to make this work with Caddy on a VPS. Should be really simple -- have Caddy serve all the requests, then use script like SirTunnel to automate setting up tunnels in ssh and proxying them via Caddy.
It seems like the original request was related to this -- why can't we just "funnel" requests through headscale / our own tailnet?
I'm guessing it's a business decision of tailscale, and not a technical one.
And it's nonsensical that it would require any infrastructure on tailscale's part at all. That's not even related to the issue. It's fully technically achievable in headscale via tailnet -- even if it would require proxying with Caddy -- that's fine with me. But the "funnel" feature could be made to work simply. I think it's just a matter of priority.
Something like this should not have to be outsourced. Sure, it makes sense for large companies to outsource to tailscale, but not individuals that don't have large coffers.
@stratself commented on GitHub (May 8, 2025):
I think the better approach would be to bring your own Funnel ingress (as a Tailscale node), that you expose to the public internet (e.g. as a Docker on a VPS), and with your own FQDN. Which would requires two things from the Tailscale client:
tailscale certto accept custom domains. As Tailscale uses the DNS-01 challenge, I guess they provision the*.ts.netcerts via their own infra and push it to desired nodes. So this is something headscale can reverse-engineer/emulate e.g. usinglego-acmeand the provider's API key.Since Tailscale already acts as a layer-4 router (via
serve --tcp) as well as an HTTP reverse proxy this should be fairly straightforward. I guess it hasn't been done mainly because Tailscale wouldn't want to manage your DNS records, amongst other things.@jandrews377 commented on GitHub (Jul 17, 2025):
You can roll your own simple solution using a public exit node (eg cheap vm with a public ip) and use rinetd to forward ingress traffic through the tailnet. The traffic will appear on the tailnet as though its come from the local interface on the vm, therefore the ACL rule to lock down ingress traffic back to another host on your tailnet becomes straightforward. You then access (or share) the public IP and port combination with external users to access services running on your tailnet.
@Xinayder commented on GitHub (Jul 21, 2025):
How is this different than having a public-facing server (e.g. a VPS), connected to the Tailnet and acting as a reverse proxy to the local-facing servers?
Why would I need rinetd?
@jandrews377 commented on GitHub (Jul 21, 2025):
No different. When reverse proxying, you would be routing a port request on the default interface (eg eth0) to port on another interface (in our case tailscale0). rinetd is just another tool to make this easy. Use nginx, iptables DNAT rule or anything else you are comfortable with. I suggested rinetd because it's 'ergonomically' easy to use. The same people asking for 'Funnel' would be the same people who would appreciate the ergonomics of the mechanism.
@stratself commented on GitHub (Jul 26, 2025):
Reverse-proxies, rinetd1 , TCP routing2 , tailscale serve --tcp, ... are all probable methods with their own quirks. What sets Funnel apart is it being a one-time setup without needing third-party software that works on top of (rather than integrate directly with) Tailscale.
To that end I've opened
https://github.com/tailscale/tailscale/issues/15946to request the Funnel ingress feature on Tailscale clients themselves. Hopefully with this done, an open-source implementation can be provided for Headscale to coordinate against. Maybe, just maybe, Headscale can re-use this code so it can be a Funnel relay alongside being a control server + DERP too.mentioned as early as 2022 - https://tailscale.com/blog/introducing-tailscale-funnel ↩︎
from my comment above ↩︎
@Janhouse commented on GitHub (Jul 28, 2025):
I looked at how Pangolin does it and was pleasantly surprised that they use Traefik HTTP configuration endpoint. This gave me the idea to make a standalone solution so I could use it with Headscale and my existing Traefik proxy.
So I made a simple nextjs service that generates Traefik config and provides admin panel to manage it.
All the work is handled by Traefik, including DNS challenge for letsencrypt, or you can add Cloudflare proxy in front, or you can use both Cloudflare and Letsencrypt in split DNS scenarios where you use Cloudflare for public access but still use Letsencrypt for internal network.
It could become a single docker-compose file shipping with traefik + tailscale + service, place it on some VPS and it would be ready. In my opinion this would probably be convenient enough for people already self hosting headscale.
Here is example on how it works so far: https://www.youtube.com/watch?v=ag0B1-lrOXY
I'll tidy it up and make it available on Github if anyone is interested.
@NoX1De commented on GitHub (Sep 1, 2025):
@Janhouse Please do!
@renne commented on GitHub (Sep 1, 2025):
@Janhouse How do you synchronize the configuration of the Traefik proxy of the VPS and the local LAN?
@Janhouse commented on GitHub (Sep 1, 2025):
@renne alright, I did not really clean it up, just pushed it here: https://github.com/Janhouse/traefik-proxy-admin
It is still a bit rough and don't mind the README, it is somewhat vibe-coded. 😁
There is example docker compose and once you run the service, it has some additional instructions.
@NoX1De the idea is to run Traefik and Tailscale client on VPS. And when you add the dynamic configuration entries pointing to Tailscale nodes, it will be routed by Tailscale. But also you can run this container separately from the VPS Traefik instance (in LAN or wherever) and just point to the dynamic configuration URL, still routed by Tailscale client.
Also it would be nice to tie it together with Headscale ACL management so it would open the necessary ports for the VPS node to access. Maybe something to consider in the future.