33

So I'm setting up a virtual path when pointing at a node.js app in my nginx conf. the relevant section looks like so:

location /app {
  rewrite /app/(.*) /$1 break;
  proxy_pass http://localhost:3000;
  proxy_redirect off;
  proxy_set_header Host $host;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

Works great, except that when my node.js app (an express app) calls a redirect.

As an example, the dev box is running nginx on port 8080, and so the url's to the root of the node app looks like:

http://localhost:8080/app

When I call a redirect to '/app' from node, the actual redirect goes to:

http://localhost/app

  • Here some answers that suggest use: proxy_set_header Host $http_host; But no one said that it can cause vulnerability (host header attack). Attack example here And more info here – user515775 Mar 24 at 10:46
14

The problem is that the Node.js application is not issuing the redirect correctly. You may be able to use proxy_redirect to correct this in nginx:

proxy_redirect http://localhost/ http://localhost:8080/;
46

I just had to solve the same problem with Jenkins running behind nginx. What did it for me was to include the server port into the Host header that's being sent to Jenkins:

proxy_set_header Host $host:$server_port;

Hope that helps.

  • 3
    Bingo. as @mgorven says, node is setting the redirect badly, because nginx is forwarding the host badly – Eric Oct 5 '14 at 18:54
39

I had this problem and using $http_host instead of $host worked for me, as it also includes the port number.

  • 1
    this solution worked for me. – Kita Jun 21 '16 at 10:23
  • 11
    This is better than $host:$server_port because it uses the port as present in the URL, unlike $server_port which uses the port that nginx listens on. The difference becomes real when you're connecting to nginx reverse proxy through another port map, e.g. ssh -L or Docker ports. – Jozef Oct 15 '16 at 20:00
  • @JozefKnaperek, could you please explain your comment a bit more (maybe with an example and with some references?). I find it very interesting and it should be a separate answer, or at least to edit this answer. Not only a comment. – Mohammed Noureldin Jan 4 '18 at 1:42
  • 1
    Not much to say further. $http_host holds the value as specified in HTTP HOST header, that's why it works even if you have port redirects in between your nginx and the user agent. – Jozef Jan 5 '18 at 7:35
  • 2
    @JozefKnaperek makes a great point here. This was required for me when running behind Docker (basically another layer of reverse proxying) since Docker rewrites the port when directing traffic to the container. – Mike Hill Apr 23 '18 at 16:15
5

I tried the above solutions, but they all failed whenever the node application issued a fully qualified URL in the location header, such as "http://nodeapp.com:8080/new/location"

So I wound up using the $http_host to pass host and port. And using a match ~^ to rewrite the urls entirely.

  proxy_pass http://10.0.0.3:8080;

  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header Host $http_host;

  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

  proxy_redirect default;
  proxy_redirect ~^(https?://[^:]+):\d+(?<relpath>/.+)$ http://10.0.0.3:8000$relpath;

In our case, the Node server is running on 8080, and our nginx proxy is running on 8000. This means that every fully qualified URL in a location header needs to be re-written. Hope this helps someone !!

1

Per the conversation on this question, the proper resolution is to adjust the proxy's Host header directive.

Change this:

proxy_set_header Host $host;

To this:

proxy_set_header Host $http_host;

$http_host holds the value as specified in HTTP HOST header, which includes the port. Redirects should pick up the custom port without further customization to OP's setup.

These answers (same ticket) elaborate further:

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.