FASTCGI

FastCGI 是部署 Flask 的途径之一,类似的部署途径还有 nginx 、 lighttpd 和 cherokee 。其他部署途径的信息参见 uWSGI 和 独立 WSGI 容器 。本文讲述的是使用 FastCGI 部署,因此 先决条件是要有一个 FastCGI 服务器。 flup 最流行的 FastCGI 服务器之一, 我们将会在本文中使用它。在阅读下文之前先安装好 flup 。

当心

请务必把 app.run() 放在 if __name__ == '__main__': 内部或 者放在单独的文件中,这样可以保证它不会被调用。因为,每调用一次就会 开启一个本地 WSGI 服务器。当我们使用 FastCGI 部署应用时,不需要使 用本地服务器。

创建`.fcgi`文件

首先,您需要创建fastcgi服务器文件。让我们称之为 yourapplication.fcgi: :

#!/usr/bin/python
from flup.server.fcgi import WSGIServer
from yourapplication import app

if __name__ == '__main__':
    WSGIServer(app).run()

如果使用的是 Apache ,那么使用了这个文件之后就可以正常工作了。但是如 果使用的是 nginx 或老版本的 lighttpd ,那么需要显式地把接口传递给 FastCGI 服务器,即把接口的路径传递给 WSGIServer:

WSGIServer(application, bindAddress='/path/to/fcgi.sock').run()

路径必须与在服务器配置中定义的路径完全相同。

把这个 yourapplication.fcgi 文件放在一个以后可以找得到的地方,最好 是 /var/www/yourapplication 或类似的地方。

为了让服务器可以执行这个文件,请给文件加上执行位,确保这个文件可以执行:

$ chmod +x /var/www/yourapplication/yourapplication.fcgi

配置Apache

上面的示例对于基本的Apache部署来说已经足够好了,但是您的`.fcgi`文件将出现在应用程序的URL中,例如。 example.com/yourapplication.fcgi/news/ . 有几种方法可以配置您的应用程序,使您的application.fcgi不会出现在URL中。一种更好的方法是使用脚本别名和sethandler配置指令将请求路由到fastcgi服务器。以下示例使用fastcgiserver启动应用程序的5个实例,这些实例将处理所有传入的请求:

LoadModule fastcgi_module /usr/lib64/httpd/modules/mod_fastcgi.so

FastCgiServer /var/www/html/yourapplication/app.fcgi -idle-timeout 300 -processes 5

<VirtualHost *>
    ServerName webapp1.mydomain.com
    DocumentRoot /var/www/html/yourapplication

    AddHandler fastcgi-script fcgi
    ScriptAlias / /var/www/html/yourapplication/app.fcgi/

    <Location />
        SetHandler fastcgi-script
    </Location>
</VirtualHost>

这些进程将由Apache管理。如果您使用的是独立的fastcgi服务器,那么可以改用fastcgiexternalserver指令。请注意,在下面的路径不是真实的,它只是用作其他指令(如aliasmatch)的标识符:

FastCgiServer /var/www/html/yourapplication -host 127.0.0.1:3000

如果无法设置脚本别名(例如在共享Web主机上),则可以使用wsgi中间件从URL中删除application.fcgi。这样设置:

<IfModule mod_fcgid.c>
   AddHandler fcgid-script .fcgi
   <Files ~ (\.fcgi)>
       SetHandler fcgid-script
       Options +FollowSymLinks +ExecCGI
   </Files>
</IfModule>

<IfModule mod_rewrite.c>
   Options +FollowSymlinks
   RewriteEngine On
   RewriteBase /
   RewriteCond %{REQUEST_FILENAME} !-f
   RewriteRule ^(.*)$ yourapplication.fcgi/$1 [QSA,L]
</IfModule>

设置应用程序。fcgi::

#!/usr/bin/python
#: optional path to your local python site-packages folder
import sys
sys.path.insert(0, '<your_local_path>/lib/python<your_python_version>/site-packages')

from flup.server.fcgi import WSGIServer
from yourapplication import app

class ScriptNameStripper(object):
   def __init__(self, app):
       self.app = app

   def __call__(self, environ, start_response):
       environ['SCRIPT_NAME'] = ''
       return self.app(environ, start_response)

app = ScriptNameStripper(app)

if __name__ == '__main__':
    WSGIServer(app).run()

配置LightTPD

一个基本的配置FastCGI如下:

fastcgi.server = ("/yourapplication.fcgi" =>
    ((
        "socket" => "/tmp/yourapplication-fcgi.sock",
        "bin-path" => "/var/www/yourapplication/yourapplication.fcgi",
        "check-local" => "disable",
        "max-procs" => 1
    ))
)

alias.url = (
    "/static/" => "/path/to/your/static/"
)

url.rewrite-once = (
    "^(/static($|/.*))$" => "$1",
    "^(/.*)$" => "/yourapplication.fcgi$1"
)

请记住启用 FastCGI 、 alias 和 rewrite 模块。以上配置把应用绑定到 /yourapplication 。如果你想要让应用在根 URL 下运行,那么必须使用 LighttpdCGIRootFix 中间件来解决一个 lighttpd 缺陷。

请确保只有应用在根 URL 下运行时才使用上述中间件。更多信息请阅读 FastCGI 和 Python (注意,已经不再需要把一个接口显式传递给 run() 了)。

配置nginx

在nginx上安装fastcgi应用程序有点不同,因为默认情况下不会转发fastcgi参数。

的基本配置Flask FastCGI的内容如下:

location = /yourapplication { rewrite ^ /yourapplication/ last; }
location /yourapplication { try_files $uri @yourapplication; }
location @yourapplication {
    include fastcgi_params;
    fastcgi_split_path_info ^(/yourapplication)(.*)$;
    fastcgi_param PATH_INFO $fastcgi_path_info;
    fastcgi_param SCRIPT_NAME $fastcgi_script_name;
    fastcgi_pass unix:/tmp/yourapplication-fcgi.sock;
}

此配置将应用程序绑定到 /yourapplication . 如果你想把它放在url根目录中,那就简单了一点,因为你不需要计算 PATH_INFOSCRIPT_NAME ::

location / { try_files $uri @yourapplication; }
location @yourapplication {
    include fastcgi_params;
    fastcgi_param PATH_INFO $fastcgi_script_name;
    fastcgi_param SCRIPT_NAME "";
    fastcgi_pass unix:/tmp/yourapplication-fcgi.sock;
}

运行fastcgi进程

因为nginx 和其他服务器不会载入 FastCGI 应用,你必须自己载入。 Supervisor 可以管理 FastCGI 进程。 在启动时你可以使用其他 FastCGI 进程管理器或写一个脚本来运行 .fcgi 文件, 例如使用一个 SysV init.d 脚本。如果是临时使用,你可以在一个 GNU screen 中运行 .fcgi 脚本。运行细节参见 man screen,同时请注意这是一个手动启动方法,不会在系统重启时自动启动:

$ screen
$ /var/www/yourapplication/yourapplication.fcgi

调试

在大多数Web服务器上,FastCGI部署往往很难调试。服务器日志通常只告诉您“ premature end of headers”这一行的内容。为了调试应用程序,唯一能真正让您了解它为什么中断的是切换到正确的用户并手动执行应用程序。

下例假设你的应用是 application.fcgi ,且你的网络服务用户为 www-data:

$ su www-data
$ cd /var/www/yourapplication
$ python application.fcgi
Traceback (most recent call last):
  File "yourapplication.fcgi", line 4, in <module>
ImportError: No module named yourapplication

在这种情况下,错误似乎是“yourapapplication”不在python路径上。常见问题有:

  • 正在使用的相对路径。不要依赖当前的工作目录。

  • 取决于Web服务器未设置的环境变量的代码。

  • 使用了不同的python解释器。