在uWSGI上运行CGI脚本¶
CGI插件提供了使用uWSGI服务器运行CGI脚本的能力。
Web服务器/客户端/负载均衡器使用modifier 9
发送请求给uWSGI服务器。然后,uWSGI使用从客户端传过来的变量作为CGI变量(有时会修复它们),调用对应的脚本/可执行文件,再转发其输出到客户端。
该插件会尝试模仿apache的行为,允许你即使在那种原生不支持CGI的服务器,例如nginx上,也能运行CGI脚本。
启用插件¶
默认情况下,不会将CGI插件构建到核心部分中。你需要构建一个嵌入了cgi的二进制文件,或者构建cgi插件。
要构建带CGI支持的单个二进制文件:
curl http://uwsgi.it/install | bash -s cgi /tmp/uwsgi
要将其作为插件编译,
python uwsgiconfig.py --plugin plugins/cgi
或者,在源代码目录:
make PROFILE=cgi
配置CGI模式¶
cgi <[mountpoint=]path>
选项是配置你的CGI环境的主要入口点。
path
可以是一个目录或者一个可执行文件。如果是一个目录,CGI插件将会使用该URI来查找脚本路径。如果传递了一个可执行文件,那么将会运行它,并且会在其环境中设置 SCRIPT_NAME
, SCRIPT_FILENAME
和 PATH_INFO
。
mountpoint
是可选的。你可以用它来映射不同的URI到不同的CGI目录/脚本。
注意¶
- 记得让你的CGI应用使用uWSGI的资源限制和jailing技术 (名字空间,chroot, capability, unshare....),来限制它们可能会造成的损害。
- 从uWSGI 2.0.2开始,你可以通过使用异步模式,拥有甚至更加便宜的并发。
- 如果没有映射到一个辅助函数,那么每个CGI脚本必须拥有读取和执行权限。
例子¶
例子1:启用CGI的哑目录¶
[uwsgi]
plugins = cgi
socket = uwsgi.sock
cgi = /var/www/cgi-bin
每个请求将会搜索 /var/www/cgi-bin
中的指定文件,并执行它。
到 http://example.com/foo.cgi
的请求会运行 /var/www/cgi-bin/foo.cgi
。
例子2:老式cgi-bin目录¶
[uwsgi]
plugins = cgi
socket = uwsgi.sock
cgi = /cgi-bin=/var/lib/cgi-bin
对 http://example.com/cgi-bin/foo
的调用将会运行 /var/lib/cgi-bin/foo
。
例子3:限制使用某些扩展¶
我们只想执行.cgi和.pl文件:
[uwsgi]
plugins = cgi
socket = uwsgi.sock
cgi = /cgi-bin=/var/lib/cgi-bin
cgi-allowed-ext = .cgi
cgi-allowed-ext = .pl
例子4:使用脚本扩展名,映射脚本到解释器¶
我们想要通过 php5-cgi
二进制文件,运行目录 /var/www
中的以 .php
结尾的文件:
[uwsgi]
plugins = cgi
socket = uwsgi.sock
cgi = /var/www
cgi-allowed-ext = .php
cgi-helper = .php=php5-cgi
如果用辅助函数运行一个文件,那么运行的文件将不需要执行权限。当然,辅助函数是需要的。
扩展名比较是不区分大小写的。
例子5:通过nginx,将PHP脚本作为CGI运行¶
配置Nginx来传递.php请求到uWSGI,使用 /var/www/foo
作为文档根目录。
location ~ .php$ {
include uwsgi_params;
uwsgi_param REDIRECT_STATUS 200; # required by php 5.3
uwsgi_modifier1 9;
uwsgi_pass 127.0.0.1:3031;
}
并且像这样配置uWSGI:
[uwsgi]
plugins = cgi
socket = 127.0.0.1:3031
cgi = /var/www/foo
cgi-allowed-ext = .php
cgi-helper = .php=php5-cgi
例子6:并发¶
默认情况下,每个uWSGI worker将能够运行单个CGI脚本。这意味着,使用一个进程将会阻塞传入的请求,直到结束了第一个请求。
添加更多的worker将会缓解这个问题,但是也会消耗大量内存。
线程是个更好的选择。让我们配置每个worker进程运行20个worker线程,这样,并发运行20个CGI脚本。
[uwsgi]
plugins = cgi
threads = 20
socket = 127.0.0.1:3031
cgi = /var/www/foo
cgi-allowed-ext = .php
cgi-helper = .php=php5-cgi
使用异步模式来得到甚至更廉价的并发:
[uwsgi]
plugins = cgi
async = 200
ugreen = true
socket = 127.0.0.1:3031
cgi = /var/www/foo
cgi-allowed-ext = .php
cgi-helper = .php=php5-cgi
这将会生成200个协程,每个能够管理一个CGI脚本(使用几k内存)
例子7:nginx之后到Mailman web接口¶
location /cgi-bin/mailman {
include uwsgi_params;
uwsgi_modifier1 9;
uwsgi_pass 127.0.0.1:3031;
}
[uwsgi]
plugins = cgi
threads = 20
socket = 127.0.0.1:3031
cgi = /cgi-bin/mailman=/usr/lib/cgi-bin/mailman
cgi-index = listinfo
cgi-index
指令指定了当请求一个以斜杠结尾的路径时,运行哪个脚本。这样, /cgi-bin/mailman/
将会被映射到 /cgi-bin/mailman/listinfo
脚本。
例子8:在一个子目录中作为CGI的Viewvc¶
使用挂载点选项。 .. code-block:: ini
[uwsgi] plugins = cgi threads = 20 socket = 127.0.0.1:3031 cgi = /viewvc=/usr/lib/cgi-bin/viewvc.cgi
例子9:使用uWSGI HTTP路由器和 check-static
选项¶
这是一个非常全栈的解决方案,只使用运行在8080端口上的uWSGI。
[uwsgi]
plugins = http, cgi
; bind on port 8080 and use the modifier 9
http = :8080
http-modifier1 = 9
; set the document_root as a placeholder
my_document_root = /var/www
; serve static files, skipping .pl and .cgi files
check-static = %(my_document_root)
static-skip-ext = .pl
static-skip-ext = .cgi
; run cgi (ending in .pl or .cgi) in the document_root
cgi = %(my_document_root)
cgi-index = index.pl
cgi-index = index.cgi
cgi-allowed-ext = .pl
cgi-allowed-ext = .cgi
例子10:优化CGI (高级)¶
你可以避免在每次请求上重新运行解释器的开销,启动时加载解释器(们),并且调用它们中的函数,而不是 execve()
解释器本身。
源代码发行版中的 contrib/cgi_python.c
文件是关于如何优化Python CGI脚本的一个小小的例子。
启动时加载Python解释器,并且在每次 fork()
后,调用 uwsgi_cgi_run_python
。
要编译该库,你可以使用像这样的命令:
gcc -shared -o cgi_python.so -fPIC -I /usr/include/python2.7/ cgi_python.c -lpython2.7
然后映射 .py
文件到 uwsgi_cgi_run_python
函数。
[uwsgi]
plugins = cgi
cgi = /var/www
cgi-loadlib = ./cgi_python.so:uwsgi_cgi_load_python
cgi-helper = .py=sym://uwsgi_cgi_run_python
}}}
记得在辅助函数中给符号加上 sym://
前缀,让uWSGI把它当成一个已加载符号进行搜索,而不是一个磁盘文件。