十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Flask 部署实战:使用 Nginx 反向代理托管 WSGI 应用

Flask 部署实战:使用 Nginx 反向代理托管 WSGI 应用 Flask 部署实战使用 Nginx 反向代理托管 WSGI 应用【免费下载链接】flaskThe Python micro framework for building web applications.项目地址: https://gitcode.com/gh_mirrors/fl/flask导读在生产环境中Flask 应用通常不应直接暴露给公网而是由 Nginx 这类高性能 HTTP 服务器作为反向代理接收外部请求、处理 TLS 与安全防护再将请求转发给后端的 WSGI 服务器。本文以当前仓库 docs/deploying/nginx.rst 为核心完整讲解 Nginx 的server与proxy_pass配置、X-Forwarded-*请求头的传递以及如何通过 Werkzeug 的ProxyFix中间件让 Flask 信任这些头信息读完本文你将能够独立完成域名解析 → Nginx 配置 → WSGI 服务器对接 → Flask 信任代理头的完整部署链路。一、为什么需要在 Flask 前再放一个 HTTP 服务器Flask 本身是一个 WSGI应用真正执行请求分发的是 WSGI服务器负责把 HTTP 请求转换成 WSGI environ再把 WSGI 响应转换回 HTTP 响应。在本地开发时我们使用 Flask 内置的开发服务器但它不能用于生产环境——正如 docs/deploying/index.rst 所强调的它没有针对安全、稳定或效率做特别设计。虽然绝大多数 WSGI 服务器Gunicorn、Waitress、uWSGI 等都内建了 HTTP 能力但在其前面再放一台专用的 HTTP 服务器即反向代理通常是更好甚至必要的选择安全由专业 HTTP 服务器处理 TLS 终结、请求头校验、防 DDoS 等WSGI 服务器只需专注业务性能Nginx 的事件驱动模型在处理静态文件、并发连接上比多数纯 Python WSGI 服务器更高效能力支持虚拟主机、负载均衡、访问日志、缓存等丰富特性。当前仓库的部署文档把这一主题组织为两条主线一类是 Gunicorn、Waitress、uWSGI 等 WSGI 服务器另一类就是 Nginx、Apache httpd 等站在 WSGI 服务器前面的 HTTP 服务器两者配合形成经典的 反向代理架构。二、准备工作域名与本地域名模拟Nginx 反向代理的配置以域名server_name为入口因此先解决域名问题。真实场景中你需要从域名注册商处购买域名向主机提供商购买服务器空间在注册商处把域名指向主机提供商的名称服务器。本地模拟编辑/etc/hosts如果不方便购买域名可以在本地把任意域名关联到本机 IP。在 Linux 上编辑/etc/hosts加入一行127.0.0.1 hello.localhost这样浏览器访问http://hello.localhost时就会请求本机。值得一提的是现代 Linux 系统通常默认把任何以.localhost结尾的域名视为本机地址无需在hosts文件中添加任何条目即可生效。三、Nginx 核心配置一个最小的反向代理3.1 配置文件位置在 Linux 上Nginx 的主配置文件位于/etc/nginx/nginx.conf不同发行版可能略有差异请查阅你所用系统的文档确认。3.2 最小可用的server配置块原文档给出的完整配置如下先删除或注释掉已有的任何server段再添加一个新的server段用proxy_pass指令把请求转发给 WSGI 服务器监听的地址。这里假设 WSGI 服务器在本地http://127.0.0.1:8000监听server { listen 80; server_name _; location / { proxy_pass http://127.0.0.1:8000/; 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 /; } }3.3 各配置项的含义配置项值作用listen 8080在 80 端口监听 HTTP 请求server_name __匹配任意主机名通配未匹配到其他 server 块的请求location //拦截所有路径的请求proxy_pass http://127.0.0.1:8000/末尾带/把请求转发给本地 WSGI 服务器proxy_set_header X-Forwarded-For$proxy_add_x_forwarded_for把客户端真实 IP 追加到 X-Forwarded-For 链proxy_set_header X-Forwarded-Proto$scheme传递原始请求协议http/httpsproxy_set_header X-Forwarded-Host$host传递原始请求的 Hostproxy_set_header X-Forwarded-Prefix/传递应用挂载的前缀路径3.4 关于proxy_pass的路径细节proxy_pass http://127.0.0.1:8000/;中的 URI 部分/很关键当proxy_pass带 URI 时Nginx 会用该 URI 替换location匹配到的部分。这里把整个根路径都转给后端是最常见的整站代理写法。如果你希望把应用挂载在某个子路径例如/myapp下则需同时考虑location /myapp/ { proxy_pass http://127.0.0.1:8000/; }的路径剥离逻辑在X-Forwarded-Prefix中传递该前缀让应用知道自己的挂载路径下文详述。配置完成后需要重载 Nginx 使修改生效如nginx -s reload并确保你的 WSGI 服务器已经启动并在8000端口监听。四、让 Flask 知道自己在代理之后ProxyFix4.1 为什么必须信任代理头一旦 Nginx 介入从 WSGI 服务器和 Flask 应用的视角看请求来自127.0.0.1的 Nginx而不是互联网上的真实客户端。为了把真实信息客户端 IP、原始协议、原始 Host、挂载前缀传达给应用HTTP 服务器会设置X-Forwarded-*头。但Flask 默认不会信任这些头需要显式接入 Werkzeug 提供的ProxyFix中间件from werkzeug.middleware.proxy_fix import ProxyFix app.wsgi_app ProxyFix( app.wsgi_app, x_for1, x_proto1, x_host1, x_prefix1 )这段代码出自 docs/deploying/proxy_fix.rst它把 Flask 应用的 WSGI 层用ProxyFix包裹起来使request.remote_addr、request.url、url_for等使用代理头中的真实值。4.2 参数含义与安全边界ProxyFix的各关键字参数表示前面有几层代理在设置对应头例如x_for1表示信任最外层的 1 个X-Forwarded-For值x_for信任几层X-Forwarded-For客户端 IPx_proto信任几层X-Forwarded-Proto协议x_host信任几层X-Forwarded-Host主机名x_prefix信任几层X-Forwarded-PrefixURL 前缀。原文档特别警告传入的头是可以被伪造的因此必须精确配置代理层数。如果配置错误例如信任了本不可信的层攻击者可以伪造X-Forwarded-For来伪装 IP、伪造协议绕过安全判断属于典型的安全隐患。只有当应用确实处于反向代理之后时才应启用该中间件。4.3 与 Apache httpd 配置的对照同样的思路也适用于 Apache httpd 反向代理ProxyPass / http://127.0.0.1:8000/会自动设置X-Forwarded-For与X-Forwarded-Host而X-Forwarded-Proto和X-Forwarded-Prefix需要手工通过RequestHeader设置。这印证了不同 HTTP 服务器设置的代理头集合可能不同——而ProxyFix的四个参数正是为了精确声明哪个头由谁设置、信任几层。五、URL 生成与代理前缀从源码看 Flask 的消费方式反向代理场景下Flask 内部通过 WSGI environ 中的SCRIPT_NAME和HTTP_HOST等字段来生成 URL。仓库测试 tests/test_basic.py 中有一个典型用例自定义中间件把environ[SCRIPT_NAME]设置为/bar同时将APPLICATION_ROOT配置为/bar随后验证url_for等生成的路径包含该前缀。这正对应X-Forwarded-Prefix的消费链路Nginx 把挂载前缀通过代理头传给应用ProxyFix据此修正 environ 中的SCRIPT_NAMEurl_for生成的链接才会带上正确前缀。由此可以推断两点部署要点前端路径与后端SCRIPT_NAME必须一致如果 Nginx 把应用挂载在/myapp而 Flask 认为自己的根是/则url_for生成的链接、静态资源路径都会对不上X-Forwarded-Prefix的默认值原文档示例中将其设为/应用位于根路径如果挂载到子路径应把该头改为实际前缀例如/myapp并在ProxyFix中启用x_prefix1。六、与 WSGI 服务器的配合以 Gunicorn 为例Nginx 只负责转发请求真正运行 Flask 应用的仍是 WSGI 服务器。以 Gunicorn 为例典型的启动方式是$ gunicorn -w 4 hello:create_app() Starting gunicorn 20.1.0 Listening at: http://127.0.0.1:8000 (x) Using worker: sync其中-w 4表示启动 4 个工作进程初始值可参考CPU * 2hello:create_app()是{模块导入路径}:{应用变量或工厂函数调用}的语法。Gunicorn 文档明确建议不要以 root 身份运行 WSGI 服务器否则应用代码也以 root 权限执行不安全这也正是它无法绑定 80/443 特权端口、需要 Nginx 在前的根本原因在反向代理场景下不要使用-b 0.0.0.0绑定所有网卡——否则外部流量可以绕过 Nginx 直连 WSGI 服务器反向代理的安全与治理能力形同虚设。正确的做法是只让 WSGI 服务器监听127.0.0.1由 Nginx 通过内网/本机端口访问它。七、完整部署链路与自检清单将以上内容串起来一套基于 Nginx 的 Flask 生产部署包含 5 个环节域名就绪购买域名并解析或通过/etc/hosts/.localhost后缀在本地模拟启动 WSGI 服务器在本机非特权端口如 8000监听127.0.0.1切勿绑定0.0.0.0、切勿以 root 运行配置 Nginx在/etc/nginx/nginx.conf中移除旧server段按上文示例添加server与location用proxy_pass转发并设置四个X-Forwarded-*头接入 ProxyFix用werkzeug.middleware.proxy_fix.ProxyFix包裹app.wsgi_app按真实代理层数设置x_for/x_proto/x_host/x_prefix验证通过域名访问应用检查request.remote_addr是否为真实客户端 IP、request.url是否保留原始协议与 Host、url_for生成的链接前缀是否正确。最后对照 docs/deploying/index.rst 给出的核心告诫做一次自查生产环境绝不使用 Flask 内置开发服务器ProxyFix只在真实处于代理之后时才启用且代理层数必须与 Nginx 实际配置严格一致这是反向代理部署中最容易出错、也最关乎安全的一环。【免费下载链接】flaskThe Python micro framework for building web applications.项目地址: https://gitcode.com/gh_mirrors/fl/flask创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表