mod_wsgi (Apache)

如果你使用的是 Apache 网络服务器 ,可以考虑使用 mod_wsgi

注意

请提前确认把 app.run() 放在 if __name__ == '__main__': 代码块中或者放在单独的文件中,这样可以确保它不会被调用。因为每调用一次就会开启一个本地的 WSGI 服务器,如果我们将应用部署到 mod_wsgi,并不需要开启本地服务器。

安装 mod_wsgi

如果你还没有安装 mod_wsgi,你可以使用包管理器安装或者自行编译。在 UNIX 系统中如何以源代码形式安装 mod_wsgi 请参考 安装操作

如果你使用的是 Ubuntu/Debian 系统,你可以使用如下的 apt-get 命令来安装并启用:

$ apt-get install libapache2-mod-wsgi-py3

如果你使用的是基于 yum 的发行版(Fedora、OpenSUSE 等)的系统,你可以这样安装:

$ yum install mod_wsgi

在 FreeBSD 系统中,可以通过编译 www/mod_wsgi 或是使用 pkg_add 来安装 mod_wsgi

$ pkg install ap24-py37-mod_wsgi

如果你使用 pkgsrc,可以通过编译 www/ap2-wsgi 包来安装 mod_wsgi

如果你在第一次 apache 重新加载后遇到子进程段错误的话,不必理会,重启服务器即可。

创建一个 .wsgi 文件

你需要一个 yourapplication.wsgi 文件才能启动你的应用。该文件包含 mod_wsgi 启动时所需要运行的代码,通过代码可以获取到应用对象。文件中的 application 对象就是之后使用到的应用。

对大多数应用来说,文件中包含以下内容就足够了:

from yourapplication import app as application

如果你在 __init__.py 文件中使用到了工厂函数,那么该函数应当被导入:

from yourapplication import create_app
application = create_app()

如果你没有一个用来创建应用的工厂函数,而是一个单例,那么可以直接把它导入为 application

把文件放在以后能找得到的地方(比如:/var/www/yourapplication),并确保 yourapplication 和所有使用到的库都位于 Python 加载路径中。如果你不想在系统环境中安装,你可以考虑使用 虚拟 Python 实例。请记住,这时你也需要将你的应用程序安装到虚拟环境中。另外一个选项是在 .wsgi 文件中的导入语句前加入路径:

import sys
sys.path.insert(0, '/path/to/the/application')

配置 Apache

最后,你要为你的应用创建一个 Apache 配置文件。在下面的例子中,出于安全考虑,我们让 mod_wsgi 用另一个用户执行应用程序:

<VirtualHost *>
    ServerName example.com

    WSGIDaemonProcess yourapplication user=user1 group=group1 threads=5
    WSGIScriptAlias / /var/www/yourapplication/yourapplication.wsgi

    <Directory /var/www/yourapplication>
        WSGIProcessGroup yourapplication
        WSGIApplicationGroup %{GLOBAL}
        Order deny,allow
        Allow from all
    </Directory>
</VirtualHost>

注意:WSGIDaemonProcess 未在 Windows 中实现,并且 Apache 将拒绝以上述配置运行。在 Windows 中,请删除这些行:

<VirtualHost *>
    ServerName example.com
    WSGIScriptAlias / C:\yourdir\yourapp.wsgi
    <Directory C:\yourdir>
        Order deny,allow
        Allow from all
    </Directory>
</VirtualHost>

注意:Apache 2.4 的访问控制配置发生了一些改变。

最值得注意的是,目录权限的语法已经从 httpd 2.2

Order allow,deny
Allow from all

变更为 httpd 2.4 的语法

Require all granted

想要了解更多信息,请参考 mod_wsgi 文档

故障排除

如果你的应用没有启动,请按照以下指导排除故障:

Problem: application does not run, errorlog shows SystemExit ignored

你的应用文件中有 app.run() 调用,但并未放入 if __name__ == '__main__':。要么把 run() 的调用从文件移除,放入一个单独的 run.py 文件中,否则请将它让入 if 块中。

Problem: application gives permission errors

有可能是使用了错误的用户去启动应用。请检查你的用户及其所在的组(WSGIDaemonProcessusergroup 参数)是否有权限访问应用所在的文件夹

问题: 应用在打印时抛出错误并终止

请记住 mod_wsgi 不允许使用 sys.stdout 以及 sys.stderr。你可以把 WSGIRestrictStdout 设置为 off 来关闭这个保护机制:

WSGIRestrictStdout Off

或者你也可以在 .wsgi 文件中使用不同的流(stream)替代标准输出:

import sys
sys.stdout = sys.stderr
问题: 访问资源时 IO 错误

你的应用可能是一个单独的 .py 文件,并且你把它软连接到了 site-packages 文件夹中。这样是不起作用的,你必须把文件夹放入文件所在的 Python 路径中,或者把你的应用转换成包。

产生这种错误的原因是对于非安装包来说,模块的文件名用于定位资源,如果使用软连接的话就会定位到错误的文件名。

支持自动重载

为了辅助部署工具,你可以激活自动重载。这样,一旦 .wsgi 文件有所变动,mod_wsgi 就会自动重新加载所有守护进程。

Directory 这一节中加入以下指令即可实现自动重载:

WSGIScriptReloading On

在虚拟环境中工作

使用虚拟环境的优点是不必在系统范围安装应用所需的依赖,这样就可以更好地控制哪里需要什么。如果要在虚拟环境下使用 mod_wsgi,那么我们要对 .wsgi 文件略作改变。

在你的 .wsgi 文件顶部加入下面这行:

activate_this = '/path/to/env/bin/activate_this.py'
with open(activate_this) as file_:
    exec(file_.read(), dict(__file__=activate_this))

这样设置,就会根据虚拟环境的设置加载路径。请记住,必须是绝对路径。