cgi: Поддержка CGI для NGINX
Установка
Вы можете установить этот модуль в любой дистрибутив, основанный на RHEL, включая, но не ограничиваясь:
- RedHat Enterprise Linux 7, 8, 9 и 10
- CentOS 7, 8, 9
- AlmaLinux 8, 9
- Rocky Linux 8, 9
- Amazon Linux 2 и Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install nginx-module-cgi
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install nginx-module-cgi
Включите модуль, добавив следующее в начало файла /etc/nginx/nginx.conf:
load_module modules/ngx_http_cgi_module.so;
Этот документ описывает nginx-module-cgi v0.14.1, выпущенный 15 сентября 2025 года.
Добавляет поддержку CGI для Nginx и Angie веб-сервера.
| ОС | Протестировано с | Nginx | Angie |
|---|---|---|---|
| Linux | AlmaLinux 9, Debian 12 и Ubuntu 24.04/20.04 | okay | okay |
| Darwin | MacOS 15.1 | okay | okay |
| BSD | FreeBSD 14.2 и OpenBSD 7.6 | okay | okay |
| Solaris | OmniOS r1510521 | okay | okay |
| Windows | Нет планов, nginx едва поддерживает Windows |
Перед всем
CGI не является ни демоном, ни ангелом. Это просто инструмент. Как нож шеф-повара в руках повара или меч в руках воина, вы не будете использовать меч для готовки, и не возьмете нож шеф-повара на поле боя. То же самое касается CGI, у него есть свои подходящие сценарии, и его не следует злоупотреблять или демонизировать.
CGI хорош для:
- Приложений с низкой частотой, таких как управление системой
- Систем с ограниченными ресурсами, таких как встроенные системы
- Проектов с низким бюджетом, таких как личные веб-сайты
- Прототипирования для быстрого итеративного процесса
CGI плох для:
- Высокого QPS
- Высокого трафика
- Высокой конкурентности
Я создал канал в Discord. Если:
- Вы также любите CGI
- У вас есть проблемы с nginx-cgi
- Вы хотите получать обновления о nginx-cgi
- Вы хотите познакомиться с новыми друзьями
Пожалуйста, присоединяйтесь к нам: https://discord.gg/EJSfqHHmaR.
Быстрый старт (с Debian 12+, Ubuntu 24.04+)
Соберите и установите:
## клонируйте исходный код
git clone https://github.com/pjincz/nginx-cgi
cd nginx-cgi
#!/bin/bash
echo "Content-Type: text/plain"
echo
echo Hello CGI
Добавьте разрешение на выполнение для CGI-скрипта:
chmod +x /var/www/html/cgi-bin/hello.sh
Теперь попробуйте это:
curl http://127.0.0.1/cgi-bin/hello.sh
Если вы ничего не сделали неправильно, вы получите вывод Hello CGI.
Использование
Загрузка плагина
Если этот плагин установлен в стандартный путь модуля nginx (например, /usr/lib/nginx/modules), плагин будет загружен автоматически. В противном случае вам нужно вручную загрузить плагин с помощью load_module.
Добавьте следующее утверждение в верхний уровень контекста nginx для загрузки плагина:
load_module <dir-of-plugin>/ngx_http_cgi_module.so;
Включение CGI
После загрузки плагина вы можете добавить cgi on в контексты местоположений для включения CGI. Пример:
location /cgi-bin {
cgi on;
}
Как только CGI включен в местоположении, все вложенные местоположения также будут иметь включенный CGI. Если вы хотите отключить CGI для дочернего местоположения, просто используйте cgi off.
Когда местоположение запрашивается, nginx-cgi найдет скрипт в корне документа (он указан в операторе root). Например, если вы указали корень документа как /var/www/html, то при доступе к /cgi-bin/hello.sh будет выполнен /var/www/html/cgi-bin/hello.sh.
Nginx-cgi также поддерживает alias, это как оператор root в nginx, единственное отличие заключается в том, что префикс местоположения будет удален из URI. Например, если вы хотите, чтобы /cgi/hello.sh также ссылался на тот же скрипт, вы можете сделать это:
location /cgi {
alias /var/www/html/cgi-bin;
cgi on;
}
Скрипт Hello
CGI-скрипт может быть написан на любом языке. Вот пример на shell. Вы можете сохранить его в /var/www/html/cgi-bin/hello.sh для тестирования (если вы не изменили корень документа по умолчанию):
#!/bin/sh
echo "Status: 200 OK"
echo "Content-Type: text/plain"
echo
echo "Hello world"
Первая строка скрипта — это шебанг. Если вы явно установили cgi_interpreter, можно удалить эту строку, в противном случае отсутствие шебанга приведет к ошибке 500. Некоторые оболочки позволяют скрипту быть исполняемым даже без шебанга, но здесь это не разрешено. Если скрипт выполняется оболочкой, но возвращает ошибку 500, проверьте шебанг.
Вывод CGI-скрипта состоит из 2 частей: заголовка и тела. Первые 2 оператора echo выводят заголовок, а последний оператор echo выводит тело. Оператор echo посередине выводит разделитель. Оба раздела заголовка и тела могут быть пустыми, но разделитель обязателен. Отсутствие разделителя приведет к ошибке 500.
Все строки в заголовке будут обработаны как обычные строки заголовка HTTP-ответа и переданы на клиентскую сторону. Есть один специальный заголовок Status, который будет передан в строке статуса ответа. Если cgi_strict включен, nginx-cgi проверит все заголовки вывода CGI, и будет возвращена ошибка 500, если будет найден недопустимый заголовок. В противном случае недопустимые заголовки также будут переданы на клиентскую сторону. Рекомендуется оставить cgi_strict включенным.
После разделителя весь вывод будет отправлен клиенту как тело, как есть.
Разрешение на выполнение
В конце концов, вам нужно добавить разрешение на выполнение к файлу:
chmod +x /var/www/html/cgi-bin/hello.sh
Обычно вам нужно разрешение на выполнение, чтобы сделать скрипт исполняемым. Отсутствие разрешения на выполнение может привести к ошибке 403. Если по какой-то причине вы не можете это сделать, cgi_interpreter может помочь.
Заголовок запроса
Заголовки запроса будут обработаны и затем преобразованы в переменные окружения, которые будут переданы CGI-скрипту.
Например, вы можете найти строку запроса в переменной окружения QUERY_STRING. И получить доступ к Http-Accept через HTTP_ACCEPT.
Вот пример:
#!/bin/sh
echo ""
echo "query string: $QUERY_STRING"
echo "http accept: $HTTP_ACCEPT"
Для полного списка переменных окружения смотрите раздел о переменных окружения.
Тело запроса
Тело запроса будет передано через stdin. Вот пример, чтобы прочитать все тело запроса и вывести его:
#!/bin/sh
echo ""
body=$(cat)
echo "request body: $body"
Потоковая передача
Nginx-cgi поддерживает потоковую передачу как для тела запроса, так и для тела ответа. Например, мы можем реализовать самый простой онлайн-калькулятор с помощью bc:
#!/bin/sh
echo ""
bc 2>&1
Затем мы можем протестировать наш калькулятор с помощью curl:
curl 127.0.0.1/cgi-bin/bc.sh --no-progress-meter -T .
Плагин nginx-cgi достаточно умный, чтобы выбрать правильный способ вернуть тело запроса. Если он получил весь вывод достаточно быстро, он выведет тело за один раз. Если вывод задерживается, он выведет тело по частям (HTTP 1.1) или в потоке (HTTP 1.0).
Заголовки HTTP hop-by-hop
Заголовки HTTP hop-by-hop не допускаются в выводе CGI-скрипта. Если они появляются в ответе, клиенту будет возвращена ошибка 500.
Для получения дополнительной информации: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers#hop-by-hop_headers
Уловки и часто задаваемые вопросы
Я хочу перечислить все переменные окружения
Поместите следующий скрипт в вашу директорию CGI и выполните curl из вашего терминала:
#!/bin/sh
echo 'Content-Type: text/plain'
echo
printenv
Я хочу получить права root
Поместите файл sudo в /etc/sudoers.d и выполните sudo в вашем скрипте или установите cgi_interpreter как /usr/bin/sudo.
Вот пример конфигурационного файла sudo:
## разрешить www-data запускать /var/www/bin/my-danger-script с правами root
www-data ALL=(root) NOPASSWD: /var/www/bin/my-danger-script
## разрешить запуск всех CGI-скриптов с sudo непосредственно через nginx-cgi
www-data ALL=(root) NOPASSWD: SETENV: /var/www/html/cgi-bin/*
Как я могу запускать CGI-скрипты с chroot
Рекомендуется не запускать CGI-скрипты с chroot. Поскольку chroot не предназначен для целей безопасности. Он по-прежнему делит много пространств ядра с хост-системой. Например, запустив ps -ef в процессе chroot, все процессы в хост-системе будут возвращены. Это не должно быть слишком ужасно? Нет, это действительно ужасно, потому что вы также можете выполнить kill в chroot-скрипте по той же причине. И люди обычно запускают программы с правами root в chroot-среде. Это крайне плохо. Это ставит систему под высокий риск по сравнению с запуском скрипта с www-data.
Если вам нужна песочница, lxc, docker и jails гораздо лучше для этой цели.
Если вы все же хотите использовать chroot, хорошо, позвольте мне показать вам, как это сделать.
В этом примере я предполагаю, что вы используете /var/www/html в качестве корня документа.
Сначала подготовьте CGI-скрипт:
mkdir -p /var/www/html/cgi-bin
cat > /var/www/html/cgi-bin/ls.sh <<EOF
#!/bin/sh
echo "Status: 200"
echo "Content-Type: text-plain"
echo
echo "files under /:"
ls /
EOF
chmod +x /var/www/html/cgi-bin/ls.sh
## попробуйте это
/var/www/html/cgi-bin/ls.sh
Шаг 1: подготовьте директорию chroot.
Существует множество способов сделать этот шаг. debootstrap — популярный способ на системах, основанных на Debian. busybox — самый легкий способ. docker — современный способ.
Давайте создадим самую легкую директорию с помощью busybox здесь:
## В этом примере я помещаю все в /var/www/chroot
## Будьте осторожны, я скачиваю версию busybox для x86_64, вам может потребоваться изменить это
## Вам нужны права root для выполнения всех следующих команд, мне слишком лень
## добавлять sudo ко всем командам здесь.
root_dir=/var/www/chroot
mkdir -p "$root_dir/bin" && cd "$root_dir/bin"
wget https://www.busybox.net/downloads/binaries/1.35.0-x86_64-linux-musl/busybox
chmod +x busybox
cd "$root_dir"
mkdir -p $(dirname $(./bin/busybox --list-full) | sort -u)
./bin/busybox --list-full | while read line; do ln -sf /bin/busybox $line; done
## попробуйте это
chroot "$root_dir" ls
Шаг 2: смонтируйте корень документа в директорию chroot
mkdir -p /var/www/chroot/var/www/html
mount --bind /var/www/html /var/www/chroot/var/www/html
## попробуйте это
ls /var/www/chroot/var/www/html
Обратите внимание:
-
Я использую трюк здесь, после chroot корень документа остается прежним. Таким образом, мы можем сэкономить время на сопоставлении путей.
-
Монтирование не сохранится после перезагрузки. Вам может потребоваться добавить запись в /etc/fstab. Или переместить /var/www/html в chroot и создать символическую ссылку снаружи.
Шаг 3: разрешите www-data запускать chroot с правами root.
cat >/etc/sudoers.d/www-run-with-chroot <<EOF
## разрешить и только разрешить www-data запускать chroot с /var/www/chroot
www-data ALL=(root) NOPASSWD: /usr/sbin/chroot /var/www/chroot *
EOF
Теперь все готово, добавьте следующий раздел в ваш nginx/angie:
location /cgi-bin {
cgi on;
cgi_interpreter /usr/bin/sudo /usr/sbin/chroot /var/www/chroot;
}
Попробуйте это:
curl 127.0.0.1/cgi-bin/ls.sh
Как я могу запускать CGI-скрипты с docker
В этом примере я предполагаю, что вы используете /var/www/html в качестве корня документа.
Сначала подготовьте CGI-скрипт:
mkdir -p /var/www/html/cgi-bin
cat > /var/www/html/cgi-bin/ls.sh <<EOF
#!/bin/sh
echo "Status: 200"
echo "Content-Type: text-plain"
echo
echo "files under /:"
ls /
EOF
chmod +x /var/www/html/cgi-bin/ls.sh
## попробуйте это
/var/www/html/cgi-bin/ls.sh
Создайте контейнер и запустите его в фоновом режиме:
## Измените -v, если необходимо
## -d: работает в фоновом режиме
## -i -t: сохраняет терминал
## --restart always: поддерживает контейнер в живых
docker run -dit --restart always --name my_cgi_docker -v /var/www:/var/www busybox sh
## попробуйте это
docker exec my_cgi_docker /var/www/html/cgi-bin/ls.sh
Разрешите www-data выполнять команды docker:
sudo usermod -aG docker www-data
## попробуйте это
sudo -u www-data docker exec my_cgi_docker /var/www/html/cgi-bin/ls.sh
Теперь все готово, добавьте следующий раздел в ваш nginx/angie:
location /cgi-bin {
cgi on;
cgi_interpreter /usr/bin/docker exec my_cgi_docker;
}
Как я могу запускать CGI-скрипты с jails
Хорошо, вы фанат FreeBSD? Я тоже.
Это очень похоже на запуск скриптов с помощью chroot.
Здесь я также предполагаю, что вы используете /var/www/html в качестве корня документа.
Сначала подготовьте CGI-скрипт:
mkdir -p /var/www/html/cgi-bin
cat > /var/www/html/cgi-bin/ls.sh <<EOF
#!/bin/sh
echo "Status: 200"
echo "Content-Type: text-plain"
echo
echo "files under /:"
ls /
EOF
chmod +x /var/www/html/cgi-bin/ls.sh
## попробуйте это
/var/www/html/cgi-bin/ls.sh
Шаг 1: создайте тюрьму
Давайте поместим тюрьму в /var/www/jail.
mkdir -p /var/www/jail && cd /var/www/jail
fetch https://download.freebsd.org/ftp/releases/$(uname -m)/$(uname -m)/$(uname -r)/base.txz
tar -xvf base.txz -C .
## создайте точки монтирования
mkdir -p /var/www/jail/var/www/html
touch /var/www/jail/etc/resolv.conf
Поместите следующую конфигурацию в /etc/jail.conf:
www-jail {
path = "/var/www/jail";
host.hostname = "www-jail.local";
exec.clean;
exec.start = "/bin/sh /etc/rc";
exec.stop = "/bin/sh /etc/rc.shutdown";
# монтировать /var/www/html => /var/www/jail/var/www/html
exec.prestart += "mount_nullfs /var/www/html /var/www/jail/var/www/html || true";
mount.devfs;
# раскомментируйте следующие строки, если хотите разрешить сетевой доступ в тюрьме
# ip4 = inherit;
# ip6 = inherit;
# exec.prestart += "mount_nullfs /etc/resolv.conf /var/www/jail/etc/resolv.conf || true";
# раскомментируйте следующие строки, если хотите, чтобы `ping` был доступен в тюрьме
# allow.raw_sockets = 1;
persist; # сохранять тюрьму, если процессы не запущены
}
И убедитесь, что следующая строка присутствует в /etc/rc.conf:
jail_enable="YES"
И запустите тюрьму:
service jail start www-jail
## попробуйте это
jexec www-jail ls /
jexec www-jail /var/www/html/cgi-bin/ls.sh
Шаг 2: разрешите www запускать jexec с правами root.
Я использую sudo здесь. Я не знаком с doas, если вы предпочитаете doas, вы можете попробовать это сами. В любом случае, ни sudo, ни doas не предустановлены в FreeBSD. Вам нужно вручную установить один из них.
cat >/usr/local/etc/sudoers.d/www-jexec <<EOF
## разрешить и только разрешить `www` запускать `jexec` с `www-jail`
www ALL=(root) NOPASSWD: /usr/sbin/jexec www-jail *
EOF
## попробуйте это
sudo -u www sudo jexec www-jail /var/www/html/cgi-bin/ls.sh
Теперь все готово, добавьте следующий раздел в ваш nginx/angie:
location /cgi-bin {
cgi on;
cgi_interpreter /usr/local/bin/sudo /usr/sbin/jexec www-jail;
}
Попробуйте:
curl 127.0.0.1/cgi-bin/ls.sh
Я хочу создать долгосрочный фоновый процесс
Просто убедитесь, что не наследуете stdout, когда создаете процесс (в идеале, также избегайте наследования stdin и stderr). Вот пример, написанный на shell.
taskid=1234
logfile="/var/lib/my-project/$taskid"
./long-run-task.sh "$taskid" </dev/null >"$logfile" 2>&1 &
Или, если вы знакомы с операцией пайпа, просто закройте stdout (также лучше закрыть stdin и stderr), HTTP-запрос будет завершен немедленно. И вы можете использовать процесс как фоновый процесс.
exec </dev/null >somewhere 2>&1
## теперь HTTP-ответ завершен, делайте что хотите
sleep 9999
Мой HTTP-запрос завис
Как вы видите выше. В мире CGI жизненный цикл HTTP-запроса зависит от жизненного цикла пайпа (stdout).
Каждый дочерний процесс может наследовать пайп процесса CGI. Если какой-либо процесс, унаследовавший stdout, остается живым, HTTP-запрос никогда не завершится.
Это может вызвать путаницу, когда вы хотите запустить долгосрочный фон или убить процесс CGI.
Для создания долгосрочного процесса смотрите вышеуказанную тему.
Для убийства процесса CGI убивайте целую группу процессов, а не сам процесс CGI.
cgi_pid=...
## не делайте этого
## kill "$cgi_pid"
## делайте это
kill -- "-$cgi_pid"
Я хочу убить свой CGI-скрипт
Смотрите вышеуказанную тему.
Я хочу динамически генерировать контент
Традиционно люди используют переписывание для достижения этого. Но здесь это намного проще. Вы можете сделать это с помощью cgi pass. Вот пример для динамической генерации markdown:
{
location ~ ^.*\.md$ {
cgi_pass /var/www/bin/cgi/render-markdown.sh;
}
}
#!/bin/sh
set -e
if [ ! -f "${DOCUMENT_ROOT}${PATH_INFO}" ]; then
echo "Status: 404"
echo
exit
fi
echo "Status: 200"
echo "Content-Type: text/html"
echo
echo "<html><body>"
markdown "${DOCUMENT_ROOT}${PATH_INFO}"
echo "</body></html>"
Мне не нравятся суффиксы в URL
Способ 1: Удаление суффикса CGI-скрипта
Способ 2: переписывание
Способ 3: cgi pass
Как я могу ответить статусом, отличным от 200
#!/bin/sh
echo "Status: 404"
echo "Content-Type: text/plain"
echo
echo "Welcome to the void"
Как я могу ответить перенаправлением
#!/bin/sh
echo "Status: 302"
echo "Location: https://theuselessweb.com"
echo
Как я могу получить тело HTTP-запроса
Вы можете прочитать тело запроса из stdin. Если вы используете shell, cat может быстро сохранить тело запроса в файл.
Как я могу отправить файл клиенту
Для небольших файлов вы можете записать файл непосредственно в stdout.
Для больших файлов гораздо лучше отправить ответ 302. Поскольку ответ CGI является потоковым, протокол не может легко обрабатывать кэширование, загрузку по частям или поддержку возобновления.
Я хочу писать CGI на python, ruby, perl, C, C++...
Делайте это. Nginx-cgi не заботится о том, на каком языке вы пишете. Просто извлекайте информацию из переменных окружения, читайте тело запроса из stdin и записывайте вывод в stdout.
Руководство
Опции
cgi <on|off> или cgi pass <script_path> [script_args...]
Включите или отключите модуль CGI в заданном блоке местоположения.
Если вы укажете on, плагин будет работать в традиционном режиме. Он сначала анализирует URI запроса, а затем находит скрипт в корневом каталоге документа с URI запроса. После этого он разделяет URI запроса на SCRIPT_NAME и PATH_INFO. Это хорошо, если у вас есть старый проект CGI или вы хотите строго следовать rfc3875.
Я также предоставил синтаксис в стиле nginx. Если вы укажете cgi pass, плагин пропустит шаг поиска CGI-скрипта. Он использует значение, которое вы предоставили напрямую. Вы можете ссылаться на переменные nginx во втором аргументе, например: cgi pass $document_root$uri. Приведенный выше пример делает что-то похожее на rfc3875, но не равно. В этой форме URI запроса будет присвоен переменной PATH_INFO напрямую. А SCRIPT_NAME будет пустым. Эта форма действительно хороша для динамической генерации контента. Она обходит сложное и ненужное переписывание URI.
Кроме того, вторая форма также предоставляет вам возможность передавать дополнительные аргументы скрипту, например: cgi pass my_script.sh $uri. С этим вы можете полностью избежать путаницы с переменными окружения rfc3875.
Если вы укажете off, плагин будет отключен.
По умолчанию: off
cgi_pass <script_path>
Псевдоним для cgi pass <script_path>.
cgi_interpreter [interpreter] [args...]
Установите интерпретатор и аргументы интерпретатора для CGI-скрипта.
Когда эта опция не пуста, CGI-скрипт будет запущен с указанным интерпретатором. В противном случае скрипт будет выполнен напрямую.
Эта опция может содержать переменные nginx, смотрите https://nginx.org/en/docs/varindex.html для получения дополнительной информации.
Эта опция чрезвычайно полезна во многих сценариях, например:
- запуск CGI-скриптов без разрешения на выполнение
- выполнение sudo перед выполнением CGI-скрипта
- обертывание общего двоичного файла в CGI-скрипт
- фильтрация вывода CGI-скрипта
- ...
По умолчанию: пусто
cgi_working_dir <dir>
Установите рабочую директорию для CGI-скрипта.
Если это значение установлено в пустое, CGI-скрипты будут наследовать рабочую директорию nginx.
Если это значение установлено в непустую строку, CGI-скрипт будет запущен с указанной рабочей директорией.
Изменение рабочей директории может не сработать. Например, если указанная директория не существует, нет разрешения или имя слишком длинное. В этом случае скрипт не сможет выполниться.
Эта опция не изменяет способ поиска интерпретатора или скрипта (если они указаны с относительным путем, они всегда будут относиться к рабочей директории nginx).
Эта опция может содержать переменную nginx. Хотя я не знаю, для чего это нужно. Возможно, вы можете настроить разные рабочие директории для разных server_name с помощью этого.
По умолчанию: пусто
cgi_body_only <on|off>
Стандартный CGI-скрипт должен выводить две части: заголовок и тело. И пустая строка, чтобы разделить эти две части.
Если вы хотите просто запустить обычную программу как CGI-программу, вы можете включить это.
Как только эта опция включена, весь вывод будет рассматриваться как тело ответа и будет отправлен клиенту.
По умолчанию: off
cgi_path <PATH>
Изменить переменную окружения PATH для CGI-скрипта.
По умолчанию: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
cgi_strict <on|off>
Включить или отключить строгий режим.
Когда строгий режим включен, плохие заголовки CGI приведут к ошибке 500. Когда строгий режим отключен, плохие заголовки CGI будут переданы как есть.
По умолчанию: on
cgi_set_var <name> <value>
Добавить и передать дополнительные переменные окружения в CGI-скрипт. Первый аргумент этой команды — это имя переменной окружения. Оно должно содержать только буквы, цифры и символ подчеркивания и не должно начинаться с цифры. Второй аргумент этой команды — это значение переменной. Оно может содержать переменные nginx, смотрите https://nginx.org/en/docs/varindex.html для получения дополнительной информации.
Эта опция может появляться более одного раза для установки нескольких переменных. Если более одной опции устанавливают одну и ту же переменную, то работает последняя. Эти директивы наследуются из предыдущего уровня конфигурации, если только на текущем уровне не определены директивы cgi_set_var.
Эта опция также может использоваться для переопределения стандартных переменных CGI. Это может быть полезно в некоторых случаях, например, для взлома старого CGI-скрипта или для имитации стандартных переменных, которые в настоящее время не поддерживаются этим плагином (таких как PATH_TRANSLATED, REMOTE_IDENT). Но это не рекомендуется, так как это может вызвать путаницу в вашей системе.
cgi_stderr <path>
Перенаправить stderr CGI в указанный файл.
По умолчанию nginx-cgi захватывает вывод stderr CGI-скрипта и записывает его в журнал nginx. Но это действие довольно дорогостоящее, так как оно требует создания дополнительного соединения для прослушивания вывода stderr. Если вы хотите избежать этого, вы можете использовать эту опцию для перенаправления вывода stderr CGI-скрипта в файл. Или вы можете даже отбросить весь вывод stderr, перенаправив его в /dev/null. Также вы можете использовать это для перенаправления всего вывода stderr в stderr nginx, установив его как /dev/stderr.
cgi_rdns <on|off|double> [required]
Включить или отключить обратный DNS.
off: отключить функцию rdns.
on: Выполнить обратный DNS перед запуском CGI-скрипта и передать результат rdns в CGI-скрипт через переменную окружения REMOTE_HOST.
double: После обратного DNS снова выполнить прямой DNS, чтобы проверить результат rdns. Если результат совпадает, передать результат как REMOTE_HOST.
required: Если обратный DNS не удался, клиенту будет возвращен 403, 503 или 500. В зависимости от причины сбоя rdns.
Если вы включите эту опцию, вам также нужно настроить resolver в nginx. В противном случае вы получите ошибку no resolver defined to resolve.
замечания автора: не включайте эту опцию, она замедлит каждый запрос. Эта функция может быть легко реализована с помощью dig -x или nslookup в скрипте. Единственная причина, по которой я реализовал это, — это сделать модуль полностью совместимым со стандартом rfc3875.
cgi_timeout <t1> [t2]
Отправить сигналы TERM/KILL процессу CGI, если он работает слишком долго.
Если и t1, и t2 равны 0. Функция таймаута отключена.
Если t1 или t2 не равны 0. Сигнал TERM или KILL будет отправлен процессу после таймаута.
Если и t1, и t2 не равны нулю. Сначала отправьте TERM в момент t1. И снова отправьте KILL в момент t1+t2 (если процесс все еще жив в этот момент).
Если t2 не указано, оно рассматривается как 0.
По умолчанию: 0 0
Стандартные переменные окружения
Nginx-cgi реализовал почти все стандартные переменные rfc3875. Если они не могут покрыть все ваши потребности, вы можете добавить свою собственную переменную с помощью cgi_set_var. Также эти переменные могут быть переопределены с помощью cgi_set_var, если вы действительно хотите.
AUTH_TYPE,REMOTE_USER(стандарт rfc3875)
Если CGI-скрипт находится за модулем авторизации (например, ngx_http_auth_basic_module), и авторизация прошла успешно, значение устанавливается в тип авторизации (например, Basic) и авторизованного пользователя.
Если модуль авторизации не включен, независимо от того, передает ли клиент заголовок авторизации или нет. Эти 2 поля отсутствуют.
Заголовок Authorization не виден в CGI-скрипте по соображениям безопасности. Если вы действительно хотите выполнить авторизацию в CGI-скрипте, попробуйте cgi_set_var.
CONTENT_LENGTH,CONTENT_TYPE(стандарт rfc3875)
То же самое, что и заголовки запроса Content-Length и Content-Type.
GATEWAY_INTERFACE(стандарт rfc3875)
Всегда будет CGI/1.1 в этом плагине.
PATH_INFO(стандарт rfc3875)
Предположим, у вас есть скрипт по адресу /cgi-bin/hello.sh, и вы обращаетесь к http://127.0.0.1/cgi-bin/hello.sh/somewhat.
Тогда PATH_INFO будет содержать строку /somewhat.
В сочетании с переписыванием URL или cgi pass, эта переменная может использоваться для динамической генерации контента.
PATH_TRANSLATED(стандарт rfc3875)
Примечание: эта опция не реализована строго в соответствии с rfc3875. Пожалуйста, избегайте этого, если вы пишете новый CGI-скрипт.
Это связано с PATH_INFO.
Предположим, у вас есть скрипт по адресу /cgi-bin/hello.sh, и вы обращаетесь к http://127.0.0.1/cgi-bin/hello.sh/somewhat.
Стандарт говорит, что сервер должен попробовать снова с http://127.0.0.1/somewhat и выяснить, куда должен быть сопоставлен URI.
По техническим причинам я просто конструирую эту переменную из корня документа и PATH_INFO.
Поведение может измениться в будущих версиях.
QUERY_STRING(стандарт rfc3875)
Содержит строку запроса запроса. Например, если вы обращаетесь к http://127.0.0.1/cgi-bin/hello.sh?a=1&b=2, QUERY_STRING будет содержать a=1&b=2.
REMOTE_ADDR(стандарт rfc3875)
IP-адрес клиента.
REMOTE_HOST(стандарт rfc3875)
Имя хоста клиента. Доступно только если включен cgi_rdns.
Если cgi_rdns включен, nginx-cgi выполнит обратный DNS и найдет домен, соответствующий REMOTE_ADDR. Если что-то найдено, оно будет установлено в REMOTE_HOST.
Если cgi_rdns в режиме double, после обратного DNS nginx-cgi снова выполнит прямой DNS. REMOTE_HOST будет установлен только в том случае, если результат прямого DNS совпадает с исходным адресом.
Смотрите cgi_rdns для получения дополнительной информации.
REMOTE_IDENT(стандарт rfc3875)
Плагин nginx-cgi не поддерживает это по соображениям безопасности.
REQUEST_METHOD(стандарт rfc3875)
Метод запроса, например: GET, POST...
SCRIPT_NAME(стандарт rfc3875)
Путь к текущему скрипту. Обычно вам это не нужно. Он не содержит полного пути. Смотрите SCRIPT_FILENAME.
Единственная причина использовать это — построить URI после переписывания. Вы можете использовать SCRIPT_NAME + PATH_INFO, чтобы получить URI после переписывания.
SERVER_NAME(стандарт rfc3875)
Имя сервера, обычно оно равно заголовку Host без части порта. Если заголовок Host не появляется в запросе (HTTP/1.0) или содержит недопустимое значение, то это значение устанавливается в отражающий IP-адрес сервера. Если IP-адрес является адресом ipv6, он будет заключен в квадратные скобки, например [::1].
SERVER_PORT(стандарт rfc3875)
Порт, на котором слушает сервер, например 80, 443...
SERVER_PROTOCOL(стандарт rfc3875)
Протокол, используемый между клиентом и сервером. Например, HTTP/1.0, HTTP/1.1...
SERVER_SOFTWARE(стандарт rfc3875)
Содержит строку nginx и версию, например nginx/1.27.4.
X_(стандарт rfc3875)
Все заголовки HTTP, начинающиеся с X-, будут преобразованы в переменные X_. Например:
Если в заголовке появляется X-a: 123, X_A будет установлено в 123.
HTTP_(стандарт rfc3875)
Все остальные заголовки HTTP будут преобразованы в переменные HTTP_, например:
Если в заголовке появляется Accept: */*, HTTP_ACCEPT будет установлено в */*.
DOCUMENT_ROOT(нестандартный, реализованный apache2)
Корень документа текущего блока местоположения, смотрите оператор root в nginx.
REMOTE_PORT(нестандартный, реализованный apache2)
Номер порта клиента.
REQUEST_SCHEME(нестандартный, реализованный apache2)
http или https.
REQUEST_URI(нестандартный, реализованный apache2)
Сырой URI до переписывания. Если вы хотите URL после переписывания, попробуйте SCRIPT_NAME + PATH_INFO.
Примечание: эта переменная не совпадает с переменной nginx $request_uri. Вы можете найти документ по адресу https://httpd.apache.org/docs/2.4/mod/mod_rewrite.html.
SCRIPT_FILENAME(нестандартный, реализованный apache2)
Полный путь к CGI-скрипту.
SERVER_ADDR(нестандартный, реализованный apache2)
IP-адрес сервера. Если у сервера несколько IP-адресов, значение этой переменной может отличаться, если запросы поступают с разных интерфейсов.
Известные проблемы
Реализация PATH_TRANSLATED неточная
Согласно rfc3875, PATH_TRANSLATED должен указывать на файл, как если бы $PATH_INFO был доступен как uri. Но это действительно сложно реализовать на nginx, это требует повторного запуска процесса местоположения nginx. И эти функции являются частными, к ним нельзя получить доступ напрямую из плагина. Другой способ реализовать это — начать подзапрос, но это слишком дорого, и эта переменная действительно редко используется. Это действительно не стоит делать. Поэтому я просто конструирую эту переменную из корня документа и переменных path_info.
Реализация RDNS не обращается к /etc/hosts
Реализация резольвера nginx не обращается к /etc/hosts. Я не хочу реализовывать дополнительный резольвер в плагине. Поэтому я просто игнорирую эту проблему.
Ссылки
rfc3875
https://datatracker.ietf.org/doc/html/rfc3875
nginx
https://nginx.org/en/docs/dev/development_guide.html https://hg.nginx.org/nginx-tests
Заголовки hop-by-hop
https://datatracker.ietf.org/doc/html/rfc2616#section-13.5.1
CGI окружения
https://datatracker.ietf.org/doc/html/rfc3875#section-4.1
Apache CGI
https://httpd.apache.org/docs/2.4/howto/cgi.html
Lighttpd CGI
https://redmine.lighttpd.net/projects/lighttpd/wiki/Mod_cgi
GitHub
Вы можете найти дополнительные советы по конфигурации и документацию для этого модуля в репозитории GitHub для nginx-module-cgi.