Flask结合gunicorn和nginx反向代理的生产环境部署及踩坑记录
前言
之前自己写的flask使用gunicorn上线生产环境没有什么问题,但是最近搭建了一个现成的flask项目,当使用python直接运行时不会有问题,而使用gunicorn时则会出现一些问题。
部署过程
运行测试
这里使用pyenv创建了一个虚拟环境,并安装好依赖
pyenv virtualenv 3.9.6 freegpt
pyenv activate freegpt
pip install -r requirements.txt
下面是入口函数run.py:
from server.app import app
from server.website import Website
from server.backend import Backend_Api
from json import load
if __name__ == '__main__':
# Load configuration from config.json
config = load(open('config.json', 'r'))
site_config = config['site_config']
# Set up the website routes
site = Website(app)
for route in site.routes:
app.add_url_rule(
route,
view_func=site.routes[route]['function'],
methods=site.routes[route]['methods'],
)
# Set up the backend API routes
backend_api = Backend_Api(app, config)
for route in backend_api.routes:
app.add_url_rule(
route,
view_func=backend_api.routes[route]['function'],
methods=backend_api.routes[route]['methods'],
)
# Run the Flask server
print(f"Running on port {site_config['port']}")
app.run(**site_config)
print(f"Closing port {site_config['port']}")
其中site_config.json文件如下:
{
"site_config": {
"host": "127.0.0.1",
"port": 1234,
"debug": false
},
"use_auto_proxy": false
}
意思是,运行flask服务于127.0.0.1:1234,只运行本地访问,后期我们需要搭建Nginx进行反向代理。
我们先使用python直接运行测试一下看能否跑起来以及能否正常访问。
python run.py

我们在服务器使用curl进行请求
curl 127.0.0.1:1234

数据返回正常,说明可以正常访问。
gunicorn搭建
Gunicorn是一个WSGI HTTP Server,是针对Python的、在Unix系统上运行的、用来解析HTTP请求的网关服务。
它的特点是:能和大多数的Python web框架兼容;使用简单;轻量级的资源消耗;高性能。
首先在当前虚拟环境下安装gunicorn
pip install gunicorn
然后我们使用gunicorn将flask项目跑起来,并且仅对本机开放,端口4444
gunicorn run:app -b 127.0.0.1:4444 --access-logfile access.log --error-logfile error.log &
使用ps命令可以看到当前已经成功在后台运行起来了
ps aux | grep gunicorn

踩坑
但是此时当我们再次使用curl访问127.0.0.1:4444时:

出现了404的错误。
我们查看gunicorn生成的日志文件:
# access.log
127.0.0.1 - - [13/Jul/2023:12:51:11 -0400] "GET / HTTP/1.1" 404 207 "-" "curl/7.76.1"
可以看到成功的请求到了我们的wsgi server,但是返回了404。在外网论坛上摸索了一番,问题出在了run.py上。
run.py文件中的所有代码都是写在if __name__ == "__main__":之下的,这在python语法中代表着主函数入口。
- 当使用Python直接运行脚本时(例如:
python run.py),if __name__ == '__main__'条件下的代码块会被执行,包括app.run()。这将启动Flask服务器,并让应用程序开始监听指定的主机和端口。 - 当使用
Gunicorn运行应用程序时(例如:gunicorn --bind 127.0.0.1:4444 run:app),if __name__ == '__main__'条件下的代码块不会被执行。因为Gunicorn实际上是将你的代码作为一个模块导入,而不是直接运行该代码。在这种情况下,Gunicorn会在内部处理Flask服务器的启动逻辑,并监听指定的主机和端口。也就因此自己在app.run(**kwargs)中设定的host、port、debug等参数也就失效了。
因此,无论是使用Python直接运行还是使用Gunicorn运行应用程序,app.run()只会在Python直接运行脚本时执行。而在使用Gunicorn运行时,if __name__ == '__main__'条件下的代码块将被跳过,包括app.run()。这是因为Gunicorn已经处理了服务器的启动逻辑。
因此,if __name__ == '__main__'条件的目的是为了确保在直接运行脚本时才执行特定的代码块,而在被导入为模块时跳过这些代码块。这样可以确保在使用Gunicorn启动应用程序时不会重复启动Flask服务器,并避免出现意外行为。
解决方案
既然已经知道了错误的逻辑,那么解决方法就很简单了,只要把除了app.run()的其他代码全部移出if __name__ == "__main__"即可。修改后的run.py如下:
from server.app import app
from server.website import Website
from server.backend import Backend_Api
from json import load
# Load configuration from config.json
config = load(open('config.json', 'r'))
site_config = config['site_config']
# Set up the website routes
site = Website(app)
for route in site.routes:
app.add_url_rule(
route,
view_func=site.routes[route]['function'],
methods=site.routes[route]['methods'],
)
# Set up the backend API routes
backend_api = Backend_Api(app, config)
for route in backend_api.routes:
app.add_url_rule(
route,
view_func=backend_api.routes[route]['function'],
methods=backend_api.routes[route]['methods'],
)
if __name__ == '__main__':
# Run the Flask server
print(f"Running on port {site_config['port']}")
app.run(**site_config)
print(f"Closing port {site_config['port']}")
这样就可以保证python和gunicorn方式均可正常运行。
先kill掉之前正在运行的gunicorn,并重新启动
kill -9 1275864 1275865
gunicorn run:app -b 127.0.0.1:4444 --access-logfile access.log --error-logfile error.log &
可以看到现在请求127.0.0.1:4444已经正确响应了

Nginx反向代理
目前搭建的服务只能服务器自己访问到,下面我们通过nginx反向代理将其映射到对外的80端口
安装配置nginx就不多说了,下面讲讲配置文件的写法。其实很简单
vim /etc/nginx/nginx.conf
# nginx.conf
...
server {
listen 80;
server_name xxxxxxxx; # 此处填绑定的域名
location / {
proxy_pass http://localhost:4444;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
}
}
...
然后运行nginx即可
nginx -t
nginx
此时使用本机访问域名的80端口已可以正常访问了。

Flask结合gunicorn和nginx反向代理的生产环境部署及踩坑记录的更多相关文章
- [转]Nginx反向代理和负载均衡部署指南
Nginx反向代理和负载均衡部署指南 1. 安装 1) 从Nginx官网下载页面(http://nginx.org/en/download.html)下载Nginx最 ...
- Nginx反向代理和负载均衡部署指南
1. 安装 1) 从Nginx官网下载页面(http://nginx.org/en/download.html)下载Nginx最新版本(目前是1.5.13版本)安装包: ...
- Nginx反向代理腾讯云COS的一个坑
版权声明:本文由黄希彤 原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/668639001484812620 来源:腾云 ...
- Nginx入门及如何反向代理解决生产环境跨域问题
1.Nginx入门与基本操作篇 注:由于服务器是windows系统,所以本文主要讲解Nginx在windows下的操作. 首先下载Nginx 解压缩,我们所有的配置基本都在万能的 nginx/conf ...
- Nginx反向代理其他使用方式
Nginx反向代理在生产环境中使用很多的. 场景1: 域名没有备案,可以把域名解析到香港一台云主机上,在香港云主机做个代理,而网站数据是在大陆的服务器上. 示例1: server { listen 8 ...
- Vue Nginx反向代理配置 解决生产环境跨域
Vue本地代理举例: module.exports = { publicPath: './', devServer: { proxy: { '/api': { target: 'https://mov ...
- nginx 反向代理配置示例
Nginx反向代理在生产环境中使用很多的. 场景1: 域名没有备案,可以把域名解析到香港一台云主机上,在香港云主机做个代理,而网站数据是在大陆的服务器上. server { listen ; serv ...
- Server 主机屋云服务器 宝塔面板 部署nginx反向代理的vue项目
图文记录云服务器上部署需要nginx反向代理的vue项目: 一.先登录并购买云服务器,根据自己需求购买,此处不详细介绍: 二.登录后如下图,点击进入云服务器界面: 三.在云服务器界面点击管理,进入管理 ...
- Nginx反向代理实现Tomcat多个应用80端口访问
应用背景 一般我们在开发时,一个工程里会有多个Web应用,比如一个前台一个后台,那我们就需要配置2个Tomcat服务器,比如一个是http://localhost:8080,一个是http://loc ...
- CORS跨域与Nginx反向代理跨域优劣对比
最近写了一些关于前后端分离项目之后,跨域相关方案的基本原理和常见误区的帖子,主要包括CORS和Nginx反向代理.这两种方案项目中都有在用,各有优缺,关于具体使用哪种方案,大家的观点也不大一致,本文主 ...
随机推荐
- C 语言版线程池
一.初始线程池 1.1 何为线程池? 我们先来打个比方,线程池就好像一个工具箱,我们每次需要拧螺丝的时候都要从工具箱里面取出一个螺丝刀来.有时候需要取出一个来拧,有时候螺丝多的时候需要多个人取出多个来 ...
- Cmder: 懒癌必备!从此告别记事本记命令的日子
前言 平时开发中遇到这样那样的命令需要记下来,一般做法是这样. 新建记事本 将需要记下的关键命令保存. 每次需要使用时,粘贴复制即可. 好像没什么毛病!直到遇到了 Cmder... 当看到同事分析问题 ...
- 看了绝对不会忘的 去中心化金融 - DeFi
DeFi Decentralized Finance, 去中心化金融,主要就是 以区块链技术为载体的金融模式. 注意:区块链是一种技术,而比特币是一种应用. Terminology fungible ...
- NEQR: novel enhanced quantum representation
一.概述 NEQR利用量子叠加和量子纠缠的特性,将数字图像转换为量子态表示,并通过量子门操作进行处理和操作.相较于传统的经典图像表示方法,NEQR具有更高的图像压缩率和更强的安全性,能够在保持图像 ...
- vivo 推送系统的容灾建设与实践
作者:vivo 互联网服务器团队 - Yu Quan 本文介绍了推送系统容灾建设和关键技术方案,以及实践过程中的思考与挑战. 一.推送系统介绍 vivo推送平台是vivo公司向开发者提供的消息推送服务 ...
- 【JS】Knockout动态刷新及绑定数据
<script> // Knockout ViewModel Define function RemarkTemplateModel() { var self = this; // Cur ...
- Grafana系列-统一展示-7-ElasticSearch数据源
系列文章 Grafana 系列文章 ElasticSearch 数据源 Grafana内置了对Elasticsearch的支持.你可以进行多种类型的查询,以可视化存储在Elasticsearch中的日 ...
- 文心一言 VS chatgpt (2)-- 算法导论1.2
一.给出在应用层需要算法内容的应用的一个例子,并讨论涉及的算法的功能. 文心一言: 在应用层需要算法内容的应用的一个例子是无人机自主飞行控制.无人机自主飞行控制需要算法来确定无人机的位置.速度和方向, ...
- 2021-01-03:java中,描述一下什么情况下,对象会从年轻代进入老年代?
福哥答案2021-01-03: 1.对象的年龄超过一定阀值,-XX:MaxTenuringThreshold 可以指定该阀值.2.动态对象年龄判定,有的垃圾回收算法,比如 G1,并不要求 age 必须 ...
- 2021-09-05:单词搜索 II。给定一个 m x n 二维字符网格 board 和一个单词(字符串)列表 words,找出所有同时在二维网格和字典中出现的单词。单词必须按照字母顺序,通过 相邻的
2021-09-05:单词搜索 II.给定一个 m x n 二维字符网格 board 和一个单词(字符串)列表 words,找出所有同时在二维网格和字典中出现的单词.单词必须按照字母顺序,通过 相邻的 ...