Sèkun Blog

Flask derrière un reverse-proxy et un chemin racine différent de "/"

Sekun   29-04-2020 12:58 informatique

Lorsque l'on crée une application avec flask, on peut avoir avoir besoin de la rendre accessible à partir d'un autre emplacement que la racine /.

On peut, de ce fait, exposer plusieurs applications indépendantes via un reverse proxy avec nginx.

Contexte

Prenons le code suivant:

from flask import Flask
@app.route('/')
def index():
    return 'Hello World'

if __name__ == '__main__':
  app.debug = True
  app.run(8000)

En l'exécutant, un serveur est lancé sur le port 8000, on peut afficher le message à la page http://localhost:8000/.

$ curl http://localhost:8000/
Hello World

Utilisation de cherrypy

Pour rendre la racine accessible via http://localhost:8000/hello/, on peut utiliser cherrypy:

# ...
import cherrypy
def run_server():
    app_logged = TransLogger(app)
    cherrypy.tree.graft(app_logged, '/code')

    cherrypy.config.update({
        'engine.autoreload_on': True,
        'log.screen': True,
        'server.socket_port': 8000,
        'server.socket_host': '0.0.0.0'
    })

    cherrypy.engine.start()
    cherrypy.engine.block()
if __name__ == '__main__':
  app.debug = True
  run_server()

On vérifie que l'accès à /hello/ renvoie bien la réponse de la fonction index():

$ curl http://localhost:8000/hello/
Hello World

Reverse proxy avec nginx

On peut maintenant rendre accessible notre script à partir du serveur nginx.

server {
    listen 80;
    server_name exemple.com;
    location /hello {
        proxy_pass              http://127.0.0.1:8000;
        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-Script-Name '/hello;
    }
}

On aura accès à notre application via la page http://exemple.com/hello/.

Autres resources

flask-reverse-proxy

Voir aussi flask-reverse-proxy, qui permet de se baser uniquement sur le header Script-Name envoyé par nginx.

from flask_reverse_proxy import FlaskReverseProxied
proxied = FlaskReverseProxied(app)

Via gunicorn

Avec gunicorn, on peut spécifier la valeur du SCRIPT_NAME comme variable d'environnement qui est prise en compte par flask:

gunicorn -e SCRIPT_NAME=/my-app my_app:app

Solution trouvée sur ce gist.

Des commentaires ? J'y répondrai sur mastodon .

Ce texte est publié sous la licence cc-by-sa.