Nginx支持

自0.8.40版本起,Nginx本身就包含了对使用 uwsgi protocol 的上游服务器的的支持。

配置Nginx

一般来说,你只需包含uwsgi_params文件 (包含在nginx发行版本中),使用uwsgi_pass指令来设置uWSGI socket的地址。

uwsgi_pass unix:///tmp/uwsgi.sock;
include uwsgi_params;

—— 或者如果你使用的是TCP socket,

uwsgi_pass 127.0.0.1:3031;
include uwsgi_params;

然后,只需重载Nginx,你就准备好了经过Nginx的,由uWSGI驱动的应用。

uwsgi_params 文件是啥?

它就是为了方便,仅此而已!为了让你阅读愉快,自uWSGI 1.3起,该文件的内容是:

uwsgi_param QUERY_STRING $query_string;
uwsgi_param REQUEST_METHOD $request_method;
uwsgi_param CONTENT_TYPE $content_type;
uwsgi_param CONTENT_LENGTH $content_length;
uwsgi_param REQUEST_URI $request_uri;
uwsgi_param PATH_INFO $document_uri;
uwsgi_param DOCUMENT_ROOT $document_root;
uwsgi_param SERVER_PROTOCOL $server_protocol;
uwsgi_param REMOTE_ADDR $remote_addr;
uwsgi_param REMOTE_PORT $remote_port;
uwsgi_param SERVER_ADDR $server_addr;
uwsgi_param SERVER_PORT $server_port;
uwsgi_param SERVER_NAME $server_name;

集群

对于所有的上游处理程序,Nginx支持漂亮的集群集成。

添加一个 upstream 指令到server配置块外:

upstream uwsgicluster {
  server unix:///tmp/uwsgi.sock;
  server 192.168.1.235:3031;
  server 10.0.0.17:3017;
}

然后修改你的uwsgi_pass指令:

uwsgi_pass uwsgicluster;

这样,你的请求将会在配置的uWSGI服务器之间进行均衡。

动态应用

当传递特殊变量的使用,uWSGI服务器可以按需加载应用。

可以在不传递任何应用配置的情况下启动uWSGI:

./uwsgi -s /tmp/uwsgi.sock

如果请求设置了 UWSGI_SCRIPT 变量,那么服务器将会加载指定的模块:

location / {
  root html;
  uwsgi_pass uwsgicluster;
  uwsgi_param UWSGI_SCRIPT testapp;
  include uwsgi_params;
}

你甚至还可以在每个location内配置多个应用:

location / {
  root html;
  uwsgi_pass uwsgicluster;
  uwsgi_param UWSGI_SCRIPT testapp;
  include uwsgi_params;
}

location /django {
  uwsgi_pass uwsgicluster;
  include uwsgi_params;
  uwsgi_param UWSGI_SCRIPT django_wsgi;
}

在同一个进程中托管多个应用 (亦称管理SCRIPT_NAME和PATH_INFO)

WSGI标准决定了 SCRIPT_NAME 是一个用来选择特定应用的变量。不幸的是, nginx不能够根据SCRIPT_NAME重写PATH_INFO。出于这样的原因,你需要指示uWSGI在所谓的“挂载点”中映射特定的应用,并且自动重写SCRIPT_NAME和PATH_INFO:

[uwsgi]
socket = 127.0.0.1:3031
; mount apps
mount = /app1=app1.py
mount = /app2=app2.py
; rewrite SCRIPT_NAME and PATH_INFO accordingly
manage-script-name = true

考虑到应用本身 (最终使用WSGI/Rack/PSGI中间件) 可以重写SCRIPT_NAME和PATH_INFO。

你也可以使用内部路由子系统来重写请求变量。特别是对于动态应用,这会是一种不错的方法。

注意:古老的uWSGI版本习惯支持所谓的”uwsgi_modifier1 30”方法。不要这样做。它实际上是一种丑陋的hack

SCRIPT_NAME是一个方便的惯例,但是允许你使用任何“映射方法”,例如,可以使用UWSGI_APPID变量在挂载点表中设置一个键。

[uwsgi]
socket = 127.0.0.1:3031
; mount apps
mount = the_app1=app1.py
mount = the_app2=app2.py

还记得吗,你可以使用nginx变量作为变量值,因此你可以使用Host头来实行某种形式的应用路由:

现在,只需在uWSGI挂载你的应用,将域名作为挂载键

[uwsgi]
socket = 127.0.0.1:3031
; mount apps
mount = example.com=app1.py
mount = foobar.it=app2.py

静态文件

为了最佳性能和安全性,记得配置Nginx来提供静态文件服务,而不是让你可怜的应用自己来处理它。

uWSGI服务器可以完美提供静态文件服务,但是并不如一个专用的web服务器,例如Nginx,那么快速有效。

例如,可以像这样映射Django的 /media 路径:

location /media {
  alias /var/lib/python-support/python2.6/django/contrib/admin/media;
}

只有在请求的文件名不存在的时候,一些应用需要传递控制权给UWSGI服务器:

if (!-f $request_filename) {
  uwsgi_pass uwsgicluster;
}

WARNING

如果使用不当,那么像这样的配置可能会引发安全性问题。理智考虑,请务必三番五次检查你的应用文件、配置文件和其他敏感文件位于静态文件的根目录之外。

虚拟主机

你可以使用Nginx虚拟主机,这并无什么特殊问题。

如果你运行“不可信的”web应用 (如果你恰巧是ISP,那么就如你那些客户一样),那么你应该限制它们的内存/地址空间使用,并且对每个主机/应用使用不同的 uid

server {
  listen 80;
  server_name customersite1.com;
  access_log /var/log/customersite1/access_log;
  location / {
    root /var/www/customersite1;
    uwsgi_pass 127.0.0.1:3031;
    include uwsgi_params;
  }
}

server {
  listen 80;
  server_name customersite2.it;
  access_log /var/log/customersite2/access_log;
  location / {
    root /var/www/customersite2;
    uwsgi_pass 127.0.0.1:3032;
    include uwsgi_params;
  }
}

server {
  listen 80;
  server_name sivusto3.fi;
  access_log /var/log/customersite3/access_log;
  location / {
    root /var/www/customersite3;
    uwsgi_pass 127.0.0.1:3033;
    include uwsgi_params;
  }
}

现在,可以在为每个socket使用不同的uid和受限(如果你想的话)地址空间来运行客户应用 (使用你选择的进程管理器,例如 rc.local, 通过Upstart运行uWSGI, Supervisord 或者任何激起你想象的工具)

uwsgi --uid 1001 -w customer1app --limit-as 128 -p 3 -M -s 127.0.0.1:3031
uwsgi --uid 1002 -w customer2app --limit-as 128 -p 3 -M -s 127.0.0.1:3032
uwsgi --uid 1003 -w django3app --limit-as 96 -p 6 -M -s 127.0.0.1:3033