nginx + pserve + supervisord¶
This setup can be accomplished simply and is capable of serving a large amount of traffic. The advantage in deployment is that by using pserve
, it is not unlike the basic development environment you're probably using on your local machine.
nginx 是一个高度优化的HTTP服务器,非常能够提供静态内容,并充当其他应用程序和外部世界之间的代理。作为代理,它还很好地支持应用程序多个实例之间的基本负载平衡。
Client <---> nginx [0.0.0.0:80] <---> (static files)
/|\
|-------> WSGI App [localhost:5000]
`-------> WSGI App [localhost:5001]
我们的目标设置是一个nginx服务器,监听端口80和两个pserver进程之间的负载平衡。它还将服务于项目目录中的静态文件。
Let's assume a basic project setup:
1/home/example/myapp 2 | 3 |-- env (your virtualenv) 4 | 5 |-- myapp 6 | | 7 | |-- __init__.py (defining your main entry point) 8 | | 9 | `-- static (your static files) 10 | 11 |-- production.ini 12 | 13 `-- supervisord.conf (optional)
Step 1: Configuring nginx¶
nginx needs to be configured as a proxy for your application. 配置示例如下:
1# nginx.conf
2
3user www-data;
4worker_processes 4;
5pid /var/run/nginx.pid;
6
7events {
8 worker_connections 1024;
9 # multi_accept on;
10}
11
12http {
13
14 ##
15 # Basic Settings
16 ##
17
18 sendfile on;
19 tcp_nopush on;
20 tcp_nodelay on;
21 keepalive_timeout 65;
22 types_hash_max_size 2048;
23 # server_tokens off;
24
25 # server_names_hash_bucket_size 64;
26 # server_name_in_redirect off;
27
28 include /etc/nginx/mime.types;
29 default_type application/octet-stream;
30
31 ##
32 # Logging Settings
33 ##
34
35 access_log /var/log/nginx/access.log;
36 error_log /var/log/nginx/error.log;
37
38 ##
39 # Gzip Settings
40 ##
41
42 gzip on;
43 gzip_disable "msie6";
44
45 ##
46 # Virtual Host Configs
47 ##
48
49 include /etc/nginx/conf.d/*.conf;
50 include /etc/nginx/sites-enabled/*;
51}
1# myapp.conf
2
3upstream myapp-site {
4 server 127.0.0.1:5000;
5 server 127.0.0.1:5001;
6}
7
8server {
9 listen 80;
10
11 # optional ssl configuration
12
13 listen 443 ssl;
14 ssl_certificate /path/to/ssl/pem_file;
15 ssl_certificate_key /path/to/ssl/certificate_key;
16
17 # end of optional ssl configuration
18
19 server_name example.com;
20
21 access_log /home/example/env/access.log;
22
23 location / {
24 proxy_set_header X-Forwarded-Proto $scheme;
25 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
26 proxy_set_header X-Forwarded-Host $host:$server_port;
27 proxy_set_header X-Forwarded-Port $server_port;
28
29 client_max_body_size 10m;
30 client_body_buffer_size 128k;
31 proxy_connect_timeout 60s;
32 proxy_send_timeout 90s;
33 proxy_read_timeout 90s;
34 proxy_buffering off;
35 proxy_temp_file_write_size 64k;
36 proxy_pass http://myapp-site;
37 proxy_redirect off;
38 }
39}
备注
myapp.conf
is actually included into the http {{}}
主截面 nginx.conf
文件。
可选的 listen
directive, as well as the 2 following lines, are the only configuration changes required to enable SSL from the Client to nginx. You will need to have already created your SSL certificate and key for this to work. More details on this process can be found in the OpenSSL wiki for Command Line Utilities . You will also need to update the paths that are shown to match the actual path to your SSL certificates.
这个 upstream
directive sets up a round-robin load-balancer between two processes. The proxy is then configured to pass requests through the balancer with the proxy_pass
指令。重要的是调查许多其他设置的影响,因为它们可能是特定于应用程序的。
这个 proxy_set_header
directives inform our application of the exact deployment setup. They will help the WSGI server configure our environment's SCRIPT_NAME
, HTTP_HOST
, and the actual IP address of the client.
Step 2: Starting pserve¶
警告
Be sure to create a production.ini
此配置使用 waitress to automatically convert the X-Forwarded-Proto
到WSGI环境中正确的HTTP方案中。这一点很重要,这样应用程序生成的url可以区分不同的域,HTTP和HTTPS。
1#---------- App Configuration ----------
2[app:main]
3use = egg:myapp#main
4
5pyramid.reload_templates = false
6pyramid.debug_authorization = false
7pyramid.debug_notfound = false
8pyramid.default_locale_name = en
9
10#---------- Server Configuration ----------
11[server:main]
12use = egg:waitress#main
13host = 127.0.0.1
14port = %(http_port)s
15
16trusted_proxy = 127.0.0.1
17trusted_proxy_count = 1
18trusted_proxy_headers = x-forwarded-for x-forwarded-host x-forwarded-proto x-forwarded-port
19clear_untrusted_proxy_headers = yes
20
21#---------- Logging Configuration ----------
22# ...
运行pserve进程:
$ pserve production.ini\?http_port=5000
$ pserve production.ini\?http_port=5001
备注
pserver的守护进程为 deprecated in Pyramid 1.6 然后 removed in Pyramid 1.8 .
Step 3: Serving Static Files with nginx (Optional)¶
假设静态文件位于 Pyramid 应用程序的子目录中,那么可以使用nginx高度优化的Web服务器轻松地提供这些文件。这将大大提高性能,因为对该内容的请求不需要代理到WSGi应用程序,并且可以直接提供服务。
警告
如果您的静态内容是公开的,那么这只是一个好主意。它将不尊重您在此目录上放置的任何视图权限。
1location / {
2 # all of your proxy configuration
3}
4
5location /static {
6 root /home/example/myapp/myapp;
7 expires 30d;
8 add_header Cache-Control public;
9 access_log off;
10}
奇怪的是, root
不是指 static
目录,但它起作用,因为nginx将把实际的url附加到指定的路径上。
步骤4:使用Supervisor管理pserver进程(可选)¶
打开所有的 pserve
processes manually and daemonizing them works for the simplest setups, but for a really robust server, you're going to want to automate the startup and shutdown of those processes, as well as have some way of managing failures.
进入 supervisord
:
$ pip install supervisor
这是一个很好的程序,可以管理任意的进程,在它们失败时重新启动它们,在事情发生变化时提供发送电子邮件等的Hook,甚至公开用于确定系统状态的XML-RPC接口。
Below is an example configuration that starts up two instances of the pserve process, automatically filling in the http_port
基于 process_num
因此,5000和5001。
这只是一个精简版的 supervisord.conf
,请阅读文档,了解所提供的所有伟大选项的完整细目。
1[unix_http_server]
2file=%(here)s/env/supervisor.sock
3
4[supervisord]
5pidfile=%(here)s/env/supervisord.pid
6logfile=%(here)s/env/supervisord.log
7logfile_maxbytes=50MB
8logfile_backups=10
9loglevel=info
10nodaemon=false
11minfds=1024
12minprocs=200
13
14[rpcinterface:supervisor]
15supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
16
17[supervisorctl]
18serverurl=unix://%(here)s/env/supervisor.sock
19
20[program:myapp]
21autorestart=true
22command=%(here)s/env/bin/pserve %(here)s/production.ini?http_port=50%(process_num)02d
23process_name=%(program_name)s-%(process_num)01d
24numprocs=2
25numprocs_start=0
26redirect_stderr=true
27stdout_logfile=%(here)s/env/%(program_name)s-%(process_num)01d.log