Overview
这次我们开发Bastion4服务器使用了JAVA+Perl的架构,后端用Perl做服务器提供Webservice,用JAVA框架Struts接收处理用户请求,再跟Perl服务器交互。
我们使用Apache2作为Perl服务器,由于Apache2默认并不支持Perl,因此需要简单配置一下,使得Apache2以CGI的方式支持Perl运行。在配置的过程中,参考了一些网页,但由于各个网页都没有完整地描述配置过程(至少在我们的服务器上是这样),所以这里记录一下我们配置的全过程。
1. Apache2基本配置
我们为Bastion4申请了一个新的云服务器,版本为NeCTAR Ubuntu 16.04 LTS x86_64,自带了Apache2服务器,下面简单列出了Apache2的一些基本信息:
/etc/apache2/Apache2的配置文件目录/var/www/Apache2的网站存放目录/var/log/apache2/Apache2的日志存放目录/etc/apache2/apache2.confApache2的配置主文件,以前的Apache版本中,主配置文件名字叫httpd.conf,所以很多网页中还用到这个名字,不知道的话会造成很多混淆。尽管apache2.conf是主配置文件,但是多数具体的配置信息并不是写在这个文件中的,/etc/apache2目录中有还有几个文件夹分别记录了几个模块的配置信息,apache2.conf负责把他们导入整合在一起。/etc/apache2/sites-enabled/看名字就可以明白,Apache2的网站配置文件一般都是放在这个目录中的,这个目录下的000-default.conf是我们经常要修改的配置文件。
我们假定Apache存放网站的根目录是/var/www/,如果不确定(因为默认好像是/var/www/html这个目录),打开/etc/apache2/apache2.conf目录,查看下面的配置:
<Directory /var/www/>
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
如果在你的配置里是
<Directory /var/www/html/>
修改成
<Directory /var/www/>
这样,当你把一个名叫Mywebsite的网站(通常是一个文件夹),扔到/var/www中时,你就可以以http://localhost/Mywebsite/访问到这个网站了。
如果你的配置是
<Directory /var/www/html/>,那你需要把你的网站扔到/var/www/html中,才能使用http://localhost/Mywebsite/访问,这是因为<Directory>设置了Apache的根目录,当你使用http://****/Mywebsite访问时,Apache会去当前的根目录/Mywebsite找这个网站。
由于Apache的端口号默认是80,而不加端口号的url访问都会被服务器默认定向到80端口,因此这里不需要添加端口号,如果你手动将Apache端口号修改成了别的端口号(比如8888),那你需要使用http://localhost:8888/Mywebsite/访问这个网站。
2. 配置Apache2支持Perl CGI程序
2.1 创建一个Perl网站
在
/var/www下创建网站的目录,我们创建一个名字叫cgi-bin的网站作为例子:mkdir /var/www/cgi-bin需要使用管理员权限的命令,请自己加上
sudo。在
/var/www/cgi-bin中创建一个cgi_test.pl脚本,输入下面的内容:#!/usr/bin/perl -w use warnings; use CGI qw(:standard); #! must use 'my' to define a variable print header; my $now_string = localtime(); print "<b>Hello, CGI using Perl!</b><br/>It's $now_string NOW!<br />";为
cgi_test.pl添加可执行权限:chmod +x /var/www/cgi-bin/cgi_test.pl在命令行运行
cgi_test.pl:/var/cgi-bin/www/cgi_test.pl会得到下面的结果:
Content-Type: text/html; charset=ISO-8859-1 <b>Hello, CGI using Perl!</b><br/>It's Mon Aug 1 03:35:42 2016 NOW!<br />成功运行这个
perl脚本需要先安装perl的CGI库尽管现在我们可以在本地以命令行的形式运行这个
perl脚本,但还是不能让这个脚本在服务器中运行,访问http://localhost:8888/cgi-bin/cgi_test.pl,浏览器会直接显示整个脚本的内容:#!/usr/bin/perl -w use warnings; use CGI qw(:standard); #! must use 'my' to define a variable print header; my $now_string = localtime(); print "<b>Hello, CGI using Perl!</b><br/>It's $now_string NOW!<br />";而不是只把脚本打印的内容显示出来,所以,接下来我们继续配置
Apache服务器。
2.2 配置Apache服务器
打开
/etc/apache2/sites-enabled/000-default.conf配置文件,找到下面的配置信息:<VirtualHost *:8080> ... ServerAdmin webmaster@localhost DocumentRoot /var/www ... ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost>我们需要添加一些配置信息,添加之后,
000-default.conf的内容如下:<VirtualHost *:8080> ... ServerAdmin webmaster@localhost DocumentRoot /var/www ScriptAlias /cgi-bin/ /var/www/cgi-bin/ <Directory "/var/www/cgi-bin"> AllowOverride all Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch Order allow,deny Allow from all AddHandler cgi-script .cgi .pl </Directory> ... ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost>很容易看得出来,这部分配置主要是用来添加
Apache对perl的支持。默认情况下,
Apache并没有启用CGI模块,我们可以从/etc/apache2/mods-enabled/中确认这点。ls -l /etc/apache2/mods-enabled/ | grep cgi显示结果为空。
ls -l /etc/apache2/mods-available/ | grep cgi显示下面的结果:
-rw-r--r-- 1 root root 74 Mar 19 09:48 authnz_fcgi.load -rw-r--r-- 1 root root 58 Mar 19 09:48 cgi.load -rw-r--r-- 1 root root 115 Mar 19 09:48 cgid.conf -rw-r--r-- 1 root root 60 Mar 19 09:48 cgid.load -rw-r--r-- 1 root root 89 Mar 19 09:48 proxy_fcgi.load -rw-r--r-- 1 root root 89 Mar 19 09:48 proxy_scgi.load从名字上就可以看出来,
mods-enabled中存放的是已经启用的模块,mods-available中存放的是所有可用的模块,所以启用CGI模块变得很简单,把mods-available中的相关文件在mods-enabled中创建软连接就可以了。在
mods-enabled中创建软连接,指向mods-available中的cgid.*文件:ln -s /etc/apache2/mods-available/cgid.load /etc/apache2/mods-enabled/ ln -s /etc/apache2/mods-available/cgid.conf /etc/apache2/mods-enabled/再次查看
mods-enabled:ls -l /etc/apache2/mods-enabled/ | grep cgi显示结果为:
lrwxrwxrwx 1 root root 37 Jul 24 11:55 cgid.conf -> /etc/apache2/mods-available/cgid.conf lrwxrwxrwx 1 root root 37 Jul 24 11:55 cgid.load -> /etc/apache2/mods-available/cgid.load重启
Apache服务器:service apache2 restart或者重新载入配置文件:
service apache2 reload稳妥的方式是
restart Apache服务器,而不只是reload服务器,参见3.2。在浏览器中访问:
http://localhost:8888/cgi-bin/cgi_test.pl就会显示:Hello, CGI using Perl! It's Mon Aug 1 03:48:37 2016 NOW!
可以看到perl脚本在Apache服务器中以CGI脚本的形式运行了。
3. 可能遇到的一些错误
实际上,如果你严格按照上面的步骤,基本上不会出现错误,但是在这里,还是列出一些常见的错误,以便真的遇到这些问题时可以快速查看。
本节主要取自Perl/CGI script with Apache2,所以里面的脚本名字(这里是
echo.pl,脚本的路径(这里是/var/cgi-bin而不是/var/www/cgi-bin)和错误信息都沿用了这篇文章的内容,与本文上面使用的脚本名字,脚本路径和脚本内容内容稍有不同,但也都大同小异。
3.1 500 Internal Server Error
如果你使用浏览器访问perl脚本时,看到500 Internal Server Error错误,打开Apache的错误日志/var/log/apache2/error.log。
如果显示下面的错误信息:
[Wed Mar 19 15:19:15.740781 2014] [cgid:error] [pid 3493:tid 139896478103424] (8)Exec format error: AH01241: exec of '/var/cgi-bin/echo.pl' failed [Wed Mar 19 15:19:15.741057 2014] [cgid:error] [pid 3413:tid 139896186423040] [client 192.120.120.120:62309] End of script output before headers: echo.pl说明脚本的第一行
sh-bang line没有正确指向'perl'的安装路径,检查你的perl脚本,确认第一行是下面的样子:#!/usr/bin/perl其实这样的错误非常罕见,除非你是新手,而且又完全自己手写了一段
perl脚本。如果显示下面的错误信息:
No such file or directory: AH01241: exec of '/var/cgi-bin/echo.pl' failed [Wed Mar 19 15:24:33.505429 2014] [cgid:error] [pid 3412:tid 139896261957376] [client 192.120.120.120:58087] End of script output before headers: echo.pl说明
echo.pl是DOS格式,而非Unix格式,如果你经常的是Windows,或者喜欢在Windows下写好脚本再上传到Unix/Linux服务器中,那么这会是一个常见而且通用的错误。使用dos2unix命令转换脚本的格式:dos2unix /var/cgi-bin/echo.pl系统默认可能并没有装
dos2unix命令,需要自己安装一下。如果你用的是Ubuntu,用sudo apt install dos2unix安装。如果显示下面的错误信息:
[Wed Mar 19 15:40:31.179155 2014] [cgid:error] [pid 4796:tid 140208841959296] (13)Permission denied: AH01241: exec of '/var/cgi-bin/echo.pl' failed [Wed Mar 19 15:40:31.179515 2014] [cgid:error] [pid 4702:tid 140208670504704] [client 192.120.120.120:60337] End of script output before headers: echo.pl说明你没有为
perl脚本添加可执行权限,使用chmod命令很容易更正这个错误:chmod +x /var/cgi-bin/echo.pl如果显示下面的错误信息:
Wed Mar 19 16:02:20.239624 2014] [cgid:error] [pid 4703:tid 140208594970368] [client 192.120.120.120:62841] malformed header from script 'echo.pl': Bad header: hi上面错误对应的脚本:
#!/usr/bin/perl use strict; use warnings; print "hi\n"; print qq(Content-type: text/plain\n\n);在
perl脚本输出Content-type之前输出了别的字符,而浏览器解析的时候把那些字符当做了Content-type,所以报了Bad header错误。所以,不要在print qq(Content-type: text/plain\n\n);之前,输出别的字符。如果显示下面的错误信息:
[Wed Mar 19 16:08:00.342999 2014] [cgid:error] [pid 4703:tid 140208536221440] [client 192.120.120.120:59319] End of script output before headers: echo.pl还是一个跟
header相关的问题,说明你的脚本在打印Content-type之前就出了错误或者异常,error.log中也可能在上面的错误信息之前提供其他更具体的相关信息。所以,请仔细检查打印Content-type之前的perl代码。关于
End of script output before headers错误,原文作者认为可能与Premature end of script headers是同样的原因。
3.2 503 Service Unavailable
如果在本文2.2节为mods-enabled创建了软连接之后,并及时重载了apache,会报下面的错误:
[Wed Mar 19 15:30:22.515457 2014] [cgid:error] [pid 3927:tid 140206699169536] (22)Invalid argument: [client 192.120.120.120:58349] AH01257: unable to connect to cgi daemon after multiple tries: /var/cgi-bin/echo.pl
我猜
reload只是重新载入了服务器配置信息,并未将CGI进程启动,所以尽管已经配置了,但是由于CGI模块并未启动,所以自然也就没法连接CGI的守护进程。
所以,如果你只是修改了配置文件,reload就可以了,如果你启用或禁用了某个模块,需要restart,因为所有启用的模块,是在服务器启动过程中启动的。
稳妥的方式是restart Apache服务器,而不只是reload服务器。
3.3 404 Not Found
如果显示下面的错误信息:
[Wed Mar 19 15:35:13.487333 2014] [cgid:error] [pid 4194:tid 139911599433472] [client 192.120.120.120:58339] AH01264: script not found or unable to stat: /usr/lib/cgi-bin/echo.pl
而echo.pl确实已经存在了,那么检查/etc/apache2/sites-enabled/000-default.conf中的DocumentRoot和ScriptAlias是否配置正确。
3.4 403 Forbidden
如果你遇到403 Forbidden错误,问题一般也出现在/etc/apache2/sites-enabled/000-default.conf这里。检查<Directory>,确保里面涉及到权限的语句正确配置了。
4. 小结
以CGI的方式运行perl是最直接最原始的方式,如果你已经成功地以CGI形式运行了perl脚本,建议你尝试下面的方式:
- PSGI: 更灵活也更高效的方式。
- Perl Dancer或者Mojolicious:成熟的
perl服务器框架,非常易用。
Thank you! Loads of knowledge!