纸上得来终觉浅,绝知此事要躬行。
1. CGI
CGI(Common Gateway Interface)通用网关接口,CGI技术可以让用户使用服务器所支持的编程语言(C/C++/Perl/Bash/PHP)来处理任何操作,最初的设计目的是增加用户的交互性并提供一些对服务器的基本访问,如数据库的查询、数据添加等工作。
CGI 的工作原理
- CGI允许Web页面通过服务器执行任何程序,当服务器收到执行的请求时会将请求信息头和一些环境变量传送给CGI脚本,CGI脚本在独立于Apache服务器外的内存空间内运行,并将运行结果返回给Apache,最后Apache将结果包含在HTTP页中发送给用户。
CGI 的实现方式
- 在早期的Apache服务器中,CGI是通过mod_CGI模块来实现的
- 目前的Apache版本中,Apache会根据不同的平台自动选择运行不同的CGI模块
- 在非线程平台(worker)上使用mod_cgi模块,在线程型平台(prefork)上使用mod_cgid模块
1.1 mod_cgi 模块
启用只需在配置文件家在对应的模块就可启动CGI功能。
LoadModule cgi_module modules/mod_cgi.so
为了更好的管理和监控mod_cgi模块,mod_cgi模块提供了三个指令用于配置mod_cgi日志记录。
- ScriptLog指令
- 设置CGI脚本错误信息的日志位置和名称,如果使用相对路径则以ServerRoot作为参考路径
- 示例:ScriptLog logs/cgi_log
- ScriptLogBuffer指令
- 设置日志记录的put或post内容的大小,以防止日志增长过快,默认为1024字节
- 示例:ScriptLogBuffer 1024
- ScriptLogLength指令
- 设置CGI脚本日志的大小
- 这个日志会记录所有的请求头、所有脚本输出信息,当记录信息超过了日志大小限制则不会再想日志内写入了
- 示例:ScriptLogLength 10385760
Apache服务器提供了很多模块,这些模块通常都会带有与之相对应的处理器,Apache会将不同的资源交给不同的处理器进行处理。当加载完CGI模块后,用户可以使用由mod_cgi模块提供的cgi-script处理器来对所有的CGI资源进行处理。所有,我们需要对CGI进行定义,让CGI资源使用cgi-script来进行处理。
对于CGI资源,常见的定义方法有三种:定义目录、定义请求、定义文件。
- 定义目录
- 使用mod_alias模块提供的ScriptAlias指令来定义一个CGI脚本的专用目录,访问这个目录内的任何文件的链接都会被当成对CGI脚本的访问,因此需要进行严格的安全权限设置才可以保证CGI的安全。
- 为了保证安全性,需要对CGI脚本的权限进行配置,使用专门的用户和组。
# 示例一 # 访问http://192.168.1.100/cgi-bin/printenv地址,会在/usr/local/httpd-ssl/cgi-bin目录下查找printenv脚本,如果找到了会把它当做CGI脚本执行 ScriptAlias /cgi-bin/ "/usr/local/httpd-ssl/cgi-bin/" # 示例二 # 除了可以在全局环境中定义整个目录为CGI目录外,还可以在特定的目录中启用CGI # 还可以结合AddHandle指令来设置何种文件为CGI文件 <Directory /usr/local/apche2/htdocs/somedir> Options +ExecCGI </Directory>
- 定义请求
- 可以使用ScriptAliasMatch指令来进行定义,作用于ScriptAlias一样,只是它可以使用正则表达式匹配用户请求
- 示例:ScriptAliasMatch ^/cig-bin(.*) /usr/local/httpd-ssl/cgi-bin/$1
- 解释:匹配用户请求的URL路径,对于到服务器的目录下查找对应文件
- 定义文件
- 将文件定义成CGI脚本,用户使用AddHandle指令指定一种文件作为CGI资源使用
- 只能用于目录容器中,无法将它作用于全局配置中。
- 示例:AddHandler cgi-script .cgi .pl
- 解释:匹配以.cgi和.pl结尾的文件,当成是CGI脚本文件
1.2 mod_cgid 模块
mod_cgid模块与mod_cgi模块类似,它除了多提供一个ScriptSock指令外,当你选择了使用多线程模型的mpm模块时,mod_cgid会自己代替mod_cgi进行工作。
- ScriptSock指令
- 设置与CGI守护进程通信的套接字文件名前缀
- 我们可以需要设置一下这个文件的权限,只允许root访问
ScriptSock /var/run/cgid.sock
1.3 mod_actions 模块
通常定义CGI的方式有定义目录、定义请求、定义文件这三种方法,但对于一些特殊的情况。例如,根据特定的媒体类型或请求方法,需要使用CGI脚本,而提供这些方法就是mod_actions模块,提供了两个指令:Action指令和Script指令。
Action 指令
- 可以对指定类型的文件使用特定的CGI脚本来进行处理
# 示例1 # 将所有的gif文件交由cgi-bin目录下的images.cgi的处理 Action image/gif /cgi-bin/images.cgi # 示例2 # 先定义了一个文件类型.xyz,随后将这个文件类型交由program.cgi处理 AddHandler my-file-type .xyz Action my-file-type /cgi-bin/program.cgi # 示例3 # news目录会被强制使用news-handler处理器来进行处理 # 随后通过Action设置news-handler会被news.cgi处理,并通过virtual参数,关闭所有对于所请求的文件是否真实存在的检查 <Location /news> SetHandler news-handler Action news-handler /cgi-bin/news.cgi virtual </Location>
Script 指令
- 可以在使用特定请求方法时运行CGI脚本
# 用户使用GET方式访问时会调用search脚本进行处理 # 但是这种处理也仅限制于收到查询参数时才会被处理,否则GET请求会被正常处理 # Script指令可以使用任意的请求方法,对大小写敏感 Script GET /cgi-bin/search
1.4 CGI 环境变量
CGI的环境变量是CGI于服务器之间交换信息的主要途径。
1.5 修改 CGI/SSI 环境变量
通常来说,对于Apache的环境变量时很少被修改的,这是因为大部分的CGI变量都已经通过输入请求送入到CGI脚本中,即使没有输入CGI也可以获得一些变量信息。即便如此,Apache还是提供mod_env和mod_setenvif模块用于设置CGI、SSI的环境变量。
mod_env 模块
- 用于控制向CGI脚本或SSI页面输入的环境变量
- 可以使用mod_env模块提供的三个指定来修改、删除CGI脚本或SSI页面的环境变量
- PassEnv指令:指定一个或多个环境变量,并从Shell环境传送给CGI脚本
- SetEnv指令:设置一个环境变量传送给CGI脚本,如果这个变量不存在,则创建该变量
- UnsetEnv指令:在传送到CGI脚本与SSI页面之前删除一个环境变量
mod_setenvif 模块
- mod_setenvif模块比mod_env模块复杂点,允许根据请求的条件匹配指定的正则表达式来设置环境变量
- 同时在mod_setenvif模块中,同样的指令排列的顺序不同也会产生不同的效果
- BrowserMatch指令:根据HTTP头部的User-Agent字段定义环境变量,可以使用正则表达式来指定它的第一个参数
- BrowserMatchNoCase指令:与BrowserMatch指令功能一样,只是区分大小写
- SetEnvIf指令:根据当前HTTP请求中的属性定义一个或多个环境变量
- 首先指定一个HTTP请求头区域,如Host、User-Agent、Referer等
- 而第二个参数则通常是一个Perl兼容的正则表达式,用来判断之前属性内容是否匹配,最后设置环境变量
- SetEnvIfNoCase指令:与SetEnvIf指令功能一样,只是区分大小写
# BrowserMatch # 为Mozilla浏览器设置netscape头,而对于MSIE不设置netscape头 BrowserMatch ^Mozilla netscape BrowserMatch MSIE !netscape
# SetEnvIf # 如果Referer头表示来自www.mydomain.com,则设置intra_site_referral环境变量 SetEnvIf Referer www.mydomain.com intra_site_referral
2. FastCGI
CGI技术是随着互联网的出现一同出现的技术,长期以来它一直是Web服务器上通用的编程接口,但是这种技术在当初设置的时候显然并没有考虑到几十年之后的今天会遇到如此多的问题,如安全威胁、执行性能地下等。为了解决这个问题,应运而生了FastCGI以取代CGI技术。
使用FastCGI只需要简单修改原有的CGI脚本即可实现对CGI而支持,同时还针对CGI的执行性能地下做了专门的设置,FastCGI模块在启用后长期驻留内存,只需要激活后即可使用,而不像CGI一样每次启动时都需要fork操作,从而极大提高了执行效率。
- FastCGI 工作流程
- FastCGI 的优点
- FastCGI独立于Web服务器,FastCGI的奔溃不会影响到Web服务本身
- FastCGI比传统的CGI更加安全,提供了在独立进程中运行程序的能力
- 更多的可扩展性,FastCGI除了可以完成HTTP请求响应,还可以提供如模块化的身份验证和授权检查等
- 开始支持分布式计算,管理员可以在多台服务器上服务运行FastCGI程序,以分担Web服务器的压力
- 性能更加出色,传统的CGI只能一个程序处理一个请求,而FastCGI可以同时处理多个请求
FastCGI的缺点主要是需要长期占用内存,如果你的访问很多或除了内存泄漏,时间一长就会占用很大的内存空间,而CGI在执行完成后直接退出,所有不会出现这个问题。
目前在Apache上实现FastCGI由两种方式,这两种方式都是使用模块来实现的,但是他们的区别就像当年的apache-ssl与mod_ssl一样。一种方法是你可以使用由Apache官方提供的mod_fcgid模块,另一种方法则是使用http://www.fastcgi.com上提供的mod_fastcgi模块来实现。在Apache2.4会将mod_fcgid模块作为正式官方的fcgi模块。
2.1 安装 mod_fcgid 模块
# 下载mod_fcgid模块 tar xf mod_fcgid-2.4.5.tar.gz && cd mod_fcgid.2.4.5/ # 配置mod_fcgid模块 APXS=/usr/local/httpd-ssl/bin/apxs ./configure.apxs # 编译安装 make && make install
2.2 配置 mod_fcgid
现在只需要使用由mod_fcgid源代码提供的一个小工具fixconf.sed来进行调整,其实就是一个sed的脚本,通过sed程序对配置文件中旧的mod_fcgid指令进行替换。
# 使用fixconf.sed脚本替换旧的mod_fcgid模块指令 ./ fixconf.sed httpd.conf
- 设置 fcgid 支持 perl
# httpd.conf配置文件 <Directory /usr/local/apache/fcgi-bin/> SetHandler fcgid-script Options +ExecCGI Order allow,deny Allow from all </Directory> # 重启测试 apachectl restart
- 设置 fcgid 支持 PHP
fcgid对PHP的支持是通过PHP所提供的php-cgi程序来实现的,php-cgi程序是一个FastCGI管理器,可以通过fcgid来对它进行调用。如果系统中安装了PHP,但是没有php-cgi程序,说明你的PHP是以模块方式安装的,此时需要重新安装PHP为CGI方式。
# httpd.conf配置文件 FcgidMaxRequestsPerProcess 10000 Alias /phpapp/ /usr/local/phpapp/ AddHanler fcgid-script .php Options +ExecCGI FcgidWrapper /usr/local/bin/php-wrapper .php Order allow,deny Allow from all
# 在/usr/local/bin/目录下新建一个php-wrapper文件 #!/bin/sh PHP_FCGI_MAX_REQUESTS=10000 export PHP_FCGI_MAX_REQUESTS exec /usr/local/bin/php-cgi chmod a+x /usr/local/bin/php-wrapper
2.3 mod_fcgid 模块