cgi: Support CGI pour NGINX
Installation
Vous pouvez installer ce module dans n'importe quelle distribution basée sur RHEL, y compris, mais sans s'y limiter :
- RedHat Enterprise Linux 7, 8, 9 et 10
- CentOS 7, 8, 9
- AlmaLinux 8, 9
- Rocky Linux 8, 9
- Amazon Linux 2 et 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
Activez le module en ajoutant ce qui suit en haut de /etc/nginx/nginx.conf :
load_module modules/ngx_http_cgi_module.so;
Ce document décrit nginx-module-cgi v0.15 publié le 5 mars 2026.
Apporte le support CGI à Nginx et Angie serveur web.
| OS | Testé avec | Nginx | Angie |
|---|---|---|---|
| Linux | AlmaLinux 9, Debian 12 et Ubuntu 24.04/20.04 | ok | ok |
| Darwin | MacOS 15.1 | ok | ok |
| BSD | FreeBSD 14.2 et OpenBSD 7.6 | ok | ok |
| Solaris | OmniOS r1510521 | ok | ok |
| Windows | Pas de plan, nginx prend à peine en charge Windows |
Avant tout
CGI n'est ni un démon ni un ange. C'est simplement un outil. Tout comme un couteau de chef dans les mains d'un cuisinier ou une épée dans les mains d'un guerrier, vous n'utiliserez pas une épée pour cuisiner, ni n'emporterez un couteau de chef sur le champ de bataille. Il en va de même pour CGI, il a ses scénarios appropriés, et il ne doit pas être mal utilisé ou diabolisé.
CGI est bon pour :
- Applications à faible fréquence, telles que la gestion système
- Systèmes à ressources limitées, tels que les systèmes embarqués
- Projets à petit budget, tels que les sites web personnels
- Prototypage, pour itérations rapides
CGI est mauvais pour :
- Haute QPS
- Fort trafic
- Haute concurrence
J'ai créé un canal Discord. Si :
- Vous êtes également un fan de CGI
- Vous avez un problème avec nginx-cgi
- Vous souhaitez obtenir des mises à jour sur nginx-cgi
- Vous voulez connaître plus d'amis
Veuillez nous rejoindre : https://discord.gg/EJSfqHHmaR.
Benchmark
CGI n'est pas aussi lent que les gens le pensent généralement. En réalité, ses principales limitations sont la surcharge de processus et la variabilité de latence -- pas qu'il ne puisse gérer que quelques requêtes par minute.
J'ai effectué un test simple.
Environnement de test :
- Machine : instance Vultr à bas coût (5 $/mois) (1 vCPU partagé ~2,3GHz, 1 Go de RAM)
- OS : Debian 12
- Commande de test pour CGI :
ab -n 1000 -c 100 127.0.0.1/cgi-bin/hello.sh - Commande de test pour texte brut :
ab -n 1000 -c 100 127.0.0.1/hello.txt
Résultats :
hello.sh: 1007 req/shello.txt: 4891 req/s
Démarrage rapide
Ajoutez le dépôt (exemple Ubuntu - remplacez 'ubuntu' et 'jammy' par votre distribution)
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
vérifiez le code source
git clone https://github.com/pjincz/nginx-cgi cd nginx-cgi
initialisez rpmbuild
rpmdev-setuptree cd ~/rpmbuild
téléchargez le fichier spec depuis le dépôt
wget https://github.com/pjincz/nginx-cgi/raw/refs/heads/main/fedora/nginx-cgi.spec
!/bin/bash
echo "Content-Type: text/plain" echo
echo "Bienvenue dans le monde CGI !"
N'oubliez pas d'ajouter x-perm au script CGI :
```sh
chmod +x your-document-root-dir/cgi-bin/hello.sh
Redémarrez nginx et essayez :
systemctl restart nginx
curl http://127.0.0.1/cgi-bin/hello.sh
Si tout se passe bien, vous trouverez un accueil du monde CGI. :D
Utilisation
Chargement du plugin
Si ce plugin est installé dans le chemin de module par défaut de nginx (tel que
/usr/lib/nginx/modules), le plugin sera chargé automatiquement.
Sinon, vous devez charger manuellement le plugin par load_module.
Ajoutez l'instruction suivante au contexte de niveau supérieur de nginx pour charger le plugin :
load_module <dir-of-plugin>/ngx_http_cgi_module.so;
Activer cgi
Après avoir chargé le plugin, vous pouvez ajouter cgi on aux contextes de localisation pour activer
cgi. Exemple :
location /cgi-bin {
cgi on;
}
Une fois que cgi est activé dans une localisation, toutes les localisations imbriquées auront également cgi activé. Si vous souhaitez désactiver cgi pour une localisation enfant, utilisez simplement cgi off.
Lorsque la localisation est accédée, nginx-cgi trouvera le script sous le document root (il est spécifié par l'instruction root). Par exemple, si vous avez spécifié le document root comme /var/www/html, alors lorsque vous accédez à /cgi-bin/hello.sh,
/var/www/html/cgi-bin/hello.sh sera exécuté.
Nginx-cgi prend également en charge alias, c'est comme l'instruction root dans nginx, la seule différence est que le préfixe de localisation sera supprimé de l'uri. Par exemple, si vous souhaitez que /cgi/hello.sh fasse également référence au même script, vous pouvez faire ceci :
location /cgi {
alias /var/www/html/cgi-bin;
cgi on;
}
Script hello
Un script cgi peut être écrit dans n'importe quel langage. Voici un exemple avec shell. Vous
pouvez le sauvegarder dans /var/www/html/cgi-bin/hello.sh pour le test (si vous n'avez pas
changé le document root par défaut) :
#!/bin/sh
echo "Status: 200 OK"
echo "Content-Type: text/plain"
echo
echo "Bonjour le monde"
La première ligne du script est un shebang. Si vous avez clairement défini cgi_interpreter,
vous pouvez supprimer cette ligne, sinon l'absence de shebang entraînera une erreur 500. Certains shells permettent au script d'être exécutable même sans shebang, mais ce n'est pas autorisé ici. Si un script exécutable par shell retourne une erreur 500, vérifiez le
shebang.
La sortie du script cgi contient 2 sections : la section d'en-tête et la section corps. Les 2 premières instructions echo produisent la section d'en-tête, et la dernière instruction echo produit la section corps. L'instruction echo au milieu produit le séparateur. Les sections d'en-tête et de corps peuvent être vides, mais le séparateur est obligatoire. L'absence de séparateur entraînera une erreur 500.
Toutes les lignes de la section d'en-tête seront analysées comme des lignes d'en-tête de réponse http normales.
Et ensuite passées au client. Il y a un en-tête spécial Status, qui sera passé dans la ligne de statut de réponse. Si cgi_strict est activé, nginx-cgi vérifiera tous les en-têtes de sortie cgi, et une erreur 500 sera renvoyée si un en-tête invalide est trouvé.
Sinon, les en-têtes invalides seront également transférés au client. Il est fortement recommandé de garder cgi_strict activé.
Après le séparateur, toute sortie sera envoyée au client comme corps tel quel.
Permission x
Après tout, vous devez ajouter la permission x au fichier :
chmod +x /var/www/html/cgi-bin/hello.sh
Normalement, vous avez besoin de la permission x pour rendre le script exécutable. L'absence de permission x peut entraîner une erreur 403. Si vous ne pouvez pas le faire pour une raison quelconque, cgi_interpreter peut aider.
En-tête de requête
Les en-têtes de requête seront analysés puis traduits en variables d'environnement et ensuite passés au script cgi.
Par exemple, vous pouvez trouver la chaîne de requête dans la variable d'environnement QUERY_STRING.
Et accéder à Http-Accept par HTTP_ACCPET.
Voici un exemple :
#!/bin/sh
echo ""
echo "chaîne de requête : $QUERY_STRING"
echo "http accept : $HTTP_ACCEPT"
Pour la liste complète des variables d'environnement, voir la section environnement.
Corps de requête
Le corps de la requête sera passé via stdin. Voici un exemple pour lire tout le corps de la requête et l'écho :
#!/bin/sh
echo ""
body=$(cat)
echo "corps de la requête : $body"
Streaming
Nginx-cgi a un support de streaming pour le corps de la requête et de la réponse. Par exemple,
nous pouvons implémenter une calculatrice en ligne la plus simple par bc :
#!/bin/sh
echo ""
bc 2>&1
Ensuite, nous pouvons tester notre calculatrice par curl :
curl 127.0.0.1/cgi-bin/bc.sh --no-progress-meter -T .
Le plugin nginx-cgi est assez intelligent pour choisir la bonne façon de retourner le corps de la requête. S'il obtient toute la sortie assez rapidement, il sortira le corps en une fois. Si la sortie est retardée, il sortira le corps par morceaux (HTTP 1.1) ou en streaming (HTTP 1.0).
En-têtes http hop-by-hop
Les en-têtes http hop-by-hop ne sont pas autorisés dans la sortie du script cgi. S'ils apparaissent dans la réponse ici, une erreur 500 sera renvoyée au client.
Pour plus d'informations : https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers#hop-by-hop_headers
Astuces et FAQ
Je veux lister toutes les variables d'environnement
Mettez le script suivant dans votre répertoire cgi, et curl depuis votre terminal :
#!/bin/sh
echo 'Content-Type: text/plain'
echo
printenv
Je veux des permissions root
Mettez un fichier sudo dans /etc/sudoers.d et exécutez sudo dans votre script ou définissez
cgi_interpreter comme /usr/bin/sudo.
Voici un exemple de fichier de configuration sudo :
# autoriser www-data à exécuter /var/www/bin/my-danger-script avec le compte root
www-data ALL=(root) NOPASSWD: /var/www/bin/my-danger-script
# autoriser tous les scripts CGI à être lancés avec sudo par nginx-cgi directement
www-data ALL=(root) NOPASSWD: SETENV: /var/www/html/cgi-bin/*
Comment puis-je exécuter des scripts CGI avec chroot
Il n'est pas recommandé d'exécuter des scripts CGI avec chroot. Parce que chroot n'est pas
conçu à des fins de sécurité. Il partage encore beaucoup d'espaces de noyau avec le système hôte.
Par exemple, exécuter ps -ef dans un processus chrooté, tous les processus dans le système hôte seront retournés. Cela ne devrait pas être trop horrible ? Non, c'est vraiment terrible,
car vous pouvez également faire kill dans le script chrooté pour la même raison. Et
les gens exécutent généralement des programmes avec des permissions root dans un environnement chrooté.
C'est terriblement mauvais. Cela expose le système à un risque plus élevé que d'exécuter simplement le script avec
www-data.
Si vous voulez un environnement de bac à sable, lxc, docker et jails sont beaucoup mieux
pour cela.
Si vous voulez toujours chroot, d'accord, laissez-moi vous montrer comment le faire.
Dans cet exemple, je suppose que vous utilisez /var/www/html comme document root.
Préparez d'abord 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 "fichiers sous /:"
ls /
EOF
chmod +x /var/www/html/cgi-bin/ls.sh
# essayez-le
/var/www/html/cgi-bin/ls.sh
Étape 1 : préparez un répertoire chroot.
Il y a beaucoup de façons de faire cette étape. debootstrap est un moyen populaire sur les systèmes basés sur debian. busybox est le moyen le plus léger. docker est un moyen moderne.
Faisons un répertoire le plus léger avec busybox ici :
# Dans cet exemple, je mets tout dans /var/www/chroot
# Faites attention, je télécharge ici la version busybox x86_64, vous devrez peut-être la changer
# Vous avez besoin de permissions root pour exécuter toutes les commandes suivantes, je suis trop paresseux pour
# préfixer sudo à chaque commande ici.
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
# essayez-le
chroot "$root_dir" ls
Étape 2 : montez le document root dans le répertoire chroot
mkdir -p /var/www/chroot/var/www/html
mount --bind /var/www/html /var/www/chroot/var/www/html
# essayez-le
ls /var/www/chroot/var/www/html
Remarque :
-
J'utilise une astuce ici, après chroot, le document root reste le même. Par cela, nous pouvons gagner du temps pour faire la correspondance des chemins.
-
Le montage ne persistera pas après un redémarrage. Vous devrez peut-être ajouter une entrée à /etc/fstab. Ou déplacer /var/www/html dans chroot, et faire un lien symbolique à l'extérieur.
Étape 3 : autoriser www-data à exécuter chroot avec des permissions root.
cat >/etc/sudoers.d/www-run-with-chroot <<EOF
# autoriser et seulement autoriser www-data à exécuter chroot avec /var/www/chroot
www-data ALL=(root) NOPASSWD: /usr/sbin/chroot /var/www/chroot *
EOF
Maintenant, tout est prêt, ajoutez la section suivante à votre nginx/angie :
location /cgi-bin {
cgi on;
cgi_interpreter /usr/bin/sudo /usr/sbin/chroot /var/www/chroot;
}
essayez-le :
curl 127.0.0.1/cgi-bin/ls.sh
Comment puis-je exécuter des scripts CGI avec docker
Dans cet exemple, je suppose que vous utilisez /var/www/html comme document root.
Préparez d'abord 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 "fichiers sous /:"
ls /
EOF
chmod +x /var/www/html/cgi-bin/ls.sh
# essayez-le
/var/www/html/cgi-bin/ls.sh
Créez un conteneur et maintenez-le en cours d'exécution en arrière-plan :
# Changez -v si nécessaire
# -d : exécute en arrière-plan
# -i -t : garde un terminal
# --restart always : garde le conteneur vivant
docker run -dit --restart always --name my_cgi_docker -v /var/www:/var/www busybox sh
# essayez-le
docker exec my_cgi_docker /var/www/html/cgi-bin/ls.sh
Autorisez www-data à exécuter des commandes docker :
sudo usermod -aG docker www-data
# essayez-le
sudo -u www-data docker exec my_cgi_docker /var/www/html/cgi-bin/ls.sh
Maintenant, tout est prêt, ajoutez la section suivante à votre nginx/angie :
location /cgi-bin {
cgi on;
cgi_interpreter /usr/bin/docker exec my_cgi_docker;
}
Comment puis-je exécuter des scripts CGI avec jails
D'accord, vous êtes un fan de FreeBSD ? Moi aussi.
C'est vraiment similaire à l'exécution de scripts avec chroot.
Ici, je suppose que vous utilisez également /var/www/html comme document root.
Préparez d'abord 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 "fichiers sous /:"
ls /
EOF
chmod +x /var/www/html/cgi-bin/ls.sh
# essayez-le
/var/www/html/cgi-bin/ls.sh
Étape 1 : créez une jail
Mettons la jail dans /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 .
# créez des points de montage
mkdir -p /var/www/jail/var/www/html
touch /var/www/jail/etc/resolv.conf
Mettez la configuration suivante dans /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";
# monter /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;
# décommentez les lignes suivantes, si vous souhaitez autoriser l'accès réseau dans la jail
# ip4 = inherit;
# ip6 = inherit;
# exec.prestart += "mount_nullfs /etc/resolv.conf /var/www/jail/etc/resolv.conf || true";
# décommentez les lignes suivantes, si vous souhaitez également que `ping` soit disponible dans la jail
# allow.raw_sockets = 1;
persist; # garder la jail si aucun processus n'est en cours d'exécution
}
Et assurez-vous que la ligne suivante apparaît dans /etc/rc.conf :
jail_enable="YES"
Et démarrez la jail :
service jail start www-jail
# essayez-le
jexec www-jail ls /
jexec www-jail /var/www/html/cgi-bin/ls.sh
Étape 2 : autoriser www à exécuter jexec avec des permissions root.
J'utilise sudo ici. Je ne suis pas familier avec doas, si vous préférez doas, vous pouvez
essayer vous-même. Quoi qu'il en soit, ni sudo ni doas ne sont préchargés avec FreeBSD. Vous
devez manuellement en installer un.
cat >/usr/local/etc/sudoers.d/www-jexec <<EOF
# autoriser et seulement autoriser `www` à exécuter `jexec` avec `www-jail`
www ALL=(root) NOPASSWD: /usr/sbin/jexec www-jail *
EOF
# essayez-le
sudo -u www sudo jexec www-jail /var/www/html/cgi-bin/ls.sh
Maintenant, tout est prêt, ajoutez la section suivante à votre nginx/angie :
location /cgi-bin {
cgi on;
cgi_interpreter /usr/local/bin/sudo /usr/sbin/jexec www-jail;
}
essayez-le :
curl 127.0.0.1/cgi-bin/ls.sh
Je veux créer un processus d'arrière-plan qui s'exécute longtemps
Assurez-vous simplement de ne pas hériter de stdout lors de la création du processus (idéalement, évitez également d'hériter de stdin et stderr). Voici un exemple écrit en shell.
taskid=1234
logfile="/var/lib/my-project/$taskid"
./long-run-task.sh "$taskid" </dev/null >"$logfile" 2>&1 &
Ou si vous êtes familier avec l'opération de pipe, fermez simplement stdout (de plus, il est
préférable de fermer également stdin et stderr), la requête http se terminera immédiatement. Et vous pouvez utiliser le processus comme processus d'arrière-plan.
exec </dev/null >somewhere 2>&1
# maintenant la réponse http est terminée, faites ce que vous voulez
sleep 9999
Ma requête http est bloquée
Comme vous le voyez ci-dessus. Dans le monde CGI, le cycle de vie de la requête http dépend du cycle de vie du pipe (stdout).
Chaque processus enfant pourrait hériter du pipe du processus CGI. Si un processus qui hérite de stdout reste actif, la requête HTTP ne se terminera jamais.
Cela peut causer de la confusion lorsque vous souhaitez un long processus d'arrière-plan ou tuer le processus CGI.
Pour créer un processus de longue durée, voir le sujet ci-dessus.
Pour tuer le processus CGI, tuez tout le groupe de processus plutôt que le processus CGI lui-même.
cgi_pid=...
# ne faites pas ça
# kill "$cgi_pid"
# faites cela
kill -- "-$cgi_pid"
Je veux tuer mon script cgi
Voir le sujet ci-dessus.
Je veux générer du contenu dynamiquement
Traditionnellement, les gens utilisent la réécriture pour y parvenir. Mais c'est beaucoup plus facile ici.
Vous pouvez le faire avec cgi pass. Voici un exemple pour rendre markdown dynamiquement :
{
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>"
Je n'aime pas les suffixes dans l'url
Méthode 1 : Supprimer le suffixe du script CGI
Méthode 2 : faire de la réécriture
Méthode 3 : cgi pass
Comment puis-je répondre avec un statut autre que 200
#!/bin/sh
echo "Status: 404"
echo "Content-Type: text/plain"
echo
echo "Bienvenue dans le vide"
Comment puis-je répondre avec une redirection
#!/bin/sh
echo "Status: 302"
echo "Location: https://theuselessweb.com"
echo
Comment puis-je obtenir le corps de la requête http
Vous pouvez lire le corps de la requête depuis stdin. Si vous utilisez shell, cat peut
rapidement sauvegarder le corps de la requête dans un fichier.
Comment puis-je envoyer un fichier au client
Pour les petits fichiers, vous pouvez écrire le fichier directement dans stdout.
Pour les gros fichiers, il est beaucoup mieux d'envoyer une réponse 302. Parce que la réponse CGI est en streaming, le protocole ne peut pas facilement gérer la mise en cache, les téléchargements par morceaux ou le support de reprise.
Je veux écrire CGI avec python, ruby, perl, C, C++...
Allez-y. Nginx-cgi ne se soucie pas du langage que vous utilisez. Il suffit de récupérer des informations
des variables d'environnement, de lire le corps de la requête depuis stdin, et d'écrire la sortie dans
stdout.
Manuel
Options
cgi <on|off> ou cgi pass <script_path> [script_args...]
Active ou désactive le module cgi dans le bloc de localisation donné.
Si vous spécifiez on ici, le plugin fonctionnera en mode traditionnel. Il analyse
d'abord l'uri de la requête, puis localise le script sous le répertoire racine du document
avec l'uri de la requête. Après tout, il divise l'uri de la requête en SCRIPT_NAME et
PATH_INFO. C'est bon si vous avez un ancien projet CGI ou si vous souhaitez suivre strictement
rfc3875.
J'ai également fourni une syntaxe de style nginx ici. Si vous spécifiez cgi pass ici, le
plugin sautera l'étape de localisation du script CGI. Il utilise directement la valeur que vous
avez fournie. Vous pouvez référencer des variables nginx dans le deuxième argument,
par exemple : cgi pass $document_root$uri. L'exemple ci-dessus fait quelque chose de similaire à
rfc3875, mais pas égal. Dans cette forme, l'uri de la requête sera assignée à
PATH_INFO directement. Et SCRIPT_NAME sera vide. Cette forme est vraiment bonne
pour la génération de contenu dynamique. Elle contourne la réécriture d'uri complexe et inutile.
De plus, la deuxième forme vous donne également la possibilité de passer des arguments supplémentaires
au script, par exemple : cgi pass my_script.sh $uri. Avec cela, vous pouvez totalement
éviter les variables d'environnement rfc3875 déroutantes.
Si vous spécifiez off ici, le plugin sera désactivé.
Par défaut : off
cgi_pass <script_path>
Alias de cgi pass <script_path>.
cgi_interpreter [interpreter] [args...]
Définir l'interpréteur et les arguments de l'interpréteur pour le script cgi.
Lorsque cette option n'est pas vide, le script cgi sera exécuté avec l'interpréteur donné. Sinon, le script sera exécuté directement.
Cette option peut contenir des variables nginx, voir https://nginx.org/en/docs/varindex.html pour plus de détails.
Cette option est extrêmement utile dans de nombreux scénarios, par exemple :
- exécuter des scripts CGI manquants de permission x
- faire sudo avant d'exécuter le script CGI
- envelopper un binaire général en tant que script CGI
- filtrer la sortie du script CGI
- ...
Par défaut : vide
cgi_working_dir <dir>
Définir le répertoire de travail du script CGI.
Si cette valeur est définie sur vide, les scripts CGI hériteront du répertoire de travail de nginx.
Si cette valeur est définie sur une chaîne non vide, le script CGI sera lancé avec le répertoire de travail donné.
L'action de changement de répertoire de travail peut échouer. Par exemple, si le répertoire donné n'existe pas, pas de permission ou nom trop long. Dans ce cas, le script échouera à s'exécuter.
Cette option ne change pas la manière de trouver l'interpréteur ou le script (s'ils sont spécifiés avec un chemin relatif, ils sont toujours liés au répertoire de travail de nginx).
Cette option peut contenir une variable nginx. Bien que je ne sache pas à quoi cela sert. Peut-être que vous pouvez configurer un répertoire de travail différent pour différents server_name grâce à cela.
Par défaut : vide
cgi_body_only <on|off>
Un script CGI standard doit produire deux parties : l'en-tête et le corps. Et une ligne vide pour séparer ces deux parties.
Si vous souhaitez simplement exécuter un programme normal en tant que programme CGI. Vous pouvez activer cela.
Une fois cette option activée, toute sortie sera traitée comme corps de réponse, et sera envoyée au client.
Par défaut : off
cgi_path <PATH>
Changer la variable d'environnement PATH du script cgi.
Par défaut : /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
cgi_strict <on|off>
Activer ou désactiver le mode strict.
Lorsque le mode strict est activé, un mauvais en-tête cgi entraînera une erreur 500. Lorsque le mode strict est désactivé, un mauvais en-tête cgi sera transmis tel quel.
Par défaut : on
cgi_set_var <name> <value>
Ajouter et passer des variables d'environnement supplémentaires au script CGI. Le premier argument de cette commande est le nom de la variable d'environnement. Il ne doit contenir que des lettres, des chiffres et des underscores, et ne doit pas commencer par un chiffre. Le deuxième argument de cette commande est l'expression de valeur de la variable. Elle peut contenir des variables nginx, voir https://nginx.org/en/docs/varindex.html pour plus de détails.
Cette option peut apparaître plus d'une fois pour définir plusieurs variables. Si plus d'une option définit la même variable, alors la dernière fonctionne. Ces directives sont héritées du niveau de configuration précédent uniquement s'il n'y a pas de directives cgi_set_var définies au niveau actuel.
Cette option peut également être utilisée pour remplacer les variables CGI standard. Cela peut être utile
dans certains cas, par exemple pour pirater un ancien script CGI ou simuler des variables standard qui
ne sont pas prises en charge par ce plugin actuellement (comme PATH_TRANSLATED,
REMOTE_IDENT). Mais ce n'est pas recommandé, cela peut introduire des problèmes déroutants dans
votre système.
cgi_stderr <off|info|warn|error|crit|alert|emerg|stderr>
cgi_stderr file <path_to_file>
Par défaut, nginx-cgi récupère la sortie stderr du script cgi et la déverse dans le journal nginx
avec un niveau warn.
Vous pouvez changer le comportement ici.
-
off : rejeter complètement la sortie stderr.
-
info, warn, error, crit, alert, emerg : rediriger le stderr CGI vers le journal nginx avec le niveau donné. Remarque : cette option peut être un peu coûteuse, car elle nécessite un pipe supplémentaire pour chaque processus CGI. Si cela vous préoccupe, vous devriez éviter cela.
-
stderr : rediriger le stderr CGI vers le stderr du processus nginx
-
file
: rediriger le stderr CGI vers un fichier
cgi_rdns <on|off|double> [required]
Activer ou désactiver le dns inverse.
off : désactiver la fonctionnalité rdns.
on : Effectuer un dns inverse avant de lancer le script cgi, et passer le résultat rdns au script cgi via la variable d'environnement REMOTE_HOST.
double : Après le dns inverse, effectuer à nouveau un dns direct pour vérifier le résultat rdns. si
le résultat correspond, passer le résultat en tant que REMOTE_HOST.
required : Si le rdns échoue, 403, 503 ou 500 sera renvoyé au client. Cela dépend de
la raison de l'échec du rdns.
Si vous activez cette option, vous devez également configurer un resolver dans nginx.
Sinon, vous obtiendrez une erreur de no resolver defined to resolve.
notes de l'auteur : ne pas activer cette option, cela ralentira chaque requête.
cette fonctionnalité peut être facilement implémentée par dig -x ou nslookup dans le script. la
seule raison pour laquelle j'ai implémenté cela est simplement pour rendre le module entièrement conforme à la
norme rfc3875.
cgi_timeout <t1> [t2]
Envoyer des signaux TERM/KILL au processus CGI s'il s'exécute trop longtemps.
Si t1 et t2 sont tous deux égaux à 0. La fonctionnalité de délai d'attente est désactivée.
Si t1 ou t2 n'est pas égal à 0. Un signal TERM ou KILL sera envoyé au
processus après le délai d'attente.
Si t1 et t2 ne sont pas nuls. Envoyez TERM à l'horodatage t1 en premier. Et envoyez
à nouveau KILL à l'horodatage t1+t2 (si le processus est toujours vivant à cet horodatage).
Si t2 n'est pas présent, il est traité comme 0.
Par défaut : 0 0
Variables d'environnement standard
Nginx-cgi a implémenté presque toutes les variables standard rfc3875. Si elles ne peuvent pas
couvrir tous vos usages, vous pouvez ajouter votre propre variable par cgi_set_var. De plus,
ces variables peuvent être remplacées par cgi_set_var si vous le souhaitez vraiment.
AUTH_TYPE,REMOTE_USER(standard rfc3875)
Déprécié depuis v0.15 pour des raisons de sécurité. Voir [issue
22](https://github.com/pjincz/nginx-cgi/issues/22) pour des détails et des solutions de contournement.
De plus, l'en-tête Authorization n'est pas visible par défaut dans le script cgi pour
des raisons de sécurité également. Si vous souhaitez accéder à l'en-tête d'autorisation dans le script CGI,
essayez cgi_set_var HTTP_AUTHORIZATION $http_authorization.
CONTENT_LENGTH,CONTENT_TYPE(standard rfc3875)
Identique aux en-têtes de requête Content-Length et Content-Type.
GATEWAY_INTERFACE(standard rfc3875)
Toujours CGI/1.1 dans ce plugin.
PATH_INFO(standard rfc3875)
Disons que vous avez un script sous /cgi-bin/hello.sh, et que vous accédez à
http://127.0.0.1/cgi-bin/hello.sh/somewhat.
Alors PATH_INFO contient la chaîne /somewhat.
En combinaison avec rewrite d'url ou cgi pass, cette variable peut être utilisée pour
générer du contenu dynamique.
PATH_TRANSLATED(standard rfc3875)
Remarque : cette option n'est pas implémentée en conformité stricte avec rfc3875. Veuillez éviter cela, si vous écrivez un nouveau script CGI.
Cela est lié à PATH_INFO.
Disons que vous avez un script sous /cgi-bin/hello.sh, et que vous accédez à
http://127.0.0.1/cgi-bin/hello.sh/somewhat.
La norme dit que le serveur doit réessayer avec http://127.0.0.1/somewhat,
et découvrir où l'uri doit être mappé.
Pour des raisons techniques, je construis simplement cette variable par la racine du document et
PATH_INFO.
Le comportement peut changer dans une version future.
QUERY_STRING(standard rfc3875)
Contient la chaîne de requête de la requête. Par exemple, si vous accédez à
http://127.0.0.1/cgi-bin/hello.sh?a=1&b=2, QUERY_STRING contiendra
a=1&b=2.
REMOTE_ADDR, (standard rfc3875)
Adresse IP du client.
REMOTE_HOST(standard rfc3875)
Nom d'hôte du client. Disponible uniquement si cgi_rdns est activé.
Si cgi_rdns est activé, nginx-cgi effectuera un DNS inverse et trouvera un domaine correspondant
à REMOTE_ADDR. Si un domaine est trouvé, il sera défini sur REMOTE_HOST.
Si cgi_rdns est double, après le RDNS, nginx-cgi effectuera à nouveau un DNS direct.
REMOTE_HOST ne sera défini que si le résultat du DNS direct correspond à l'adresse d'origine.
Voir cgi_rdns pour plus d'informations.
REMOTE_IDENT(standard rfc3875)
Le plugin nginx-cgi ne prend pas en charge cela pour des raisons de sécurité.
REQUEST_METHOD(standard rfc3875)
Méthode de requête de la requête, par exemple : GET, POST...
SCRIPT_NAME(standard rfc3875)
Chemin vers le script actuel. Normalement, vous n'avez pas besoin de cela. Il ne contient pas le
chemin complet. Voir SCRIPT_FILENAME.
La seule raison d'utiliser cela est de construire l'URI après réécriture. Vous pouvez utiliser
SCRIPT_NAME + PATH_INFO pour obtenir l'URI après réécriture.
SERVER_NAME(standard rfc3875)
Nom du serveur, normalement il est égal à l'en-tête Host sans la partie port. Si l'en-tête Host
n'apparaît pas dans la requête (HTTP/1.0) ou contient une valeur invalide, alors
cette valeur est définie sur l'adresse IP du serveur. Si l'adresse IP est une adresse ipv6,
elle sera entre crochets comme [::1].
SERVER_PORT(standard rfc3875)
Port d'écoute du serveur, tel que 80, 443...
SERVER_PROTOCOL(standard rfc3875)
Le protocole utilisé entre le client et le serveur. Tel que HTTP/1.0, HTTP/1.1...
SERVER_SOFTWARE(standard rfc3875)
Contient une chaîne de nginx et de version, telle que nginx/1.27.4.
X_(standard rfc3875)
Tous les en-têtes de requête http préfixés par X- seront convertis en variables X_. Par exemple :
Si X-a: 123 apparaît dans l'en-tête, X_A sera défini sur 123.
HTTP_(standard rfc3875)
Tous les autres en-têtes de requête http seront convertis en variables HTTP_, par exemple :
Si Accept: */* apparaît dans l'en-tête, HTTP_ACCEPT sera défini sur */*.
DOCUMENT_ROOT(non-standard, implémenté par apache2)
Racine du document du bloc de localisation actuel, voir l'instruction root dans nginx.
REMOTE_PORT(non-standard, implémenté par apache2)
Numéro de port du client.
REQUEST_SCHEME(non-standard, implémenté par apache2)
http ou https.
REQUEST_URI(non-standard, implémenté par apache2)
L'uri brute avant réécriture. Si vous souhaitez l'URL après réécriture, essayez
SCRIPT_NAME + PATH_INFO.
Remarque : cette variable n'est pas la même que la variable nginx $request_uri. Vous pouvez trouver
le document à https://httpd.apache.org/docs/2.4/mod/mod_rewrite.html.
SCRIPT_FILENAME(non-standard, implémenté par apache2)
Le chemin complet vers le script CGI.
SERVER_ADDR(non-standard, implémenté par apache2)
Adresse IP du serveur. Si le serveur a plusieurs adresses IP. La valeur de cette variable peut être différente si les requêtes proviennent d'interfaces différentes.
Problèmes connus
Implémentation de PATH_TRANSLATED inexacte
Selon rfc3875, PATH_TRANSLATED devrait pointer vers le fichier qui serait accessible si $PATH_INFO
était accédé en tant qu'uri. Mais c'est vraiment difficile à implémenter sur nginx, cela nécessite de relancer
le processus de localisation de nginx. Et ces fonctions sont privées, ne peuvent pas être accessibles par
le plugin. L'autre moyen de l'implémenter est de démarrer une sous-requête, mais c'est trop coûteux, et cette variable est vraiment rarement utilisée. Cela ne vaut vraiment pas le coup de le faire. Donc je construis simplement cette variable par la racine du document et
les variables path_info.
L'implémentation de RDNS n'accède pas à /etc/hosts
L'implémentation du résolveur de nginx n'accède pas à /etc/hosts. Je ne veux pas implémenter un résolveur supplémentaire dans le plugin. Donc j'ignore simplement ce problème.
Référence
rfc3875
https://datatracker.ietf.org/doc/html/rfc3875
nginx
https://nginx.org/en/docs/dev/development_guide.html https://hg.nginx.org/nginx-tests
En-têtes hop-by-hop
https://datatracker.ietf.org/doc/html/rfc2616#section-13.5.1
Environnements 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
Vous pouvez trouver des conseils de configuration supplémentaires et de la documentation pour ce module dans le dépôt GitHub pour nginx-module-cgi.