nginx-gunicorn-flask-生产环境部署

Flask自带的web服务器只适合我们在开发时调试使用,不适用于生产环境。通用的我们选用gunicorn来部署Flask的应用,然后在外层利用nginx作代理

这里使用前后端分离, 后端通过提供restful api 给前端调用

gunicorn 配置

cat /etc/example_app/gunv2.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
bind = 'example.com:5001'
workers = 4
backlog = 2048
#worker_class = "gevent"
debug = True
proc_name = 'gunicorn.pid'
pidfile = '/var/log/example_app/gun.log'
loglevel = 'debug'
errorlog = '/var/log/example_app/app-error.log'
accesslog = '/var/log/example_app/app.log'

nginx 配置

手动编译安装nginx,编译的时候启用了动态模块(modules/*.so 文件), 默认没这些模块

1
2
3
4
5
6
ngx_http_geoip_module.so
ngx_http_headers_more_filter_module.so
ngx_http_image_filter_module.so
ngx_http_xslt_filter_module.so
ngx_mail_module.so
ngx_stream_module.so

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
user root;
worker_processes 8;
load_module modules/ngx_http_headers_more_filter_module.so;
load_module modules/ngx_stream_module.so;
events {
worker_connections 102400;
}
http {
include mime.types;
default_type application/octet-stream;
vhost_traffic_status_zone;
vhost_traffic_status_filter_by_host on;
vhost_traffic_status_zone shared:vhost_traffic_status:32m;
#log_format access '$remote_addr - $remote_user [$time_local] "$request" "$host" '
#'$status $body_bytes_sent "$http_referer" '
#'"$http_user_agent" $http_x_forwarded_for'
#' $http_x_forwarded_for- $remote_user [$time_local] ';
log_format access ' { "time_local": "$time_local",' ' "host": "$host", ' ' "remote_addr": "$remote_addr",' ' "remote_user": "$remote_user",' ' "request": "$request", ' ' "connection_requests": "$connection_requests",' ' "request_time": "$request_time", ' ' "upstream_addr": "$upstream_addr",' ' "upstream_status": "$upstream_status",' ' "upstream_response_time": "$upstream_response_time", ' ' "request_length": "$request_length",' ' "status": "$status",' ' "body_bytes_sent": "$body_bytes_sent",' ' "http_host": "$http_host",' ' "http_referer": "$http_referer", ' ' "http_user_agent": "$http_user_agent", ' ' "http_x_forwarded_for": "$http_x_forwarded_for" }';
access_log logs/access.log access;
#access_log /usr/local/nginx/logs/access.log access;
client_max_body_size 20m;
sendfile on;
ignore_invalid_headers off;
proxy_connect_timeout 120;
proxy_send_timeout 120;
proxy_read_timeout 120;
proxy_buffer_size 128k;
proxy_buffers 8 128k;
keepalive_timeout 0;
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 9;
gzip_min_length 1024;
gzip_types text/plain application/x-javascript application/javascript text/css text/javascript application/x-httpd-php image/jpeg image/gif image/png application/json;
lua_shared_dict httpserverinfo 10m;
include vhost.d/*.conf;
}
server {
listen 80;
server_name example.com;
location / {
alias /opt/app/dist/; # 指向静态文件目录
index index.html;
}
location /v1 {
proxy_pass http://example.com:5001; # 反向代理,后端服务端口为5001
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
}
}
server {
listen 443 ssl; # 启用ssl,绑定443端口
server_name example.com;
#add_header Strict-Transport-Security "max-age=31536000";
add_header Access-Control-Allow-Origin *; # 允许跨域
#add_header Access-Control-Allow-Headers X-Requested-With;
# header 允许的返回信息
add_header Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept, Authorization, X_POOL_ID, X_REGION_ID, X_TOKEN, X_EXEC_FROM, X_EXEC_FROM_OA, X_API_ACCESS_TOKEN";
add_header Access-Control-Allow-Methods GET,POST,OPTIONS,DELETE,PUT,PATCH;
# 配置的ssl认证信息,该认证信息需要与example.com绑定,可以通过阿里云免费申请
ssl_certificate /usr/local/nginx/ssl/example.com.pem;
ssl_certificate_key /usr/local/nginx/ssl/example.com.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS";
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
location / {
alias /opt/example-frontend/dist/;
index index.html;
}
location /v1 {
proxy_pass http://example.com:5001;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
}
}

systemctl 启动服务配置

cat /usr/lib/systemd/system/app.service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[Unit]
Description=Example Web Server
After=syslog.target
After=network.target
[Service]
Type=simple
Environment=PYTHONPATH=$PYTHONPATH:/opt/example_app
Environment=APP_CONF=/etc/example_app/app.conf
ExecStart=/usr/bin/gunicorn -c /etc/example_app/gunv2.conf app.base.api.main:app
TimeoutSec=300
[Install]
WantedBy=multi-user.target