Setting up Apache Superset with Nginx as Reverse Proxy - python

I'm having trouble setting up apache superset with Nginx as a reverse proxy (This is probably an nginx misconfig).
Server block of config (if I'm missing something, let me know and I'll add it):
server {
listen 80 default_server;
server_name _;
root /var/www/data;
error_log /var/www/bokehapps/log/nginx.error.log info;
location /static {
alias /usr/lib/python2.7/site-packages/bokeh/server/static;
}
location /superset {
proxy_pass http://0.0.0.0:8088;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_http_version 1.1;
proxy_connect_timeout 600;
proxy_send_timeout 600;
proxy_read_timeout 600;
send_timeout 600;
}
}
I'm able to curl into 0.0.0.0:8088 to get a redirect page, and my request are making it to werkzeug. But in my browser, everything is 404.

Since you are serving on a prefixed location (/superset), and even though you are proxy passing to /, werkzeug is trying to serve /superset route, which does not exist, hence 404.
What you should to is define a prefix middleware, a very nice explanation can be found in this thread: Add a prefix to all Flask routes .
The middleware should than be passed to Superset/FAB as part of the superset-config.py, relevant documentation
Combining the two you'll likely end up with something like this in your superset-config.py:
class PrefixMiddleware(object):
def __init__(self, app, prefix='superset'):
self.app = app
self.prefix = prefix
def __call__(self, environ, start_response):
if environ['PATH_INFO'].startswith(self.prefix):
environ['PATH_INFO'] = environ['PATH_INFO'][len(self.prefix):]
environ['SCRIPT_NAME'] = self.prefix
return self.app(environ, start_response)
else:
start_response('404', [('Content-Type', 'text/plain')])
return ["This url does not belong to the app.".encode()]
ADDITIONAL_MIDDLEWARE = [PrefixMiddleware, ]

Related

enable cors in a nginx with reverse proxy to strawberry-graphql python app with asgi using daphne

I have a website that has the following setup:
the client is an angular 14 project
the server is a python app with strawberry for graphql
using nginx as web server
using asgi python script to run the app using daphne
I'm having cors related errors when I try to access graphql from the angular app
Access to XMLHttpRequest at 'https://URL/graphql' from origin 'https://URL' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.
in the nginx server i have listen 443 ssl http2; set with certificates from lets encrypt
I created an upstream setup for the python project:
upstream myproj-server {
server 127.0.0.1:8001;
}
created a location backend:
location #backend {
proxy_pass http://myproj-server; # <--- THIS DOES NOT HAVE A TRAILING '/'
#proxy_set_header 'Access-Control-Allow-Origin' "*";
#proxy_set_header 'Access-Control-Allow-Credentials' 'true';
#proxy_set_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
#proxy_set_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With';
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_http_version 1.1;
proxy_set_header X-NginX-Proxy true;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_cache_bypass $http_upgrade;
proxy_redirect off;
proxy_set_header X-Forwarded-Proto $scheme;
}
and setup graphql location:
location /graphql {
# add_header 'Access-Control-Allow-Origin' "*" always;
# add_header 'Access-Control-Allow-Credentials' 'true' always;
# add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
# add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With' always;
try_files $uri $uri/ #backend;
}
i commented out the CORS lines with # but i did try to enable them, to add cors at the /graphql location or at the proxy configured in the backend, both configurations did not change anything.
next, i have a server.py with the asgi application with the strawberry plugin for the graphql:
from strawberry.asgi import GraphQL
from app import schema
app = GraphQL(schema, graphiql=False)
and i start it with daphne -b 0.0.0.0 -p 8001 server:app
and here I tried to modify server.py to use the Starlette CORS middleware
from strawberry.asgi import GraphQL
from starlette.middleware.cors import CORSMiddleware
from starlette.middleware import Middleware
from starlette.applications import Starlette
from app import schema
middleware = [
Middleware(CORSMiddleware, allow_origins=['*'],
allow_methods=["*"],
allow_credentials=True,
allow_headers=["*"],)
]
graphql_app=GraphQL(schema, graphiql=True)
app = Starlette(middleware=middleware)
app.add_route("/graphql", graphql_app)
app.add_websocket_route("/graphql", graphql_app)
and also here the results are the same
I'm sure that the reverse proxy works properly because if i set graphiql to True and i browse mydomain/graphql it does open the graphql-playground.
so I tried anything i can think of and i'm pretty lots, so any ideas or any information regarding this issue would be greatly appreciated.
I checked the network tab of my browser and I noticed that what the OPTIONS request (for the CORS preflight request) fails with error 301, which is redirect. and then I noticed that the graphql url is mydomain.com/graphql and not www.mydomain.com/graphql and I do redirect to www in my nginx configuration.
i disabled the headers in the nginx i prefer to control it outside of the nginx configuration.
the server.py configuration with starlette did the trick. of course now i'll make it more secured.

After implementation of nginx reverse-proxy Js Client connects with Flask socketio but doesn't receive any messages

For some reason my Angular client connects with the backend server (apparently successfully) but it doens't receive any message. Neither direct messages nor broadcasted.
This problem was introduced after using Nginx configured as reverse-proxy for the backend. I followed the latest official documentation of flask socketio module but still didn't found any clue of what's going on.
On the client I connect and prepare to receive messages with:
const API = "http://146.250.180.213/api/"
::
socket: io;
::
this.socket = io(API);
::
this.socket.on('connect', function() {
console.log('Conection with server estblished - socketio');
});
::
this.socket.on('update_monitor', (data: any) => {
console.log('Broadcasted message received! Data:', data);
});
On Flask I start the server and define endpoints with:
app = Flask(__name__)
socketio = SocketIO(app)
if __name__ == '__main__':
socketio.run(app, port=5000, debug=True)
===
#app.route('/test_endpoint', methods=['GET'])
def test_endpoint():
socketio.emit('update_monitor', {"mrtp": app.config['MOST_RECENT_TIMESTAMP_PROCESSED'], 'updated_elements': ['ESICAS23C_ESICAS23']})
return jsonify({'message': 'ok'}), 200
#socketio.on('connect')
def connect():
print('Client connected')
I use the 'test_endpoint' to test the socketio mechanism by requesting it with Postman.
On Nginx, I followed the configuration provided by the documentation:
server {
listen 0.0.0.0:80;
root /usr/share/nginx/html;
index index.html index.htm;
include /etc/nginx/mime.types;
location / {
try_files $uri /index.html;
}
location /socket.io {
# include proxy_params; dont know what this stands for
proxy_http_version 1.1;
proxy_buffering off;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_pass http://127.0.0.1:5000/socket.io;
}
location /grafana/ {
proxy_pass http://localhost:3000/;
proxy_hide_header X-Frame-Options;
}
location /api {
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_hide_header X-Frame-Options;
proxy_connect_timeout 9999;
proxy_send_timeout 9999;
proxy_read_timeout 9999;
send_timeout 9999;
rewrite ^/api/(.*) /$1 break;
proxy_pass http://localhost:5000;
}
}
Both on client and backend I see that they connects, but client never receives any message.
Already checked nginx (docker logs) logs output and nothing abnormal happens. There isn't any error message, anywhere. Any clue of what's happening? Suggestions?
The solution is to use http://146.250.180.213/ as the API url i.e. without the /api/ namespace.

How to setup nginx + tornado + flask?

These are my fully working tornado and flask files:
Tornado:
from flaskk import app
from tornado.wsgi import WSGIContainer
from tornado.ioloop import IOLoop
from tornado.web import FallbackHandler, RequestHandler, Application
class MainHandler(RequestHandler):
def get(self):
self.write("This message comes from Tornado ^_^")
tr = WSGIContainer(app)
application = Application([
(r"/tornado", MainHandler),
(r".*", FallbackHandler, dict(fallback=tr)),
])
if __name__ == '__main__':
application.listen(5052)
IOLoop.instance().start()
Flask:
from flask import Flask, jsonify
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
class Report(Resource):
def get(self):
return 'hello from flask'
api.add_resource(Report, '/report')
Now I'm trying to setup nginx in front of tornado.
My nginx config file is:
worker_processes 3;
error_log logs/error.;
events {
worker_connections 1024;
}
http {
# Enumerate all the Tornado servers here
upstream frontends {
server 127.0.0.1:5052;
}
include mime.types;
default_type application/octet-stream;
keepalive_timeout 65;
sendfile on;
server {
listen 5050;
server_name localhost;
location / {
proxy_pass_header Server;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_pass http://localhost:5050;
}
}
}
When I do a
localhost:5050/
then I get the nginx welcome page. But when I do
localhost:5050/report
then I get a 404. Tornado is running on port 5052.
Why is nginx not calling tornado which thereby should get the result from flask?
Am I missing something here?
Firstly, you don't want to proxy to localhost:5050 because that is Nginx itself
You want to proxy to upstream frontends.
proxy_pass http://frontends;
Regarding your Flask issues, I've gotten this to work fine.
#app.route('/report')
def report():
return 'hello from flask'
$ curl localhost:5052/report
hello from flask
When I added in Flask Restful, that still worked.
You said you see the index page of nginx, so it is running, you just need to correctly hook the other ports together.
The proxy_pass fix seemed to work for me.
$ curl localhost:5050/report
"hello from flask"
$ curl localhost:5050/tornado
This message comes from Tornado ^_^

Checking proxy set header forwaded by nginx reverse proxy (Django app)

I'm using nginx as reverse proxy with gunicorn for my Django app, and am new to webserver configuration. My app has a postgres backend, and the machine hosting it has Ubuntu 14.04 lts installed.
I have reason to suspect that my nginx configuration is not forwarding proxy set header to the Django app correctly. Is there a way I can see (e.g. print?) the host, http_user_agent, remote_addr etc. forwarded, on the linux command line to test my gut feel?
Secondly, how do I check whether my Django app received the correct forwarded IP? E.g. can I somehow print?
/etc/nginx/sites-available/myproject:
server {
listen 80;
server_name example.cloudapp.net;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /home/mhb11/folder/myproject;
}
location / {
proxy_set_header Host $host;
proxy_set_header User-Agent $http_user_agent;
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_pass http://unix:/home/mhb11/folder/myproject/myproject.sock;
}
error_page 500 502 503 504 /500.html;
location = /500.html {
root /home/mhb11/folder/myproject/templates/;
}
}
All you have to do is print out request.META at the Django project level to see what all of those values are being set to. This automatically happens for you if you get an error and debug is set to True (just scroll down, you'll see a big table with all request.META values populated therein).
Or you can print it yourself from your views.py, or if that doesn't work, then from any middleware you have. You can even write custom middleware for this. Let me know if you need further clarification on this, I can give you basic code snippets too.
This question was posted a long time ago but since I landed here when needed help, below are some code which I ended up using to attain the same goal for the help of other people.
def getClientIP(request):
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
if x_forwarded_for:
ip = x_forwarded_for.split(',')[-1].strip()
else:
ip = request.META.get('REMOTE_ADDR')
return ip

Passing JSON from Nginx to Gunicorn

I am using nginx as a proxy server for a Django app using gunicorn. The Django app is binded to http://127.0.0.1:8000. And here's my nginx setup from etc/nginx/sites-enabled/parkitbackend:
server {
server_name AA.BB.CC.DD;
access_log off;
location /static/ {
autoindex on;
alias /home/zihe/parkitbackend/parkitbackend/common-static/;
}
location / {
proxy_pass http://127.0.0.1:8000;
}
}
I am using python requests module:
requests.post("http://AA.BB.CC.DD/dashboard/checkin/", data=unicode(json.dumps(payload), "utf8"))
to post JSON objects to my django app called dashboard, where I have a function in dashboard/views.py called checkin to process the JSON object.
I did not receive any errors from running JSON posting script. However, Nginx does not seem to be able to pass the request to gunicorn binded at 127.0.0.1:8000. What should I do so I can use Nginx to pass the JSON to my django app? Thank you!
Additional notes:
I am very sure JSON posting code and my django app work properly since I tested it by binding Django app to http://AA.BB.CC.DD:8000 and ran this code in python:
requests.post("http://AA.BB.CC.DD:8000/dashboard/checkin/", data=unicode(json.dumps(payload), "utf8"))
and my django app received the JSON as expected.
I checked the error.log located at /var/log/nginx/. It turns out that the JSON I was sending was too large and was giving this error:
[error] 3450#0: *9 client intended to send too large body: 1243811 bytes, client: 127.0.0.1, server: _, request: "POST /dashboard/checkin/ HTTP/1.1", host: "127.0.0.1"
After reading up on this link: http://gunicorn-docs.readthedocs.org/en/19.3/deploy.html#nginx-configuration
I reduced the size of the JSON and modified etc/nginx/sites-enabled/parkitbackend to be like this:
upstream app_server {
server 127.0.0.1:8000;
}
server {
listen AA.BB.CC.DD:80;
server_name = _;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app_server;
}
location /static/ {
autoindex on;
alias /home/username/parkitbackend/parkitbackend/common-static/;
}
}
and replaced this line in /etc/nginx/nginx.conf:
include /etc/nginx/sites-enabled/*;
with this:
include /etc/nginx/sites-enabled/parkitbackend;
And the problem is resolved.

Categories

Resources