Reputation: 113
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
Upvotes: 3
Views: 1286
Reputation: 18792
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;
}
Upvotes: 2
Reputation: 389
This likely happens because your backend server thinks the request is http and redirects it to https. Try adding this in your location block:
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
It lets your backend server know that the request is in fact coming with https but tls is terminated further up (in most cases you have to whitelist your proxyserver to make it work).
According to this answer you can do that like this in application.properties:
server.use-forward-headers=true
Upvotes: 2