Nginx try_files未加载index.html,请求转发至Flask的原因咨询
我在AWS EC2实例上使用Nginx/Gunicorn/Flask搭建Web应用,整体运行正常,但存在一个疑问,希望得到解答或建议!
- AWS EC2实例
- Python v3.10.10
- Nginx v1.22.1
- Gunicorn v21.2.0
- Flask v2.3.2
已为Python创建名为“venv”的虚拟环境,路径为“/home/ec2-user/venv”
Nginx配置文件(部分内容省略)@ /etc/nginx
user nginx; worker_processes 1; pid /run/nginx.pid; events{ worker_connections 1024; } http{ include /etc/nginx/mime.types; default_type application/octet-stream; server{ listen 80; server_name example.com; <------ 虚拟域名! root /usr/share/nginx/html; location / { try_files $uri @flask; } location @flask { proxy_set_header Host $http_host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_pass http://localhost:8080; } } }
执行以下步骤重启Nginx:
sudo systemctl stop nginx sudo systemctl start nginx
在根目录“/usr/share/nginx/html”下存在index.html文件。
flask_app.py @ /home/ec2-user/python.source
from flask import Flask app = Flask(__name__) @app.route("/") def index(): return "Hello World" if __name__ == '__main__': app.run()
wsgi.py @ /home/ec2-user/python.source
from flask_app import app if __name__ == '__main__': app.run()
flask.service @ /etc/systemd/system
[Unit] Description=Gunicorn instance to serve Flask After=network.target [Service] User=ec2-user Group=ec2-user WorkingDirectory=/home/ec2-user/python.source Environment="PATH=/home/ec2-user/venv/bin" ExecStart=/home/ec2-user/venv/bin/gunicorn --bind 0.0.0.0:80 wsgi:app [Install] WantedBy=multi-user.target
执行以下步骤启动flask.service并设置开机自启:
sudo systemctl start flask sudo systemctl enable flask
当访问http://example.com/时,页面显示:
Hello World
我对try_files指令的理解是Nginx会从左到右尝试匹配资源,在此场景下,应该先匹配$uri,而根目录下存在index.html,但实际却显示Flask返回的Hello World,说明try_files未找到静态资源转而转发至Flask。请问该指令的匹配逻辑是怎样的?为何index.html未被加载?
核心原因
问题出在try_files的匹配逻辑和缺少index指令的配合:
- 当访问
http://example.com/时,$uri的值是/,这是一个目录路径,而非具体文件路径。 try_files $uri @flask的逻辑是:仅尝试查找与$uri完全匹配的文件,不会自动去目录下查找index.html这类默认索引文件。- 由于
/不是一个存在的文件,Nginx直接触发最后一个选项@flask,将请求转发给Flask处理。
try_files的匹配逻辑
try_files的工作流程是:
- 从左到右依次检查每个参数对应的文件/路径是否存在
- 如果找到存在的文件,直接返回该文件
- 如果所有文件都不存在,执行最后一个选项(可以是内部重定向、命名location或者返回错误码)
注意:try_files不会自动处理目录的默认索引文件,必须通过显式配置来支持。
解决方法
有两种方式可以让Nginx优先加载index.html:
方法1:修改try_files,添加目录匹配
将location /中的try_files指令修改为:
try_files $uri $uri/ @flask;
$uri/表示尝试访问$uri对应的目录,此时如果配置了index指令,Nginx会自动查找目录下的索引文件。
方法2:添加index指令
在server块或location /块中添加index指令,指定默认索引文件:
index index.html;
配合修改后的try_files(如上),当访问目录/时,Nginx会先尝试加载/usr/share/nginx/html/index.html,只有当该文件不存在时,才会转发给Flask。
额外注意点
你的flask.service中Gunicorn绑定的是0.0.0.0:80,但Nginx也监听80端口,这会导致端口冲突,理论上两个服务无法同时启动。而Nginx的proxy_pass指向的是localhost:8080,推测这里是配置笔误,建议将Gunicorn的绑定端口改为8080:
ExecStart=/home/ec2-user/venv/bin/gunicorn --bind 0.0.0.0:8080 wsgi:app
内容的提问来源于stack exchange,提问作者kazutaka

