本文介绍用Nginx 和 Gunicorn 在ubuntu上发布 Flask 服务应用,Ubuntu 的版本原文是18,我的测试环境是20。
前提条件
本文内容不包含nginx 的安装,可以参考:Nginx 在Ubuntu 上的安装,测试
本文需要你有一个非root 的用户,但属于sudo组,如果没有,在根用户下如下操作:
-
adduser sammy
-
usermod -aG sudo sammy
安装
执行下面操作:
sudo apt update
sudo apt install python3-pip python3-dev build-essential libssl-dev libffi-dev python3-setuptools
建立一个python虚拟环境
安装虚拟环境程序
sudo apt install python3-venv
建立一个工作目录:
mkdir ~/myproject
cd ~/myproject
在目录里建立一个虚拟环境:
python3.6 -m venv myprojectenv
上面是原文的操作,可能原文是ubuntu18的原因,python3的版本是3.6, ubuntu20 的版本是3.8,所以我的操作是:
python3.8 -m venv myprojectenv
我估计直接python3 -m venv myprojectenv 应该也是可以的,否则还要查看自己python3的版本。
在安装其他应用之前,激活虚拟环境:
source myprojectenv/bin/activate
在虚拟环境安装 gunicorn flask,在虚拟环境里不要用pip3,而是pip
pip install gunicorn flask
建立简单样例应用
建立一个非常简单的Flask 应用:
nano ~/myproject/myproject.py
文件内容为:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "<h1 style='color:blue'>Hello There!</h1>"
if __name__ == "__main__":
app.run(host='0.0.0.0')
如果有防火墙,需要设置:
sudo ufw allow 5000
现在启动我们的应用:
python myproject.py
应该可以看到:
Output
* Serving Flask app "myproject" (lazy loading)
* Environment: production
WARNING: Do not use the development server in a production environment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
在浏览器里输入:
http://your_server_ip:5000
这里一定要用你主机的ip地址替代上面的your_server_ip。
你应该可以看到
说明我们的简单Flask 应用是成功的。
建立WSGI入口点
建立一个wsgi 入口点文件:
nano ~/myproject/wsgi.py
文件内容为:
from myproject import app
if __name__ == "__main__":
app.run()
配置Gunicorn
首先,我们测试 Gunicorn 应用:
cd ~/myproject
gunicorn --bind 0.0.0.0:5000 wsgi:app
应该可以看到输出:
Output
[2018-07-13 19:35:13 +0000] [28217] [INFO] Starting gunicorn 19.9.0
[2018-07-13 19:35:13 +0000] [28217] [INFO] Listening at: http://0.0.0.0:5000 (28217)
[2018-07-13 19:35:13 +0000] [28217] [INFO] Using worker: sync
[2018-07-13 19:35:13 +0000] [28220] [INFO] Booting worker with pid: 28220
与上面的测试flask 应用一样,在浏览器里输入ip地址和端口号:
http://your_server_ip:5000
输出的结果和上面应该一样:
退出环境:
deactivate
下面建立一个看守程序:
sudo nano /etc/systemd/system/myproject.service
文件内容为:
[Unit]
Description=Gunicorn instance to serve myproject
After=network.target
[Service]
User=sammy
Group=www-data
WorkingDirectory=/home/sammy/myproject
Environment="PATH=/home/sammy/myproject/myprojectenv/bin"
ExecStart=/home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app
[Install]
WantedBy=multi-user.target
这里假定用户名是sammy,还有环境目录是否一致,都需要你看情况做更改。
这里对ExecStart 行做个说明:
启动3个工作进程(应该根据需要进行调整)
在我们的项目目录中创建并绑定到Unix套接字文件myproject.sock。 将umask值设置为007,以便创建套接字文件以授予所有者和组访问权限,同时限制其他访问权限
指定WSGI入口点文件名,以及该文件中可调用的Python(wsgi:app)
现在我们启动服务,并使能启动时自动执行。
sudo systemctl start myproject
sudo systemctl enable myproject
我们检查运行状态 :
sudo systemctl status myproject
应该有如下类似输出:
Output
● myproject.service - Gunicorn instance to serve myproject
Loaded: loaded (/etc/systemd/system/myproject.service; enabled; vendor preset: enabled)
Active: active (running) since Fri 2018-07-13 14:28:39 UTC; 46s ago
Main PID: 28232 (gunicorn)
Tasks: 4 (limit: 1153)
CGroup: /system.slice/myproject.service
├─28232 /home/sammy/myproject/myprojectenv/bin/python3.6 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007
├─28250 /home/sammy/myproject/myprojectenv/bin/python3.6 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007
├─28251 /home/sammy/myproject/myprojectenv/bin/python3.6 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007
└─28252 /home/sammy/myproject/myprojectenv/bin/python3.6 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007
配置Nginx
建立一个Nginx 的站点配置文件
sudo nano /etc/nginx/sites-available/myproject
文件内容为:
server {
listen 80;
server_name your_domain www.your_domain;
location / {
include proxy_params;
proxy_pass http://unix:/home/sammy/myproject/myproject.sock;
}
}
特别注意:your_domain 应该用你实际的域名代替,sammy/myprojecct/project 这部分也要修改成你的一致
对于我的理解来说,sammy/project 指工作目录 WorkingDirectory, myproject.sock 指Unix套接字文件 unix:myproject.sock,对应/etc/systemd/system/myproject.service 里面的内容。
使能Nginx站点配置块(server block configuration):
sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled
使能之后,可以测试nginx 的配置:
sudo nginx -t
如果有错误,可以检查上面配置块文件的语法等,也要检查/etc/nginx/sites-enabled 目录下还有除default外还有的文件,删除不必要的文件。因为每个文件都加入到配置中。
如果没有错误,就可以重新启动nginx:
sudo systemctl restart nginx
因为我们不再需要防火墙5000端口号了,可以修改防火墙如下:
sudo ufw delete allow 5000
sudo ufw allow 'Nginx Full'
在浏览器地址里输入你的域名:
http://your_domain
应该可以看到:
如果出现什么错误,可以检查:
sudo less /var/log/nginx/error.log
: 检查 Nginx 错误日志.sudo less /var/log/nginx/access.log
: 检查 Nginx 访问日志.sudo journalctl -u nginx
: 检查 Nginx 进程日志.sudo journalctl -u myproject
: 检查 Flask 应用的 Gunicorn 日志.
介绍到此。在原文中还介绍了应用安全,我没弄懂,有需要可以看看原文。