Unable to link Flask module to nginx through uwsgi - python

I'm sure I am missing something simple here. I can get PART of a python/flask script to be available through nginx, but the important bits are just not working. Here is my python:
#!/usr/bin/python
import flask
from flask import Flask, jsonify, render_template, request
import os
app = flask.Flask(__name__)
app.config['SERVER_NAME']='localhost'
#app.route("/stuff")
def index():
return render_template('index.html')
#app.errorhandler(404)
def page_not_found(e):
return render_template('404.html'), 404
def application(environ, start_response):
start_response("200 OK", [("Content-Type", "text/plain")])
return ["Hello World!"]
Here is my uwsgi start up:
sudo -u www-data uwsgi -s /tmp/myApp.sock --module MyApp
The socket is correctly linked and available to nginx.
And here is my nginx config snippet:
location /test {
uwsgi_pass unix:/tmp/myApp.sock;
include uwsgi_params;
}
When I go to myserver/test I get the "Hello World!" like I Would expect. But when I go to myserver/test/stuff, I ALSO get "Hello World!" rather than the contents of my index.html(Which is valid, I use it elsewhere). And if I enter myserver/test/garbage.html, I get a generic nginx 404, rather than my custom one.
Can anyone point me in a direction?
Thanks
--edit--
Thank you for the answer, it does help, but does not solve my entire issue.
Adding "--callable app" to my uwsgi startup line DOES link the uwsgi server to nginx. Yah! I can confirm this by the fact that my customized 404 file IS being returned by nginx.
But that 404 is ALL I can get. I cannot get to my index.html, which is present in the same directory as the 404.html, has the same owner, and the same rights. It is almost the same file really with slightly different text.
This MAY be a problem with expectations. I am expecting to find my index.html at http://(myserver)/test/stuff But I get a 404.
Am I looking in the wrong place? Or is there something off in my flask, uwsgi, or nginx?
Thanks

You're application function does not call your flask app, which is why every route returns "Hello World", 200. I'm pretty sure you have two easy options.
The first is to drop the application function and replace it with application = app.
The second would be to change the uwsgi line to
sudo -u www-data uwsgi -s /tmp/myApp.sock --module MyApp --callable app
which renders your application function irrelevant anyway.
You can read more about using uwsgi here.
edit
As far as my knowledge about nginx goes, your nginx config should look like this
location = /test { rewrite ^ /test/; }
location /test { try_files $uri #test; }
location #test {
include uwsgi_params;
uwsgi_param SCRIPT_NAME /test;
uwsgi_modifier1 30;
uwsgi_pass unix:/tmp/myApp.sock;
}
It is the same as the recommended one on the linked uwsgi page above. You seem to be running not on the root url, so the basic config will not work.

Related

Unable to load _dash-layout and _dash-dependencies from dash app running behind Nginx

I am serving dash content inside a Flask app which uses blueprint for registering the routes.
App setup:
Dash is initialised with route_pathname_prefix=/dashapp/
dash_app = dash.Dash(
server=server,
routes_pathname_prefix='/dashapp/',
)
dash_app.css.config.serve_locally = True
dash_app.scripts.config.serve_locally = True
Registered dash app with Flask server
Used UWSGI to serve Flask app inside a docker container
[uwsgi]
wsgi-file = </path/to/app.py>
callable = app
http = 0.0.0.0:8080
processes = 4
threads = 2
master = true
chmod-socket = 660
vacuum = true
die-on-term = true
Upto this point everything was working fine locally. Once I added Nginx proxy, I got the below issue
Issue:
urls for _dash-layout and _dash-dependencies are missing the revers proxy uri. For example, I am serving my flask app at www.example.com/app/. But, on the browser, I saw that requests for _dash-layout and _dash-dependencies are coming at www.example.com/dashpp/_dash-layout instead of www.example.com/app/dashpp/_dash-layout.
I read the following forum discussion and tried applying the solution, and got this error,
requests_pathname_prefix needs to start with '/'`
This is my Nginx config,
location /app/ {
proxy_pass http://localhost:<port>;
proxy_redirect http://localhost:<port> http://example.com/app/;
proxy_set_header Accept Encoding "";
sub_filter_types *;
sub_filter 'href="/' 'href="/app/';
sub_filter 'src="/' 'src="/app/';
sub_filter_once off;
}
Anyone has pointers to what is missing. I am new to dash. So, if I missed adding any information please let me know, I will be happy to give additional details
Thanks
PS: I added the same question in dash forum. Posting it here for better reach.
Edit:
To add additional context, I found out that url for _dash-component-suites is generated as expected www.example.com/app/dashpp/_dash-component-suites. I went through the dash source code to understand how urls are generated. Both, _dash-component-suites and _dash-layout are prefixed with routes_pathname_prefix. Line 428 to 448 of dash.py in version 1.14.0 has the code for building urls.
This is confusing!!!.
I was able to fix this by removing sub_filter directive from nginx conf and updating url_prefixes in flask app. The steps I took are posted on this dash forum

configuring Nginx to run flask automatically with uwsgi

I am developing python programs and I have a flask file which runs them. Now I am trying to run flask automatically from Nginx and linking them with uWSGI. It's not working and getting stuck.
I followed this page.here is the link: https://vladikk.com/2013/09/12/serving-flask-with-nginx-on-ubuntu/
I have performed all the necessary steps and got 502 bad gateway error.
while executing
uswgi --ini /var/www/tg/tg_uswgi.ini
I am getting the following
[uSWGI] getting INI configuration from /var/www/tg/tg_uwsgi.ini
after this, I am not getting anything.when i run my server, it still gives me 502 Bad gateway.
this is my
tg_nginx.conf
server {
listen 80;
server_name localhost;
charset utf-8;
client_max_body_size 75M;
location / { try_files $uri #yourapplication; }
location #yourapplication {
include uwsgi_params;
uwsgi_pass unix:/var/www/tg/tg_uwsgi.sock;
}
}
this is my tg_uwsgi.ini
[uwsgi]
#application's base folder
base = /var/www/tg
#python module to import
app = fileforflk //fileforflk is my flask file which calls other python
//files
module = %(app)
home = %(base)/venv
pythonpath = %(base)
#socket file's location
socket = /var/www/demoapp/%n.sock
#permissions for the socket file
chmod-socket = 666
#the variable that holds a flask application inside the module imported at line #6
callable = app
#location of log files
logto = /var/log/uwsgi/%n.log
this is my flask file
from flask import Flask
import browser //python file the flask is calling
app = Flask(_name_)
#app.route('/test',methods= ['GET'])
def result():
return ("success")
if _name_ == '_main_':
app.run(host = '0.0.0.0',port=5000)
After getting INI configuration, the terminal is not showing anything and the server still returns bad gateway. please help me with this.
You should define:
socket = /var/www/demoapp/%n.sock
And :
uwsgi_pass unix:/var/www/tg/tg_uwsgi.sock;
should be matching. So for example, define:
socket = /var/www/tg/%n.sock
And :
sudo chown -R www-data:www-data /var/www/tg/
sudo chown -R www-data:www-data /var/log/uwsgi/

Unable to render create-react-app boilerplate views from Flask backend

I'm having a hard time integrating create-react-app single page application to my flask backend. I want to be able to make a fetch/axios call from my front end like so: axios.get('/getResults') and fetch('/getResults'). Some things I have tried but not limited to is specifying the Flask port as 3000 which is the same used by create-react-app. Also, used the proxy configuration feature on the "package.json" file of create-react-app but to no avail. I suspect my folder structure and Flask code implementation may likely be causing this. Below is my folder structure and "app.py" code. Any help I could get will be appreciated. I can provide additional information if necessary. Thanks
Project -build(contains static folder, index.html...Other meta files)-node_modules-public-srcapp.pypackage.jsonrequirements.txt
app.py:
from flask import Flask, Response, request, jsonify, make_response, send_from_directory,render_template
app = Flask(__name__, static_path='/build/static/')
app.debug=True
#app.route('/')
def root():
print('Inside root function')
return app.send_static_file('index.html')
#app.route('/getResults', methods=["GET"])
def results():
print('Inside getResults path')
return app.send_static_file('index.html')
#app.route('/postData', methods=["POST"])
def data_results():
print('Inside postData path')
data = request.get_json
return jsonify(data)
#app.route('/<path:path>')
def send_js(path):
print("inside send_js fxn")
return send_from_directory('./build/static',path)
if __name__ == "__main__":
print("inside main host call")
app.run(host='0.0.0.0', port=3000)
Errors I get when I run "python app.py" are:
On the terminal: Inside root function
127.0.0.1 - - [12/Jun/2017 09:42:24] "GET / HTTP/1.1" 404 -
On the browser:Not Found - The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
I was having the exact same issue and I was able to solve it by appeasing Flask with symlinks.
Keep the templates and static directory paths at their defaults and in the directory with your Flask main file, add these symlinks
ln -s build/ templates
ln -s build/static static
In case you were curious, this was my specific problem, which just involved a few more nested directories but was in essence the same:
Running NPM Build from Flask
You can then use Nurzhan's root configuration:
#app.route('/')
def root():
print('Inside root function')
return render_template('index.html')
But you only require your app declaration to be: app = Flask(__name__)
The only thing that doesn't work for me is the favicon, and I will update this answer once I figure that out.
In development mode, you need to configure your create-react-app package.json to forward "ajax" request to the flask server.
Here is what my package.json looks like:
{
"name": "socialite",
"version": "0.1.0",
"private": true,
"proxy": "http://localhost:8080",
"devDependencies": {
"react-scripts": "1.0.10"
},
"dependencies": {
"react": "^15.6.1",
"react-dom": "^15.6.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}
See the proxy field? That's where the magic happens, replace its value with the flask server address. That way, you can take advantage of CRA hot reloading feature. This is documented at in create-react-app as "Proxying API Requests in Development"
Then do run your application, you go at localhost:3000 or whatever port yarn opens for you. And when you do an API call in javascript over the rainbow to the server for instance: fetch('/api/model/') or something nodejs' server will forward to the flask app. I think the nodejs server does look at the content-type field of the ajax request to know whether it should forward the request to the backend server or not.
I recommend you prefix all your backend routes with something like /api/v1/ or something so the nginx configuration is neat and easy to write.
I think you have a number of misunderstandings.
The create-react-app runs on its own server on port 3000 and if you try to run your flask app on the same port on the same machine it will complain that port 3000 is already in use. So from this we move to another question - the structure of your application.
Will it be a separate reactjs based client on the frontend and api based on flask in the backend which will be 2 separate applications communicating with each other over HTTP? In this case the frontend and backend will usually run on separate servers.
Or it will one flask application which will use reactjs in its template pages?
You can fix your current problem with not finding URL by changing to this in your code:
#app.route('/')
def root():
print('Inside root function')
return render_template('index.html')
And this:
template_dir = os.path.abspath('build/templates')
app = Flask(__name__, static_path='/build/static/',
template_folder=template_dir)
Since your templates folder is in the build directory.

Flask - Uwsgi - Not found error [duplicate]

I have a prefix that I want to add to every route. Right now I add a constant to the route at every definition. Is there a way to do this automatically?
PREFIX = "/abc/123"
#app.route(PREFIX + "/")
def index_page():
return "This is a website about burritos"
#app.route(PREFIX + "/about")
def about_page():
return "This is a website about burritos"
You can put your routes in a blueprint:
bp = Blueprint('burritos', __name__,
template_folder='templates')
#bp.route("/")
def index_page():
return "This is a website about burritos"
#bp.route("/about")
def about_page():
return "This is a website about burritos"
Then you register the blueprint with the application using a prefix:
app = Flask(__name__)
app.register_blueprint(bp, url_prefix='/abc/123')
The answer depends on how you are serving this application.
Sub-mounted inside of another WSGI container
Assuming that you are going to run this application inside of a WSGI container (mod_wsgi, uwsgi, gunicorn, etc); you need to actually mount, at that prefix the application as a sub-part of that WSGI container (anything that speaks WSGI will do) and to set your APPLICATION_ROOT config value to your prefix:
app.config["APPLICATION_ROOT"] = "/abc/123"
#app.route("/")
def index():
return "The URL for this page is {}".format(url_for("index"))
# Will return "The URL for this page is /abc/123/"
Setting the APPLICATION_ROOT config value simply limit Flask's session cookie to that URL prefix. Everything else will be automatically handled for you by Flask and Werkzeug's excellent WSGI handling capabilities.
An example of properly sub-mounting your app
If you are not sure what the first paragraph means, take a look at this example application with Flask mounted inside of it:
from flask import Flask, url_for
from werkzeug.serving import run_simple
from werkzeug.middleware.dispatcher import DispatcherMiddleware
app = Flask(__name__)
app.config['APPLICATION_ROOT'] = '/abc/123'
#app.route('/')
def index():
return 'The URL for this page is {}'.format(url_for('index'))
def simple(env, resp):
resp(b'200 OK', [(b'Content-Type', b'text/plain')])
return [b'Hello WSGI World']
app.wsgi_app = DispatcherMiddleware(simple, {'/abc/123': app.wsgi_app})
if __name__ == '__main__':
app.run('localhost', 5000)
Proxying requests to the app
If, on the other hand, you will be running your Flask application at the root of its WSGI container and proxying requests to it (for example, if it's being FastCGI'd to, or if nginx is proxy_pass-ing requests for a sub-endpoint to your stand-alone uwsgi / gevent server then you can either:
Use a Blueprint, as Miguel points out in his answer.
or use the DispatcherMiddleware from werkzeug (or the PrefixMiddleware from su27's answer) to sub-mount your application in the stand-alone WSGI server you're using. (See An example of properly sub-mounting your app above for the code to use).
You should note that the APPLICATION_ROOT is NOT for this purpose.
All you have to do is to write a middleware to make the following changes:
modify PATH_INFO to handle the prefixed url.
modify SCRIPT_NAME to generate the prefixed url.
Like this:
class PrefixMiddleware(object):
def __init__(self, app, prefix=''):
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()]
Wrap your app with the middleware, like this:
from flask import Flask, url_for
app = Flask(__name__)
app.debug = True
app.wsgi_app = PrefixMiddleware(app.wsgi_app, prefix='/foo')
#app.route('/bar')
def bar():
return "The URL for this page is {}".format(url_for('bar'))
if __name__ == '__main__':
app.run('0.0.0.0', 9010)
Visit http://localhost:9010/foo/bar,
You will get the right result: The URL for this page is /foo/bar
And don't forget to set the cookie domain if you need to.
This solution is given by Larivact's gist. The APPLICATION_ROOT is not for this job, although it looks like to be. It's really confusing.
This is more of a python answer than a Flask/werkzeug answer; but it's simple and works.
If, like me, you want your application settings (loaded from an .ini file) to also contain the prefix of your Flask application (thus, not to have the value set during deployment, but during runtime), you can opt for the following:
def prefix_route(route_function, prefix='', mask='{0}{1}'):
'''
Defines a new route function with a prefix.
The mask argument is a `format string` formatted with, in that order:
prefix, route
'''
def newroute(route, *args, **kwargs):
'''New function to prefix the route'''
return route_function(mask.format(prefix, route), *args, **kwargs)
return newroute
Arguably, this is somewhat hackish and relies on the fact that the Flask route function requires a route as a first positional argument.
You can use it like this:
app = Flask(__name__)
app.route = prefix_route(app.route, '/your_prefix')
NB: It is worth nothing that it is possible to use a variable in the prefix (for example by setting it to /<prefix>), and then process this prefix in the functions you decorate with your #app.route(...). If you do so, you obviously have to declare the prefix parameter in your decorated function(s). In addition, you might want to check the submitted prefix against some rules, and return a 404 if the check fails. In order to avoid a 404 custom re-implementation, please from werkzeug.exceptions import NotFound and then raise NotFound() if the check fails.
So, I believe that a valid answer to this is: the prefix should be configured in the actual server application that you use when development is completed. Apache, nginx, etc.
However, if you would like this to work during development while running the Flask app in debug, take a look at this gist.
Flask's DispatcherMiddleware to the rescue!
I'll copy the code here for posterity:
"Serve a Flask app on a sub-url during localhost development."
from flask import Flask
APPLICATION_ROOT = '/spam'
app = Flask(__name__)
app.config.from_object(__name__) # I think this adds APPLICATION_ROOT
# to the config - I'm not exactly sure how!
# alternatively:
# app.config['APPLICATION_ROOT'] = APPLICATION_ROOT
#app.route('/')
def index():
return 'Hello, world!'
if __name__ == '__main__':
# Relevant documents:
# http://werkzeug.pocoo.org/docs/middlewares/
# http://flask.pocoo.org/docs/patterns/appdispatch/
from werkzeug.serving import run_simple
from werkzeug.wsgi import DispatcherMiddleware
app.config['DEBUG'] = True
# Load a dummy app at the root URL to give 404 errors.
# Serve app at APPLICATION_ROOT for localhost development.
application = DispatcherMiddleware(Flask('dummy_app'), {
app.config['APPLICATION_ROOT']: app,
})
run_simple('localhost', 5000, application, use_reloader=True)
Now, when running the above code as a standalone Flask app, http://localhost:5000/spam/ will display Hello, world!.
In a comment on another answer, I expressed that I wished to do something like this:
from flask import Flask, Blueprint
# Let's pretend module_blueprint defines a route, '/record/<id>/'
from some_submodule.flask import module_blueprint
app = Flask(__name__)
app.config['APPLICATION_ROOT'] = '/api'
app.register_blueprint(module_blueprint, url_prefix='/some_submodule')
app.run()
# I now would like to be able to get to my route via this url:
# http://host:8080/api/some_submodule/record/1/
Applying DispatcherMiddleware to my contrived example:
from flask import Flask, Blueprint
from flask.serving import run_simple
from flask.wsgi import DispatcherMiddleware
# Let's pretend module_blueprint defines a route, '/record/<id>/'
from some_submodule.flask import module_blueprint
app = Flask(__name__)
app.config['APPLICATION_ROOT'] = '/api'
app.register_blueprint(module_blueprint, url_prefix='/some_submodule')
application = DispatcherMiddleware(Flask('dummy_app'), {
app.config['APPLICATION_ROOT']: app
})
run_simple('localhost', 5000, application, use_reloader=True)
# Now, this url works!
# http://host:8080/api/some_submodule/record/1/
Another completely different way is with mountpoints in uwsgi.
From the doc about Hosting multiple apps in the same process (permalink).
In your uwsgi.ini you add
[uwsgi]
mount = /foo=main.py
manage-script-name = true
# also stuff which is not relevant for this, but included for completeness sake:
module = main
callable = app
socket = /tmp/uwsgi.sock
If you don't call your file main.py, you need to change both the mount and the module
Your main.py could look like this:
from flask import Flask, url_for
app = Flask(__name__)
#app.route('/bar')
def bar():
return "The URL for this page is {}".format(url_for('bar'))
# end def
And a nginx config (again for completeness):
server {
listen 80;
server_name example.com
location /foo {
include uwsgi_params;
uwsgi_pass unix:///temp/uwsgi.sock;
}
}
Now calling example.com/foo/bar will display /foo/bar as returned by flask's url_for('bar'), as it adapts automatically. That way your links will work without prefix problems.
from flask import Flask
app = Flask(__name__)
app.register_blueprint(bp, url_prefix='/abc/123')
if __name__ == "__main__":
app.run(debug='True', port=4444)
bp = Blueprint('burritos', __name__,
template_folder='templates')
#bp.route('/')
def test():
return "success"
I needed similar so called "context-root". I did it in conf file under /etc/httpd/conf.d/ using WSGIScriptAlias :
myapp.conf:
<VirtualHost *:80>
WSGIScriptAlias /myapp /home/<myid>/myapp/wsgi.py
<Directory /home/<myid>/myapp>
Order deny,allow
Allow from all
</Directory>
</VirtualHost>
So now I can access my app as : http://localhost:5000/myapp
See the guide - http://modwsgi.readthedocs.io/en/develop/user-guides/quick-configuration-guide.html
My solution where flask and PHP apps coexist
nginx and PHP5.6
KEEP Flask in root and PHP in subdirectories
sudo vi /etc/php/5.6/fpm/php.ini
Add 1 line
cgi.fix_pathinfo=0
sudo vi /etc/php/5.6/fpm/pool.d/www.conf
listen = /run/php/php5.6-fpm.sock
uwsgi
sudo vi /etc/nginx/sites-available/default
USE NESTED LOCATIONS for PHP and let FLASK remain in root
server {
listen 80 default_server;
listen [::]:80 default_server;
# SSL configuration
#
# listen 443 ssl default_server;
# listen [::]:443 ssl default_server;
#
# Note: You should disable gzip for SSL traffic.
# See: https://bugs.debian.org/773332
#
# Read up on ssl_ciphers to ensure a secure configuration.
# See: https://bugs.debian.org/765782
#
# Self signed certs generated by the ssl-cert package
# Don't use them in a production server!
#
# include snippets/snakeoil.conf;
root /var/www/html;
# Add index.php to the list if you are using PHP
index index.html index.htm index.php index.nginx-debian.html;
server_name _;
# Serve a static file (ex. favico) outside static dir.
location = /favico.ico {
root /var/www/html/favico.ico;
}
# Proxying connections to application servers
location / {
include uwsgi_params;
uwsgi_pass 127.0.0.1:5000;
}
location /pcdp {
location ~* \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php/php5.6-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
location /phpmyadmin {
location ~* \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php/php5.6-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# include snippets/fastcgi-php.conf;
#
# # With php7.0-cgi alone:
# fastcgi_pass 127.0.0.1:9000;
# # With php7.0-fpm:
# fastcgi_pass unix:/run/php/php7.0-fpm.sock;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
READ carefully
https://www.digitalocean.com/community/tutorials/understanding-nginx-server-and-location-block-selection-algorithms
We need to understand location matching
(none): If no modifiers are present, the location is interpreted as a prefix match. This means that the location given will be matched against the beginning of the request URI to determine a match.
=: If an equal sign is used, this block will be considered a match if the request URI exactly matches the location given.
~: If a tilde modifier is present, this location will be interpreted as a case-sensitive regular expression match.
~*: If a tilde and asterisk modifier is used, the location block will be interpreted as a case-insensitive regular expression match.
^~: If a carat and tilde modifier is present, and if this block is selected as the best non-regular expression match, regular expression matching will not take place.
Order is important, from nginx's "location" description:
To find location matching a given request, nginx first checks locations defined using the prefix strings (prefix locations). Among them, the location with the longest matching prefix is selected and remembered. Then regular expressions are checked, in the order of their appearance in the configuration file. The search of regular expressions terminates on the first match, and the corresponding configuration is used. If no match with a regular expression is found then the configuration of the prefix location remembered earlier is used.
It means:
First =. ("longest matching prefix" match)
Then implicit ones. ("longest matching prefix" match)
Then regex. (first match)
For people still struggling with this, the first example does work, but the full example is here if you have a Flask app that is not under your control:
from os import getenv
from werkzeug.middleware.dispatcher import DispatcherMiddleware
from werkzeug.serving import run_simple
from custom_app import app
application = DispatcherMiddleware(
app, {getenv("REBROW_BASEURL", "/rebrow"): app}
)
if __name__ == "__main__":
run_simple(
"0.0.0.0",
int(getenv("REBROW_PORT", "5001")),
application,
use_debugger=False,
threaded=True,
)
In flask blueprint, we can use -
app = Flask(__name__)
app.config['APPLICATION_ROOT'] = '/prefix-text'
Anyone looking to do in flask-restful can make use of -
doc link
app = Flask(__name__)
api = Api(app, prefix='/pefix-text')
Now, all your routes will be prefixed with /prefix-text. Just make sure you use url_for('link') in places where you might have simply used a /link.
I think su27's answer is right. And I am using gevent, here is my code and it works fine:
from gevent import pywsgi
# your flask code ...
# app = Flask(__name__)
if __name__ == "__main__":
class MyHandler(pywsgi.WSGIHandler):
def get_environ(self):
prefix = "/your_prefix"
env = super().get_environ()
if env['PATH_INFO'].startswith(prefix):
env['PATH_INFO'] = env['PATH_INFO'][len(prefix):]
env['SCRIPT_NAME'] = prefix
return env
server = pywsgi.WSGIServer(('', 8080), app, handler_class=MyHandler)
server.serve_forever()
From all the answers I have seen above, they are either too simplistic or over complicating.
That said, I like to accomplish it using nested blueprints:
from .blueprints import blueprint1, blueprint2, blueprint3, etc
app = Flask(__name__)
url_prefix = "/abc/123"
parent = Blueprint('index', __name__, url_prefix=url_prefix)
index.register_blueprint(blueprint1)
index.register_blueprint(blueprint2)
index.register_blueprint(blueprint3)
app.register_blueprint(index)
This way, you basically link your child blueprints to a parent blueprint, where you define the prefix. This is documented here.
With your example, you would simply rewrite it to:
blueprint1 = Blueprint('blueprint1', __name__)
#blueprint1.route("/")
def index_page():
return "Index page"
#blueprint1.route("/about")
def about_page():
return "About page"
If your purpose is to add the prefix in some way,
take a look at the answer https://stackoverflow.com/a/73883005/553095
and https://github.com/mskimm/prefixed-superset
If you want to handle the prefix when using Nginx as a reverse proxy. Werkzeug's ProxyFix middleware will be a simpler solution:
from werkzeug.middleware.proxy_fix import ProxyFix
from flask import Flask
app = Flask(__name__)
app.wsgi_app = ProxyFix(
app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1
)
Werkzeug will read the X-Forwarded-Prefix header and set it to SCRIPT_NAME. So be sure to set the X-Forwarded-Prefix header in Nginx config:
server {
listen 80;
server_name _;
location /api {
proxy_pass http://127.0.0.1:5000/;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Prefix /api;
}
}
See more details at https://stackoverflow.com/a/75123044/5511849

uwsgi + python + nginx + willy nilly file execution

I'm using uwsgi on Nginx to run some Python code.
I'd like to bind uwsgi to a directory and make it render any .py file that I call from the server in the browser. I'm thinking like PHP, here (/index.php executes that file, /login.php executes that file).
Is this a possibility? Or am I only able to explicitly specify a single module/app/file in uwsgi?
Here is my init syntax:
/opt/uwsgi/uwsgi -s 127.0.0.1:9001 -M 4 -t 30 -A 4 -p 4 -d /var/log/uwsgi.log --pidfile /var/run/uwsgi.pid --pythonpath /srv/www
I thought that would allow /srv/www to act as the folder where any .py files are executed.
Here is my nginx config:
server {
listen 80;
server_name DONT_NEED_THIS;
access_log /srv/www/logs/access.log;
error_log /srv/www/logs/error.log;
location / {
root /srv/www;
# added lines
include uwsgi_params;
uwsgi_pass 127.0.0.1:9001;
}
As it stands, when I try to call web root (ie www.site.com/) I get a:
wsgi application not found
With the following index.py file:
import sys
import os
sys.path.append(os.path.abspath(os.path.dirname(__file__)))
def application(environ, start_response):
status = '200 OK'
output = 'Hello World!'
response_headers = [('Content-type', 'text/plain'),
('Content-Length', str(len(output)))]
start_response(status, response_headers)
return [output]
Any ideas?
Thanks!
WSGI is not like PHP. You can't just point uwsgi to a directory with a bunch of .py files. In fact, never, ever make your python modules available in a public directory, accessible from the server. You need to hook uwsgi up to a WSGI application, preferably a framework. Read more about WSGI here. Check out bottle which is small, simple WSGI framework. It has great docs, and it's easy to get started with. There are actually tons of great web frameworks for Python though, so feel free to look around :)
You may want to read this thread:
http://lists.unbit.it/pipermail/uwsgi/2011-March/001657.html

Categories