如何使用Nginx和uWSGI或Gunicorn在Ubuntu上部署Flask Web应用
你好!欢迎阅读我的博文,你可以跳转到我的个人博客网站,会有更好的排版效果和功能。
此外,本篇博文为本人Pushy原创,如需转载请注明出处:https://pushy.site/posts/1519817202
我在很多的博客中都看过有关Flask应用的部署,也有很多博主在开博后都记录了部署的教程,因为其中的坑可以说不少。一开始我在网上看到相比较与Ubuntu,CentOS因为更新少作为服务器的操作系统会更加稳定。所以在第一次购买云服务器时,我选择了CentOS,后来由于CentOS不同发行版的Nginx缘故,我又换成了Ubuntu的镜像
首先呢,我们先来了解下关于Web服务器与Web应用还有WSGI之间的联系
一、介绍
WSGI(Web Server Gateway Interface),翻译为Python web服务器网关接口,即Python的Web应用程序(如Flask)和Web服务器(如Nginx)之间的一种通信协议。也就是说,如果让你的Web应用在任何服务器上运行,就必须遵循这个协议。
那么实现WSGI协议的web服务器有哪些呢?就比如uWSGI与gunicorn。两者都可以作为Web服务器。可能你在许多地方看到的都是采用Nginx + uWSGI(或gunicorn)的部署方式。实际上,直接通过uWSGI或gunicorn直接部署也是可以让外网访问的,那你可能会说,那要Nginx何用?别急,那么接来下介绍另一个Web服务器——Nginx
Nginx作为一个高性能Web服务器,具有负载均衡、拦截静态请求、高并发...等等许多功能,你可能要问了,这些功能和使用Nginx + WSGI容器的部署方式有什么关系?
首先是负载均衡,如果你了解过OSI模型的话,其实负载均衡器就是该模型中4~7层交换机中的一种,它的作用是能够仅通过一个前端唯一的URL访问分发到后台的多个服务器,这对于并发量非常大的企业级Web站点非常有效。在实际应用中我们通常会让Nginx监听(绑定)80端口,通过多域名或者多个location分发到不同的后端应用。
其次是拦截静态请求,简单来说,Nginx会拦截到静态请求(静态文件,如图片),并交给自己处理。而动态请求内容将会通过WSGI容器交给Web应用处理;
Nginx还有其他很多的功能,这里便不一一介绍。那么前面说了,直接通过uWSGI或gunicorn也可以让外网访问到的,但是鉴于Nginx具有高性能、高并发、静态文件缓存、及以上两点、甚至还可以做到限流与访问控制,所以选择Nginx是很有必要的;
这里可以说明,如果你选择的架构是:Nginx + WSGI容器 + web应用,WSGI容器相当于一个中间件;如果选择的架构是uWSGI + web应用,WSGI容器则为一个web服务器
二、实际部署:
该篇部署的教程是在你已经购买好虚拟主机,并且已经搭建好开发环境的前提下进行的,如果你还没有搭建好开发环境,可以参考我写的文档:
普遍的部署方式都是通过让Nginx绑定80端口,并接受客户端的请求将动态内容的请求反向代理给运行在本地端口的uWSGI或者Gunicorn,所以既可以通过Nginx + uWSGI也可以通过Nginx + Gunicorn来部署Flask应用,这篇教程中都将一一介绍这两种方法
当然采用不同的WSGI容器,Nginx中的配置也会有所不同
1. Nginx + uWSGI:
1.1 配置uWSGI:
我们现在虚拟环境下安装好uWSGI:
(venv) $ pip install uwsgi
安装完成之后我们在项目的目录下(即你实际创建的Flask项目目录,在本文所指的项目目录都假设为/www/demo)创建以.ini为扩展名的配置文件。在设置与Nginx交互的时候有两种方式:
第一种是通过配置网络地址,第二种是通过本地的.socket文件进行通信。需要注意的是,不同的交互方式下,Nginx中的配置也会有所不同
如果采用的是第一种网络地址的方式,则将之前创建uwsgi.ini配置文件添加如下的配置内容:
[uwsgi]
socket = 127.0.0.1:8001 //与nginx通信的端口
chdir = /www/demo/ //你的Flask项目目录
wsgi-file = run.py
callable = app //run.py文件中flask实例化的对象名
processes = 4 //处理器个数
threads = 2 //线程个数
stats = 127.0.0.1:9191 //获取uwsgi统计信息的服务地址
这里的wsgi-file参数所指的run.py其实是启动文件,你也可以使用manage.py。不过我通常习惯创建一个这样的文件,可以直接运行该文件来启动项目:
from app import app
if __name__ == '__main__':
app.run()
保存好配置文件后,就可以通过如下的命令来启动应用了:
(venv) $ uwsgi uwsig.ini
如果你采用的是第二种本地socket文件的方式,则添加如下的配置内容:
[uwsgi]
socket = /www/demo/socket/nginx_uwsgi.socket //与nginx通信的socket文件
chdir = /www/demo/
wsgi-file = run.py
callable = app
processes = 4
threads = 2
stats = 127.0.0.1:9191
可以看到,其实与网络地址的配置方式只有socket参数的配置不同,在这里填写好路径名和文件名并启动uWSGI后,将会自动在改目录下生成nginx_uwsgi.socket文件,这个文件就是用来与Nginx交互的。
1.2 配置Nginx
首先我们来通过apt安装Nginx:
$ sudo apt-get install nginx
安装完成之后,我们cd到/etc/nginx/的目录下(可能由于不同系统导致不同的Nginx发行版缘故,目录有所差别,在此只针对Ubuntu中的发行版的Nginx),可以看到Nginx的所有配置文件。
其中nginx.conf文件为主配置文件,可以用来修改其全局配置;sites-available存放你的配置文件,但是在这里添加配置是不会应用到Nginx的配置当中,需要软连接到同目录下的sites-enabled当中。但是在我实际操作的过程中中,当我在sites-available修改好配置文件后,会自动更新到sites-enabled。如果没有的话,则需要像上述的操作那样,将修改好的配置文件软链接到sites-enabled当中
在上边说到,配置uWSGI有两种与Nginx交互的方式,那么选择不同的方式的话在Nginx的配置也会有所不同:
第一种:网络配置方式:
这里的proxy_set_header设置的三个参数的作用都是能够直接获得到客户端的IP,如果你感兴趣可以参考:Nginx中proxy_set_header 理解
用include uwsgi_params导入uWSGI所引用的参数,通过uwsgi_pass反向代理给在localhost:8001运行的uWSGI:
server {
listen 80; # 监听的端口号
root /www/demo; #Flask的项目目录
server_name xxx.xx.xxx.xxx; # 你的公网ip或者域名
location / {
proxy_set_header x-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
include uwsgi_params;
uwsgi_pass localhost:8001;
}
# 配置static的静态文件:
location ~ ^\/static\/.*$ {
root /www/demo; # 注意!这里不需要再加/static了
}
}
在每次完Nginx配置文件内容后,需要通过如下的命令来重启Nginx:
$ nginx -s reload
第二种:socket文件方式:
与上边的配置内容大体相同,只是在配置uwsgi_pass不是反向代理给网络地址,而是通过socket文件进行交互,我们只需要指定之前设置的路径和文件名即可:
server {
listen 80;
root /www/demo;
server_name xxx.xx.xxx.xxx;
location / {
proxy_set_header x-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
include uwsgi_params;
uwsgi_pass unix:/www/demo/socket/nginx_uwsgi.socket;
}
location ~ ^\/static\/.*$ {
root /www/demo;
}
}
2. Nginx + Gunicorn
2.1 配置Gunicorn:
首先先在虚拟环境下安装Gunicorn:
(venv) $ pip install gunicorn
安装完成后,我们来创建以.py结尾的配置文件,这里我参考了Jiyuankai的GitHub关于Gunicorn的配置文件内容:
from gevent import monkey
monkey.patch_all()
import multiprocessing
debug = True
loglevel = 'debug'
bind = '127.0.0.1:5000' //绑定与Nginx通信的端口
pidfile = 'log/gunicorn.pid'
logfile = 'log/debug.log'
workers = multiprocessing.cpu_count() * 2 + 1
worker_class = 'gevent' //默认为阻塞模式,最好选择gevent模式
需要注意的是要在配置文件的同层目录下创建log文件,否则运行gunicorn将报错。添加完配置内容并保存为gconfig.py文件后,我们就也可以通过gunicorn来运行Flask应用了:
(venv)$ gunicorn -c /www/demo/gconfig.py run:app
2.2 配置Nginx:
和uWSGI的任意一种配置方法类似,只是在location中的配置有所不同:
server {
listen 80;
root /www/demo;
server_name xxx.xx.xxx.xxx;
location / {
proxy_set_header x-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_pass http://localhost:5000/; # gunicorn绑定的端口号
}
# 配置static的静态文件:
location ~ ^\/static\/.*$ {
root /www/demo;
}
}
通过Gunicorn的Nginx配置中,我们只需要通过proxy_pass参数反向代理给运行在http://localhost:5000/上的Gunicorn
三、守护进程
如果你采取如上的任意一种部署方式,在Nginx与uWSGI或Gunicorn同时运行,并且配置无误的状态下,那么你现在应该是可以通过你的公网ip或者域名访问到你的网站了。
但是还有一个问题,到目前为止,uWSGI和gunicorn都是直接通过命令行运行,并不能够在后台运行,也是当我们关闭了xShell(或者你使用的是Putty及其他SSH连接的软件),将无法再访问到你的应用。所以我们需要让uWSGI或gunicorn在后台运行,也就是所谓的daemon(守护进程)。
1. nohup:
如果你熟悉Linux命令,你应该知道在Linux中后台运行可以通过nohup命令,例如我们要让gunicorn在后台运行,我们只需要运行nohup命令:
(venv) $ nohup gunicorn -c gconfig.py run:app &
运行后你可以通过ps -e | grep gunicorn指令来查看到当前gunicorn的运行状态:

如果你选择的是uWSGI,同样也可以通过nohup命令来实现守护进程:
(venv) $ nohup uwsgi uwsgi.ini &
这样你就可以关闭连接服务器的终端,还能通过你的浏览器访问到你的Flask应用了!
2. supervisor
但是nohup运行的后台程序并不能够可靠的在后台运行,我们最好让我们的后台程序能够监控进程状态,还能在意外结束时自动重启,这就可以使用一个使用Python开发的进程管理程序supervisor。
首先我们通过apt来安装supervisor:
$ sudo apt-get install supervisor
安装完成后,我们在/etc/supervisor/conf.d/目录下创建我们控制进程的配置文件,并以.conf结尾,这样将会自动应用到主配置文件当中,创建后添加如下的配置内容:
[program:demo]
command=/www/demo/venv/bin/gunicorn -c /pushy/blog/gconfig.py run:app
directory=/www/demo //项目目录
user=root
autorestart=true //设置自动重启
startretires=3 //重启失败3次
在上面的配置文件中,[program:demo]设置了进程名,这与之后操作进程的状态名称有关,为demo;command为进程运行的命令,必须使用绝对路径,并且使用虚拟环境下的gunicorn命令;user指定了运行进程的用户,这里设置为root
保存配置文件之后,我们需要通过命令来更新配置文件:
$ supervisorctl update
命令行将显示:demo: added process group,然后我们来启动这个demo进程:
$ supervisorctl start demo
当然你也直接在命令行输入supervisorctl进入supevisor的客户端,查看到当前的进程状态:
demo RUNNING pid 17278, uptime 0:08:51
通过stop命令便可以方便的停止该进程:
supervisor> stop demo
参考资料:
如何使用Nginx和uWSGI或Gunicorn在Ubuntu上部署Flask Web应用的更多相关文章
- nginx上部署python web
nginx上部署python web http://uwsgi-docs.readthedocs.io/en/latest/tutorials/Django_and_nginx.html
- 基于nginx和uWSGI在Ubuntu上部署Djan
http://www.jianshu.com/p/e6ff4a28ab5a 文/Gevin(简书作者)原文链接:http://www.jianshu.com/p/e6ff4a28ab5a著作权归作者所 ...
- 基于Nginx和uWSGI在Ubuntu上部署Django项目
前言: 对于做Django web项目的童鞋,重要性不言而喻. 参考:https://www.cnblogs.com/alwaysInMe/p/9096565.html https://blog.cs ...
- Nginx模块之————RTMP模块在Ubuntu上以串流直播HLS视频
Nginx的安装在Ubuntu上以串流直播HLS视频 https://www.vultr.com/docs/setup-nginx-on-ubuntu-to-stream-live-hls-video
- 基于nginx和uWSGI在Ubuntu上部署Django
转自: http://www.jianshu.com/p/e6ff4a28ab5a
- nginx+uwsgi 和nginx+gunicorn区别、如何部署
[线上环境部署Django,nginx+uwsgi 和nginx+gunicorn,这两种方案,应该如何选择?] 大家是采用的何种部署方式? 第一种,高并发稳定一点 我们公司使用的是nginx+gun ...
- Nginx+uWSGI+Django+Python+ MySQL 搭建可靠的Python Web服务器
一.安装所需工具 yum -y install gcc gcc-c++ rpm-build mysql* libtool-ltdl* libtool automake autoconf libtool ...
- python3.6 ubuntu部署nginx、 uwsgi、 django
ubuntu部署nginx. uwsgi. django 将项目上传到服务器 python manager.py runserver 0:80 在浏览器输入服务器的域名或者ip地址,访问成功. 安装u ...
- 使用Nginx和uwsgi部署Flask项目
前言 之前用Flask框架开发了一个Python的Web项目,使用Nginx和uWSGI部署起来感觉挺麻烦,过程中还因为对Flask框架的不熟悉,花了好长时间才把应用完全部署起来.下面分享部署成功 ...
随机推荐
- Excel中复杂跨行跨列数据
XSSFWorkbook wb = new XSSFWorkbook(); // 工作表 XSSFSheet sheet = wb.createSheet("车辆使用情况统计"); ...
- 剑指offer五十八之对称的二叉树
一.题目 请实现一个函数,用来判断一颗二叉树是不是对称的.注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的.二.思路 递归做,详见代码 三.代码 /* public class TreeN ...
- 剑指offer三十二之把数组排成最小的数
一.题目 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个.例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323. 二.思路 ( ...
- Netty核心概念(6)之Handler
1.前言 本节介绍Netty中第三个重要的概念——Handler,这个在前两节都提到了,尤其是Channel和Handler联系紧密.handler本身的设计非常简单,但是所起到的作用却很大,Nett ...
- Java之IO(一)InputStream和OutputStream
转载请注明源出处:http://www.cnblogs.com/lighten/p/6964702.html 1.前言 计算机的IO操作一直都是比较重要的一环,IO顾名思义,就是输入输出流.不管是磁盘 ...
- 【树】Count Complete Tree Nodes
题目: 求完全二叉树节点数. 思路: 满二叉树的节点数是2^k-1,k是树的深度. 所以我们可以先判断该树是否为满二叉树,然后是的话直接返回结果,如果不是递归地求解子树. 这样不用遍历所有的节点.复杂 ...
- Go语言学习笔记六: 循环语句
Go语言学习笔记六: 循环语句 今天学了一个格式化代码的命令:gofmt -w chapter6.go for循环 for循环有3种形式: for init; condition; increment ...
- 深度学习--RNN,LSTM
一.RNN 1.定义 递归神经网络(RNN)是两种人工神经网络的总称.一种是时间递归神经网络(recurrent neural network),另一种是结构递归神经网络(recursive neur ...
- 将AJAX Post的Data转为对应的Class
在使用DataTables从服务端获取数据时,在非MVC的情况下没有MVC的自动绑定功能,所以需要自己写一个绑定,将Post过来的InputStream转为对应的类. HTML: <form i ...
- sql典例分析
1. 条件过滤 & Having 表结构 #tab_a #tab_b 表关系 tab_a.id = tab_b.relation_id 表数据 需求 查新把tab_a的ID对应的表tab_b的 ...