How would I set `host` attribute in %Plug.Conn{} under reverse proxy?

TLDR: I have an nginx reverse proxy setup for a phoenix app. Because of the reverse proxy upstream setting the host attribute in %Plug.Conn{} is set to phoenix. I assume that comes from the name given to the upstream nginx setting. In this case: http://phoenix

Long-winded version

I have this configuration for nginx reverse proxy:

location / {
  allow all;
  proxy_http_version 1.1;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header X-Cluster-Client-Ip $remote_addr;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection "upgrade";
  proxy_pass http://phoenix;
}

That forwards to localhost on the server. When I inspected the contents of %Plug.Conn{} or @conn as we typically have it set in a controller, the value for the host attribute is phoenix, not the domain name set in Endpoint host configuration. I am wondering if that is expected and if there is a special configuration for that under a reverse proxy.

The reason this was an issue for me (this is going to get less and less relevant) is because I am using Auth0 for authentication with ueberauth as the API wrapper. Things are working locally but I ran into issues on a server where the callback host was set to phoenix. After a bit of digging I figured out that ueberauth is getting it from the %Plug.Conn{}

I made my own plug as a workaround that sets the host attribute:
%Plug.Conn{conn | host: Application.get_env(:my_app, MyAppWeb.Endpoint)[:url][:host]}

That works but feels a bit silly.

I figured it is very likely that I am doing something wrong, like not setting a correct proxy header on nginx. Appreciate any help!

As the plug documentation states, Plug.Conn.host is the host from the request, as your RP knows your backend only under the name “phoenix” it uses that name in the http request.

You either need to configure your RP to set the host to a different value, or find a configuration option in ĂĽberauth that allows you to set the callback URLs directly.

I skimmed the überauth docs but was unable to find something that would help, though it might also be a setting in the providers… If there indeed is no way to configure the host, then an issue at überauth should be created.

1 Like

proxy_set_header Host $host; on nginx.

2 Likes

Thank you so much for looking into it. I couldn’t find a way to configure the host. Most configuration options involve paths. Maybe that is a feature (from security perspective)

Thank you!