笔记: 搭建基于 Nginx-uWSGI-flask 的 web app 并应用于 GitHub webhook

3 分钟读完

2019 年 03 月 09 日

Intro

未来的 App 将会是 web 的天下. 当初小学期蹭贵系的课, 学了点 Django, 然后再也没用过.. 这些天学术不顺, 于是只好学了一点点 Flask 搞 Web 应用. 整个服务的结构是 Nginx 作为 http 服务器, uWSGI 作为中间层, 用 socket 文件通信, Flask 实现应用.

这篇博文不谈任何一个层面的具体用法, 只以最简单的范例为例描述一下搭建这个环境的过程.

Flask 的简单范例

最简单的一个范例:

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello, World! This is a test for flask. '

Flask 接受了 http 的请求. 在这个例子中只关系请求的域名. 其中 '/' 是 app 的根目录, 但合理的设置 uWSGI 的情况下, 不必须是整个页面的根目录.

其他后文用到的 Flask 功能主要是 flask.requestheader, method, data 等 http 请求的具体内容. Flask 还有 flask_restful 包直接实现 RESTful 风格的 API,

uWSGI 的配置

这部分在网上能找到许多不同的具体配置方案, 我参考后采取的是使用 .ini 文件定义配置, 用 mount 连接 app, socket 进行通信, systemd 进行管理的模式.

以 Arch 为例, 需要安装的软件包除了 uwsgi 之外, 还有 uwsgi-plugin-python. 当然对于 docker 来说有现成配置好的环境可以用.

一个 example.ini 的例子;

[uwsgi]
mount = /<app_path>=<script>:app
manage-script-name = true
plugin = python
master = true
processes = 3

chdir = /srv/http/test
uid = http
gid = http
socket = /srv/http/test.sock
logto = /srv/http/test/log
chmod-socket = 660
vacuum = true

其中使用 mount 而不是像许多 “教程” 那样使用 module 的原因是, mount + manage-scipt-name 可以正确的处理相对路径. 比如在上面的例子中, 如果 <app> 填写的是根目录的话, web app 就会在网址根目录下, 否则就会在子目录下. 而这并不要求更改 @app.route('/') 中定义的 URL: uWSGI 会自动进行 URL 地址的转换. 其他 mount = /<app_path>=<script>:app<script> 是 Python Flask 脚本的文件名 (不含 .py 后缀), 而 app 则是脚本中 app = Flask(__name__) 定义的变量名.

.ini 文件中定义的三个路径 chdir, socketlogto 分别是 app 运行环境的路径, 用于和 http 服务器通信的 socket 文件的路径以及 log, 三者都可以根据需要填写. 需要注意的是, 相关路径的读写权限要和 uid 以及 gid 定义的用户一致. chmod-socket 则是 socket 文件的权限表示. vacuum=true 表示在关闭 uWSGI 时删除 socket 文件.

把编辑完成的 a.ini 文件链接或复制到 /etc/uwsgi/ 路径下, 就可以使用 systemctl status/start/enable/... u[email protected] 来进行启用等管理了.

Nginx 配置

在 Nginx 的一个 Server 中定义:

location = /<app_path>/ {
	include uwsgi_params;
	uwsgi_pass unix:/srv/http/test.sock;
}

即可在 domain/<app_path>/ 下启用 app. 其中 <app_path> 与 uwsgi 的配置应该是一致的, 同时 Nginx 的用户 (Arch 下默认是 http) 要有 socket 文件的读写权限.

这个简单的配置有一个问题是只能匹配 domain/<app_path>/ 而无法处理 domain/<app_path>. Flask 文档推荐的写法是:

location = /test {
	rewrite ^ /test/;
}
location /test {
	try_files $uri @test;
}
location @test {
	include uwsgi_params;
	uwsgi_pass unix:/srv/http/flasktest.sock;
}

一个简单的应用: GitHub Webhook 的应答器

在 Flask 上我写了一个简单的响应 GitHub Webhook 的 app. 主要功能是接收 create event 并且在发现这是个新的 tag 时, 更新 AUR 上的信息.

功能上检验了 GitHub 提供的 HMAC (密钥散列消息认证码) 签名验证, 验证通过后, 对于新增的 tag, 调用外部 bash 脚本更新 AUR 上的信息. 目前我发布在 AUR 上的 指示 Arch 更新信息的 deepin-dock 插件 已经使用这套方法自动更新了.

留下评论