Проблемы со сценариями cgi-bin, использующими uWSGI и nginx.
Я пытаюсь запустить сценарии cgi-bin в системе nginx с использованием uWSGI, и у меня возникают проблемы с этим и с отладкой, чтобы выяснить, что происходит не так. Система представляет собой Raspberry Pi, на которой работает книжный червь Rasbian, и я добавил блок местоположения nginx для cgi-bin на сайт по умолчанию в
location ^~ /cgi-bin/ {
root /var/www/cgi-bin;
include uwsgi_params;
uwsgi_pass unix:/tmp/uwsgi.sock;
}
Насколько я понимаю, этот блок местоположения определяет выражение, поэтому все, что начинается с cgi-bin, затем обрабатывается внутри. Базовая конфигурация uWSGI включает в себя файл, поставляемый с моей системой, который устанавливает некоторые значения по умолчанию:
uwsgi_param QUERY_STRING $query_string;
uwsgi_param REQUEST_METHOD $request_method;
uwsgi_param CONTENT_TYPE $content_type;
uwsgi_param CONTENT_LENGTH $content_length;
uwsgi_param REQUEST_URI $request_uri;
uwsgi_param PATH_INFO $document_uri;
uwsgi_param DOCUMENT_ROOT $document_root;
uwsgi_param SERVER_PROTOCOL $server_protocol;
uwsgi_param REQUEST_SCHEME $scheme;
uwsgi_param HTTPS $https if_not_empty;
uwsgi_param REMOTE_ADDR $remote_addr;
uwsgi_param REMOTE_PORT $remote_port;
uwsgi_param SERVER_PORT $server_port;
uwsgi_param SERVER_NAME $server_name;
Вышеописанное достаточно просто, и при этом я поэкспериментировал с несколькими вещами. Я создал модуль systemd, который запускает uWSGI с определенной конфигурацией, которую вы можете увидеть здесь...
[uwsgi]
uid = uwsgi
gid = uwsgi
plugins = cgi,logfile
socket = /tmp/uwsgi.sock
cgi = /cgi-bin=/var/www/cgi-bin
chmod-socket = 666
chown-socket = www-data:www-data
req-logger = file:/var/log/uwsgi/errors.log
logger = file:/var/log/uwsgi/errors.log
chdir = /var/www/cgi-bin
Я пробовал некоторые другие варианты с приведенной выше конфигурацией путей. Именно после того, как я взглянул на вещи с помощью приведенных ниже методов, я решил отказаться от моего интереса к этим путям и такого рода деталям.
Все запускается, разрешения для каталога установлены правильно, и у меня все работает нормально. Когда я пытаюсь запустить скрипт с URL-адресом
-- unavailable modifier requested: 0 --
В журнале не содержится подробностей о том, что здесь пошло не так, и это моя главная проблема. Я не смог найти способа получить более подробные журналы или дополнительную информацию об этой ошибке, поэтому я провел дальнейшее расследование. Было несколько тем, в которых у некоторых пользователей Django возникали проблемы из-за отсутствия плагинов. Я проверил, что плагины для CGI и эти журналы ошибок существуют и загружаются.
Это соответствует этой ошибке для запроса в журнале ошибок nginx...
2023/07/24 18:02:18 [error] 32579#32579: *5 upstream prematurely closed connection while reading response header from upstream, client: 192.168.1.4, server: _, request: "GET /cgi-bin/test.cgi HTTP/1.1", upstream: "uwsgi://unix:/tmp/uwsgi.sock:", host: "redacted.home"
Поскольку возможности получить более подробные логи не было, я решил поискать другие способы. Первым было получить экземпляр GPT-4, который дал мне друг, для создания простого сценария CGI Perl, который просто создает файл при запуске и записывает в него переменные среды...
#!/usr/bin/perl
use CGI;
my $cgi = CGI->new;
# Open the debug file
open(my $fh, '>', '/var/www/cgi-bin/test.log') or die "Could not open file 'debug_file.txt' $!";
# Print the environment variables to the file
foreach my $key (sort keys %ENV) {
print $fh "$key=$ENV{$key}\n";
}
# Close the file
close $fh;
# Generate a simple HTTP response
print $cgi->header('text/plain');
print "Debug information written to '/path/to/debug_file.txt'.\n";
exit;
Этот простой сценарий Perl никогда не создавал ни одного файла, поэтому я решил попробовать еще пару вещей, чтобы посмотреть, что происходит.
Я решил использовать инструмент socat с командой
SERVER_PROTOCO HTTP/1.1
REQUEST_SCHEME http
REQUEST_URI /cgi-bin/test.cgi
PATH_INFO /cgi-bin/test.cgi
Здесь были и другие вещи в выводе socat, но в целом здесь не было ничего особенного: ни того, что было очевидно, ни того, что я мог бы изменить. Однако я подумал, что виноваты могут быть пути, которые здесь предоставляет nginx. Изменение путей и тому подобное ничего не изменило, как показывают мои следующие исследования происходящего.
Еще я решил использовать для мониторинга рабочего процесса uWSGI,
strace: Process 32699 attached
epoll_wait(10,
Когда я отправляю HTTP-запрос к nginx для моего тестового сценария в
epoll_wait(10, [{EPOLLIN, {u32=9, u64=9}}], 1, -1) = 1
accept4(9, {sa_family=AF_UNIX}, [110->2], SOCK_NONBLOCK) = 12
read(12, "\0v\1\0\f\0QUERY_STRING\0\0\16\0REQUEST_METHOD\3\0GET\f\0CONTENT_TYPE\0\0\16\0CONTENT_LENGTH\0\0\v\0REQUEST_URI\26\0/cgi-bin/nph-proxy.cgi\t\0PATH_INFO\26\0/cgi-bin/nph-proxy.cgi\r\0DOCUMENT_ROOT\20\0/var/www/cgi-bin\17\0SERVER_PROTOCOL\10\0HTTP/1.1\16\0REQUEST_SCHEME\4\0http\v\0REMOTE_ADDR\v\000192.168.1.4\v\0REMOTE_PORT\5\00040434\v\0SERVER_PORT\2\080\v\0SERVER_NAME\1\0_\t\0HTTP_HOST\n\0pidns.home\17\0HTTP_USER_AGENT\n\0curl/8.0.1\v\0HTTP_ACCEPT\3\0*/*", 4100) = 378
write(2, "-- unavailable modifier requested: 0 --\n", 40) = 40
close(12) = 0
Здесь я разбиваю вышеизложенное на что-то более легкое для чтения...
REQUEST_URI /cgi-bin/nph-proxy.cgi
PATH_INFO /cgi-bin/nph-proxy.cgi
DOCUMENT_ROOT /var/www/cgi-bin
SERVER_PROTOCOL HTTP/1.1
REQUEST_SCHEME http
SERVER_PORT 80
SERVER_NAME (possibly empty)
Я обращаю внимание, что некоторые пути в запросе выглядят не совсем правильно, как это видно по strace. Файловая система proc также указала на некоторые проблемы с используемым рабочим каталогом, для которого было установлено значение
Я думаю, здесь много говорится о том, что strace нам здесь не показывает , а именно файловые операции или любые системные вызовы для запуска сценария. Несмотря на различные настройки nginx и настройки службы uWSGI, никогда не было попыток открыть какие-либо файлы или что-либо выполнить.
Документация показывает, что пользователям, столкнувшимся с этой ошибкой, пришлось установить и включить определенные плагины, чтобы ошибка исчезла. Однако эти люди использовали приложения Python/Django, а я просто использую CGI и расширение файлов журналов. В документации по запуску приложений CGI не упоминается ничего, кроме включения плагина CGI и наличия
Учитывая, что ошибка возникает, когда процесс не делает ничего, кроме получения запроса, процесс никогда не пытается ничего сделать с подробностями в запросе, и что некоторые пользователи получают эту ошибку, когда плагины и тому подобное отсутствуют - я думаю, можно предположить, что
Я подозреваю, что это может исправить некоторое сокращение того, что передается здесь nginx, но я не могу найти ничего об этом в документации. Если кто-то более знаком с работой CGI, возможно, что-то в моей конфигурации или отладке выше выделяется.