Score:1

How to proxy the full url at nginx config?

ve flag

I need to proxy locations /v1/api/ to another url as:

location /api/v1/ {
        proxy_pass http://frontend-api.preprod.my-app.com/api/v1/;
    }

however, at the mainstream, only the slug is received:

"GET /api/v1/ HTTP/1.1" 404 209 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36"

because the upstream is configured to the specific domain frontend-api.preprod.my-app.com:

server {
    listen 80;
    server_name frontend-api.preprod.my-app.com;

   location / {
      root /var/www/frontend_api/current/public;

      # Turn on Passenger
      passenger_enabled on;
      passenger_ruby /home/deploy/.rvm/gems/ruby-2.7.2/wrappers/ruby;
    }

}

the final result is 404, How would configure proxy_pass at the proxy server to send the host as well, so that the receiving server receives the full url instead of just the /api/v1/ ?

Score:2
us flag

nginx documentation explains the behavior:

If the proxy_pass directive is specified with a URI, then when a request is passed to the server, the part of a normalized request URI matching the location is replaced by a URI specified in the directive:

In your case, it means that the request URI is replaced by the /api/v1/ URI specified in your proxy_pass directive.

If you want the URI to be passed as-is, then you need to do:

location /api/v1/ {
    proxy_pass http://frontend-api.preprod.example.com;
}

In this case, nginx uses the URI from the original request with the proxy_pass destination, as described by:

If proxy_pass is specified without a URI, the request URI is passed to the server in the same form as sent by a client when the original request is processed, or the full normalized request URI is passed when processing the changed URI:

If you want to replace part of the request URI with different part, you need to use regular expression capture:

location ~ ^/source/path/(.*) {
    proxy_pass http://example.com/destination/path/$1;
}

Edit:

To get the domain name of the original request passed to the upstream, one needs to set the Host HTTP header for the upstream request:

proxy_set_header Host       $host;

It is often useful to pass also the IP address of the visitor via header:

proxy_set_header X-Forwarded-For $remote_addr;
simo avatar
ve flag
I tried `proxy_pass http://frontend-api.preprod.example.com;` but at the other side, I still get the same result. I don't have an issue with passing the slug, the issue is that the base url is not passed, only`/api/v1/` is seen at the receiving server, not `http://frontend-api.preprod.example.com/api/v1/`
us flag
You cannot pass the full URL as URI to the request to the backend. To get the host name, you need to use HTTP headers. I added an example to the answer.
simo avatar
ve flag
Thanks, I tried setting the Host header to $host, however, after that, I can't see the logs coming in the access.log of the receiver nginx!
us flag
Then your virtual host name setting in receiver nginx is not correct.
simo avatar
ve flag
Thank you, there were an issue..
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.