Flask应用部署

本文记录一次 Flask 应用阿里云ECS部署实践过程,环境为 Ubuntu 16.04 ,工具集 Nginx + Gunicorn + Supervisor + Flask。

Linux 环境准备

因为阿里云安装的 Ubuntu 系统默认带 python 环境,所以只需要安装 python 虚拟环境 virtualenv 包

1
pip install virtualenv

然后安装 nignx:

1
sudo apt-get install nginx

创建项目目录,阿里云 root 用户登陆后默认当前目录为 /root 目录,你可以将程序放在任何目录下,推荐 /var/www/ 下,本例中程序目录为:/var/www/MyFlaskApp

当然通常是实用 scp 命令将程序包从本机传到服务器目录:

1
scp -r MyFlaskApp root@example.com:/var/www/MyFlaskApp

安装 supervisor:

1
sudo apt-get install supervisor

gunicorn

进入程序目录,在虚拟环境下安装 gunicorn

1
(venv) $ pip install gunicorn

运行 gunicorn

1
(venv) $ gunicorn -w 4 -b 127.0.0.1:8080 wsgi:app

其中 -w 指定工作进程数量,-b 指定 Flask 服务地址,wsgi:app 实为 [MODULE_NAME:VARIABLE_NAME],通常在程序目录下单独创建一个文件(如:wsgi.py)将 Flask 实例暴露出来:

1
2
3
4
5
6
7
8
9
10
11
12
from flask import Flask
#from app import create_app
def create_app():
# 这个方法通常是在 MyFlaskApp/app/__init__.py 中导入
app = Flask(__name__)
return app
app = create_app()
if __name__ == '__main__':
app.run()

命令执行完后可在服务器端通过 127.0.0.1:8080 访问服务。

nginx 配置

直接修改配置文件 /etc/nginx/site-available/default。(可先备份再修改)

1
2
3
4
5
6
7
8
9
10
11
12
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name example.com # 修改
location / { # 修改
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}

完成修改后重启 nginx: sudo service nginx restart

supervisor

supervisor 安装后,在配置目录下 /etc/supervisor/conf.d/ 增加控制程序配置 MyFlaskApp.conf

1
2
3
[program:MyFlaskApp]
command=/var/www/MyFlaskApp/venv/bin/gunicorn -w 4 -b 127.0.0.1:8080 wsgi:app
directory=/var/www/MyFlaskApp/

command 启动 gunicorn 的命令,应该指向程序虚拟环境下的 gunicorn。
directory 为程序所在目录。

重启 supervisor

1
2
supervisorctl reload
supervisorctl restart

现在就可以通过服务器外网访问 flask 服务了。

其他

安装 MySQL :

1
2
3
sudo apt-get install mysql-server
sudo apt-get install mysql-client
sudo apt-get install libmysqlclient-dev

确保 MySQL 字符编码都是 utf8 格式(如果要支持emoji表情,格式为:utf8mb4):

1
2
3
4
5
6
7
8
9
10
11
12
# /etc/mysql/my.cnf
[client]
default-character-set = utf8mb4
[mysql]
default-character-set = utf8mb4
[mysqld]
character-set-client-handshake = FALSE
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
init_connect='SET NAMES utf8mb4'
1
2
3
mysql> status
mysql> set character_set_server=utf8
mysql> set character_set_database=utf8

阿里云外网访问

阿里云默认的安全组规则只包含:ICMP访问、SSH(TCP 22)、远程桌面(UDP 3389),并不包含 Web (HTTP(s) 80(443))访问

HTTPS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# /etc/nginx/
server {
server_name example.com;
listen 80 default_server;
listen [::]:80 default_server;
# SSL configuration
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
ssl_certificate cert/cert.pem;
ssl_certificate_key cert/key.key;
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
fastcgi_intercept_errors on;
error_page 404 /404.html;
location / {
root /var/www/html;
index index.html;
}
location ~ /(admin|api) {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}

HTTP 跳转 HTTPS:

1
2
3
4
5
6
server {
server_name example.com;
listen 80 default_server;
listen [::]:80 default_server;
return 301 https://$host$request_uri;
}