get Client IP in a flask based application - nginx

I have Flask application deployed in server. and we are using Nginx. nginx setup is as below:
proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_read_timeout 25s;
proxy_pass http://127.0.0.1:8000;
add_header X-Cache $upstream_cache_status;
In Flask setup I have done the following :
app = Flask(__name__, static_folder=None)
app.wsgi_app = ProxyFix(app.wsgi_app)
Now, whenever user visits a site, I want a real ip. Currently I am getting
127.0.0.1
I have tried like below:
if request.headers.getlist("X-Forwarded-For"):
ip = request.environ['HTTP_X_FORWARDED_FOR']
else:
ip = request.remote_addr
Could anybody guide me here please.

Use request.access_route
https://github.com/pallets/werkzeug/blob/master/werkzeug/wrappers.py
#cached_property
def access_route(self):
"""If a forwarded header exists this is a list of all ip addresses
from the client ip to the last proxy server.
"""
if 'HTTP_X_FORWARDED_FOR' in self.environ:
addr = self.environ['HTTP_X_FORWARDED_FOR'].split(',')
return self.list_storage_class([x.strip() for x in addr])
elif 'REMOTE_ADDR' in self.environ:
return self.list_storage_class([self.environ['REMOTE_ADDR']])
return self.list_storage_class()
Example Nginx config:
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Protocol https;
proxy_set_header X-Real-IP $remote_addr;
proxy_redirect off;
proxy_pass http://127.0.0.1:9000;
}

You should just have:
ip = request.access_route[-1]

Related

nginx proxy_pass to https / image-server not working

I'm trying to proxy an image server imagekit.io so that all requests have same domain name.
Have tried multiple configurations in HTTPS nginx server (with self-signed certificate) and even in HTTP server.
Let's say the URL is https://ik.imagekit.io/hj8sm3kk7/brochures/92/1579/suzuki-gsx-r150-615123.pdf
With the below configuration, I'm trying to hit http://localhost.com:8800/brochures/92/1579/suzuki-gsx-r150-615123.pdf
server {
listen 8800;
server_name localhost.com;
location /brochures {
proxy_ignore_headers Set-Cookie;
proxy_set_header Host ik.imagekit.io;
# proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Pragma no-cache;
proxy_set_header Accept $http_accept;
proxy_set_header User-Agent $http_user_agent;
proxy_set_header Accept-Encoding $http_accept_encoding;
proxy_set_header Accept-Language $http_accept_language;
proxy_set_header sec-fetch-mode navigate;
proxy_set_header sec-fetch-site cross-site;
proxy_set_header sec-fetch-user ?1;
proxy_set_header :authority ik.imagekit.io;
proxy_set_header :method GET;
proxy_set_header :path $path;
proxy_set_header :scheme https;
proxy_set_header Upgrade-Insecure-Requests 1;
proxy_pass https://ik.imagekit.io/hj8sm3kk7/brochures;
}
}
This however works:
http://localhost.com:8800/financial-advisor/mfs-investment-management-review opens the same page as https://smartasset.com/financial-advisor/mfs-investment-management-review
location /financial-advisor {
proxy_ignore_headers Set-Cookie;
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_pass https://smartasset.com;
}
The real issue turned out to be an SSL problem with ik.imagekit.io, using http:// instead of https:// in the proxy_pass value helps.
Original (and wrong) answer I've given:
The first example requires a manipulation of the URL path. Consider a similar approach:
location ~ ^/(brochures/.*) {
# all the previous config you used should be added here
proxy_pass https://ik.imagekit.io/hj8sm3kk7/$1;
}
This will proxy the request to the proper URL path, which changes from the original request. $1 is the part of the request URL path that matches the first brackets (...).

Airflow + Nginx set up gives Airflow 404 = lots of circles

I'm trying to set up Airflow behind nginx, using the instructions given here.
airflow.cfg file
base_url = https://myorg.com/airflow
web_server_port = 8081
.
.
.
enable_proxy_fix = True
nginx configuration
server {
listen 443 ssl http2 default_server;
server_name myorg.com;
.
.
.
location /airflow {
proxy_pass http://localhost:8081;
proxy_set_header Host $host;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Forwarded-Proto "https";
}
}
Airflow webserver and scheduler are up and running as systemd. When I try to access https://myorg.com/airflow/, it gives Airflow 404 = lots of circles.
What could be wrong? Really appreciate your help in getting this running.
I just had the same problem and fixed it by adding a tailing / to the location: location /airflow/ { instead of location /airflow {. The tailing backslash tells nginx to remove the preceeding /airflow in uri paths to the corresponding python app.
My overall config looks as follows:
server_name my_server.my_org.net;
location /airflow/ {
proxy_pass http://localhost:9997;
proxy_set_header Host $host;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
In airflow.cfg I additionally specified:
base_url = http://my_server.my_org.net/airflow
enable_proxy_fix = False # Seems to be deprecated?
web_server_port = 9997
I run into the same problem using https.
But using the configuration in the solution led me to another problem.
Anything other than /airflow/ location falls back to / location.
Returning 404 errors to assets.
Using the configuration bellow solved the issue:
location ^~ /airflow/ {
proxy_pass_header Authorization;
proxy_pass http://localhost:8080/airflow/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host:$server_port;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_http_version 1.1;
proxy_redirect off;
proxy_set_header Connection "";
proxy_buffering off;
client_max_body_size 0;
proxy_read_timeout 36000s;
}

Modify request body before PROXY_PASS

I have nginx setup that passes all request to nodejs, however I want to modify request body in nginx before passing it to nodejs. Like if body has http://www.example.com then replace it with https://www.example.com
Here is my nginx configuration:
location / {
proxy_pass http://127.0.0.1:8008;
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 ;
proxy_set_header X-Forwarded-Proto https ;
}

Same location with different proxy urls nginx

We am trying to get nexus via nginx reverse proxy working as a private registry for docker images. We are able to perform all the operations such as pull,search and tag but not able to push to nexus registry .
Below is the nginx configuration under location block.
location ~ ^/(v1|v2)/
{
proxy_set_header Host $http_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 "https";
proxy_pass http://box.company.net:5555;
proxy_read_timeout 90;
}
We are able to search and pull images.
But with push we face below error.
x.x.x.x - admin [23/Jun/2017:14:32:34 +0800] "POST /v2/fedora/apache/blobs/uploads/?from=fedora%2Fssh&mount=sha256%3Aacd6cf67daf4cd1fcff55ece5a906a45e1569b81271b80136a1f5fecfa4546ed HTTP/1.1" 404 717 "-" "docker/1.12.6 go/go1.7.4 kernel/3.10.0-514.10.2.el7.x86_64 os/linux arch/amd64 UpstreamClient(Docker-Client/1.12.6 \x5C(linux\x5C))"
when we try with proxy _pass url as http://box.company.net:4444, we are able to push but cant pull the images .
Is it possible in nginx to pass two different proxy_pass urls under the same location but for different request methods . Any help would be really great ..Thanks
#sempasha : Thanks for you help . It working for me just with a minor tweak .
Below is the location block added to get it working.
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
if ($request_method !~* GET) {
proxy_pass http://box.company.net:4444;
}
if ($request_method = GET) {
proxy_pass http://box.company.net:5555;
}
proxy_read_timeout 90;
}
You can use if or map directives to select backend port.
Note, that If is Evil, not in you case of course.
location ~ ^/(v1|v2)/
{
set $port 5555;
if ($request_method = POST) {
set $port 4444;
}
proxy_set_header Host $http_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 "https";
proxy_pass http://box.company.net:$port;
proxy_read_timeout 90;
}

NGINX => serve several applications on a single host name with sub-uris

I'd like to serve several applications from the same server, reversed-proxied through nginx. I'd like these applications to be available through a single domain name with sub-uris.
e.g.
www.mydomain.com/nodejs
=> caught by nginx listening to port 80 and served through to a node.js app running on port 3001
www.mydomain.com/rails
=> caught by nginx listening to port 80 and served through to a rails app running on port 3002
My first stab is to start with two upstreams:
# /etc/nginx/sites-available/mydomain.com
upstream nodejs {
server 127.0.0.1:3001;
}
upstream rails {
server 127.0.0.1:3002;
}
server {
listen 80 default deferred;
# What do I put here so that
# mydomain.com/nodejs is proxied to the nodejs upstream and
# mydomain.com/rails is proxied to the rails upstream ???
}
Does anyone know this or point me in the right direction?
How about:
upstream nodejs {
server 127.0.0.1:3001;
}
upstream rails {
server 127.0.0.1:3002;
}
server {
listen 80;
location /nodejs {
proxy_pass http://nodejs;
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;
}
location /rails {
proxy_pass http://rails;
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;
}
}
or shortly:
server {
listen 80;
location /nodejs {
proxy_pass http://127.0.0.1:3001;
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;
}
location /rails {
proxy_pass http://127.0.0.1:3002;
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;
}
}
?
Most of the proxy directives are optional (you probably just need proxy_pass and proxy_redirect) but useful.
About the question ,css、js、images files are missed , you can do like this,
if you use express framework。
you need add this code line
app.enable('trust proxy');
this value 'trust proxy' default value is disable.

Resources