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

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

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;
}

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

Related

Redirecting request fails with 503 Service Unavailable in NGINX

I'm trying to redirect the requests between lower and Prod environments, which gives 503 service unavailable error.
It seems the requests is still going to lower environment I've another location block for /api/ which drives the request to lower APIGW where the actual uderlying service doesn't exist.
Having NGINX as proxy server which redirects requests to Microservices hosted on Rancher platform through API Gateway.
PFB location block I've added to redirect the request URI which comes in to NGINX, to Prod APIGW.
location = /testdetail {
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Content-Length "";
proxy_set_header Host $host;
proxy_set_header X-Original-URI-NGINX $request_uri;
proxy_set_header X-Forwarded-For-NGINX $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto-NGINX $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Authorization $http_authorization;
proxy_pass_header Authorization;
proxy_pass https://apigateway.xxx.xxx.com/test/***/***/***/***/testdetail;
proxy_pass_request_body off; # no need to send the POST body
}
In addition to it, there is another location block for /api/.
location /api/ {
proxy_http_version 1.1;
proxy_set_header Connection "";
auth_request /validate;
auth_request_set $auth_status $upstream_status;
proxy_set_header AuthStatus $upstream_status;
**proxy_pass https://apigateway-preview.xxx.xxx.com/;**
proxy_pass_request_headers on;
#proxy_connect_timeout 800;
proxy_read_timeout 90;
#proxy_send_timeout 800;
#proxy_redirect off;

Running Swift Perfect and NGINX

So I have a Swift server-side app running on my Ubuntu box, it's using the Perfect Framework and runs on port 8080.
I want NGINX to forward requests on port 80 to port 8080 (behind the scenes)
My config is
server {
listen 80;
server_name burf.co;
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 90;
} }
I have done similar things with VueJS, Node etc but for what am I missing here?
Is it a Perfect issue?
When I go to 127.0.0.1:8080 the page renders fine

Mixed HTTP / HTTPS content with Gitlab behind a reverse proxy

I'm running sameersbn/docker behind a nginx reverse proxy, but I get a mixed content warning on the avatar image.
No matter what I try, it is either the mixed content warning or a too many redirects error page.
I forward my http traffic automatically in nginx with this config:
server
{
listen 80;
server_name myserver.com;
return 301 https://myserver.com$request_uri;
}
server
{
listen 443 ssl;
server_name myserver.com;
ssl on;
ssl_certificate myserver.cert.combined;
ssl_certificate_key myserver.key;
include nginx_php.conf;
location / {
proxy_set_header X-Forwarded-Proto: https;
proxy_set_header X-Forwarded-Ssl: on;
proxy_pass http://127.0.0.1:10080;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
include /etc/nginx/webapps.ssl.conf;
}
As soon as I run my gitlab container with the following options, I get the too many redirects
- GITLAB_HTTPS=true
- SSL_SELF_SIGNED=false
- GITLAB_HOST=myserver.com
- GITLAB_PORT=443
- GITLAB_SSH_PORT=22
What am I doing wrong here?
And why does Gitlab try to load the avatar over http?

Nginx, gunicorn, python-flask application. Https is lost on redirect

I am having some troubles with my application. During redirects my flask application lose the https and redirect to http instead.
I've been trying to find the solution but nothing works.
My nginx configuration for the application (location /) is as follows:
proxy_pass http://localhost:5400;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-port 443;
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Forwarded-Protocol $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
(Some examples on the internet says to use "X-Forwarded-Proto". I've tried that without success. And also to use "ssl" or "https" as value on that parameters.
A simple print in the flask application (before_request:) shows that it is still http-requests made event though i use https between client and nginx.
print(request.environ["wsgi.url_scheme"])
What am I doing wrong?
If your application ignores the X-Forwarded headers for setting the scheme in http 3xx responses, you could try setting one or more proxy_redirect rules:
proxy_redirect http:// $scheme://;
See this document for details.
Warning. Making unwanted HTTP redirects is a security flaw as in those requests the connection is not encrypted!!
The only solution here is to correctly configure NGINX and GUNICORN to allow Flask to use the correct headers.
NGINX config should contain at least following directives:
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $http_host;
proxy_pass http://appserver:5000;
And, this is the real solution here, GUnicorn must be started with the --forwarded-allow-ips parameter.
Following is how I start it in production, fixing also the real IP address in logs (beware to complain to the GDPR :P ):
PYTHONUNBUFFERED=FALSE gunicorn \
--access-logfile '-' \
--access-logformat '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" "%({X-Real-IP}i)s"' \
-b :5000 \
--forwarded-allow-ips="*" \
app:app
You should NEVER send a request in HTTP. The first and only redirect should be the /.

Nginx sometimes misteriously redirect to backend internal url

I have a very annoying problem, i use nginx to proxy a apache server(http://internalip.com:18080), the config is like this:
location /svn {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://internalip.com:18080;
}
It is ok most-timely, but sometimes nginx just redirect user to internal address, so the user will be prompt error.
I don't know what's wrong, it just is being happening.
The nginx version is 1.4.4-4~precise0.
Could anybody know this?
Thanks in advance!
I have found out the problem. The key point is the Apache DirectorySlash, if I visit https://outipaddress.com/theurl, apache will redirect to http://internalip.com:18080/theurl/ even if the X-Forword-* headers are set. I think it is a bug of apache httpd.
The workaround is to perform the redirect on nginx side.
`location /svn/ {
if ($request_uri ~ "/[a-zA-Z0-9-_]+$") {
rewrite ^ https://$server_name$request_uri/;
}
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://internalip.com:18080;
}`
Now nginx will redirect all urls that are not ended with slash and seem like a directory(contain only symbol characters).