独立的wsgi容器

有一些用 Python 写的流行服务器可以容纳 WSGI 应用,提供 HTTP 服务。这些服务 器是独立运行的,你可以把代理从你的网络服务器指向它们。如果遇到问题,请阅读 代理设置 一节。

Gunicorn

Gunicorn ‘Green Unicorn’ 是一个 UNIX 下的 WSGI HTTP 服务器,它是一个 移植自 Ruby 的 Unicorn 项目的 pre-fork worker 模型。它既支持 eventlet , 也支持 greenlet 。在 Gunicorn 上运行 Flask 应用非常简单:

$ gunicorn myproject:app

Gunicorn 提供许多命令行参数,可以使用 gunicorn -h 来获得帮助。下面 的例子使用 4 worker 进程( -w 4 )来运行 Flask 应用,绑定到 localhost 的 4000 端口( -b 127.0.0.1:4000 ):

$ gunicorn -w 4 -b 127.0.0.1:4000 myproject:app

这个 gunicorn 命令需要应用程序模块或包的名称以及模块中的应用程序实例。如果使用应用程序工厂模式,则可以将调用传递给:

$ gunicorn "myproject:create_app()"

uWSGI

uWSGI 是一个用C语言编写的快速应用服务器。它是非常可配置的,这使得设置比Gunicorn更复杂。

运行 uWSGI HTTP Router ::

$ uwsgi --http 127.0.0.1:5000 --module myproject:app

有关更优化的设置,请参阅 configuring uWSGI and NGINX .

Gevent

Gevent 是一个 Python 并发网络库,它使用了基于 libev 事件循环的 greenlet 来提供一个高级同步 API:

from gevent.pywsgi import WSGIServer
from yourapplication import app

http_server = WSGIServer(('', 5000), app)
http_server.serve_forever()

Twisted Web

Twisted Web 是一个 Twisted 自带的网络服务器,是一个成熟的、异步的、 事件驱动的网络库。 Twisted Web 带有一个标准的 WSGI 容器,该容器可以使用 twistd 工具运行命令行来控制:

$ twistd web --wsgi myproject.app

这个命令会运行一个名为 app 的 Flask 应用,其模块名为 myproject 。

Twisted Web支持许多标志和选项,并且 twistd 效用也一样;参见 twistd -htwistd web -h 更多信息。例如,在前台的端口8080上运行一个Twisted Web服务器,其中的应用程序来自 myproject ::

$ twistd -n web --port tcp:8080 --wsgi myproject.app

代理设置

如果你要在一个 HTTP 代理后面在上述服务器上运行应用,那么必须重写一些头部才 行。通常在 WSGI 环境中经常会出现问题的有两个变量: REMOTE_ADDR 和 HTTP_HOST 。你可以通过设置你的 httpd 来传递这些头部,或者在中间件中修 正这些问题。 Werkzeug 带有一个修复工具可以用于常用的设置,但是你可能需要为 特定的设置编写你自己的 WSGI 中间件。

下面是一个简单的nginx配置,它代理本地主机上的应用程序(端口8000),设置适当的头文件:

server {
    listen 80;

    server_name _;

    access_log  /var/log/nginx/access.log;
    error_log  /var/log/nginx/error.log;

    location / {
        proxy_pass         http://127.0.0.1:8000/;
        proxy_redirect     off;

        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-Proto    $scheme;
    }
}

如果你的 httpd 无法提供这些头部,那么最常用的设置是调用 X-Forwarded-Host 定义的主机和 X-Forwarded-For 定义的远程地址:

from werkzeug.middleware.proxy_fix import ProxyFix
app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1, x_host=1)

头部可信问题

请记住,在非代理设置中使用此类中间件是一个安全问题,因为它将盲目信任可能由恶意客户端伪造的传入头。

如果要重写另一个头中的头,可能需要使用如下修复程序:

class CustomProxyFix(object):

    def __init__(self, app):
        self.app = app

    def __call__(self, environ, start_response):
        host = environ.get('HTTP_X_FHOST', '')
        if host:
            environ['HTTP_HOST'] = host
        return self.app(environ, start_response)

app.wsgi_app = CustomProxyFix(app.wsgi_app)