Docker容器中Flask应用配置Nginx反向代理后返回404的问题排查与解决
你的问题核心非常明确:Nginx把请求的完整路径/my-app原封不动转发给了Flask,但你的Flask应用只配置了/这个根路由,自然会返回404。我们来拆解背后的原理和具体解决方案:
为什么会出现这个问题?
当你访问http://my-server.org/my-app时,Nginx的location /my-app规则会直接把请求转发到http://127.0.0.1:8080/my-app——而你的Flask应用根本没有/my-app这个路由,只有/,所以日志里才会出现GET /my-app HTTP/1.0" 404的记录。
解决方案一:让Nginx处理路径映射(最简单快速)
修改你的Nginx配置,在proxy_pass的末尾加上斜杠,这样Nginx会自动把/my-app之后的路径替换为Flask的根路径:
server { listen 80; listen [::]:80; server_name my-server.org; location /my-app { # 关键:末尾的斜杠会让Nginx做路径替换 proxy_pass http://127.0.0.1:8080/; # 可选但建议:添加代理头让Flask获取真实客户端信息 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-Forwarded-Proto $scheme; } }
修改后重启Nginx生效:
sudo service nginx restart
这样配置后,访问http://my-server.org/my-app会被转发到Flask的根路径/,首页就能正常加载;访问/my-app/static/css/style.css时,会被转发到/static/css/style.css,静态文件也能正常获取。
解决方案二:让Flask感知子路径(更适合复杂应用)
如果你的应用需要生成带子路径的链接(比如用url_for生成跳转链接),或者后续要扩展路由,让Flask自己知道运行在/my-app前缀下会更可靠。
方法1:在代码中配置
直接在Flask应用代码里设置应用根路径:
from flask import Flask app = Flask(__name__) # 设置应用的子路径前缀 app.config['APPLICATION_ROOT'] = '/my-app' @app.route('/') def home(): return "Hello from Flask!"
方法2:通过环境变量配置
启动Flask时,通过环境变量传递前缀配置:
export APPLICATION_ROOT="/my-app" flask run --host 0.0.0.0 --port 5000
这样配置后,Flask会自动给所有路由、静态文件路径加上/my-app前缀,url_for('home')会生成/my-app/,此时Nginx的配置不需要加斜杠,直接转发即可:
location /my-app { proxy_pass http://127.0.0.1:8080; # 同样建议添加代理头 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-Forwarded-Proto $scheme; }
后续使用Gunicorn的注意事项
不管你用flask run还是Gunicorn,原理完全一致:
- 如果用方案一(Nginx处理路径),Gunicorn的配置不需要任何变化,正常启动即可。
- 如果用方案二(Flask感知子路径),启动Gunicorn时同样可以通过环境变量传递配置:
APPLICATION_ROOT="/my-app" gunicorn --bind 0.0.0.0:5000 app:app
验证生效
修改配置后,访问http://my-server.org/my-app,你应该能看到Flask返回的首页,日志里会显示GET / HTTP/1.0" 200(方案一)或者GET /my-app HTTP/1.0" 200(方案二),静态文件也能正常加载。
内容的提问来源于stack exchange,提问作者swiss_knight




