Хотя лучше использовать PSGI сервер, чем CGI, все же очень полезно знать, как же писать cgi-скрипты. Особенно, если вам нужно поддерживать какой-нибудь из них.
Эта статья поможет настроить веб-сервер Apache для запуска с CGI-скриптов.
Начнем с запуска Linux и установки Apache2
Мы сконфигурируем Digital Ocean droplet, используя Ubuntu 13.10 64bit.
После создания Droplet, ssh и установки всех обновлений перезапустим машину. (droplet, который я использую, имеет IP 107.170.93.222 )
ssh root@107.170.93.222
# aptitude update
# aptitude safe-upgrade
Установим Apache2 версии MPM preforking.
ssh root@107.170.93.222
# aptitude install apache2-mpm-prefork
Можете проверить, запустился ли Apache, командой ps axuw
:
# ps axuw | grep apache
Вывод на моей машине выглядит вот так:
root 1961 0.0 0.5 71284 2608 ? Ss 14:16 0:00 /usr/sbin/apache2 -k start
www-data 1964 0.0 0.4 360448 2220 ? Sl 14:16 0:00 /usr/sbin/apache2 -k start
www-data 1965 0.0 0.4 360448 2220 ? Sl 14:16 0:00 /usr/sbin/apache2 -k start
root 2091 0.0 0.1 9452 908 pts/0 S+ 14:16 0:00 grep --color=auto apache
Теперь вы можете смотреть свои локальные веб-сайты, просто указывая в браузере IP рабочей машины. В моем случае это так: http://107.170.93.222/ Запомните, некоторые браузеры не будут запрашивать страницу, если вы не напишете http:// перед IP адресом.
Если все работает нормально, вы увидите в браузере что-то в этом роде:
Это содержимое файла /var/www/index.html на сервере.
Вы можете его отредактировать и перезагрузить страницу в браузере.
Создание первого CGI-скрипта на Perl
Создадим директорию /var/cgi-bin
(Заметьте, мы специально не создаем ее внутри директории /var/www. Таким образом, даже если сервер сконфигурирован неверно, то браузер не будет отображать исходный код скриптов. Это отличная идея.)
mkdir /var/cgi-bin
Создадим файл с названием /var/cgi-bin/echo.pl
и следующим содержимым:
#!/usr/bin/perl
use strict;
use warnings;
print qq(Content-type: text/plain\n\n);
print "hi\n";
Сделаем файл исполнимым:
chomd +x /var/cgi-bin/echo.pl
и запустим в командной строке:
# /var/cgi-bin/echo.pl
Должно получиться:
Content-type: text/plain
hi
Это ваш первый CGI-скрипт на Perl.
Теперь нам нужно правильно сконфигурировать Apache.
Конфигурируем Apache для запуска CGI-файлов
Откроем файл конфигурации Apache /etc/apache2/sites-enabled/000-default.conf
Там есть такой блок (с кучей комментариев):
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot /var/www
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
Добавьте следующие строки после строки DocumentRoot:
ScriptAlias /cgi-bin/ /var/cgi-bin/
<Directory "/var/cgi-bin">
AllowOverride None
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
Require all granted
</Directory>
Получится вот так:
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot /var/www
ScriptAlias /cgi-bin/ /var/cgi-bin/
<Directory "/var/cgi-bin">
AllowOverride None
Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
По-умолчанию Apache не включает CGI модуль. Это можно определить, потому что в директории mods-enabled нет ни одного CGI-файла, которые есть в директории mods-available.
# ls -l /etc/apache2/mods-enabled/ | grep cgi
# ls -l /etc/apache2/mods-available/ | grep cgi
-rw-r--r-- 1 root root 115 Jul 20 2013 cgid.conf
-rw-r--r-- 1 root root 60 Jul 20 2013 cgid.load
-rw-r--r-- 1 root root 58 Jul 20 2013 cgi.load
-rw-r--r-- 1 root root 89 Jul 20 2013 proxy_fcgi.load
-rw-r--r-- 1 root root 89 Jul 20 2013 proxy_scgi.load
Создадим символную ссылку из директории mods-enabled в mods-available для двух cgid.* файлов.
И затем проверим снова, что ссылки нормально создались, запустив ls -l
.
# ln -s /etc/apache2/mods-available/cgid.load /etc/apache2/mods-enabled/
# ln -s /etc/apache2/mods-available/cgid.conf /etc/apache2/mods-enabled/
# ls -l /etc/apache2/mods-enabled/ | grep cgi
lrwxrwxrwx 1 root root 37 Mar 19 14:39 cgid.conf -> /etc/apache2/mods-available/cgid.conf
lrwxrwxrwx 1 root root 37 Mar 19 14:39 cgid.load -> /etc/apache2/mods-available/cgid.load
Теперь мы может перезагрузить Apache командой:
# service apache2 reload
Команда reload говорит Apache перечитать свои файлы конфигурации.
Теперь можно написать в браузере http://107.170.93.222/cgi-bin/echo.pl (конечно, заменив IP адрес на ваш) и вы увидете слово "hi".
Мои поздравления, ваш первый CGI-скрипт работает!
Поиск и устранение проблем
Если при заходе по адресу http://107.170.93.222/cgi-bin/echo.pl вы видите содержимое файла, а не слово "hi", тогда проверьте, что ваша директория cgi-bin не находится внутри /var/www, и так же возможно, что вы забыли создать символьные ссылки на файлы cgid.*. Переместите директорию cgi-bin вне /var/www, обновите конфигурационные файлы, установите символьные ссылки, перезагрузите сервер.
Ошибка 500 Internal Server Error
Если вы получили сообщение 500 Internal Server Error
, посмотрите лог сервера /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, либо не указывает на корректное размещение установленного Perl. Первая строка должна быть такая:
#!/usr/bin/perl
[Wed Mar 19 15:24:33.504988 2014] [cgid:error] [pid 3781:tid 139896478103424] (2)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
Это может означать, что файл в формате DOS. Такое может случиться, если вы закачали файл по ftp с компьютера под управлением Windows в бинарном режиме. (Вообще не стоит использовать ftp.) Эту проблему можно решить запустив:
dos2unix /var/cgi-bin/echo.pl
[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
Верхняя строка из error.log указывает, что у файла не установлен исполнимый бит. Чтобы исправить, сделайте так:
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
Такое сообщение можно получить, если вы что-то выводите до вывода заголовка Content-type. Например так:
#!/usr/bin/perl
use strict;
use warnings;
print "hi\n";
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
Это сообщение может означать, что скрипт завершил работу (умер) до того, как напечатал Content-type
Error.log, вероятно, содержит исключение в строках выше.
Также вы можете включить буферизацию STDOUT, установив $|
в значение Истина.
$| = 1;
Я не уверен, но думаю, что Premature end of script headers это то же самое, что и End of script output before headers.
Ошибка 503 Service Unavailable
После создания символьной ссылки на файлы cgid.* и перезапуска Apache, я получил ошибку 503 Service Unavailable в браузере и следующую запись в error.log:
[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
Не уверен точно, почему это произошло, но после перезагрузки Apache, все стало работать нормально:
# service apache2 restart
В большинстве случаев команды reload достаточно, но, возможно, не при включении/отключении модуля.
Ошибка 404 Not Found
Если вы получили 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
в логе ошибок, тогда возможно директива ScriptAlias
отсутствует, либо указывает не на тут директорию.
Ошибка 403 Forbidden
Если вы получили 403 Forbidden, возможно директива Directory
сконфигурирована неверно, либо указывает не на ту директорию.
Резюме
Вот и все. Надеюсь, у вас теперь есть первый работающий CGI-скрипт на Perl.
Конечно, использование PSGI это более современно и более гибко, чем CGI. Возможно, вам стоит посмотреть Perl Dancer или Mojolicious фреймворки, чтобы получить больше опыта.