Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proxy upstream depending on hostname #990

Open
meyskens opened this issue Aug 2, 2016 · 23 comments

Comments

Projects
None yet
7 participants
@meyskens
Copy link

commented Aug 2, 2016

It would be nice if Caddy could use a different proxy upstream dependent on the host that is requested.
eg.

proxy / http://{host}.internal.somedomain

in Nginx we do this by using server_name ~^(?<subdomain>.+)\.domain\.com$; and proxy_pass http://$subdoain.int.domain.com;

Not sure how hard it is to add this.

@mholt

This comment has been minimized.

Copy link
Owner

commented Aug 2, 2016

Thanks for your question, Maartje. Try this:

host1.com {
    proxy / http://host1.com.internal.somedomain
}
host2.com {
    proxy / http://host2.com.internal.somedomain
}

Much simpler I think, no?

@meyskens

This comment has been minimized.

Copy link
Author

commented Aug 2, 2016

Not in our usecase. We use it to proxy dynamic subdomains (client's username) to their specific internal ip for a container where a server runs.

@mholt

This comment has been minimized.

Copy link
Owner

commented Aug 2, 2016

It could be possible to enable placeholders for upstream addresses, we'll have to look into that! Anyone is welcome to look into this, not sure I'll have time right now.

@vchimishuk

This comment has been minimized.

Copy link
Contributor

commented Aug 2, 2016

I can try, if nobody minds.

@meyskens

This comment has been minimized.

Copy link
Author

commented Aug 2, 2016

Was just thinking the same, never worked with the Caddy codebase but i imagine the upstream values just have to be passed through some parser. Will take a look myself later

@meyskens

This comment has been minimized.

Copy link
Author

commented Aug 2, 2016

@vchimishuk didn't see your reply, sorry. Feel free to try!

@meyskens

This comment has been minimized.

Copy link
Author

commented Aug 2, 2016

I've been able to add outreq.Host = replacer.Replace(outreq.Host) which should do what I think it has to. But it seems on the setup net/url parses the URL where it returns the error that it doesn't like the {}. Not sure how to solve that issue

@mholt mholt added the help wanted label Aug 3, 2016

@tpng

This comment has been minimized.

Copy link
Collaborator

commented Aug 4, 2016

Seems you will have to create a new func like NewDynamicHostReverseProxy similar to NewSingleHostReverseProxy and call it instead at https://github.com/mholt/caddy/blob/master/caddyhttp/proxy/upstream.go#L152 if uh.Name contain {host}.

@meyskens

This comment has been minimized.

Copy link
Author

commented Aug 4, 2016

Ok I added that and parse the URL in there (with a dirty strings.Replace 😛 to get it parsed). The code runs but still parse http://{host}:8080: invalid character "{" in host name. Seems like it still parses it before passing it on. Will keep on looking.

@meyskens

This comment has been minimized.

Copy link
Author

commented Aug 4, 2016

Pushed my work (https://github.com/meyskens/caddy) if anybody spots my mistake you'll get many love.

@tpng

This comment has been minimized.

Copy link
Collaborator

commented Aug 4, 2016

You have to update https://github.com/mholt/caddy/blob/master/caddyhttp/proxy/upstream.go#L152 to call NewDynamicHostReverseProxy too.

Something like:

if strings.Contains(uh.Name, "{host}") {
    uh.ReverseProxy = NewDynamicHostReverseProxy(uh.Name, uh.WithoutPathPrefix)
} else {
    baseURL, err := url.Parse(uh.Name)
    if err != nil {
        return nil, err
    }
    uh.ReverseProxy = NewSingleHostReverseProxy(baseURL, uh.WithoutPathPrefix)
}

if u.insecureSkipVerify {
    uh.ReverseProxy.Transport = InsecureTransport
}
@meyskens

This comment has been minimized.

Copy link
Author

commented Aug 4, 2016

@tpng sorry, wrote exactly that but forgot to add that to Git. My bad. Will push it.

@meyskens

This comment has been minimized.

Copy link
Author

commented Aug 4, 2016

Pushed, even with only uh.ReverseProxy = NewDynamicHostReverseProxy(uh.Name, uh.WithoutPathPrefix) I had the same issue.

@meyskens

This comment has been minimized.

Copy link
Author

commented Aug 4, 2016

Nevermind, I didn't notice ./build.bash didn't replace the binary in /bin. It works fine now!

@mholt

This comment has been minimized.

Copy link
Owner

commented Aug 12, 2016

What will probably happen is we will release 0.9.1 without this change, since it's quite invasive, and will need some time to test it before the first release including it.

@ulrichSchreiner

This comment has been minimized.

Copy link

commented Sep 1, 2016

hi,
it would be great to have other placeholders too. not only {host} but also {port}, {scheme} and some more.

@mholt

This comment has been minimized.

Copy link
Owner

commented Sep 1, 2016

@ulrichSchreiner Good news is that if one request placeholder is supported, all of them are.

@mholt

This comment has been minimized.

Copy link
Owner

commented Sep 15, 2016

For those following along at home, we've decided that the proxy middleware would probably best be redesigned to support dynamic upstreams rather than hacking it into the staticUpstream type.

@yura8

This comment has been minimized.

Copy link

commented Apr 13, 2017

A lot of thoughts and efforts went into building proxy capabilities of Caddy and especially in the recent releases. It proved how important and useful simplicity and universality for many use cases it has. Thank you to Caddy creator and contributors for that.

I want to bring to attention that providing a way for dynamic hostnames (or other means for automatic configuration of up stream servers) combined with Caddy's "wildcard" tls allows the most effortless and convenient way to set up an arbitrary number of web services each in it's own VM or container and served using single public ipv4! That would be truly exciting news for self-hosters.

@tobya

This comment has been minimized.

Copy link
Collaborator

commented Apr 13, 2017

@yura8 can you provide a little more detail of what specifically you would like to see.

@yura8

This comment has been minimized.

Copy link

commented Apr 14, 2017

@tobya

Dedicated server with 1 public IP. Install Proxmox on it. Then install Caddy on the host node or inside a container inside the hypervisor. Use Caddy as a transparent proxy for containers/KVMs with NextCloud, RSS, Plex, Seafile, Koel, Calibre, Wger, et cetera. One container for each application with it's own webserver and database.

Each time new VM with a new application would be spin up in Proxmox Caddy will acquire certificate for new subdomain-hostnode (tv.example.com) and transparently proxy all ports needed for this application without virtualized application and/or it's webserver being aware of it. Automagically :)

@mholt

This comment has been minimized.

Copy link
Owner

commented Apr 14, 2017

Obtaining the certificate dynamically can already be done

🔳 But proxying to a dynamic backend is what requires a redesign of the Proxy middleware; the type is called "StaticUpstream" because it is static, not dynamic.

@yura8

This comment has been minimized.

Copy link

commented Apr 14, 2017

DynamicUpstream would be neat. I read the corresponding PR where you stated that redesign of middleware would be required and I posted here to inquire if such changed happened since last year's discussion or not.

Just throwing it out there, this feature would be very popular and useful. Kudos to all Go developers, hope this will be implemented someday.

@mholt mholt added this to the 2.0 milestone May 9, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.