Hu Zhang
Hu Zhang

Reputation: 107

How to host a Flask app on a subfolder / URL prefix with Nginx?

I have a flask app which I want to host it on a subfolder of a website, like example.com/cn.

I configured my nginx like

location /cn {
    proxy_pass http://localhost:8000/;
}

So if I access example.com/cn, It will redirect to the index page of flask.

However, I have wrote the routes of other pages on flask like app.route('/a'). So if I click the link of page a, the URI is example.com/a, then nginx cannot redirect it to the right ​page.

​I think I can rewrite all the routes on flask like app.route('/cn/a'), but it's complex. And if someday I want to deploy it on example.com/en, I think I need to rewrite all the routes again.

Does anyone have other methods?

Upvotes: 6

Views: 7696

Answers (4)

box fry
box fry

Reputation: 3

This is a very common and good question for flask beginners, I think the correct answer is here

Run the app with a WSGI-compliant web server, e.g. Gunicorn (again, not Flask's builtin dev server, see above), while setting the SCRIPT_NAME env var:

$ SCRIPT_NAME=/my-app gunicorn app:app

Upvotes: 0

Grey Li
Grey Li

Reputation: 12782

Suppose you want to host your application under /api with Nginx.

First, config your URL prefix to location and X-Forwarded-Prefix header:

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

Then use Werkzeug's ProxyFix middleware to tell Flask it's behind a proxy:

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
)

See also:

P.S. If you are using OpenAPI, also remember to update the servers field to indicate the location of the server.

Upvotes: 2

Matteo Pasini
Matteo Pasini

Reputation: 2022

You need to add APPLICATION_ROOT params to your flask app:

from flask import Flask, url_for
from werkzeug.serving import run_simple
from werkzeug.wsgi import DispatcherMiddleware

app = Flask(__name__)
app.config['APPLICATION_ROOT'] = '/cn'

if you need to host more than one application on your server, you can configure nginx to redirect all request to your specific flask app served by gunicorn like this. (it is not necessary if your server hosts only one application) Find out more about gunicorn and nginx here: https://docs.gunicorn.org/en/stable/deploy.html

server {
    listen 8000;
    server_name example.com;

    proxy_intercept_errors on;
    fastcgi_intercept_errors on;

    location / {
        include proxy_params;
        proxy_pass http://unix:/path_to_example_flask_app_1/app.sock;
    }

    location /cn/{
        include proxy_params;
        proxy_pass http://unix:/path_to_example_flask_app_cn/app.sock;
    }
}

serve flask app with gunicorn: A complete exmaple here: https://www.digitalocean.com/community/tutorials/how-to-serve-flask-applications-with-gunicorn-and-nginx-on-ubuntu-18-04

#move into project directory
/path_to_gunicorn/gunicorn --workers 3 --bind unix:app.sock -m 007 run:app

If you are using flask_restful instead, you can specify the root path also in the following way:

from flask import Flask
from flask_restful import Api

app = Flask(__name__)
app.debug = False
api = Api(app, prefix='/cn')

api.add_resource(ResourceClass, '/example_path') #will be served when the resource is requested at path /cn/example_path

if __name__ == '__main__':
    app.run(host="0.0.0.0", port=8000)

Upvotes: 3

JBLaf
JBLaf

Reputation: 838

You can use url_prefix="/cn" option when defining blueprints:

https://flask.palletsprojects.com/en/2.0.x/blueprints/#nesting-blueprints

Upvotes: 0

Related Questions