Nginx反向代理下Gunicorn+Flask的SCRIPT_NAME配置问题排查
解决Gunicorn+Flask在Nginx反向代理下SCRIPT_NAME不生效的问题
问题原因
Flask的request.script_name和url_for()依赖WSGI环境中的SCRIPT_NAME变量,而非直接读取HTTP请求头。Nginx配置中设置的SCRIPT_NAME请求头不会自动被Gunicorn转换为WSGI环境变量,因此Flask无法正确获取前缀,导致request.script_name为空、url_for()生成的URL缺失上下文路径。
解决方案
方案1:配置Flask的APPLICATION_ROOT(推荐)
直接在Flask应用中设置上下文根路径,这是Flask原生支持的方式,无需依赖服务器配置:
from flask import Flask, request app = Flask(__name__) app.config['APPLICATION_ROOT'] = '/my-app' # 示例路由 @app.route('/') def index(): return f"Script Name: {request.script_name}"
同时调整Nginx配置,确保路径正确传递:
location /my-app/ { include proxy_params; proxy_pass http://localhost:5000/; # 末尾添加斜杠,将/my-app/后的路径转发给Gunicorn }
此方法会自动让request.script_name返回/my-app,url_for()生成的URL也会自动带上/my-app前缀。
方案2:通过WSGI中间件读取请求头
自定义WSGI中间件,将Nginx传递的SCRIPT_NAME请求头注入到WSGI环境中:
from flask import Flask, request class ScriptNameMiddleware: def __init__(self, app): self.app = app def __call__(self, environ, start_response): # 从请求头中获取SCRIPT_NAME(HTTP_前缀是WSGI对请求头的标准转换) script_name = environ.get('HTTP_SCRIPT_NAME', '') if script_name: environ['SCRIPT_NAME'] = script_name return self.app(environ, start_response) app = Flask(__name__) app.wsgi_app = ScriptNameMiddleware(app.wsgi_app)
Nginx配置保持原有的即可:
location /my-app/ { include proxy_params; proxy_set_header SCRIPT_NAME "/my-app"; proxy_pass http://localhost:5000; }
方案3:在Gunicorn启动时设置环境变量
如果使用systemd管理Gunicorn服务,在服务描述符中添加SCRIPT_NAME环境变量:
[Unit] Description=Gunicorn instance for my Flask app After=network.target [Service] User=your_user Group=www-data WorkingDirectory=/path/to/your/app Environment="SCRIPT_NAME=/my-app" ExecStart=/path/to/gunicorn --workers 3 --bind unix:myapp.sock wsgi:app [Install] WantedBy=multi-user.target
修改后需重新加载systemd配置并重启服务:
sudo systemctl daemon-reload sudo systemctl restart gunicorn
此方式会让Gunicorn默认将SCRIPT_NAME注入到WSGI环境,无需依赖Nginx请求头。
内容的提问来源于stack exchange,提问作者Kaj Kandler
相关产品推荐
相关产品推荐

