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.15, выпущенный 5 марта 2026 года.
Добавляет поддержку CGI для Nginx и Angie веб-сервера.
| ОС | Протестировано с | Nginx | Angie |
|---|---|---|---|
| Linux | AlmaLinux 9, Debian 12 и Ubuntu 24.04/20.04 | нормально | нормально |
| Darwin | MacOS 15.1 | нормально | нормально |
| BSD | FreeBSD 14.2 и OpenBSD 7.6 | нормально | нормально |
| Solaris | OmniOS r1510521 | нормально | нормально |
| Windows | Нет планов, nginx едва поддерживает Windows |
Прежде всего
CGI не является ни демоном, ни ангелом. Это просто инструмент. Как нож шеф-повара в руках повара или меч в руках воина, вы не будете использовать меч для готовки, и не возьмете нож шеф-повара на поле боя. То же самое касается CGI, у него есть свои подходящие сценарии, и его не следует злоупотреблять или демонизировать.
CGI хорош для:
- Приложений с низкой частотой, таких как управление системой
- Систем с ограниченными ресурсами, таких как встроенные системы
- Проектов с низким бюджетом, таких как личные веб-сайты
- Прототипирования для быстрой итерации
CGI плох для:
- Высокого QPS
- Высокого трафика
- Высокой конкурентности
Я создал канал в Discord. Если:
- Вы тоже любите CGI
- У вас есть проблемы с nginx-cgi
- Вы хотите получать обновления о nginx-cgi
- Вы хотите познакомиться с новыми друзьями
Пожалуйста, присоединяйтесь к нам: https://discord.gg/EJSfqHHmaR.
Бенчмарк
CGI не так медленен, как обычно думают люди. На самом деле, его основные ограничения связаны с накладными расходами на процессы и изменчивостью задержки — не в том, что он может обрабатывать только несколько запросов в минуту.
Я провел простой тест.
Тестовая среда:
- Машина: недорогой экземпляр Vultr ($5/месяц) (1 общий vCPU ~2.3GHz, 1GB RAM)
- ОС: Debian 12
- Тестовая команда для CGI:
ab -n 1000 -c 100 127.0.0.1/cgi-bin/hello.sh - Тестовая команда для простого текста:
ab -n 1000 -c 100 127.0.0.1/hello.txt
Результаты:
hello.sh: 1007 req/shello.txt: 4891 req/s
Быстрый старт
Добавьте репозиторий (пример для Ubuntu - замените 'ubuntu' и 'jammy' на ваш дистрибутив)
echo "deb [signed-by=/etc/apt/keyrings/getpagespeed.gpg] https://extras.getpagespeed.com/ubuntu jammy main" \ | sudo tee /etc/apt/sources.list.d/getpagespeed-extras.list
загрузите исходный код
git clone https://github.com/pjincz/nginx-cgi cd nginx-cgi
инициализируйте rpmbuild
rpmdev-setuptree cd ~/rpmbuild
загрузите файл спецификации из репозитория
wget https://github.com/pjincz/nginx-cgi/raw/refs/heads/main/fedora/nginx-cgi.spec
!/bin/bash
echo "Content-Type: text/plain" echo
echo "Добро пожаловать в мир CGI!"
Не забудьте добавить x-perm к CGI-скрипту:
```sh
chmod +x your-document-root-dir/cgi-bin/hello.sh
Перезапустите nginx и попробуйте:
systemctl restart nginx
curl http://127.0.0.1/cgi-bin/hello.sh
Если все пройдет успешно, вы увидите приветствие из мира CGI. :D
Использование
Загрузка плагина
Если этот плагин установлен в стандартный путь модуля 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 "Привет, мир"
Первая строка скрипта — это шебанг. Если вы явно установили cgi_interpreter, можно удалить эту строку, в противном случае отсутствие шебанга приведет к ошибке 500. Некоторые оболочки позволяют скрипту быть исполняемым даже без шебанга, но здесь это не разрешено. Если скрипт выполняется оболочкой, но возвращает ошибку 500, проверьте шебанг.
Вывод CGI-скрипта содержит 2 секции: секцию заголовка и секцию тела. Первые 2 оператора echo выводят секцию заголовка, а последний оператор echo выводит секцию тела. Оператор echo посередине выводит разделитель. Обе секции заголовка и тела могут быть пустыми, но разделитель обязателен. Отсутствие разделителя приведет к ошибке 500.
Все строки в секции заголовка будут разобраны как обычные строки заголовка HTTP-ответа. Затем они будут переданы на клиентскую сторону. Есть один специальный заголовок Status, он будет передан в строке статуса ответа. Если cgi_strict включен, nginx-cgi проверит все заголовки вывода CGI, и если будет найден недопустимый заголовок, будет возвращена ошибка 500. В противном случае недопустимые заголовки также будут переданы на клиентскую сторону. Настоятельно рекомендуется оставить cgi_strict включенным.
После разделителя весь вывод будет отправлен клиенту как тело, как есть.
x разрешение
В конце концов, вам нужно добавить разрешение x к файлу:
chmod +x /var/www/html/cgi-bin/hello.sh
Обычно вам нужно разрешение x, чтобы сделать скрипт исполняемым. Отсутствие разрешения x может вызвать ошибку 403. Если по какой-либо причине вы не можете это сделать, cgi_interpreter может помочь.
Заголовок запроса
Заголовки запроса будут разобраны, а затем переведены в переменные окружения и переданы CGI-скрипту.
Например, вы можете найти строку запроса в переменной окружения QUERY_STRING. И получить доступ к Http-Accept через HTTP_ACCPET.
Вот пример:
#!/bin/sh
echo ""
echo "строка запроса: $QUERY_STRING"
echo "http accept: $HTTP_ACCEPT"
Для полного списка переменных окружения смотрите раздел о переменных окружения.
Тело запроса
Тело запроса будет передано через stdin. Вот пример, чтобы прочитать все тело запроса и вывести его:
#!/bin/sh
echo ""
body=$(cat)
echo "тело запроса: $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:
# разрешить wwww-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 "файлы в /:"
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 "файлы в /:"
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 "файлы в /:"
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 &
Или, если вы знакомы с операцией pipe, просто закройте stdout (также лучше закрыть stdin и stderr), http-запрос завершится немедленно. И вы можете использовать процесс как фоновый процесс.
exec </dev/null >somewhere 2>&1
# теперь http-ответ завершен, делайте что угодно
sleep 9999
Мой http-запрос завис
Как вы видите выше. В мире CGI жизненный цикл http-запроса зависит от жизненного цикла pipe (stdout).
Каждый дочерний процесс может унаследовать pipe процесса 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 "Добро пожаловать в пустоту"
Как я могу ответить перенаправлением
#!/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-скриптов, у которых отсутствует x-perm
- выполнение 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 <off|info|warn|error|crit|alert|emerg|stderr>
cgi_stderr file <path_to_file>
По умолчанию nginx-cgi захватывает вывод stderr CGI-скрипта и сбрасывает его в журнал nginx с уровнем warn. Вы можете изменить это поведение здесь.
-
off: полностью игнорировать вывод stderr.
-
info, warn, error, crit, alert, emerg: перенаправить stderr CGI в журнал nginx с заданным уровнем. Примечание: эта опция может быть немного затратной, так как для каждого процесса CGI требуется дополнительный pipe. Если вас это беспокоит, вам следует избегать этого.
-
stderr: перенаправить stderr CGI в stderr процесса nginx
-
file
: перенаправить stderr CGI в файл
cgi_rdns <on|off|double> [required]
Включить или отключить обратный DNS.
off: отключить функцию rdns.
on: Выполнить обратный DNS перед запуском CGI-скрипта и передать результат rdns в CGI-скрипт через переменную окружения REMOTE_HOST.
double: После обратного DNS снова выполнить прямой DNS, чтобы проверить результат rdns. Если результат совпадает, передать результат как REMOTE_HOST.
required: Если rdns не удался, клиенту возвращается 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)
Устарело с версии v0.15 по соображениям безопасности. Смотрите issue #22 для получения подробностей и обходных путей.
Кроме того, заголовок Authorization по умолчанию не виден в CGI-скрипте по соображениям безопасности. Если вы хотите получить доступ к заголовку авторизации в CGI-скрипте, попробуйте cgi_set_var HTTP_AUTHORIZATION $http_authorization.
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.
В сочетании с rewrite или 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 двойной, после RDNS 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.