cgi: Suporte a CGI para NGINX
Instalação
Você pode instalar este módulo em qualquer distribuição baseada em RHEL, incluindo, mas não se limitando a:
- RedHat Enterprise Linux 7, 8, 9 e 10
- CentOS 7, 8, 9
- AlmaLinux 8, 9
- Rocky Linux 8, 9
- Amazon Linux 2 e 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
Ative o módulo adicionando o seguinte no topo de /etc/nginx/nginx.conf:
load_module modules/ngx_http_cgi_module.so;
Este documento descreve o nginx-module-cgi v0.15 lançado em 05 de março de 2026.
Adiciona suporte a CGI ao Nginx e ao servidor web Angie.
| SO | Testado com | Nginx | Angie |
|---|---|---|---|
| Linux | AlmaLinux 9, Debian 12 e Ubuntu 24.04/20.04 | ok | ok |
| Darwin | MacOS 15.1 | ok | ok |
| BSD | FreeBSD 14.2 e OpenBSD 7.6 | ok | ok |
| Solaris | OmniOS r1510521 | ok | ok |
| Windows | Sem plano, nginx mal suporta Windows |
Antes de tudo
CGI não é um demônio nem um anjo. É simplesmente uma ferramenta. Assim como a faca de um chef nas mãos de um cozinheiro ou uma espada nas mãos de um guerreiro, você não usará uma espada para cozinhar, nem levará a faca de um chef para o campo de batalha. O mesmo se aplica ao CGI, ele tem seus cenários apropriados e não deve ser mal utilizado ou demonizado.
CGI é bom para:
- Aplicações de baixa frequência, como gerenciamento de sistema
- Sistemas com recursos limitados, como sistemas embarcados
- Projetos de baixo orçamento, como sites pessoais
- Prototipagem, para iterações rápidas
CGI é ruim para:
- Alta QPS
- Alto tráfego
- Alta concorrência
Criei um canal no Discord. Se:
- Você também é fã de CGI
- Se você tiver algum problema com nginx-cgi
- Se você quiser receber atualizações sobre nginx-cgi
- Se você quiser conhecer mais amigos
Por favor, junte-se a nós: https://discord.gg/EJSfqHHmaR.
Benchmark
CGI não é tão lento quanto as pessoas normalmente pensam. Na realidade, suas principais limitações são a sobrecarga de processos e a variabilidade de latência -- não que ele só consiga lidar com algumas solicitações por minuto.
Fiz um teste simples.
Ambiente de teste:
- Máquina: instância Vultr de baixo custo ($5/mês) (1 vCPU compartilhada ~2.3GHz, 1GB RAM)
- SO: Debian 12
- Comando de teste para CGI:
ab -n 1000 -c 100 127.0.0.1/cgi-bin/hello.sh - Comando de teste para texto simples:
ab -n 1000 -c 100 127.0.0.1/hello.txt
Resultados:
hello.sh: 1007 req/shello.txt: 4891 req/s
Início rápido
Adicione o repositório (exemplo para Ubuntu - substitua 'ubuntu' e 'jammy' pela sua distribuição)
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
faça o checkout do código fonte
git clone https://github.com/pjincz/nginx-cgi cd nginx-cgi
inicialize o rpmbuild
rpmdev-setuptree cd ~/rpmbuild
baixe o arquivo spec do repositório
wget https://github.com/pjincz/nginx-cgi/raw/refs/heads/main/fedora/nginx-cgi.spec
!/bin/bash
echo "Content-Type: text/plain" echo
echo "Bem-vindo ao mundo CGI!"
Não se esqueça de adicionar permissão de execução ao script CGI:
```sh
chmod +x your-document-root-dir/cgi-bin/hello.sh
Reinicie o nginx e teste:
systemctl restart nginx
curl http://127.0.0.1/cgi-bin/hello.sh
Se nada der errado, você encontrará uma mensagem de boas-vindas do mundo CGI. :D
Uso
Carregando o plugin
Se este plugin estiver instalado no caminho padrão de módulos do nginx (como /usr/lib/nginx/modules), o plugin será carregado automaticamente. Caso contrário, você precisará carregar o plugin manualmente com load_module.
Adicione a seguinte declaração ao contexto de nível superior do nginx para carregar o plugin:
load_module <dir-of-plugin>/ngx_http_cgi_module.so;
Habilitar cgi
Após carregar o plugin, você pode adicionar cgi on aos contextos de localização para habilitar o cgi. Exemplo:
location /cgi-bin {
cgi on;
}
Uma vez que o cgi esteja ativado em uma localização, todas as localizações aninhadas também terão o cgi ativado. Se você quiser desativar o cgi para uma localização filha, basta usar cgi off.
Quando a localização for acessada, o nginx-cgi encontrará o script sob o diretório raiz do documento (especificado pela declaração root). Por exemplo, se você especificou o diretório raiz como /var/www/html, então, ao acessar /cgi-bin/hello.sh, /var/www/html/cgi-bin/hello.sh será executado.
Nginx-cgi também suporta alias, que é como a declaração root no nginx, a única diferença é que o prefixo da localização será removido da URI. Por exemplo, se você quiser que /cgi/hello.sh também faça referência ao mesmo script, você pode fazer isso:
location /cgi {
alias /var/www/html/cgi-bin;
cgi on;
}
Script de Olá
Um script CGI pode ser escrito em qualquer linguagem. Aqui está um exemplo em shell. Você pode salvá-lo em /var/www/html/cgi-bin/hello.sh para teste (se você não mudou o diretório raiz do documento padrão):
#!/bin/sh
echo "Status: 200 OK"
echo "Content-Type: text/plain"
echo
echo "Olá mundo"
A primeira linha do script é um shebang. Se você definir claramente cgi_interpreter, pode remover esta linha; caso contrário, a falta do shebang causará um erro 500. Alguns shells permitem que scripts sejam executáveis mesmo sem shebang, mas isso não é permitido aqui. Se um script for executável pelo shell, mas retornar erro 500, verifique o shebang.
A saída do script CGI contém 2 seções: a seção de cabeçalho e a seção de corpo. As duas primeiras declarações echo produzem a seção de cabeçalho, e a última declaração echo produz a seção de corpo. A declaração echo no meio produz o separador. Tanto a seção de cabeçalho quanto a seção de corpo podem estar vazias, mas o separador é obrigatório. A falta do separador causará um erro 500.
Todas as linhas na seção de cabeçalho serão analisadas como linhas de cabeçalho de resposta HTTP normais. E então passadas para o lado do cliente. Há um cabeçalho especial Status, que será passado na linha de status da resposta. Se cgi_strict estiver ativado, o nginx-cgi verificará todos os cabeçalhos de saída do CGI, e um erro 500 será retornado se um cabeçalho inválido for encontrado. Caso contrário, cabeçalhos inválidos também serão encaminhados para o lado do cliente. É altamente recomendável manter cgi_strict ativado.
Após o separador, toda a saída será enviada ao cliente como corpo, como está.
Permissão x
Após tudo, você precisa adicionar a permissão x ao arquivo:
chmod +x /var/www/html/cgi-bin/hello.sh
Normalmente, você precisa de permissão x para tornar o script executável. A falta de permissão x pode causar erro 403. Se não puder fazer isso por qualquer motivo, cgi_interpreter pode ajudar.
Cabeçalho da solicitação
Os cabeçalhos da solicitação serão analisados e, em seguida, traduzidos em variáveis de ambiente e passados para o script CGI.
Por exemplo, você pode encontrar a string de consulta na variável de ambiente QUERY_STRING. E acessar Http-Accept através de HTTP_ACCEPT.
Aqui está um exemplo:
#!/bin/sh
echo ""
echo "string de consulta: $QUERY_STRING"
echo "aceitação http: $HTTP_ACCEPT"
Para a lista completa de variáveis de ambiente, veja a seção de ambiente.
Corpo da solicitação
O corpo da solicitação será passado via stdin. Aqui está um exemplo para ler todo o corpo da solicitação e ecoá-lo:
#!/bin/sh
echo ""
body=$(cat)
echo "corpo da solicitação: $body"
Streaming
Nginx-cgi tem suporte a streaming para o corpo da solicitação e da resposta. Por exemplo, podemos implementar uma calculadora online mais simples usando bc:
#!/bin/sh
echo ""
bc 2>&1
Então, podemos testar nossa calculadora com curl:
curl 127.0.0.1/cgi-bin/bc.sh --no-progress-meter -T .
O plugin nginx-cgi é inteligente o suficiente para escolher a maneira correta de retornar o corpo da solicitação. Se ele obtiver toda a saída rapidamente, ele a enviará de uma vez. Se a saída for atrasada, ele a enviará de forma fragmentada (HTTP 1.1) ou em streaming (HTTP 1.0).
Cabeçalhos HTTP hop-by-hop
Cabeçalhos HTTP hop-by-hop não são permitidos na saída do script CGI. Se aparecerem na resposta aqui, um erro 500 será retornado ao cliente.
Para mais informações:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers#hop-by-hop_headers
Truques e FAQ
Eu quero listar todas as variáveis de ambiente
Coloque o seguinte script no seu diretório CGI e faça um curl a partir do seu terminal:
#!/bin/sh
echo 'Content-Type: text/plain'
echo
printenv
Eu quero permissão de root
Coloque um arquivo sudo em /etc/sudoers.d e execute sudo no seu script ou defina cgi_interpreter como /usr/bin/sudo.
Aqui está um exemplo de arquivo de configuração sudo:
# permite que www-data execute /var/www/bin/my-danger-script com a conta root
www-data ALL=(root) NOPASSWD: /var/www/bin/my-danger-script
# permite que todos os scripts CGI sejam lançados com sudo pelo nginx-cgi diretamente
www-data ALL=(root) NOPASSWD: SETENV: /var/www/html/cgi-bin/*
Como posso executar scripts CGI com chroot
Não é altamente recomendável executar scripts CGI com chroot. Porque chroot não é projetado para fins de segurança. Ele ainda compartilha muitos espaços de kernel com o sistema host. Por exemplo, executar ps -ef em um processo chrooted, todos os processos no sistema host serão retornados. Isso não deveria ser muito horrível? Não, isso é realmente terrível, porque você também pode fazer kill em um script chrooted pelo mesmo motivo. E as pessoas normalmente executam programas com permissão de root em um ambiente chrooted. Isso é terrivelmente ruim. Isso coloca o sistema em alto risco do que apenas executar o script com www-data.
Se você quiser um ambiente de sandbox, lxc, docker e jails são muito melhores para esse propósito.
Se você ainda quiser chroot, ok, deixe-me mostrar como fazê-lo.
Neste exemplo, assumo que você está usando /var/www/html como o diretório raiz do documento.
Prepare primeiro um 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 "arquivos em /:"
ls /
EOF
chmod +x /var/www/html/cgi-bin/ls.sh
# tente
/var/www/html/cgi-bin/ls.sh
Passo 1: prepare um diretório chroot.
Há muitas maneiras de fazer este passo. debootstrap é uma maneira popular em sistemas baseados em Debian. busybox é a maneira mais leve. docker é uma maneira moderna.
Vamos fazer um diretório mais leve com busybox aqui:
# Neste exemplo, coloco tudo em /var/www/chroot
# Tenha cuidado, estou baixando a versão busybox x86_64 aqui, você pode precisar mudá-la
# Você precisa de permissão de root para executar todos os comandos a seguir, estou com preguiça de
# colocar sudo em todos os comandos aqui.
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
# tente
chroot "$root_dir" ls
Passo 2: monte o diretório raiz do documento no diretório chroot
mkdir -p /var/www/chroot/var/www/html
mount --bind /var/www/html /var/www/chroot/var/www/html
# tente
ls /var/www/chroot/var/www/html
Nota:
-
Estou usando um truque aqui, após chroot, a raiz do documento ainda é a mesma. Com isso, podemos economizar algum tempo para fazer o mapeamento de caminho.
-
A montagem não persistirá após uma reinicialização. Você pode precisar adicionar uma entrada em /etc/fstab. Ou mover /var/www/html para chroot e fazer um link simbólico fora.
Passo 3: permita que www-data execute chroot com permissão de root.
cat >/etc/sudoers.d/www-run-with-chroot <<EOF
# permite e somente permite que www-data execute chroot com /var/www/chroot
www-data ALL=(root) NOPASSWD: /usr/sbin/chroot /var/www/chroot *
EOF
Agora tudo está pronto, adicione a seguinte seção ao seu nginx/angie:
location /cgi-bin {
cgi on;
cgi_interpreter /usr/bin/sudo /usr/sbin/chroot /var/www/chroot;
}
tente:
curl 127.0.0.1/cgi-bin/ls.sh
Como posso executar scripts CGI com docker
Neste exemplo, assumo que você está usando /var/www/html como o diretório raiz do documento.
Prepare primeiro um 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 "arquivos em /:"
ls /
EOF
chmod +x /var/www/html/cgi-bin/ls.sh
# tente
/var/www/html/cgi-bin/ls.sh
Crie um contêiner e mantenha-o em execução em segundo plano:
# Altere -v se necessário
# -d: executa em segundo plano
# -i -t: mantém um terminal
# --restart always: mantém o contêiner ativo
docker run -dit --restart always --name my_cgi_docker -v /var/www:/var/www busybox sh
# tente
docker exec my_cgi_docker /var/www/html/cgi-bin/ls.sh
Permita que www-data execute comandos docker:
sudo usermod -aG docker www-data
# tente
sudo -u www-data docker exec my_cgi_docker /var/www/html/cgi-bin/ls.sh
Agora tudo está pronto, adicione a seguinte seção ao seu nginx/angie:
location /cgi-bin {
cgi on;
cgi_interpreter /usr/bin/docker exec my_cgi_docker;
}
Como posso executar scripts CGI com jails
Ok, você é fã do FreeBSD? Eu também.
É muito semelhante a executar scripts com chroot.
Aqui assumo que você está usando /var/www/html como o diretório raiz do documento também.
Prepare primeiro um 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 "arquivos em /:"
ls /
EOF
chmod +x /var/www/html/cgi-bin/ls.sh
# tente
/var/www/html/cgi-bin/ls.sh
Passo 1: crie um jail
Vamos colocar o jail em /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 .
# crie pontos de montagem
mkdir -p /var/www/jail/var/www/html
touch /var/www/jail/etc/resolv.conf
Coloque a seguinte configuração em /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";
# monte /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;
# descomente as linhas a seguir, se você quiser permitir acesso à rede no jail
# ip4 = inherit;
# ip6 = inherit;
# exec.prestart += "mount_nullfs /etc/resolv.conf /var/www/jail/etc/resolv.conf || true";
# descomente as linhas a seguir, se você também quiser que `ping` esteja disponível no jail
# allow.raw_sockets = 1;
persist; # mantém o jail se nenhum processo estiver em execução
}
E certifique-se de que a seguinte linha apareça em /etc/rc.conf:
jail_enable="YES"
E inicie o jail:
service jail start www-jail
# tente
jexec www-jail ls /
jexec www-jail /var/www/html/cgi-bin/ls.sh
Passo 2: permita que www execute jexec com permissão de root.
Eu uso sudo aqui. Não estou familiarizado com doas, se você preferir doas, pode tentar por conta própria. De qualquer forma, nem sudo nem doas vêm pré-instalados com o FreeBSD. Você precisa instalar manualmente um deles.
cat >/usr/local/etc/sudoers.d/www-jexec <<EOF
# permite e somente permite que `www` execute `jexec` com `www-jail`
www ALL=(root) NOPASSWD: /usr/sbin/jexec www-jail *
EOF
# tente
sudo -u www sudo jexec www-jail /var/www/html/cgi-bin/ls.sh
Agora tudo está pronto, adicione a seguinte seção ao seu nginx/angie:
location /cgi-bin {
cgi on;
cgi_interpreter /usr/local/bin/sudo /usr/sbin/jexec www-jail;
}
tente:
curl 127.0.0.1/cgi-bin/ls.sh
Eu quero criar um processo em segundo plano de longa duração
Apenas certifique-se de não herdar stdout ao criar o processo (idealmente, evite herdar stdin e stderr também). Aqui está um exemplo escrito em shell.
taskid=1234
logfile="/var/lib/my-project/$taskid"
./long-run-task.sh "$taskid" </dev/null >"$logfile" 2>&1 &
Ou, se você estiver familiarizado com operações de pipe, basta fechar stdout (também é melhor fechar stdin e stderr), a solicitação HTTP será concluída imediatamente. E você pode usar o processo como um processo em segundo plano.
exec </dev/null >somewhere 2>&1
# agora a resposta http está concluída, faça o que quiser
sleep 9999
Minha solicitação http está pendurada
Como você vê acima. No mundo CGI, o ciclo de vida da solicitação http depende do ciclo de vida do pipe (stdout).
Cada processo filho pode herdar o pipe do processo CGI. Se qualquer processo que herdou stdout permanecer ativo, a solicitação HTTP nunca será concluída.
Isso pode causar confusão, quando você deseja um fundo de longa duração ou matar o processo CGI.
Para criar um processo de longa duração, veja o tópico acima.
Para matar o processo CGI, mate todo o grupo de processos em vez do próprio processo CGI.
cgi_pid=...
# não faça isso
# kill "$cgi_pid"
# faça isso
kill -- "-$cgi_pid"
Eu quero matar meu script cgi
Veja o tópico acima.
Eu quero gerar conteúdo dinamicamente
Tradicionalmente, as pessoas usam reescrita para alcançar isso. Mas é muito mais fácil aqui. Você pode fazer isso com cgi pass. Aqui está um exemplo para renderizar markdown dinamicamente:
{
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>"
Eu não gosto de sufixos na URL
Forma 1: Remover o sufixo do script CGI
Forma 2: fazer reescrita
Forma 3: cgi pass
Como posso responder com status diferente de 200
#!/bin/sh
echo "Status: 404"
echo "Content-Type: text/plain"
echo
echo "Bem-vindo ao vazio"
Como posso responder com um redirecionamento
#!/bin/sh
echo "Status: 302"
echo "Location: https://theuselessweb.com"
echo
Como posso obter o corpo da solicitação HTTP
Você pode ler o corpo da solicitação a partir de stdin. Se você estiver usando shell, cat pode rapidamente salvar o corpo da solicitação em um arquivo.
Como posso enviar um arquivo ao cliente
Para arquivos pequenos, você pode escrever o arquivo diretamente para stdout.
Para arquivos grandes, é muito melhor enviar uma resposta 302. Porque a resposta CGI é streaming, o protocolo não pode lidar facilmente com cache, downloads em partes ou suporte a retomar.
Eu quero escrever CGI com python, ruby, perl, C, C++...
Vá em frente. O nginx-cgi não se importa com qual linguagem você usa. Basta pegar informações das variáveis de ambiente, ler o corpo da solicitação a partir de stdin e escrever a saída para stdout.
Manual
Opções
cgi <on|off> ou cgi pass <script_path> [script_args...]
Habilita ou desabilita o módulo cgi no bloco de localização fornecido.
Se você especificar on aqui, o plugin funcionará no modo tradicional. Ele analisa a URI da solicitação primeiro e, em seguida, localiza o script no diretório raiz do documento com a URI da solicitação. Após tudo, ele divide a URI da solicitação em SCRIPT_NAME e PATH_INFO. Isso é bom se você tiver um projeto CGI antigo ou se quiser seguir estritamente o rfc3875.
Eu também forneci uma sintaxe no estilo nginx aqui. Se você especificar cgi pass aqui, o plugin pulará a etapa de localizar o script CGI. Ele usará o valor que você forneceu diretamente. Você pode referenciar variáveis do nginx no segundo argumento, por exemplo: cgi pass $document_root$uri. O exemplo acima faz algo semelhante ao rfc3875, mas não é igual. Nesta forma, a URI da solicitação será atribuída a PATH_INFO diretamente. E SCRIPT_NAME ficará vazio. Esta forma é realmente boa para gerar conteúdo dinâmico. Ela contorna a reescrita de URI complexa e desnecessária.
Além disso, a segunda forma também fornece a capacidade de passar argumentos adicionais para o script, por exemplo: cgi pass my_script.sh $uri. Com isso, você pode evitar totalmente variáveis de ambiente confusas do rfc3875.
Se você especificar off aqui, o plugin será desativado.
Padrão: off
cgi_pass <script_path>
Alias de cgi pass <script_path>.
cgi_interpreter [interpreter] [args...]
Defina o interpretador e os argumentos do interpretador para o script CGI.
Quando esta opção não estiver vazia, o script CGI será executado com o interpretador fornecido. Caso contrário, o script será executado diretamente.
Esta opção pode conter variáveis do nginx, veja https://nginx.org/en/docs/varindex.html para mais detalhes.
Esta opção é extremamente útil em muitos cenários, por exemplo:
- executar scripts CGI que faltam permissão x
- fazer sudo antes de executar o script CGI
- envolver um binário geral como script CGI
- filtrar a saída do script CGI
- ...
Padrão: vazio
cgi_working_dir <dir>
Defina o diretório de trabalho do script CGI.
Se este valor for definido como vazio, os scripts CGI herdarão o diretório de trabalho do nginx.
Se este valor for definido como uma string não vazia, o script CGI será iniciado com o diretório de trabalho fornecido.
A ação de mudar o diretório de trabalho pode falhar. Por exemplo, se o diretório fornecido não existir, não houver permissão ou o nome for muito longo. Nesse caso, o script falhará ao executar.
Esta opção não muda a maneira de encontrar o interpretador ou o script (se eles forem especificados com caminho relacionado, eles sempre estarão relacionados ao diretório de trabalho do nginx).
Esta opção pode conter uma variável do nginx. Embora eu não saiba qual é a utilidade disso. Talvez você possa configurar um diretório de trabalho diferente para diferentes server_name por isso.
Padrão: vazio
cgi_body_only <on|off>
Um script CGI padrão deve produzir duas partes: cabeçalho e corpo. E uma linha vazia para separar essas duas partes.
Se você quiser simplesmente executar um programa normal como um programa CGI. Você pode ativar isso.
Uma vez que esta opção esteja habilitada, toda a saída será tratada como corpo da resposta e enviada ao cliente.
Padrão: off
cgi_path <PATH>
Mude a variável de ambiente PATH do script CGI.
Padrão: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
cgi_strict <on|off>
Habilite ou desabilite o modo estrito.
Quando o modo estrito está ativado, cabeçalhos CGI ruins causarão erro 500. Quando o modo estrito está desativado, cabeçalhos CGI ruins serão encaminhados como estão.
Padrão: on
cgi_set_var <name> <value>
Adicione e passe variáveis de ambiente extras para o script CGI. O primeiro argumento deste comando é o nome da variável de ambiente. Deve conter apenas letras, números e sublinhados, e não deve começar com número. O segundo argumento deste comando é a expressão de valor da variável. Pode conter variáveis do nginx, veja https://nginx.org/en/docs/varindex.html para mais detalhes.
Esta opção pode aparecer mais de 1 vez para definir várias variáveis. Se mais de uma opção definir a mesma variável, então a última funciona. Essas diretivas são herdadas do nível de configuração anterior se e somente se não houver diretivas cgi_set_var definidas no nível atual.
Esta opção também pode ser usada para substituir variáveis padrão do CGI. Isso pode ser útil em alguns casos, por exemplo, hackear scripts CGI antigos ou simular variáveis padrão que não são suportadas por este plugin agora (como PATH_TRANSLATED, REMOTE_IDENT). Mas não é recomendado, pode introduzir problemas confusos ao seu sistema.
cgi_stderr <off|info|warn|error|crit|alert|emerg|stderr>
cgi_stderr file <path_to_file>
Por padrão, o nginx-cgi captura a saída stderr do script CGI e a despeja no log do nginx com nível warn. Você pode mudar o comportamento aqui.
-
off: descartar completamente a saída stderr.
-
info, warn, error, crit, alert, emerg: redirecionar stderr do CGI para o log do nginx com o nível fornecido. Nota: esta opção pode ser um pouco cara, porque precisa de um pipe extra para cada processo CGI. Se você se importar com isso, deve evitá-la.
-
stderr: redirecionar stderr do CGI para o stderr do processo nginx
-
file
: redirecionar stderr do CGI para um arquivo
cgi_rdns <on|off|double> [required]
Habilite ou desabilite DNS reverso.
off: desabilitar a funcionalidade rdns.
on: Fazer DNS reverso antes de lançar o script CGI e passar o resultado do rdns para o script CGI via variável de ambiente REMOTE_HOST.
double: Após o DNS reverso, faça um DNS direto novamente para verificar o resultado do rdns. Se o resultado corresponder, passe o resultado como REMOTE_HOST.
required: Se o rdns falhar, 403, 503 ou 500 retornam ao cliente. Dependendo da razão da falha do rdns.
Se você ativar esta opção, precisará configurar um resolver no nginx também. Caso contrário, você receberá um erro de no resolver defined to resolve.
Notas do autor: não habilite esta opção, ela tornará cada solicitação mais lenta. Este recurso pode ser facilmente implementado por dig -x ou nslookup no script. A única razão pela qual implementei isso é apenas para tornar o módulo totalmente compatível com o padrão rfc3875.
cgi_timeout <t1> [t2]
Envie sinais TERM/KILL para o processo CGI se ele demorar muito.
Se tanto t1 quanto t2 forem iguais a 0. O recurso de timeout está desabilitado.
Se t1 ou t2 não forem iguais a 0. Um sinal TERM ou KILL será enviado ao processo após o timeout.
Se tanto t1 quanto t2 não forem zero. Envie TERM no timestamp t1 primeiro. E envie KILL novamente no timestamp t1+t2 (se o processo ainda estiver vivo nesse timestamp).
Se t2 não estiver presente, será tratado como 0.
Padrão: 0 0
Variáveis de Ambiente Padrão
O nginx-cgi implementou quase todas as variáveis padrão do rfc3875. Se elas não puderem cobrir todo o seu uso, você pode adicionar sua própria variável com cgi_set_var. Além disso, essas variáveis podem ser sobrescritas por cgi_set_var se você realmente quiser.
AUTH_TYPE,REMOTE_USER(padrão rfc3875)
Descontinuado desde v0.15 por razões de segurança. Veja issue #22 para detalhes e soluções alternativas.
Além disso, o cabeçalho Authorization não é visível por padrão no script CGI por razões de segurança também. Se você quiser acessar o cabeçalho de autorização no script CGI, tente cgi_set_var HTTP_AUTHORIZATION $http_authorization.
CONTENT_LENGTH,CONTENT_TYPE(padrão rfc3875)
Igual aos cabeçalhos de solicitação Content-Length e Content-Type.
GATEWAY_INTERFACE(padrão rfc3875)
Sempre será CGI/1.1 neste plugin.
PATH_INFO(padrão rfc3875)
Vamos supor que você tenha um script em /cgi-bin/hello.sh, e você acesse http://127.0.0.1/cgi-bin/hello.sh/somewhat.
Então PATH_INFO contém a string /somewhat.
Combinado com rewrite de URL ou cgi pass, esta variável pode ser usada para gerar conteúdo dinâmico.
PATH_TRANSLATED(padrão rfc3875)
Nota: esta opção não é implementada estritamente em conformidade com o rfc3875. Por favor, evite isso, se você estiver escrevendo um novo script CGI.
Isso está relacionado a PATH_INFO.
Vamos supor que você tenha um script em /cgi-bin/hello.sh, e você acesse http://127.0.0.1/cgi-bin/hello.sh/somewhat.
O padrão diz que o servidor deve tentar novamente com http://127.0.0.1/somewhat, e descobrir onde a URI deve ser mapeada.
Por razões técnicas, eu apenas construí esta variável pela raiz do documento e PATH_INFO.
O comportamento pode mudar em versões futuras.
QUERY_STRING(padrão rfc3875)
Contém a string de consulta da solicitação. Por exemplo, se você estiver acessando http://127.0.0.1/cgi-bin/hello.sh?a=1&b=2, QUERY_STRING conterá a=1&b=2.
REMOTE_ADDR, (padrão rfc3875)
Endereço IP do cliente.
REMOTE_HOST(padrão rfc3875)
Nome do host do cliente. Disponível apenas se cgi_rdns estiver ativado.
Se cgi_rdns estiver ativado, o nginx-cgi fará um DNS reverso e encontrará um domínio que corresponda a REMOTE_ADDR. Se algum for encontrado, será definido como REMOTE_HOST.
Se cgi_rdns for duplo, após o RDNS, o nginx-cgi fará um DNS direto novamente. REMOTE_HOST só será definido se o resultado do DNS direto corresponder ao endereço original.
Veja cgi_rdns para mais informações.
REMOTE_IDENT(padrão rfc3875)
O plugin nginx-cgi não suporta isso por razões de segurança.
REQUEST_METHOD(padrão rfc3875)
Método da solicitação, por exemplo: GET, POST...
SCRIPT_NAME(padrão rfc3875)
Caminho para o script atual. Normalmente, você não precisa disso. Não contém o caminho completo. Veja SCRIPT_FILENAME.
A única razão para usar isso é construir a URI após a reescrita. Você pode usar SCRIPT_NAME + PATH_INFO para obter a URI após a reescrita.
SERVER_NAME(padrão rfc3875)
Nome do servidor, normalmente é igual ao cabeçalho Host sem a parte da porta. Se o cabeçalho Host não aparecer na solicitação (HTTP/1.0) ou contiver um valor inválido, então esse valor é definido para refletir o endereço IP do servidor. Se o endereço IP for um endereço ipv6, ele será colocado entre colchetes como [::1].
SERVER_PORT(padrão rfc3875)
Porta de escuta do servidor, como 80, 443...
SERVER_PROTOCOL(padrão rfc3875)
O protocolo usado entre cliente e servidor. Como HTTP/1.0, HTTP/1.1...
SERVER_SOFTWARE(padrão rfc3875)
Contém uma string do nginx e versão, como nginx/1.27.4.
X_(padrão rfc3875)
Todos os cabeçalhos de solicitação HTTP com prefixo X- serão convertidos em variáveis X_. Por exemplo:
Se X-a: 123 aparecer no cabeçalho, X_A será definido como 123.
HTTP_(padrão rfc3875)
Todos os outros cabeçalhos de solicitação HTTP serão convertidos em variáveis HTTP_, por exemplo:
Se Accept: */* aparecer no cabeçalho, HTTP_ACCEPT será definido como */*.
DOCUMENT_ROOT(não padrão, implementado pelo apache2)
Raiz do documento do bloco de localização atual, veja a declaração root no nginx.
REMOTE_PORT(não padrão, implementado pelo apache2)
Número da porta do cliente.
REQUEST_SCHEME(não padrão, implementado pelo apache2)
http ou https.
REQUEST_URI(não padrão, implementado pelo apache2)
A URI bruta antes da reescrita. Se você quiser a URL após a reescrita, tente SCRIPT_NAME + PATH_INFO.
Nota: esta variável não é a mesma que a variável do nginx $request_uri. Você pode encontrar o documento em https://httpd.apache.org/docs/2.4/mod/mod_rewrite.html.
SCRIPT_FILENAME(não padrão, implementado pelo apache2)
O caminho completo para o script CGI.
SERVER_ADDR(não padrão, implementado pelo apache2)
Endereço IP do servidor. Se o servidor tiver vários endereços IP. O valor desta variável pode ser diferente se as solicitações vierem de diferentes interfaces.
Problemas Conhecidos
Implementação de PATH_TRANSLATED não precisa
Pelo rfc3875, PATH_TRANSLATED deve apontar para o arquivo que seria acessado como $PATH_INFO como uri. Mas isso é realmente difícil de implementar no nginx, precisa reativar o processo de localização do nginx. E essas funções são privadas, não podem ser acessadas pelo plugin. A outra maneira de implementá-lo é iniciar uma sub-solicitação, mas é muito caro, e esta variável é realmente raramente usada. Não vale a pena fazer isso. Então eu simplesmente construí esta variável pela raiz do documento e as variáveis path_info.
Implementação de RDNS não acessa /etc/hosts
A implementação do resolvedor do nginx não acessa /etc/hosts. Eu não quero implementar um resolvedor extra no plugin. Então eu apenas ignoro esse problema.
Referência
rfc3875
https://datatracker.ietf.org/doc/html/rfc3875
nginx
https://nginx.org/en/docs/dev/development_guide.html
https://hg.nginx.org/nginx-tests
Cabeçalhos hop-by-hop
https://datatracker.ietf.org/doc/html/rfc2616#section-13.5.1
Ambientes 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
Você pode encontrar dicas de configuração adicionais e documentação para este módulo no repositório GitHub do nginx-module-cgi.