mod_php ou PHP-FPM: Risco, Desempenho e Migração

O PHP apontou o mod_php como o pior cenário no PHP2Shell. Veja o que muda na arquitetura e como migrar para FPM sem parar o site.

por Cleverson Gouvêa

Diagrama comparando mod_php ou PHP-FPM no Apache após o PHP2Shell

Escolher entre mod_php ou PHP-FPM deixou de ser uma decisão de desempenho e virou uma decisão de risco. No aviso de 21 de outubro de 2026 sobre o PHP2Shell, a própria equipe de segurança do PHP escreveu que o risco é maior no mod_php, porque o ataque demonstrado dispara antes de qualquer linha do código da aplicação. Neste comparativo eu mostro a diferença de arquitetura, segurança e desempenho, e como migrar sem tirar o site do ar.

TL;DR

  • O PHP2Shell (CVE-2026-109618 e CVE-2026-109619) é execução remota de código sem autenticação, com CVSS 4.0 de 9,2. A correção saiu em 21/10/2026 nas versões 8.5.12, 8.4.27, 8.3.36 e 8.2.35.
  • Todos os modos de rodar PHP para web estão afetados: PHP-FPM, Apache com mod_php, php-cgi, FrankenPHP e LiteSpeed. Mas o PHP classifica o mod_php como o cenário de maior risco.
  • Migrar para PHP-FPM não substitui o patch. A ordem certa é atualizar o PHP primeiro e migrar depois, com calma.
  • O próprio manual do PHP já diz para não usar mod_php em instalações novas: ele prende o Apache no MPM prefork, que limita a concorrência.
  • A migração em Apache leva poucos comandos, mas tem armadilhas reais: php_value no .htaccess para de funcionar e o pool do FPM precisa ser dimensionado.

O que muda na escolha mod_php ou PHP-FPM depois do PHP2Shell

Até a semana passada, a conversa sobre mod_php ou PHP-FPM era sobre memória, concorrência e comodidade. O mod_php era o caminho "funciona de primeira" do Apache, e muito servidor antigo ficou nele por inércia.

O PHP2Shell mudou o peso dessa escolha. Os fatos, confirmados nas fontes oficiais:

  • Duas falhas, ambas sem autenticação. A CVE-2026-109618 é uma corrupção de memória no tratamento de out-of-memory (falta de memória): o PHP é interrompido com dados internos da requisição montados pela metade, e a limpeza do fim da requisição trata esses dados como válidos. A CVE-2026-109619 é estado global obsoleto (use-after-free): um dado interno sobrevive à memória que ele apontava, e a requisição seguinte no mesmo processo usa esse lixo.
  • Gravidade. As duas têm CVSS 4.0 de 9,2, segundo a equipe de segurança do PHP. O FAQ da Tenable registra que identificadores com nota 10,0 circularam antes e estavam errados.
  • Linha do tempo. A Amazon viu uma tentativa de exploração no seu honeypot em 17/10, quatro dias antes da divulgação, segundo a Tenable. Os detalhes vazaram em 20/10, antes da data coordenada, e o PHP antecipou a correção para 21/10 às 14h UTC, segundo a Huntress.
  • Exposição. A Unit 42, da Palo Alto Networks, contou pelo Cortex Xpanse mais de 22,6 milhões de instâncias expostas potencialmente vulneráveis.

E a frase que muda a conta de mod_php ou PHP-FPM para quem decide infraestrutura vem do aviso oficial do PHP: o risco é considerado maior para o mod_php, "com um exploit demonstrado em que uma requisição não autenticada pode disparar o ataque antes de qualquer código da aplicação rodar".

Traduzindo para quem paga a conta: no mod_php, não importa se o seu WordPress, Moodle ou Laravel está atualizado e bem escrito. O ataque acontece antes de a aplicação ter chance de fazer qualquer coisa.

Arquitetura: como cada modelo roda o PHP

Para entender por que o risco muda entre mod_php ou PHP-FPM na prática, vale olhar onde o PHP vive em cada modelo.

mod_php: o PHP dentro do Apache

No mod_php (o módulo apache2handler), o interpretador PHP é carregado dentro de cada processo do Apache. Cada processo filho do servidor web é, ao mesmo tempo, servidor HTTP e interpretador PHP.

Isso tem duas consequências diretas:

  1. O Apache fica preso ao MPM prefork. O manual do PHP diz que, sem PHP compilado com thread safety (ZTS), o mod_php exige o prefork, "o que limita significativamente a concorrência". A maioria dos pacotes de distribuição não vem com ZTS.
  2. Todo processo carrega o PHP, mesmo para servir uma imagem. Um pedido de logo.png ocupa um processo inteiro com o interpretador carregado.

PHP-FPM: o PHP como serviço separado

No PHP-FPM (FastCGI Process Manager), o PHP roda num serviço próprio, com pools de processos. O servidor web (Apache com mod_proxy_fcgi ou Nginx) só repassa as requisições .php para o pool, por socket Unix ou TCP.

Cada pool tem seu usuário, seu limite de processos e suas configurações. A documentação de configuração do FPM traz as diretivas que fazem a diferença na prática: user/group, pm.max_children, pm.max_requests, request_terminate_timeout e php_admin_value, esta última com valores que o script não consegue sobrescrever com ini_set().

E quem usa Nginx?

Nginx não tem módulo de PHP embutido. Se o seu site roda em Nginx, você já está em PHP-FPM (ou em outro processo FastCGI) e a pergunta mod_php ou PHP-FPM não se aplica. Isso não te tira do PHP2Shell: o FPM também está na lista de afetados.

Segurança: por que o mod_php é o pior cenário

O ponto central na comparação mod_php ou PHP-FPM não é que o FPM seja imune. Não é. O ponto é que o mod_php junta três fatores ruins no mesmo processo.

O ataque roda antes da aplicação

O relato técnico da Datadog Security Labs detalha o que o PHP confirmou. No caminho de upload da CVE-2026-109619, houve execução de comandos tanto em mod_php quanto em PHP-FPM, mas no FPM o ataque também exige que a aplicação faça uma operação adequada depois que a inicialização terminou. No mod_php, não há essa condição.

Para a CVE-2026-109618, a Huntress registra que o PHP validou RCE completo via HTTP contra mod_php com os limites padrão de entrada e memória e configurações prefork normais. O laboratório da Datadog também usou Apache prefork com mod_php.

Um usuário para todos os sites

No mod_php, todo site do servidor roda como o usuário do Apache (www-data no Debian/Ubuntu, apache no Red Hat). Se um atacante executa comando por um site, ele tem a permissão do Apache, que normalmente lê os arquivos de todos os sites daquele servidor, incluindo wp-config.php e config.php com senha de banco.

No PHP-FPM, o padrão saudável é um pool por site, cada um com seu usuário Linux. A invasão de um site fica contida nas permissões daquele usuário. É o mesmo princípio de menor privilégio que eu defendo no checklist de hardening de servidor Linux.

O que o PHP-FPM não resolve

Aqui mora a armadilha comercial: tem gente vendendo "migre para FPM e fique seguro". Não é verdade.

  • O FPM continua vulnerável sem o patch. O aviso oficial lista o PHP-FPM entre os afetados.
  • A Datadog explica que um pool maior reduz a chance de sucesso por tentativa, mas não elimina a falha, e que atacantes tentam ocupar todos os processos menos um para cair sempre no mesmo.
  • O exploit bem-sucedido não derruba necessariamente o processo. O ataque pode gerar só dois a quatro erros de memória e depois ficar em silêncio.

A ordem é sempre: patch primeiro, arquitetura depois.

Desempenho e consumo de memória

Saindo do incidente, a escolha entre mod_php ou PHP-FPM também pesa no bolso, porque define quanto servidor você precisa.

Prefork contra event

Com mod_php, o Apache roda em prefork: um processo por conexão, cada um com o PHP carregado. Conexões lentas, keep-alive e arquivos estáticos ocupam processos pesados.

Com PHP-FPM, o Apache pode usar o MPM event, que é o padrão desde o Apache 2.4, como lembra o manual do PHP. O event atende muitas conexões com poucas threads leves, e só o que é PHP vai para o pool. O manual chega a chamar o MPM com threads de "recomendado para melhor desempenho sob carga".

Onde o FPM ganha na operação

  • Reiniciar o PHP sem reiniciar o Apache. Aplicar patch, mudar php.ini ou matar um processo travado afeta só o PHP. Isso conta muito numa semana como esta, em que o PHP pede para reiniciar todos os workers depois do patch.
  • Limites por site. Um site com plugin problemático não consome todos os processos do servidor, porque o pool dele tem teto próprio em pm.max_children.
  • Diagnóstico. request_slowlog_timeout grava o backtrace de requisições lentas, e pm.status_path mostra em tempo real quantos processos estão ocupados.
  • Várias versões de PHP lado a lado. Um pool em 8.3 e outro em 8.4 no mesmo servidor, coisa que o mod_php não faz.

Onde o mod_php ainda "ganha"

Sendo justo: na balança mod_php ou PHP-FPM o mod_php tem menos peças. Não há socket, não há segundo serviço para monitorar e o .htaccess com php_value funciona direto. Em servidor de laboratório com um único site e tráfego mínimo, a diferença de desempenho é pequena. Só que, depois do PHP2Shell, simplicidade não compensa ficar no cenário de maior risco.

Tabela comparativa: mod_php ou PHP-FPM

O resumo da comparação mod_php ou PHP-FPM nos critérios que pesam na operação de um servidor de produção:

Critério mod_php (Apache) PHP-FPM
Onde o PHP roda Dentro de cada processo do Apache Serviço separado, com pools
MPM do Apache Prefork (sem ZTS) Event (padrão do Apache 2.4)
Risco no PHP2Shell, segundo o PHP O maior: exploit antes do código da aplicação Afetado; no caminho de upload da 109619, depende de operação da aplicação
Usuário de execução Um só (usuário do Apache) para todos os sites Um por pool, isolando sites
Reiniciar o PHP Reinicia o Apache inteiro Reinicia só o FPM (ou um pool)
Várias versões de PHP Não Sim, um pool por versão
Limite de processos por site Não pm.max_children por pool
Configuração por diretório php_value no .htaccess .user.ini ou php_admin_value no pool
Recomendação do manual do PHP Não usar em instalações novas Recomendado para implantações modernas
Suporte em Nginx Não existe Padrão

Como descobrir o que o seu servidor usa hoje

Antes de decidir entre mod_php ou PHP-FPM no seu caso, confirme o modo atual. Três jeitos, do mais rápido ao mais completo:

  1. Pelo Apache. Rode apachectl -M | grep -i php. Se aparecer php_module (ou php7_module, php8_module), o mod_php está carregado.
  2. Pelo MPM. Rode apachectl -V | grep -i mpm. prefork é forte indício de mod_php; event indica que o PHP está fora do Apache.
  3. Por um phpinfo() temporário. O campo Server API mostra Apache 2.0 Handler (mod_php) ou FPM/FastCGI. Apague o arquivo logo em seguida: phpinfo() exposto entrega versão e caminhos para quem está varrendo a internet.

Aproveite para anotar a versão exata do PHP. Se ela estiver abaixo de 8.5.12, 8.4.27, 8.3.36 ou 8.2.35 (ou do pacote corrigido da sua distribuição), o problema urgente é esse, não a arquitetura.

Como migrar de mod_php para PHP-FPM sem derrubar o site

Se a resposta para mod_php ou PHP-FPM no seu servidor é migrar, o roteiro abaixo vale para Debian e Ubuntu com Apache 2.4, que é o cenário mais comum que encontramos. Troque 8.3 pela sua versão.

Passo 0: patch antes de tudo

Atualize o PHP para a versão corrigida da sua distribuição e reinicie o Apache. Isso já fecha a janela do PHP2Shell no mod_php. A migração vem depois, em janela planejada. Se você ainda não fez isso, este é o único passo que importa hoje. A dúvida mod_php ou PHP-FPM pode esperar alguns dias; o patch não. No post sobre como proteger o servidor web contra ataques eu explico as camadas de WAF e rate limit que ajudam enquanto isso, sem substituir a correção.

Passo 1: instalar o FPM e criar o pool

Instale o php8.3-fpm com as mesmas extensões que o mod_php usa (compare php -m antes e depois). Crie um pool por site em /etc/php/8.3/fpm/pool.d/, com usuário próprio, socket próprio e limites:

  • user e group do site, não www-data
  • listen = /run/php/site1.sock
  • pm = dynamic e pm.max_children calculado pela memória (próximo passo)
  • pm.max_requests = 500, para reciclar processos periodicamente
  • request_terminate_timeout coerente com o max_execution_time
  • php_admin_value[session.upload_progress.enabled] = 0, se a aplicação não usa barra de progresso de upload

Esse último item vem do aviso oficial: ele bloqueia os caminhos de sessão confirmados da CVE-2026-109619, mas não outras variantes. O PHP pede para aplicar em php.ini, no pool do FPM ou na configuração do servidor, e para não confiar em ini_set() nem em .user.ini.

Passo 2: dimensionar o pool

A conta básica é pm.max_children = memória disponível para o PHP ÷ memória média por processo. Meça o consumo real com ps durante o horário de pico, não use o memory_limit como estimativa. Pool pequeno demais gera fila e erro 503; grande demais leva o servidor a usar swap.

Se o servidor roda Moodle, a conta muda bastante entre horário normal e semana de prova. Os números de referência estão no guia de requisitos de servidor para Moodle 5.x.

Passo 3: trocar o Apache de modo

No Debian/Ubuntu, a sequência típica é:

  1. a2enmod proxy_fcgi setenvif
  2. a2enconf php8.3-fpm (ou um SetHandler "proxy:unix:/run/php/site1.sock|fcgi://localhost" no vhost, para pool por site)
  3. a2dismod php8.3
  4. a2dismod mpm_prefork e a2enmod mpm_event
  5. apachectl configtest e, se estiver tudo certo, systemctl restart apache2

A troca derruba as conexões por poucos segundos. Faça em horário de baixo tráfego e tenha o caminho de volta anotado: os mesmos comandos, invertidos.

Passo 4: as armadilhas que quebram o site

  • php_value e php_flag no .htaccess. Essas diretivas só existem no mod_php. No FPM, o Apache devolve erro 500. Mova os valores para o pool (php_admin_value) ou para .user.ini.
  • Permissões de arquivo. Com o usuário novo do pool, pastas de upload e cache que pertenciam a www-data deixam de ser graváveis. Ajuste o dono antes da troca.
  • Variáveis de ambiente e autenticação HTTP. Algumas aplicações leem cabeçalhos de autorização de um jeito que muda no FastCGI. Teste login e integrações de API.
  • Timeouts. O ProxyTimeout do Apache precisa ser maior que o tempo das tarefas longas, como relatórios e importações.

Passo 5: validar e monitorar

Confirme no phpinfo() temporário que o Server API virou FPM, rode os fluxos críticos (login, checkout, upload, cron) e acompanhe o slowlog e a página de status do pool nas primeiras 48 horas. Só considere a troca de mod_php ou PHP-FPM concluída depois desse período sem alerta.

Quando não migrar agora

Na decisão mod_php ou PHP-FPM a resposta de longo prazo é o FPM, mas há momentos em que fazer isso agora é erro.

  • Quando o PHP ainda não foi atualizado. Migrar um PHP vulnerável para FPM troca o cenário de maior risco por um cenário ainda vulnerável. Patch primeiro.
  • Quando o servidor roda PHP 7.3 ou mais antigo. Para as versões 5.4 a 7.3 não há correção do projeto, e para 7.4 a 8.1 existem só backports mínimos de código-fonte, segundo a Tenable. Aqui o projeto é atualizar o PHP e a aplicação. A CISA recomenda tirar do ar sistemas PHP que não podem ser atualizados ou que rodam 8.1 ou anterior.
  • Quando o servidor é gerenciado por painel. cPanel, Plesk e HestiaCP têm o próprio jeito de trocar o modo PHP por domínio. Mexer à mão no Apache pode ser desfeito na próxima atualização do painel. Use a opção do painel.
  • No meio de um período crítico. Semana de matrícula, campanha de vendas ou prova no AVA não é hora de trocar arquitetura. Atualize o PHP, aplique as mitigações oficiais e agende a migração.

E um ponto sobre as mitigações: memory_limit=-1, session.upload_progress.enabled=0 e, no PHP 8.5, fatal_error_backtraces=0 reduzem caminhos de ataque específicos. O PHP diz textualmente que elas não deixam a instalação segura e que atualizar é a única escolha segura. Em 23/10 saiu ainda um terceiro alerta, a CVE-2026-115560, ligado ao upload progress de sessão. O vetor é improvável: exige que a aplicação troque o session.serialize_handler em tempo de execução. A correção vem na próxima versão regular, e a recomendação é manter session.upload_progress.enabled=0 até lá.

Como a Agathas Web resolve isso

Eu administro servidores Linux com PHP desde 2008: Moodle de instituições de ensino, WordPress, Laravel e sistemas que conversam com a API oficial do WhatsApp. A pergunta mod_php ou PHP-FPM, para mim, tem resposta padrão há anos: FPM, um pool por aplicação, cada um com seu usuário. O PHP2Shell só deixou claro por que isso importa.

Na hospedagem gerenciada da Agathas Web, o que está incluso para um cenário como este:

  • Atualização do runtime PHP em janela combinada, com teste em staging antes, como parte da rotina de patches de sistema operacional, PHP e banco.
  • Arquitetura revisada: diagnóstico do modo atual (mod_php, FPM, painel), plano de migração para PHP-FPM com pools isolados, dimensionamento de pm.max_children com base no consumo real e plano de volta.
  • Camadas de proteção já previstas no serviço: WAF da Cloudflare, fail2ban e hardening do sistema operacional, para reduzir exposição enquanto um patch é aplicado.
  • Monitoramento 24/7 com alertas no WhatsApp da equipe técnica, para enxergar sinais como rajadas de erro de memória e processos do PHP abrindo shell.
  • Resposta a incidentes com plano documentado, e backups verificados com restauração testada.

Como funciona: você nos dá acesso ao servidor (ou começamos por uma migração para infraestrutura nova), fazemos o inventário de versões e modos de PHP, apresentamos o plano com janela e rollback, e executamos com a sua aprovação por escrito. A migração do fornecedor atual entra no setup. Para contratar, fale com a equipe pela página de hospedagem gerenciada e conte quantos sites e quais aplicações rodam no servidor.

Conclusão: mod_php ou PHP-FPM, a resposta ficou simples

Para servidor que atende internet, a resposta para mod_php ou PHP-FPM é PHP-FPM, com um pool isolado por site. O manual do PHP já desaconselhava o mod_php em instalações novas por desempenho e operação, e o PHP2Shell acrescentou o argumento de segurança: é o cenário que a própria equipe do PHP aponta como o de maior risco.

Só não inverta a ordem. Primeiro, PHP atualizado para 8.5.12, 8.4.27, 8.3.36, 8.2.35 ou o pacote corrigido da distribuição, com todos os workers reiniciados. Depois, a migração planejada, com teste e caminho de volta. E lembre que o PHP 8.2 chega ao fim de vida em 31/12/2026: se o seu servidor está nele, vale casar a migração para FPM com a atualização de versão.

Se você não tem um sysadmin para fazer isso agora, a hospedagem gerenciada da Agathas Web assume o patch, a migração e o monitoramento.

Fontes: aviso de segurança e arquivo de notícias do PHP, manual do PHP sobre Apache, configuração do PHP-FPM, Tenable, Unit 42, Datadog Security Labs, Huntress, watchTowr e Help Net Security.

Perguntas frequentes

O PHP-FPM é imune ao PHP2Shell?

Não. O aviso oficial do PHP lista o PHP-FPM entre as instalações afetadas, ao lado de Apache com mod_php, php-cgi, FrankenPHP e LiteSpeed. A diferença é de grau: o PHP considera o risco maior no mod_php, onde o exploit demonstrado dispara antes de qualquer código da aplicação. No FPM, segundo a análise da Datadog, o caminho de upload da CVE-2026-109619 também exige que a aplicação faça uma operação específica depois da inicialização. Por isso a proteção real é atualizar para 8.5.12, 8.4.27, 8.3.36 ou 8.2.35 (ou o pacote corrigido da distribuição) e reiniciar todos os workers. A migração para FPM vem depois, como melhoria de arquitetura.

Como saber se meu servidor usa mod_php ou PHP-FPM?

No Apache, rode apachectl -M e procure por php_module, php7_module ou php8_module: se aparecer, o mod_php está carregado. O comando apachectl -V mostra o MPM; prefork costuma indicar mod_php, event indica PHP fora do Apache. Outra forma é criar um phpinfo() temporário e ver o campo Server API: Apache 2.0 Handler é mod_php, FPM/FastCGI é PHP-FPM. Apague o arquivo logo depois, porque ele expõe versão e caminhos do servidor. Se o site roda em Nginx, ele já usa PHP-FPM ou outro processo FastCGI.

Migrar para PHP-FPM derruba o site?

A troca em si causa uma queda de poucos segundos, no reinício do Apache. O que derruba site de verdade são as armadilhas: diretivas php_value e php_flag no .htaccess, que só existem no mod_php e passam a gerar erro 500; permissões de pastas de upload e cache que deixam de ser graváveis com o novo usuário do pool; e timeouts menores que tarefas longas. Com um inventário dessas configurações, teste em staging, janela de baixo tráfego e os comandos de volta anotados, a migração costuma ser tranquila. Em servidores com cPanel, Plesk ou HestiaCP, use a opção do próprio painel.

As mitigações de configuração bastam se eu não puder atualizar o PHP?

Não. O PHP afirma que não há mitigação completa e que atualizar é a única escolha segura. memory_limit=-1 remove a falha de limite de memória controlável, mas uma falha de alocação ainda pode alcançar o caminho vulnerável. session.upload_progress.enabled=0 bloqueia os caminhos de sessão confirmados, não outras variantes, e fatal_error_backtraces=0 só vale para o PHP 8.5. Essas medidas compram tempo. Para versões 5.4 a 7.3 não há correção, e a CISA recomenda tirar do ar sistemas PHP que não podem ser atualizados ou que rodam 8.1 ou anterior.