# Configurar o Nginx para PHP com segurança

> Configurar o Nginx para PHP com segurança: passar ao PHP-FPM só scripts reais, libertar o front controller, bloquear dotfiles e definir limites de tamanho.

Fonte: https://phpsos.de/pt/blog/nginx-fuer-php-absichern/  
Atualizado em: 25/10/2026  
Prestador: PHP SOS, Assistência de emergência PHP e segurança de servidores. Ajuda imediata por WhatsApp: https://wa.me/491736494914?text=Ol%C3%A1%2C%20PHP%20SOS%2C%20precisamos%20de%20ajuda%20com%20o%20nosso%20servidor%20PHP.%20Empresa%3A%20%E2%80%A6%20Site%3A%20%E2%80%A6

**Em resumo:** Para configurar o Nginx para PHP com segurança, passe ao PHP-FPM apenas os scripts que realmente existem e, nas aplicações com front controller, apenas o `index.php`. A isto juntam-se dotfiles bloqueados como `.git` e `.env`, um servidor predefinido para nomes de anfitrião desconhecidos, limites de tamanho adequados e `security.limit_extensions = .php` no pool. Isto não protege contra vulnerabilidades do próprio PHP, mas limita o que pode ser executado após um erro.

## As linhas mais perigosas estão na location PHP

Desde o PHP2Shell, muitas equipas verificam as suas versões e pools PHP-FPM, como descreve a página [Proteger o Nginx com PHP-FPM](https://phpsos.de/pt/server/nginx-php-fpm/), e reiniciam, após a atualização, [todos os workers](https://phpsos.de/pt/php2shell/php-fpm-neustart/). Uma segunda olhada vai para a própria configuração do Nginx. É aí que se decide que ficheiros são sequer executados como PHP.

Em muitas configurações há um bloco que passa ao PHP-FPM todo o pedido a `.php`, esteja o ficheiro onde estiver. Se um ficheiro PHP introduzido for parar a uma pasta de uploads, o servidor executa-o. De uma falha com ficheiros, surge assim uma porta dos fundos.

Este artigo concentra-se no lado do Nginx: que diretivas contam, como atua a ordem dos blocos location e como testar o resultado.

## Como o Nginx decide que bloco atua

Quem quiser configurar o Nginx para PHP com segurança tem de conhecer a escolha dos blocos location. Segundo a documentação do Nginx, decorre assim:

1. Uma correspondência exata com `location =` termina a pesquisa de imediato.
2. Entre as locations de prefixo, é retida a mais longa que corresponda. Se tiver `^~`, deixam de ser verificadas expressões regulares.
3. Caso contrário, as expressões regulares (`~`, `~*`) são verificadas pela ordem do ficheiro de configuração; ganha a primeira correspondência.
4. Se nenhuma expressão regular corresponder, aplica-se a location de prefixo retida.

Daqui decorrem duas regras práticas. Um bloqueio do PHP em pastas de uploads tem de ser criado como prefixo `^~` ou como expressão regular colocada antes do bloco PHP geral. E uma location de prefixo normal como `location /uploads/` não protege, porque a expressão regular para `.php` a sobrepõe.

## Uma configuração de base segura

O exemplo seguinte mostra um bloco server para uma aplicação com front controller, como é habitual no Laravel, Symfony, Shopware 6 ou em muitos desenvolvimentos próprios. Adapte caminhos, socket e certificados.

```nginx
server {
    listen 443 ssl;
    server_name www.example.de;
    root /var/www/seite1/public;
    index index.php;

    ssl_certificate     /etc/ssl/seite1/fullchain.pem;
    ssl_certificate_key /etc/ssl/seite1/privkey.pem;

    server_tokens off;
    client_max_body_size 32m;

    # Permitir Let's Encrypt e outros caminhos conhecidos
    location ^~ /.well-known/ {
        try_files $uri =404;
    }

    # Bloquear ficheiros e pastas ocultos (.git, .env, .htaccess)
    location ~ /\. {
        deny all;
    }

    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }

    # Só o front controller é passado ao PHP-FPM
    location = /index.php {
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        fastcgi_param DOCUMENT_ROOT $realpath_root;
        fastcgi_hide_header X-Powered-By;
        fastcgi_pass unix:/run/php/seite1.sock;
    }

    # Nenhum outro ficheiro PHP é executado
    location ~ \.php$ {
        return 404;
    }
}
```

O `$realpath_root` resolve as ligações simbólicas. Isso é importante em implementações com uma ligação simbólica variável para a versão atual, para que o PHP-FPM e a OPcache vejam o caminho certo. Tenha também em conta: segundo a documentação do Nginx, as diretivas `fastcgi_param` só são herdadas de níveis superiores se não houver outras no nível atual. Por isso, o `include fastcgi_params;` pertence ao mesmo bloco.

Os CMS clássicos como WordPress, TYPO3 ou Contao têm vários pontos de entrada. Aí, substitui-se o bloco do front controller por uma location PHP geral que só passa ficheiros existentes (`try_files $uri =404;`) e bloqueia-se a execução em todas as pastas com permissão de escrita. Como se consegue isso está em [Proibir a execução de PHP em pastas de uploads](https://phpsos.de/pt/blog/php-in-uploads-verbieten/).

## A segunda proteção no PHP-FPM

O Nginx decide o que é passado, o PHP-FPM decide o que executa. Segundo o manual do PHP, o PHP-FPM executa por defeito ficheiros com `.php` e `.phar` e recomenda ele próprio restringir a `.php`. Isso apanha erros de configuração no servidor web.

```ini
; no pool, p. ex. /etc/php/8.3/fpm/pool.d/seite1.conf
security.limit_extensions = .php
listen = /run/php/seite1.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
```

O socket só deve ser acessível ao Nginx. As portas FPM na rede, por exemplo `9000`, não devem ser abertas para o exterior. Como o servidor, no seu conjunto, mostra apenas as portas necessárias é descrito em [Firewall para servidores web: abrir só as portas necessárias](https://phpsos.de/pt/blog/firewall-fuer-webserver/).

## Nomes de anfitrião desconhecidos e outros parâmetros

Sem um servidor predefinido próprio, o Nginx responde a pedidos para nomes de anfitrião desconhecidos com o primeiro bloco server que corresponda. As análises automatizadas que apenas se dirigem ao endereço IP vão então parar diretamente à sua aplicação. Um servidor predefinido próprio termina esses pedidos sem resposta.

```nginx
server {
    listen 80 default_server;
    listen 443 ssl default_server;
    server_name _;
    ssl_reject_handshake on;
    return 444;
}
```

Outros pontos que se têm revelado eficazes:

| Parâmetro | Recomendação | Finalidade |
|---|---|---|
| `server_tokens` | `off` | nenhum número de versão em cabeçalhos e páginas de erro |
| `client_max_body_size` | adequado ao `post_max_size` | rejeitar cedo pedidos grandes |
| `autoindex` | desligado (por defeito) | nenhuma listagem de diretórios |
| `fastcgi_hide_header` | `X-Powered-By` | nenhuma versão do PHP para o exterior |
| Páginas de estado | `pm.status_path` apenas interno | nenhum dado de operação público |
| Ficheiros de cópia de segurança | bloquear ou remover `.sql`, `.zip`, `.bak` na raiz web | sem transferência de bases de dados |

Mais sobre indicações de versão está no artigo [expose_php e cabeçalhos Server](https://phpsos.de/pt/blog/expose-php-versionsangaben/).

Outro parâmetro diz respeito aos métodos HTTP permitidos. A maioria dos sites precisa apenas de GET, HEAD e POST. Com `limit_except`, podem rejeitar-se outros métodos numa location; segundo a documentação do Nginx, permitir GET permite automaticamente também HEAD. Verifique antes se as interfaces da sua aplicação usam, por exemplo, PUT ou DELETE, pois as APIs REST fazem-no com frequência.

## Testar antes de recarregar

Verifique cada alteração primeiro com `nginx -t` e só depois recarregue o Nginx. Em seguida, teste o comportamento a partir de fora com pedidos normais ao seu próprio domínio:

```bash
sudo nginx -t && sudo systemctl reload nginx
# Esperado: 403 ou 404
curl -s -o /dev/null -w "%{http_code}\n" https://www.example.de/.git/HEAD
curl -s -o /dev/null -w "%{http_code}\n" https://www.example.de/.env
# Esperado: 404, porque só o front controller é executado
curl -s -o /dev/null -w "%{http_code}\n" https://www.example.de/info.php
# Que blocos passam ao PHP-FPM?
sudo nginx -T 2>/dev/null | grep -nE "location|fastcgi_pass"
```

Antes de qualquer alteração maior, guarde com data a saída completa de `nginx -T`. Contém toda a configuração efetiva, incluindo todos os ficheiros incluídos. Se algo correr mal após uma alteração, a comparação mostra de imediato o que mudou. Na próxima vulnerabilidade crítica, tem assim também uma base fiável para o levantamento, sem ter de reunir ficheiros primeiro.

> **Dica:**
> Altere a configuração primeiro num ambiente de teste ou numa cópia do bloco server. Um ponto de entrada esquecido, por exemplo um callback de pagamento, só se nota, caso contrário, quando as encomendas deixam de chegar.

## Como ajuda concretamente a PHP SOS?

- **Ler a configuração:** analisamos toda a configuração do Nginx com `nginx -T` e associamos cada passagem ao PHP ao seu site e ao seu pool.
- **Definir os pontos de entrada:** em conjunto com os seus programadores, determinamos que scripts têm de ser executados e bloqueamos o resto.
- **Aplicar e testar:** adaptamos blocos server e pools, verificamos com `nginx -t` e testamos formulários, meios de pagamento e uploads.
- **Proteger de forma duradoura:** a configuração passa a fazer parte do nosso [reforço de segurança de servidores](https://phpsos.de/pt/leistungen/server-haertung/) e da documentação do seu servidor.


## Perguntas frequentes

**O Nginx tem de ser reiniciado após uma atualização do PHP?**  
Para o patch do PHP, não, porque o Nginx não contém PHP. Têm de ser reiniciados todos os serviços PHP-FPM. Se alterar também a configuração do Nginx, verifique-a antes com nginx -t e recarregue depois o Nginx.

**Por que passar apenas o index.php ao PHP?**  
Muitas aplicações modernas têm um único ponto de entrada, o front controller. Se apenas este ficheiro for passado ao PHP-FPM, um ficheiro PHP introduzido noutro local não pode ser executado através do navegador. Em sistemas com muitos pontos de entrada, este padrão não é possível.

**O que traz o security.limit_extensions no PHP-FPM?**  
A definição determina que extensões de ficheiro o PHP-FPM executa como script. Segundo o manual do PHP, o valor por defeito é .php .phar; recomenda-se restringir a .php. Isto apanha erros na configuração do servidor web, mas não a substitui.

**As regras do Nginx protegem contra o PHP2Shell?**  
Não. O PHP2Shell está no interpretador PHP e só se fecha com a atualização para uma versão corrigida e o reinício de todos os workers. Uma configuração segura do Nginx reduz a superfície de ataque e limita os danos após uma intrusão.

## Fontes

- [Nginx: ngx_http_core_module](https://nginx.org/en/docs/http/ngx_http_core_module.html)
- [Nginx: ngx_http_fastcgi_module](https://nginx.org/en/docs/http/ngx_http_fastcgi_module.html)
- [Manual do PHP: configuração do FPM](https://www.php.net/manual/en/install.fpm.configuration.php)
- [OWASP Cheat Sheets](https://cheatsheetseries.owasp.org/)
