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.conf
Apache2的配置主文件,以前的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!