Sorc96

Sorc96

VerifiedRoutes.url used behind reverse proxy

I’ve encountered an issue with VerifiedRoutes.url when the application is running behind nginx. I need to send a link via e-mail, so I generate the url with url(~p/some_path/), which returns http://myapp.com:5000/some_path, since the endpoint itself is using http and the port is set to 5000. Of course, what I actually need is https://myapp.com/some_path

I have nginx configured to send the X-Forwarded-For header, so the application knows the actual address that is visible to users. Is there an easy way to make url use this information instead of the endpoint config? Or should I make a custom helper instead?

Marked As Solved

ibarch

ibarch

I haven’t tested it myself, but I guess that if you configure Nginx to pass the x-forwarded-port header, and apply Plug.RewriteOn plug in the endpoint, the url helpers will generate links with the appropriate port(s).

Also Liked

voltone

voltone

This configuration might fix the generated URLs, but it does not solve the underlying issue that Phoenix does not know that the server was actually reached via HTTPS. As a result, certain security features are not enabled. In particular, (session) cookies do not get the secure option that is meant to prevent them from leaking in plaintext HTTP requests.

For more details, see TLS Vulnerabilities | EEF Security WG

The better solution is the use of HTTP headers to pass the external scheme and port from the reverse proxy to the application, as suggested by @ibarch

garrison

garrison

The URL generation is controlled by the Endpoint configuration (specifically the :url option). The value is configured in runtime.exs by default. This option only controls URL generation (for links in the app), it does not configure the webserver (that’s the :http option right below it).

I’m assuming from your post that you changed it thinking it was the webserver configuration, so if that’s the case changing it back to the default should resolve the problem :slight_smile:

(Also: If this is the case, the links in your app should all be wrong too, right?)

For the record, you could also pass a few other things into url/2 if you needed to, like a conn / socket, a different endpoint, or a URI. But I don’t think that’s what you need here.

Not sure I understand what you mean here. X-Forwarded-For contains the original client IP address(es) from the original request (and any proxies in between). The host/port are sent via the Host header, which I assume Nginx just passes along in the proxied request.

Either way, by default the URL generation is controlled by the Endpoint config.

Sorc96

Sorc96

So I think the confusion has been explained. The scheme option worked as expected, but it seems that the port from the http config gets used for url generation as well, so I had to explicitly set it to 443. Thanks for the help, this is what the config looks like in case anyone else gets confused:

config :myapp, MyappWeb.Endpoint,
  url: [
    scheme: "https",
    host: "myapp.com",
    port: 443
  ],
  http: [port: 5000]

Also, to explain why I never noticed it from links in the application itself, it’s because they only need ~p unlike links in e-mails, which need the full url, so the incorrect options never manifested.

Last Post!

garrison

garrison

I came across a couple things today which I figured I should post here for the sake of completeness.

First, Caddy actually does pass along the original Host header by default like I had thought before, though it of course also sets X-Forwarded-*. Nginx, on the other hand rewrites the header by default.

Second, there is actually a case where you do need to rewrite the Host header: if you are using HTTPS to encrypt traffic between the reverse proxy and your webserver, you need to set the Host to match the cert! In this case you would be forced to rely on X-Forwarded-Host to know the real host.

Where Next?

Popular in Questions Top

lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New
mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
New
PeterCarter
There are pre-rolled solutions for other frameworks that do work. However, Phoenix does not seem to have these. Have people had good expe...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
marius95
Hello everyone, I try to use an Javascript Event Handler in my root.html.leex file. Therefore I created a function in the app.js file: ...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
dblack
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar. I p...
New

Other popular topics Top

vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New

We're in Beta

About us Mission Statement