Phoenix: Host based routing

Created on 28 Nov 2014  路  11Comments  路  Source: phoenixframework/phoenix

It would be useful to have some way to route on the host as well as the path, so that routing for subdomains or hosting multiple sites is straightforward.

Workaround suggested by chrismccord for now is to use a :before pipeline to add the host into the path for matching inside scope. (https://gist.github.com/chrismccord/94c65dc2b61631210d3d)

Most helpful comment

This has been pushed out with the 0.6.1 release and case be used like this:

defmodule MyApp.Router do
  use Phoenix.Router
  # full host match
  scope "/", host: "host.com" do
    resources "/users", MyApp.UserController
  end

  # partial host match, i.e., matches `subdomain.foo.com`
  scope "/", host: "subdomain." do
    resources "/users", MyApp.UserController
  end
end

All 11 comments

I'm not thrilled with this hack, but it should work today if needed:

defmodule MyApp.Router do
  use Phoenix.Router

  pipeline :before do
    plug :prepend_host_to_path
  end

  scope "/www.host1.com" do
    resources "/users", MyApp.UserController
  end

  scope "/www.host2.com" do
    resources "/users", MyApp.UserController
  end



  defp prepend_host_to_path(conn, _) do
    %Conn{path_info: [conn.host | conn.path_info]}
  end
end

This is something we should be able to match on without sacrificing perf. Something like:

defmodule MyApp.Router do
  use Phoenix.Router

  scope "/", host: "www.host1.com" do
    resources "/users", MyApp.UserController
  end
  # OR we detect the host pattern from the scope arg
  scope "www.host2.com/" do
    resources "/users", MyApp.UserController
  end
end

Internally we could add conn.host to a matched arg.
// @josevalim

I think we can just add conn.host as matched arg indeed. For now, we can support two different matches:

  1. host: "foo." - the host needs to start with "foo."
  2. host: "foo.bar.com" - full match on the host

This should be fairly straight-forward to add. Thoughts?

I didn't even think about the "foo." case. Nice! I'm :+1: on adding this. I can add it to my list.

This has been pushed out with the 0.6.1 release and case be used like this:

defmodule MyApp.Router do
  use Phoenix.Router
  # full host match
  scope "/", host: "host.com" do
    resources "/users", MyApp.UserController
  end

  # partial host match, i.e., matches `subdomain.foo.com`
  scope "/", host: "subdomain." do
    resources "/users", MyApp.UserController
  end
end

Was just referred to this issue off Slack re vhost support in Phoenix - was wondering what the rationale behind using prefix vs least-to-most-specific hostname logic (a la DNS resolution) wasn't used? A more common use case I've seen in many multihost builds I've been involved in is where there is default logic for a less-specific hostname, and overrides for more-specific. For example, default behavior for "bar.com" and overrides for "*.bar.com" in the case of "vanity" hostnames.

Great question @arpieb. The rationale is that we use domains in our applications often to handle different panels like "admin.", "settings." and so on. Also, we can only optimize prefix calls, it is quite hard to optimize suffix ones (but it can be done). :)

Out of interest, what if those multiple sites need SSL certificates? Or are multi-domain certs an easier option?

Any way to wildcard route on subdomain. I am trying to route all requests with a subdomain to one set of functions(subdomains are dynamic) and route anything missing a subdomain to another set of functions.

@jpiepkow Like with the original example you can do it via a function plug. :-)

If you ask this on the https://elixirforum.com/ then you should get an example and all. :-)

@jpiepkow Here's a very good article that I followed: http://blog.gazler.com/blog/2015/07/18/subdomains-with-phoenix/

Thanks that answered my question perfectly.

Was this page helpful?
0 / 5 - 0 ratings