Nginx下配置FastCGI

11:53:00 PM 0 Comments


这是一篇讲述怎样在Nginx下配置fastcgi的文章。

适用

Nginx通过fastcgi调用python, Perl和C++等写的CGI程序。PHP有PHP-FPM (FastCGI Process Manager),这个对PHP来说更好的FastCGI进程管理器,关于PHP-FPM的更多信息,请Google php-fpm+nginx

原理

Nginx并不提供支持对外部程序的直接调用或者

解析(所以缺少像apache里的mod_php这样的模块),所有的外部程序(包括PHP)必须通过fastcgi接口来调用,在Linux下接口是socket (文件socket或者Internet socket)。所以为了调用CGI程序,我们需要一个fastcgi的wrapper,这个wrapper绑定在某个固定socket上(比如端口或者文件socket),当nginx将CGI请求发送给这个socket的时候,wrapper接纳请求并fork一个新的线程,这个线程调用外部的程序或者解释器处理脚本并读取返回值,而wrapper再将返回的数据(网页或者图片等)通过fastcgi将数据通过那个固定的socket传递给nginx。示意图如下:

Ningx的FastCGI原理

所以,我们首先需要一个wrapper,这个wrapper需要完成的工作:

  1. 通过调用fastcgi(库)的函数通过socket和ningx通信(读写socket是fastcgi内部实现的功能,对wrapper是非透明的)
  2. 调度thread,进行fork和kill
  3. 和application进行通信

Wrapper的实现

在Nginx的官方wiki中给出了一个Perl写的wrapper例子,显然这需要安装Perl和必要的module(比如FCGI)。为了追求效率,我们希望有一个C写的wrapper。我找到了这个fcgiwrap项目

只有wrapper还是不够的,我们需要一个脚本来建立socket,启动wrapper以及将wrapper和socket绑定。你可以从我的服务器上下载这个C的wrapper和启动脚本。启动脚本spawn-fcgi的内容如下:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/usr/bin/perl
use strict;
use warnings FATAL => qw( all );
use IO::Socket::UNIX;
my $bin_path = '/usr/sbin/fcgiwrap';
my $socket_path = $ARGV[0] || '/var/run/nginx/nginx-fcgi.sock';
my $num_children = $ARGV[1] || 4;
close STDIN;
unlink $socket_path;
my $socket = IO::Socket::UNIX->new(
Local => $socket_path,
Listen => 100,
);
die "Cannot create socket at $socket_path: $!\n" unless $socket;
for (1 .. $num_children) {
my $pid = fork;
die "Cannot fork: $!" unless defined $pid;
next if $pid;
exec $bin_path;
die "Failed to exec $bin_path: $!\n";
}

你需要修改脚本中高亮的三行,分别是你编译后的fcgiwrap执行文件,domain socket的位置和同时运行的fcgiwrap进程的个数。后两个参数也可以通过调用spawn-fcgi的命令行传递。

建议你用www-data或者nginx等低权限帐号而不是root来运行这个spawn-fcgi脚本,这要求该帐号能够读写那个socket文件所在的文件夹(上面的例子中是 /var/run/nginx/ )。

如果你的机器没有Perl,你可以下载编译一个C写的spawn-fcgi (本地备份),这是lighttpd中的一个子项目,调用这个C版本的spawn-fcgi时可以通过命令行指定domain socket等信息。

Nginx配置

相应地,nginx中需要做如下配置。在你的site文件的server{…}中加入:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
location ~ ^.+\.cgi$ {
root /var/www/yoursite.com;
gzip off; #gzip makes scripts feel slower since they have to complete before getting gzipped
fastcgi_pass unix:/var/run/nginx/nginx-fcgi.sock;
fastcgi_read_timeout 5m;
fastcgi_param SCRIPT_FILENAME /var/www/yoursite$fastcgi_script_name;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE Nginx;
fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;
}

你需要把上面高亮的三行修改为你的配置。注意root一行是必须的,否则wrapper会报错。