cloudflare / cloudflared

Cloudflare Tunnel client (formerly Argo Tunnel)
https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/tunnel-guide
Apache License 2.0
9.31k stars 829 forks source link

Proxy to a different path on the origin service #563

Open brenner-tobias opened 2 years ago

brenner-tobias commented 2 years ago

Is your feature request related to a problem? Please describe. In the ingress rules, it would be great to have the option to define a location of the service and not "only" a URL limited to protocol, hostname and IP (for http), e.g. http://192.168.178.1/nas

Describe the solution you'd like I do not think a new option is needed, it could just be a part of the service URL.

Describe alternatives you've considered Could also be added using an additional variable, like it is done for path on the hostname.

Additional context If I add a URL with a location attached, I get the error: http://192.168.178.1/nas is an invalid address, ingress rules don't support proxying to a different path on the origin service. The path will be the same as the eyeball request's path

nmldiegues commented 2 years ago

Hello @brenner-tobias ,

Have you checked https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/configuration/configuration-file/ingress ? I believe the path configuration of a service does what you are mentioning.

brenner-tobias commented 2 years ago

@nmldiegues thanks a lot for the response. I did see the path configuration, but my understanding is that it works in a different way than what I am looking for: The path is used as an addition to the hostname when matching the rules (using RegEx). So if I define

  - hostname: static.example.com
    path: /*.(jpg|png|css|js)
    service: https://localhost:8001

Everything that matches static.example.com/*.(jpg|png|css|js) will go to service: https://localhost:8001.

What I am looking for is the possibility to define another location to forward to, when matching a rule, so:

  - hostname: static.example.com
    service: https://localhost:8001
    location: /home

Would mean that everything that matches static.example.com would be forwarded to https://localhost:8001/home.

Does that make sense?

nmldiegues commented 2 years ago

That's much clearer, thanks!

That's not possible, indeed. Of course you can set that up by running a nginx or equivalent in localhost and doing those transformations. cloudflared is not aiming to be a general proxy, but we'll keep this in mind should it overlap with something we can provide of value

regnaio commented 2 years ago

This proposed feature would be important and can help eliminate the need for several DNS records for a single tunnel

Less DNS record clutter in your zones and fewer REST API calls for record creation and deletion


Example

3 DNS records

ingress:
  - hostname: subdomain1.domain.com
    service: https://localhost:3001
  - hostname: subdomain2.domain.com
    service: https://localhost:3002
  - hostname: subdomain3.domain.com
    service: https://localhost:3003
  # etc...

to

1 DNS record

ingress:
  - hostname: subdomain.domain.com
    path: /subdir1/.*
    service: https://localhost:3001
    location: /
  - hostname: subdomain.domain.com
    path: /subdir2/.*
    service: https://localhost:3002
    location: /
  - hostname: subdomain.domain.com
    path: /subdir3/.*
    service: https://localhost:3003
    location: /
  # etc...

In the example above /subdirX/ is being mapped to /

Without this feature, your service, e.g. a REST API, needs to run on localhost:300X/subdirX instead of localhost:300X


Could an edit to the ProxyHTTP function allow for this?

regnaio commented 2 years ago

Can a cloudflared contributor please advise?

To implement this feature, should we use ProxyHTTP function as a starting point?

nmldiegues commented 2 years ago

Can a cloudflared contributor please advise?

To implement this feature, should we use ProxyHTTP function as a starting point?

Yes, that is the starting point.

regnaio commented 2 years ago

@brenner-tobias @nmldiegues Thanks for the ideas! I came up with a rough working proof-of-concept

Diff: https://github.com/cloudflare/cloudflared/compare/master...regnaio:regnaio/location

ingress:
  - hostname: A.domain.com
    path: /B/.*
    service: https://localhost:3000
    location: /C

location replaces the first subdirectory of path

For example, the input URL A.domain.com/B/hello/hi is mapped to https://localhost:3000/C/hello/hi

I have not yet implemented any tests or strict checks on the newly added Location string field


My favorite use case for this so far is to slice off the first subdirectory in path:

ingress:
  - hostname: tunnel.domain.com
    path: /api/.*
    service: https://localhost:3000
    location: /

This is useful, since HTTP services tend to serve content starting at /

For example, tunnel.domain.com/api/users/bob is routed to https://localhost:3000/users/bob

jhuettner commented 2 years ago

+1 to this request!

wifiuk commented 2 years ago

+1 to this request.

having the ability to do /web at the end saves me sooo many troubles!

image

smartdigit commented 2 years ago

+1 to this request!

Wamy-Dev commented 2 years ago

How are people getting around this problem?

regnaio commented 2 years ago

For an unofficial workaround, you can pull my branch regnaio/location in https://github.com/cloudflare/cloudflared/issues/563#issuecomment-1081779878

And then build cloudflared using the Dockerfiles from the official repo:


Dockerfile (used to build the cloudflared Docker image)

# build Docker image
docker build -t cloudflared-location .

dev.Dockerfile (used to build the cloudflared binary)

# build Docker image
docker build -f dev.Dockerfile -t cloudflared-location-dev .

# run the Docker image with the cloudflared repo mounted as a volume
docker run -it --rm --name cloudflared-location-dev-container -v ${PWD}:/go/src/github.com/cloudflare/cloudflared/ cloudflared-location-dev

# build cloudflared binary
make cloudflared
Adamados commented 2 years ago

+1 to this request

yenba commented 2 years ago

Another +1 to this request!

skynet01 commented 2 years ago

+100 to this request. Unfortunately for me, this is way more important to me than not having 2 ports open on my router. Hope that Zero Trust access firewall will be enough to protect me from evil haxors. Back to NPM + Cloudflare without a tunnel I go 😂

brenner-tobias commented 2 years ago

@regnaio and @nmldiegues are there any updates / plans regarding this feature?

regnaio commented 2 years ago

@regnaio and @nmldiegues are there any updates / plans regarding this feature?

Just pulled all new commits to master and updated my branch regnaio/location:

Diff: https://github.com/cloudflare/cloudflared/compare/master...regnaio:regnaio/location

Agreed that we should aim to merge something. Awesome to see that @moofMoney opened a PR for this

DevinCarr commented 2 years ago

Hello all, I recently closed a PR that was attempting similar work to be merged into cloudflared. I will link my reply here: https://github.com/cloudflare/cloudflared/pull/766#issuecomment-1314756084

There has been some good discussion here on how to work around this limitation that many of you desire. Additionally, some cool forks/branches of implementations and work-arounds. As such, I won't close this issue, but I will mark it as Deferred since we won't be pursuing this type of work in the near term as we don't feel it fits the scope of what we want to provide in cloudflared.

I will work the team internally to establish a more well-formed document that better articulates what changes we are willing to see in cloudflared from external contributors.

cc @abelinkinbio

jasonmarlin commented 1 year ago

I would love there to be documentation that this sort of routing is not possible in the current release because it cost me hours of searching to find the answer here. Adding an extra reverse proxy at the origin seems to greatly limit the usefulness of tunnels for production applications - one more unnecessary point of failure. Thanks for your work on this @regnaio - going to take a look at your branch.

MiraiSubject commented 1 year ago

I agree with the person above me. I went through a couple of forum threads first and then first arrived here https://github.com/cloudflare/cloudflared/issues/286 and now here.

Adding a reverse proxy to allow multiple services to be exposed through a tunnel using path separation is very counter-intuitive to the user experience with tunnelling in Cloudflare Zero Trust. This should definitely at least be better documented in the UI why this is a wontfix.

I might have a look at the tool provided above, but it's honestly more work than it's worth it for just a showcase in a development environment.

regnaio commented 1 year ago

Since this feature seems to be highly requested, I drafted some documentation in attempt to help others understand and improve the working proof of concept:

Documentation: https://github.com/regnaio/cloudflared/blob/42f839db8173ea3070e7188815c11212afb21f99/1.md

Diff: https://github.com/cloudflare/cloudflared/compare/master...regnaio:regnaio/location

mbloodk commented 1 year ago

did you solve this somehow? I basically want same. I have home.domain.com where HA is accessible
but want to forward for example web.domain.com or even domain.com to local/index.html

genothomas commented 8 months ago

+1 to this request!

MythodeaLoL commented 6 months ago

+1 for this, please add.

regnaio commented 5 months ago

One solution is to pull my branch, build cloudflared, and add location to your config as described in my comment above

The diff is quite small: https://github.com/cloudflare/cloudflared/compare/master...regnaio:regnaio/location

Unfortunately, this functionality doesn't come with Stock cloudflared yet

victortrusov commented 1 month ago

+1 to this request, it will save a lot of time setting up the environment