cgi: Soporte CGI para NGINX
Instalación
Puedes instalar este módulo en cualquier distribución basada en RHEL, incluyendo, pero no limitado a:
- RedHat Enterprise Linux 7, 8, 9 y 10
- CentOS 7, 8, 9
- AlmaLinux 8, 9
- Rocky Linux 8, 9
- Amazon Linux 2 y 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
Habilita el módulo añadiendo lo siguiente en la parte superior de /etc/nginx/nginx.conf:
load_module modules/ngx_http_cgi_module.so;
Este documento describe nginx-module-cgi v0.15 lanzado el 05 de marzo de 2026.
Aporta soporte CGI a Nginx y Angie servidor web.
| OS | Probado con | Nginx | Angie |
|---|---|---|---|
| Linux | AlmaLinux 9, Debian 12 y Ubuntu 24.04/20.04 | bien | bien |
| Darwin | MacOS 15.1 | bien | bien |
| BSD | FreeBSD 14.2 y OpenBSD 7.6 | bien | bien |
| Solaris | OmniOS r1510521 | bien | bien |
| Windows | Sin plan, nginx apenas soporta Windows |
Antes de todo
CGI no es ni un demonio ni un ángel. Simplemente es una herramienta. Al igual que un cuchillo de chef en manos de un cocinero o una espada en manos de un guerrero, no usarás una espada para cocinar, ni llevarás un cuchillo de chef al campo de batalla. Lo mismo ocurre con CGI, tiene sus escenarios apropiados y no debe ser mal utilizado o demonizado.
CGI es bueno para:
- Aplicaciones de baja frecuencia, como la gestión del sistema
- Sistemas con recursos limitados, como sistemas embebidos
- Proyectos de bajo presupuesto, como sitios web personales
- Prototipado, para iteraciones rápidas
CGI es malo para:
- Alta QPS
- Alto tráfico
- Alta concurrencia
He creado un canal de discord. Si:
- También eres un aficionado a CGI
- Si tienes algún problema con nginx-cgi
- Si quieres recibir actualizaciones de nginx-cgi
- Si quieres conocer más amigos
Por favor, únete a nosotros: https://discord.gg/EJSfqHHmaR.
Benchmark
CGI no es tan lento como la gente normalmente piensa. En realidad, sus principales limitaciones son la sobrecarga del proceso y la variabilidad de la latencia, no que solo pueda manejar unas pocas solicitudes por minuto.
Hice una prueba simple.
Entorno de prueba:
- Máquina: instancia de Vultr de bajo costo ($5/mes) (1 vCPU compartido ~2.3GHz, 1GB RAM)
- SO: Debian 12
- Comando de prueba para CGI:
ab -n 1000 -c 100 127.0.0.1/cgi-bin/hello.sh - Comando de prueba para texto plano:
ab -n 1000 -c 100 127.0.0.1/hello.txt
Resultados:
hello.sh: 1007 req/shello.txt: 4891 req/s
Inicio rápido
Añadir el repositorio (ejemplo de Ubuntu - reemplaza 'ubuntu' y 'jammy' por tu distro)
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
clonar el código fuente
git clone https://github.com/pjincz/nginx-cgi cd nginx-cgi
inicializar rpmbuild
rpmdev-setuptree cd ~/rpmbuild
descargar el archivo spec del repositorio
wget https://github.com/pjincz/nginx-cgi/raw/refs/heads/main/fedora/nginx-cgi.spec
!/bin/bash
echo "Content-Type: text/plain" echo
echo "¡Bienvenido al mundo CGI!"
No olvides añadir permisos de ejecución al script CGI:
```sh
chmod +x your-document-root-dir/cgi-bin/hello.sh
Reinicia nginx y pruébalo:
systemctl restart nginx
curl http://127.0.0.1/cgi-bin/hello.sh
Si todo va bien, encontrarás un saludo del mundo CGI. :D
Uso
Cargando el plugin
Si este plugin está instalado en la ruta de módulo predeterminada de nginx (como
/usr/lib/nginx/modules), el plugin se cargará automáticamente. De lo contrario, necesitas cargar manualmente el plugin mediante load_module.
Agrega la siguiente declaración al contexto de nivel superior de nginx para cargar el plugin:
load_module <dir-of-plugin>/ngx_http_cgi_module.so;
Habilitar cgi
Después de cargar el plugin, puedes añadir cgi on a los contextos de ubicación para habilitar cgi. Ejemplo:
location /cgi-bin {
cgi on;
}
Una vez que cgi esté activado en una ubicación, todas las ubicaciones anidadas también tendrán cgi activado. Si deseas desactivar cgi para una ubicación hija, simplemente usa cgi off.
Cuando se accede a la ubicación, nginx-cgi encontrará el script bajo la raíz del documento (especificada por la declaración root). Por ejemplo, si has especificado la raíz del documento como /var/www/html, entonces cuando accedas a /cgi-bin/hello.sh, se ejecutará /var/www/html/cgi-bin/hello.sh.
Nginx-cgi también soporta alias, es como la declaración root en nginx, la única diferencia es que el prefijo de ubicación se eliminará de la URI. Por ejemplo, si deseas que /cgi/hello.sh también haga referencia al mismo script, puedes hacer esto:
location /cgi {
alias /var/www/html/cgi-bin;
cgi on;
}
Script hello
Un script CGI puede ser escrito en cualquier lenguaje. Aquí hay un ejemplo con shell. Puedes guardarlo en /var/www/html/cgi-bin/hello.sh para probar (si no cambiaste la raíz del documento predeterminada):
#!/bin/sh
echo "Status: 200 OK"
echo "Content-Type: text/plain"
echo
echo "Hola mundo"
La primera línea del script es un shebang. Si estableces claramente cgi_interpreter, está bien eliminar esta línea, de lo contrario, la falta de shebang causará un error 500. Algunos shells permiten que el script sea ejecutable incluso sin shebang, pero no está permitido aquí. Si un script es ejecutable por shell, pero devuelve un error 500, verifica el shebang.
La salida del script CGI contiene 2 secciones: la sección de encabezado y la sección de cuerpo. Las primeras 2 declaraciones echo generan la sección de encabezado, y la última declaración echo genera la sección de cuerpo. La declaración echo en medio genera el separador. Tanto la sección de encabezado como la sección de cuerpo pueden estar vacías, pero el separador es obligatorio. La falta de un separador causará un error 500.
Todas las líneas en la sección de encabezado serán analizadas como líneas de encabezado de respuesta HTTP normales. Y luego se pasarán al lado del cliente. Hay un encabezado especial Status, que se pasará en la línea de estado de respuesta. Si cgi_strict está activado, nginx-cgi verificará todos los encabezados de salida de CGI, y se responderá con un error 500 si se encuentra un encabezado inválido. De lo contrario, los encabezados inválidos también se enviarán al lado del cliente. Se recomienda encarecidamente mantener cgi_strict activado.
Después del separador, toda la salida se enviará al cliente como cuerpo tal como está.
Permiso x
Después de todo, necesitas añadir el permiso x al archivo:
chmod +x /var/www/html/cgi-bin/hello.sh
Normalmente, necesitas permiso x para que el script sea ejecutable. La falta de permiso x puede causar un error 403. Si no puedes hacer esto por alguna razón, cgi_interpreter puede ayudar.
Encabezado de solicitud
Los encabezados de solicitud serán analizados y luego traducidos a variables de entorno y luego pasados al script CGI.
Por ejemplo, puedes encontrar la cadena de consulta en la variable de entorno QUERY_STRING. Y acceder a Http-Accept mediante HTTP_ACCEPT.
Aquí hay un ejemplo:
#!/bin/sh
echo ""
echo "cadena de consulta: $QUERY_STRING"
echo "http accept: $HTTP_ACCEPT"
Para una lista completa de variables de entorno, consulta la sección de entorno.
Cuerpo de solicitud
El cuerpo de la solicitud se pasará a través de stdin. Aquí hay un ejemplo para leer todo el cuerpo de la solicitud y devolverlo:
#!/bin/sh
echo ""
body=$(cat)
echo "cuerpo de la solicitud: $body"
Streaming
Nginx-cgi tiene soporte de streaming tanto para el cuerpo de solicitud como para el cuerpo de respuesta. Por ejemplo, podemos implementar una calculadora en línea más simple con bc:
#!/bin/sh
echo ""
bc 2>&1
Luego podemos probar nuestra calculadora con curl:
curl 127.0.0.1/cgi-bin/bc.sh --no-progress-meter -T .
El plugin nginx-cgi es lo suficientemente inteligente como para elegir la forma correcta de devolver el cuerpo de la solicitud. Si obtiene toda la salida lo suficientemente rápido, devolverá el cuerpo de una vez. Si la salida se retrasa, devolverá el cuerpo en fragmentos (HTTP 1.1) o de forma continua (HTTP 1.0).
Encabezados HTTP hop-by-hop
Los encabezados HTTP hop-by-hop no están permitidos en la salida del script CGI. Si aparecen en la respuesta aquí, se responderá con un error 500 al cliente.
Para más información: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers#hop-by-hop_headers
Trucos y Preguntas Frecuentes
Quiero listar todas las variables de entorno
Coloca el siguiente script en tu directorio CGI y haz curl desde tu terminal:
#!/bin/sh
echo 'Content-Type: text/plain'
echo
printenv
Quiero permisos de root
Coloca un archivo sudo en /etc/sudoers.d y ejecuta sudo en tu script o establece cgi_interpreter como /usr/bin/sudo.
Aquí hay un ejemplo de archivo de configuración sudo:
# permitir que www-data ejecute /var/www/bin/my-danger-script con la cuenta de root
www-data ALL=(root) NOPASSWD: /var/www/bin/my-danger-script
# permitir que todos los scripts CGI se lancen con sudo directamente por nginx-cgi
www-data ALL=(root) NOPASSWD: SETENV: /var/www/html/cgi-bin/*
¿Cómo puedo ejecutar scripts CGI con chroot?
No se recomienda ejecutar scripts CGI con chroot. Porque chroot no está diseñado para fines de seguridad. Aún comparte muchos espacios del kernel con el sistema host. Por ejemplo, al ejecutar ps -ef en un proceso chrooted, todos los procesos en el sistema host se devolverán. ¿Eso no debería ser demasiado horrible? No, eso es realmente terrible, porque también puedes hacer kill en el script chrooted por la misma razón. Y la gente normalmente ejecuta programas con permisos de root en un entorno chrooted. Eso es terriblemente malo. Esto pone al sistema en alto riesgo en comparación con simplemente ejecutar el script con www-data.
Si deseas un entorno de sandbox, lxc, docker y jails son mucho mejores para este propósito.
Si aún deseas chroot, está bien, déjame mostrarte cómo hacerlo.
En este ejemplo, asumo que estás usando /var/www/html como la raíz del documento.
Prepara primero un script 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 "archivos en /:"
ls /
EOF
chmod +x /var/www/html/cgi-bin/ls.sh
# pruébalo
/var/www/html/cgi-bin/ls.sh
Paso 1: prepara un directorio chroot.
Hay muchas formas de hacer este paso. debootstrap es una forma popular en sistemas basados en Debian. busybox es la forma más ligera. docker es una forma moderna.
Hagamos un directorio ligero con busybox aquí:
# En este ejemplo, coloco todo en /var/www/chroot
# Ten cuidado, aquí descargo la versión busybox x86_64, puede que necesites cambiarla
# Necesitas permisos de root para ejecutar todos los siguientes comandos, soy demasiado perezoso para
# anteponer sudo a cada comando aquí.
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
# pruébalo
chroot "$root_dir" ls
Paso 2: monta la raíz del documento en el directorio chroot
mkdir -p /var/www/chroot/var/www/html
mount --bind /var/www/html /var/www/chroot/var/www/html
# pruébalo
ls /var/www/chroot/var/www/html
Nota:
-
Uso un truco aquí, después de chroot, la raíz del documento sigue siendo la misma. De esta manera podemos ahorrar algo de tiempo en el mapeo de rutas.
-
El montaje no persistirá después de un reinicio. Puede que necesites añadir una entrada a /etc/fstab. O mover /var/www/html dentro de chroot y hacer un enlace simbólico afuera.
Paso 3: permitir que www-data ejecute chroot con permisos de root.
cat >/etc/sudoers.d/www-run-with-chroot <<EOF
# permitir y solo permitir que www-data ejecute chroot con /var/www/chroot
www-data ALL=(root) NOPASSWD: /usr/sbin/chroot /var/www/chroot *
EOF
Ahora todo está listo, añade la siguiente sección a tu nginx/angie:
location /cgi-bin {
cgi on;
cgi_interpreter /usr/bin/sudo /usr/sbin/chroot /var/www/chroot;
}
pruébalo:
curl 127.0.0.1/cgi-bin/ls.sh
¿Cómo puedo ejecutar scripts CGI con docker?
En este ejemplo, asumo que estás usando /var/www/html como la raíz del documento.
Prepara primero un script 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 "archivos en /:"
ls /
EOF
chmod +x /var/www/html/cgi-bin/ls.sh
# pruébalo
/var/www/html/cgi-bin/ls.sh
Crea un contenedor y mantenlo en ejecución en segundo plano:
# Cambia -v si es necesario
# -d: ejecuta en segundo plano
# -i -t: mantiene un terminal
# --restart always: mantiene el contenedor vivo
docker run -dit --restart always --name my_cgi_docker -v /var/www:/var/www busybox sh
# pruébalo
docker exec my_cgi_docker /var/www/html/cgi-bin/ls.sh
Permite que www-data ejecute comandos docker:
sudo usermod -aG docker www-data
# pruébalo
sudo -u www-data docker exec my_cgi_docker /var/www/html/cgi-bin/ls.sh
Ahora todo está listo, añade la siguiente sección a tu nginx/angie:
location /cgi-bin {
cgi on;
cgi_interpreter /usr/bin/docker exec my_cgi_docker;
}
¿Cómo puedo ejecutar scripts CGI con jails?
¿Está bien, eres un fan de FreeBSD? Yo también.
Es realmente similar a ejecutar scripts con chroot.
Aquí asumo que también estás usando /var/www/html como la raíz del documento.
Prepara primero un script 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 "archivos en /:"
ls /
EOF
chmod +x /var/www/html/cgi-bin/ls.sh
# pruébalo
/var/www/html/cgi-bin/ls.sh
Paso 1: crea un jail
Coloquemos el jail en /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 .
# crear puntos de montaje
mkdir -p /var/www/jail/var/www/html
touch /var/www/jail/etc/resolv.conf
Coloca la siguiente configuración en /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";
# montar /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;
# descomenta las siguientes líneas, si deseas permitir acceso a la red en el jail
# ip4 = inherit;
# ip6 = inherit;
# exec.prestart += "mount_nullfs /etc/resolv.conf /var/www/jail/etc/resolv.conf || true";
# descomenta las siguientes líneas, si también deseas que `ping` esté disponible en el jail
# allow.raw_sockets = 1;
persist; # mantener el jail si no se ejecuta ningún proceso
}
Y asegúrate de que la siguiente línea aparezca en /etc/rc.conf:
jail_enable="YES"
Y arranca el jail:
service jail start www-jail
# pruébalo
jexec www-jail ls /
jexec www-jail /var/www/html/cgi-bin/ls.sh
Paso 2: permitir que www ejecute jexec con permisos de root.
Uso sudo aquí. No estoy familiarizado con doas, si prefieres doas puedes intentarlo tú mismo. De todos modos, ni sudo ni doas vienen preinstalados con FreeBSD. Necesitas instalar uno de ellos manualmente.
cat >/usr/local/etc/sudoers.d/www-jexec <<EOF
# permitir y solo permitir que `www` ejecute `jexec` con `www-jail`
www ALL=(root) NOPASSWD: /usr/sbin/jexec www-jail *
EOF
# pruébalo
sudo -u www sudo jexec www-jail /var/www/html/cgi-bin/ls.sh
Ahora todo está listo, añade la siguiente sección a tu nginx/angie:
location /cgi-bin {
cgi on;
cgi_interpreter /usr/local/bin/sudo /usr/sbin/jexec www-jail;
}
pruébalo:
curl 127.0.0.1/cgi-bin/ls.sh
Quiero crear un proceso de fondo de larga duración
Solo asegúrate de no heredar stdout al crear el proceso (idealmente, evita heredar stdin y stderr también). Aquí hay un ejemplo escrito en shell.
taskid=1234
logfile="/var/lib/my-project/$taskid"
./long-run-task.sh "$taskid" </dev/null >"$logfile" 2>&1 &
O si estás familiarizado con la operación de tuberías, simplemente cierra stdout (además, es mejor cerrar stdin y stderr también), la solicitud HTTP se completará inmediatamente. Y puedes usar el proceso como un proceso en segundo plano.
exec </dev/null >somewhere 2>&1
# ahora la respuesta http está hecha, haz lo que quieras
sleep 9999
Mi solicitud HTTP se cuelga
Como ves arriba. En el mundo CGI, el ciclo de vida de la solicitud HTTP depende del ciclo de vida de la tubería (stdout).
Cada proceso hijo podría heredar la tubería del proceso CGI. Si algún proceso que heredó stdout permanece vivo, la solicitud HTTP nunca se completará.
Esto puede causar confusión, cuando deseas un fondo de larga duración o matar el proceso CGI.
Para crear un proceso de larga duración, consulta el tema anterior.
Para matar el proceso CGI, mata todo el grupo de procesos en lugar del proceso CGI en sí.
cgi_pid=...
# no hagas esto
# kill "$cgi_pid"
# haz esto
kill -- "-$cgi_pid"
Quiero matar mi script CGI
Consulta el tema anterior.
Quiero generar contenido dinámicamente
Tradicionalmente, la gente usa reescritura para lograr esto. Pero aquí es mucho más fácil. Puedes hacerlo con cgi pass. Aquí hay un ejemplo para renderizar markdown dinámicamente:
{
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>"
No me gustan los sufijos en la URL
Forma 1: Eliminar el sufijo del script CGI
Forma 2: hacer reescritura
Forma 3: cgi pass
¿Cómo puedo responder con un estado diferente a 200?
#!/bin/sh
echo "Status: 404"
echo "Content-Type: text/plain"
echo
echo "Bienvenido al vacío"
¿Cómo puedo responder con una redirección?
#!/bin/sh
echo "Status: 302"
echo "Location: https://theuselessweb.com"
echo
¿Cómo puedo obtener el cuerpo de la solicitud HTTP?
Puedes leer el cuerpo de la solicitud desde stdin. Si estás usando shell, cat puede guardar rápidamente el cuerpo de la solicitud en un archivo.
¿Cómo puedo enviar un archivo al cliente?
Para archivos pequeños, puedes escribir el archivo directamente en stdout.
Para archivos grandes, es mucho mejor enviar una respuesta 302. Porque la respuesta CGI es de streaming, el protocolo no puede manejar fácilmente el almacenamiento en caché, las descargas en fragmentos o el soporte de reanudación.
Quiero escribir CGI con python, ruby, perl, C, C++...
Adelante. Nginx-cgi no se preocupa por qué lenguaje usas. Simplemente toma información de las variables de entorno, lee el cuerpo de la solicitud desde stdin y escribe la salida en stdout.
Manual
Opciones
cgi <on|off> o cgi pass <script_path> [script_args...]
Habilita o deshabilita el módulo cgi en el bloque de ubicación dado.
Si especificas on aquí, el plugin funcionará en modo tradicional. Analiza primero la URI de la solicitud y luego localiza el script bajo el directorio raíz del documento con la URI de la solicitud. Después de todo, divide la URI de la solicitud en SCRIPT_NAME y PATH_INFO. Esto es bueno si tienes un viejo proyecto CGI o quieres seguir estrictamente el rfc3875.
También proporcioné una sintaxis al estilo de nginx aquí. Si especificas cgi pass aquí, el plugin omitirá el paso de localizar el script CGI. Utiliza directamente el valor que proporcionaste. Puedes hacer referencia a las variables de nginx en el segundo argumento, por ejemplo: cgi pass $document_root$uri. El ejemplo anterior hace algo similar al rfc3875, pero no es igual. En esta forma, la URI de la solicitud se asignará a PATH_INFO directamente. Y SCRIPT_NAME estará vacío. Esta forma es realmente buena para generar contenido dinámico. Evita la reescritura de URI compleja e innecesaria.
Además, la segunda forma también te proporciona la capacidad de pasar argumentos adicionales al script, por ejemplo: cgi pass my_script.sh $uri. Con esto, puedes evitar completamente las confusas variables de entorno del rfc3875.
Si especificas off aquí, el plugin se desactivará.
Predeterminado: off
cgi_pass <script_path>
Alias de cgi pass <script_path>.
cgi_interpreter [interpreter] [args...]
Establece el intérprete y los argumentos del intérprete para el script CGI.
Cuando esta opción no está vacía, el script CGI se ejecutará con el intérprete dado. De lo contrario, el script se ejecutará directamente.
Esta opción puede contener variables de nginx, consulta https://nginx.org/en/docs/varindex.html para más detalles.
Esta opción es extremadamente útil en muchos escenarios, por ejemplo:
- ejecutar scripts CGI que faltan permisos de ejecución
- hacer sudo antes de ejecutar el script CGI
- envolver un binario general como script CGI
- filtrar la salida del script CGI
- ...
Predeterminado: vacío
cgi_working_dir <dir>
Establece el directorio de trabajo del script CGI.
Si este valor se establece como vacío, los scripts CGI heredarán el directorio de trabajo de nginx.
Si este valor se establece como una cadena no vacía, el script CGI se lanzará con el directorio de trabajo dado.
La acción de cambiar el directorio de trabajo puede fallar. Por ejemplo, si el directorio dado no existe, no tiene permiso o el nombre es demasiado largo. En este caso, el script fallará al ejecutarse.
Esta opción no cambia la forma de encontrar el intérprete o el script (si se especifican con una ruta relacionada, siempre están relacionadas con el directorio de trabajo de nginx).
Esta opción puede contener una variable de nginx. Aunque no sé qué uso tiene esto. Tal vez puedas configurar diferentes directorios de trabajo para diferentes server_name por esto.
Predeterminado: vacío
cgi_body_only <on|off>
Un script CGI estándar debería generar dos partes: encabezado y cuerpo. Y una línea vacía para separar esas dos partes.
Si deseas simplemente ejecutar un programa normal como programa CGI. Puedes activar esto.
Una vez que esta opción esté habilitada, toda la salida se tratará como cuerpo de respuesta y se enviará al cliente.
Predeterminado: off
cgi_path <PATH>
Cambia la variable de entorno PATH del script CGI.
Predeterminado: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
cgi_strict <on|off>
Habilita o deshabilita el modo estricto.
Cuando el modo estricto está activado, un encabezado CGI incorrecto causará un error 500. Cuando el modo estricto está desactivado, los encabezados CGI incorrectos se reenviarán tal como están.
Predeterminado: on
cgi_set_var <name> <value>
Agrega y pasa variables de entorno adicionales al script CGI. El primer argumento de este comando es el nombre de la variable de entorno. Debe contener solo letras, números y guiones bajos, y no debe comenzar con un número. El segundo argumento de este comando es la expresión de valor de la variable. Puede contener variables de nginx, consulta https://nginx.org/en/docs/varindex.html para más detalles.
Esta opción puede aparecer más de 1 vez para establecer múltiples variables. Si más de una opción establece la misma variable, entonces la última funciona. Estas directivas se heredan del nivel de configuración anterior si y solo si no hay directivas cgi_set_var definidas en el nivel actual.
Esta opción también puede usarse para sobrescribir variables estándar de CGI. Esto puede ser útil en algunos casos, por ejemplo, al hackear un viejo script CGI o simular variables estándar que no son compatibles con este plugin ahora (como PATH_TRANSLATED, REMOTE_IDENT). Pero no se recomienda, puede introducir problemas confusos en tu sistema.
cgi_stderr <off|info|warn|error|crit|alert|emerg|stderr>
cgi_stderr file <path_to_file>
Por defecto, nginx-cgi captura la salida stderr del script CGI y la vuelca en el registro de nginx con nivel warn. Puedes cambiar el comportamiento aquí.
-
off: descartar completamente la salida stderr.
-
info, warn, error, crit, alert, emerg: redirigir stderr CGI al registro de nginx con el nivel dado. Nota: esta opción podría ser un poco costosa, porque necesita una tubería extra para cada proceso CGI. Si te importa este asunto, deberías evitar esto.
-
stderr: redirigir stderr CGI al stderr del proceso nginx
-
file
: redirigir stderr CGI a un archivo
cgi_rdns <on|off|double> [required]
Habilita o deshabilita DNS inverso.
off: deshabilitar la función rdns.
on: Realiza DNS inverso antes de lanzar el script CGI y pasa el resultado de rdns al script CGI a través de la variable de entorno REMOTE_HOST.
double: Después de DNS inverso, realiza un DNS directo nuevamente para verificar el resultado de rdns. si el resultado coincide, pasa el resultado como REMOTE_HOST.
required: Si rdns falla, se devuelve 403, 503 o 500 al cliente. Depende de la razón del fallo de rdns.
Si activas esta opción, también necesitas configurar un resolver en nginx. De lo contrario, recibirás un error de no resolver defined to resolve.
Notas del autor: no habilites esta opción, hará que cada solicitud sea más lenta. Esta función puede implementarse fácilmente con dig -x o nslookup en el script. La única razón por la que implementé esto es para hacer que el módulo sea completamente compatible con el estándar rfc3875.
cgi_timeout <t1> [t2]
Envía señales TERM/KILL al proceso CGI si se ejecuta demasiado tiempo.
Si tanto t1 como t2 son iguales a 0. La función de tiempo de espera está desactivada.
Si t1 o t2 no son iguales a 0. Se enviará una señal TERM o KILL al proceso después del tiempo de espera.
Si tanto t1 como t2 no son cero. Envía TERM en la marca de tiempo t1 primero. Y envía KILL nuevamente en la marca de tiempo t1+t2 (si el proceso sigue vivo en esa marca de tiempo).
Si t2 no está presente, se trata como 0.
Predeterminado: 0 0
Variables de Entorno Estándar
Nginx-cgi implementó casi todas las variables estándar del rfc3875. Si no pueden cubrir todos tus usos, puedes agregar tu propia variable con cgi_set_var. También estas variables pueden ser sobrescritas por cgi_set_var si realmente lo deseas.
AUTH_TYPE,REMOTE_USER(estándar rfc3875)
Obsoleto desde v0.15 por razones de seguridad. Consulta issue #22 para detalles y soluciones alternativas.
Además, el encabezado Authorization no es visible por defecto en el script CGI por razones de seguridad también. Si deseas acceder al encabezado de autorización en el script CGI, prueba cgi_set_var HTTP_AUTHORIZATION $http_authorization.
CONTENT_LENGTH,CONTENT_TYPE(estándar rfc3875)
Igual que los encabezados de solicitud Content-Length y Content-Type.
GATEWAY_INTERFACE(estándar rfc3875)
Siempre será CGI/1.1 en este plugin.
PATH_INFO(estándar rfc3875)
Digamos que tienes un script bajo /cgi-bin/hello.sh, y accedes a http://127.0.0.1/cgi-bin/hello.sh/somewhat.
Entonces PATH_INFO contiene la cadena /somewhat.
Combinado con rewrite de URL o cgi pass, esta variable puede usarse para generar contenido dinámico.
PATH_TRANSLATED(estándar rfc3875)
Nota: esta opción no está implementada de manera estrictamente conforme al rfc3875. Por favor, evita esto, si estás escribiendo un nuevo script CGI.
Esto está relacionado con PATH_INFO.
Digamos que tienes un script bajo /cgi-bin/hello.sh, y accedes a http://127.0.0.1/cgi-bin/hello.sh/somewhat.
El estándar dice que el servidor debería intentar nuevamente con http://127.0.0.1/somewhat, y averiguar a dónde debería mapearse la URI.
Por razones técnicas, simplemente construyo esta variable por la raíz del documento y PATH_INFO.
El comportamiento puede cambiar en futuras versiones.
QUERY_STRING(estándar rfc3875)
Contiene la cadena de consulta de la solicitud. Por ejemplo, si accedes a http://127.0.0.1/cgi-bin/hello.sh?a=1&b=2, QUERY_STRING contendrá a=1&b=2.
REMOTE_ADDR, (estándar rfc3875)
Dirección IP del cliente.
REMOTE_HOST(estándar rfc3875)
Nombre del host del cliente. Solo disponible si cgi_rdns está activado.
Si cgi_rdns está activado, nginx-cgi realizará un DNS inverso y encontrará un dominio que coincida con REMOTE_ADDR. Si se encuentra alguno, se establecerá en REMOTE_HOST.
Si cgi_rdns es doble, después del RDNS, nginx-cgi realizará nuevamente un DNS directo. REMOTE_HOST solo se establecerá si el resultado del DNS directo coincide con la dirección original.
Consulta cgi_rdns para más información.
REMOTE_IDENT(estándar rfc3875)
El plugin nginx-cgi no soporta esto por razones de seguridad.
REQUEST_METHOD(estándar rfc3875)
Método de solicitud de la solicitud, por ejemplo: GET, POST...
SCRIPT_NAME(estándar rfc3875)
Ruta al script actual. Normalmente, no necesitas esto. No contiene la ruta completa. Consulta SCRIPT_FILENAME.
La única razón para usar esto es construir la URI después de la reescritura. Puedes usar SCRIPT_NAME + PATH_INFO para obtener la URI después de la reescritura.
SERVER_NAME(estándar rfc3875)
Nombre del servidor, normalmente es igual al encabezado Host sin la parte del puerto. Si el encabezado Host no aparece en la solicitud (HTTP/1.0) o contiene un valor inválido, entonces este valor se establece en la dirección IP del servidor reflejada. Si la dirección IP es una dirección ipv6, se citará entre corchetes como [::1].
SERVER_PORT(estándar rfc3875)
Puerto de escucha del servidor, como 80, 443...
SERVER_PROTOCOL(estándar rfc3875)
El protocolo utilizado entre el cliente y el servidor. Como HTTP/1.0, HTTP/1.1...
SERVER_SOFTWARE(estándar rfc3875)
Contiene una cadena de nginx y versión, como nginx/1.27.4.
X_(estándar rfc3875)
Todos los encabezados de solicitud HTTP con prefijo X- se convertirán en variables X_. Por ejemplo:
Si X-a: 123 aparece en el encabezado, X_A se establecerá en 123.
HTTP_(estándar rfc3875)
Todos los demás encabezados de solicitud HTTP se convertirán en variables HTTP_, por ejemplo:
Si Accept: */* aparece en el encabezado, HTTP_ACCEPT se establecerá en */*.
DOCUMENT_ROOT(no estándar, implementado por apache2)
Raíz del documento del bloque de ubicación actual, consulta la declaración root en nginx.
REMOTE_PORT(no estándar, implementado por apache2)
Número de puerto del cliente.
REQUEST_SCHEME(no estándar, implementado por apache2)
http o https.
REQUEST_URI(no estándar, implementado por apache2)
La URI sin procesar antes de la reescritura. Si deseas la URL después de la reescritura, prueba SCRIPT_NAME + PATH_INFO.
Nota: esta variable no es la misma que la variable de nginx $request_uri. Puedes encontrar el documento en https://httpd.apache.org/docs/2.4/mod/mod_rewrite.html.
SCRIPT_FILENAME(no estándar, implementado por apache2)
La ruta completa al script CGI.
SERVER_ADDR(no estándar, implementado por apache2)
Dirección IP del servidor. Si el servidor tiene múltiples direcciones IP, el valor de esta variable puede ser diferente si las solicitudes provienen de diferentes interfaces.
Problemas Conocidos
Implementación de PATH_TRANSLATED no precisa
Por el rfc3875, PATH_TRANSLATED debería apuntar al archivo que sería accesible como si $PATH_INFO se accediera como uri. Pero eso es realmente difícil de implementar en nginx, necesita volver a activar el proceso de ubicación de nginx. Y esas funciones son privadas, no se pueden acceder directamente por el plugin. La otra forma de implementarlo es iniciar una sub-solicitud, pero es demasiado costoso, y esta variable se usa realmente raramente. No vale la pena hacerlo. Así que simplemente construyo esta variable por la raíz del documento y las variables path_info.
Implementación de RDNS no accede a /etc/hosts
La implementación del resolvedor de nginx no accede a /etc/hosts. No quiero implementar un resolvedor extra en el plugin. Así que simplemente ignoro este problema.
Referencia
rfc3875
https://datatracker.ietf.org/doc/html/rfc3875
nginx
https://nginx.org/en/docs/dev/development_guide.html https://hg.nginx.org/nginx-tests
Encabezados hop-by-hop
https://datatracker.ietf.org/doc/html/rfc2616#section-13.5.1
Entornos 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
Puedes encontrar consejos de configuración adicionales y documentación para este módulo en el repositorio de GitHub para nginx-module-cgi.