Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to reroute POST/PUT/... in Nginx to internal service?

I have a server (ubuntu 20.04 core) with nginx installed. On the same server I have a running Spring Boot Web(2.3.3.RELEASE) service on port 8080.

I want to access the resources from the Spring Boot Web service externally with e.g. http://server/api/users to access http://localhost/api/users and return that response to the client.

I have the following rule configured in nginx:

location /api {
    proxy_pass http://localhost:8080;
}

This works fine for GET request, but doesn't for POST or PUT. The first response to the client is a response with status code 301: Moved permanently and according to HTTP spec a client should change the HTTP method to either GET or HEAD. The client changes the method automatically after the first response as seen in the nginx logfile at /var/log/nginx/access.log:

192.168.0.1 - - [14/Oct/2020:11:23:56 +0100] "POST /api/users?key=key HTTP/1.1" 301 162 "-" "PostmanRuntime/7.26.5"
192.168.0.1 - - [14/Oct/2020:11:23:56 +0100] "GET /api/users?key=key HTTP/1.1" 200 93 "http://server/api/users?key=key" "PostmanRuntime/7.26.5"
192.168.0.1 - - [14/Oct/2020:11:23:59 +0100] "PUT /api/users/1/deleted?key=key&deleted=false HTTP/1.1" 301 162 "-" "PostmanRuntime/7.26.5"
192.168.0.1 - - [14/Oct/2020:11:23:59 +0100] "GET /api/users/1/deleted?key=key&deleted=false HTTP/1.1" 405 141 "http://server/api/users/1/deleted?key=key&deleted=false" "PostmanRuntime/7.26.5"

The GET-Request from the PUT-Request failed with 405 because theres no mapped GET for path "/api/users/{id}/deleted". I tried adding and modifing many different configurations in the "location /api {..}" for example:

location /api {
  proxy_pass      http://localhost:8080;
  proxy_redirect  http://localhost:8080/ /; # I tried "../api /", ".../api/ /", ".../ /api" 
  proxy_read_timeout 60s;

  proxy_set_header          Host            $host;
  proxy_set_header          X-Real-IP       $remote_addr;
  proxy_set_header          X-Forwarded-For $proxy_add_x_forwarded_for;
}

Suggested in serverfault(how do I get nginx to forward HTTP POST requests via rewrite?)

I found the exact same question on trac.nginx.com but that config didn't work either:

location /api { # "/api" and "/api/" doesn't work
    proxy_pass ​http://localhost:8080;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
}

I am currently quite lost with what else I should try to get it to work.

--- EDIT: With the help of @ti7 and @ampularius the working solution now is:

NGINX location entry:

location /api {
    proxy_pass http://localhost:8080;
    proxy_redirect off;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Port  $server_port;
}

And in application.properties of the Spring Boot Service no changes were made, so NONE of these settings does anything for this case:

server.use-forward-headers=true
server.forward-headers-strategy=native
server.forward-headers-strategy=framework
server.forward-headers-strategy=none
like image 929
Blauspecht Avatar asked Oct 15 '25 14:10

Blauspecht


1 Answers

Recently I've been working a good deal with the excellent Gunicorn WSGI server with an nginx frontend.

The deploy docs suggest disabling proxy_redirect with proxy_pass and the Host header set, which could be the source of your troubles!

This has been working great to handle POST and GET requests, albeit with a wildly-different webserver.

location @proxy_to_app {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Host $http_host;
    # we don't want nginx trying to do something clever with
    # redirects, we set the Host: header above already.
    proxy_redirect off;
    proxy_pass http://app_server;
}
like image 89
ti7 Avatar answered Oct 17 '25 08:10

ti7