115

I was trying to use Thin app server and had one issue.

When nginx proxies the request to Thin (or Unicorn) using proxy_pass http://my_app_upstream; the application receives the modified URL sent by nginx (http://my_app_upstream).

What I want is to pass the original URL and the original request from client with no modification as the app relies heavily on it.

The nginx' doc says:

If it is necessary to transmit URI in the unprocessed form then directive proxy_pass should be used without URI part.

But I don't understand how exactly to configure that as the related sample is actually using URI:

location /some/path/ { proxy_pass http://127.0.0.1; } 

So could you please help me figuring out how to preserve the original request URL from the client?

2
  • "Thin" now points to a 404 Commented Feb 16, 2022 at 8:18
  • "the related sample is actually using URI" ... I think nginx's docs are always a bit confusing here, and seem to use URI to mean "path and query" but not "protocol, host, and port". So, that example isn't using an "URI-in-nginx-sense". See also the answer below: stackoverflow.com/a/56175391/196315 Commented Oct 25, 2024 at 17:11

8 Answers 8

182

I think the proxy_set_header directive could help:

location / { proxy_pass http://my_app_upstream; proxy_set_header Host $host; # ... } 
Sign up to request clarification or add additional context in comments.

7 Comments

Note to other people finding this: The heart of the solution to make nginx not manipulate the URL, is to remove the slash at the end of the proxy_pass directive. http://my_app_upstream vs http://my_app_upstream/
For me what was happening is that when JSP was doing redirect, my_app_upstream host name was showing up. Using proxy_set_header Host $host modified and made Tomcat/JSP to think that it's an actual client requested domain. Thanks for the help
In my case, @HugoJosefson's solution would not work. I was pointing to localhost:port; I had to set the header.
It's an improvement but the scheme (http or https) is not preserved. Now my https://example.com/page uris become http://example.com/page
@HugoJosefson should be knighted
|
15

Just proxy_set_header Host $host miss port for my case. Solved by:

 location / { proxy_pass http://BACKENDIP/; include /etc/nginx/proxy.conf; } 

and then in the proxy.conf

 proxy_redirect off; proxy_set_header Host $host:$server_port; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 

Update according @iwein comment for nginx 1.8.x (see https://stackoverflow.com/a/57350306/548473):

iso proxy_set_header Host $host:$server_port; use proxy_set_header Host $http_host

3 Comments

Thanks, this was the piece I was missing (the $server_port) to get OAuth verification working on the endpoint behind the proxy.
I'm using rack-protection with sinatra and was getting Forbidden on POST URLs. Adding the port to the Host proxy header fixed it for me.
this doesn't work anymore in latest versions of Nginx I think stackoverflow.com/questions/31482796/…
13

nginx also provides the $http_host variable which will pass the port for you. its a concatenation of host and port.

So u just need to do:

proxy_set_header Host $http_host; 

Comments

10

In case something modifies the location that you're trying to serve, e.g. try_files, this preserves the request for the back-end:

location / { proxy_pass http://127.0.0.1:8080$request_uri; } 

Comments

9

Note to other people finding this: The heart of the solution to make nginx not manipulate the URL, is to remove the slash at the end of the Copy: proxy_pass directive. http://my_app_upstream vs http://my_app_upstream/ – Hugo Josefson

I found this above in the comments but I think it really should be an answer.

Comments

6

To perfectly forward without chopping the absoluteURI of the request and the Host in the header:

server { listen 35005; location / { rewrite ^(.*)$ "://$http_host$uri$is_args$args"; rewrite ^(.*)$ "http$uri$is_args$args" break; proxy_set_header Host $host; proxy_pass https://deploy.org.local:35005; } } 

Found here: https://opensysnotes.wordpress.com/2016/11/17/nginx-proxy_pass-with-absolute-url/

3 Comments

Velkan, but why it is cannot be done in one rewrite?
@MikhailPolitaev the first "rewrite" seems unnecessary. The source article has a "break" in the first "rewrite" and a comment that says to remove that "break" to make it work. So the source isn't really reliable.
First break is unnecessary, agreed. But already realized why 2 rewrite required. Because if rewrite start with "https://" Nginx will respond 301 or 302 to the client and here 2 rewrite split https:// to 2 parts "https" and "://" in result redirect not returned to the client and send in absolute form "https://..." in GET request what is required by proxy protocol. I didn't find another way how to make GET request in absolute form – starts with scheme http(s):// it's strange that not obvious in Nginx.
2

In my scenario i have make this via below code in nginx vhost configuration

server { server_name dashboards.etilize.com; location / { proxy_pass http://demo.etilize.com/dashboards/; proxy_set_header Host $http_host; }} 

$http_host will set URL in Header same as requested

Comments

-1

for my auth server... this works. i like to have options for /auth for my own humanized readability... or also i have it configured by port/upstream for machine to machine.

.

at the beginning of conf

#################################################### upstream auth { server 127.0.0.1:9011 weight=1 fail_timeout=300s; keepalive 16; } 

Inside my 443 server block

 if (-d $request_filename) { rewrite [^/]$ $scheme://$http_host$uri/ permanent; } location /auth { proxy_pass http://$http_host:9011; proxy_set_header Origin http://$host; proxy_set_header Host $http_host:9011; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $http_connection; proxy_http_version 1.1; } 

At the bottom of conf

##################################################################### # # # Proxies for all the Other servers on other ports upstream # # # ##################################################################### ####################### # Fusion # ####################### server { listen 9001 ssl; ############# Lock it down ################ # SSL certificate locations ssl_certificate /etc/letsencrypt/live/allineed.app/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/allineed.app/privkey.pem; # Exclusions include snippets/exclusions.conf; # Security include snippets/security.conf; include snippets/ssl.conf; # Fastcgi cache rules include snippets/fastcgi-cache.conf; include snippets/limits.conf; include snippets/nginx-cloudflare.conf; ########### Location upstream ############## location ~ / { proxy_pass http://auth; proxy_set_header Origin http://$host; proxy_set_header Host $host:$server_port; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $http_connection; proxy_http_version 1.1; } if (-d $request_filename) { rewrite [^/]$ $scheme://$http_host$uri/ permanent; } } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.