PHP-FPM (FastCGI Process Manager): Guia Completo de Configuração e Otimização
PHP-FPM (PHP FastCGI Process Manager) é um gestor de processos PHP alternativo de alto desempenho que implementa o protocolo FastCGI para desacoplar a execução do PHP do processo do servidor web. Em vez de criar um novo interpretador PHP para cada pedido HTTP recebido — como o CGI tradicional faz — o PHP-FPM mantém um conjunto persistente de processos worker que aceitam, executam e devolvem respostas PHP com uma sobrecarga dramaticamente menor.
Para qualquer servidor web de produção que execute WordPress, Laravel, Symfony ou aplicações PHP personalizadas, o PHP-FPM é o handler padrão da indústria. Permite um controlo detalhado sobre o ciclo de vida dos processos, limites de memória, filas de pedidos e isolamento por aplicação — capacidades que simplesmente não estão disponíveis com mod_php ou CGI simples.
Como o PHP-FPM Difere do CGI e do mod_php
Para compreender a importância do PHP-FPM, é útil ver exatamente o que substitui e por que essas alternativas ficam aquém em escala.
| Funcionalidade | CGI | mod_php | PHP-FPM |
|---|
| — | — | — | — |
|---|
| Modelo de processo | Novo processo por pedido | Incorporado no Apache | Pool de workers persistente |
|---|
| Eficiência de memória | Muito fraca | Moderada | Excelente |
|---|
| Acoplamento ao servidor web | Forte | Forte (apenas Apache) | Desacoplado (qualquer servidor) |
|---|
| Isolamento por site | Nenhum | Nenhum | Total (pools separados) |
|---|
| Recarga sem interrupções | Não | Não | Sim |
|---|
| Slow log / profiling | Não | Não | Sim |
|---|
| Escalonamento dinâmico de processos | Não | Não | Sim |
|---|
| Suporte a Unix socket | Não | Não | Sim |
|---|
| Compatível com NGINX | Não | Não | Sim |
|---|
CGI cria um novo processo do SO para cada pedido. Com tráfego moderado, isto gera milhares de ciclos fork/exec/exit por minuto, saturando a CPU e a memória. mod_php incorpora o interpretador PHP diretamente em cada worker do Apache, o que significa que cada processo Apache — mesmo aquele que serve uma imagem estática — carrega o runtime completo do PHP em memória. PHP-FPM resolve ambos os problemas: os workers são persistentes e completamente separados do servidor web, pelo que o NGINX ou o Apache tratam os ficheiros estáticos nativamente enquanto o PHP-FPM trata apenas da execução do PHP.
Arquitetura do PHP-FPM: Fluxo de Pedidos em Detalhe
Compreender o caminho interno de um pedido é essencial para ajuste e depuração.
- Um browser envia um pedido HTTP para um recurso
.php. - O servidor web (NGINX ou Apache) recebe o pedido e compara-o com um bloco de localização ou diretiva
FilesMatch. - O servidor web encaminha o pedido para o PHP-FPM via protocolo FastCGI — seja através de um Unix domain socket (
/run/php/php8.2-fpm.sock) ou de um TCP socket (127.0.0.1:9000). - O processo master do PHP-FPM encaminha o pedido para um worker disponível do pool configurado.
- O worker executa o script PHP, escreve em
stdoute devolve a resposta ao servidor web. - O servidor web entrega o HTML renderizado ao cliente.
- O processo worker não termina — regressa ao pool inativo, pronto para o próximo pedido.
Os Unix sockets são preferidos ao TCP para comunicação local porque contornam completamente a pilha TCP/IP, reduzindo a latência em 10–20% nos benchmarks e eliminando a sobrecarga do binding de portas e do encaminhamento de loopback.
Modos de Gestão de Processos
O PHP-FPM suporta três modos pm (gestor de processos), e escolher o errado é um dos erros de configuração mais comuns.
pm = static
Um número fixo de workers está sempre em execução, independentemente do tráfego. Use este modo em servidores dedicados onde pretende memória pré-alocada e previsível e pode suportar a sobrecarga de inatividade.
pm = static
pm.max_children = 20pm = dynamic
O PHP-FPM inicia um número base de workers e escala para cima ou para baixo dentro de limites definidos. Este é o modo mais utilizado e o padrão correto para a maioria dos ambientes de VPS Hosting.
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
pm.max_requests = 500pm = ondemand
Os workers são criados apenas quando um pedido chega e terminados após pm.process_idle_timeout segundos de inatividade. Isto minimiza o consumo de memória em inatividade e é ideal para sites de baixo tráfego ou ambientes partilhados onde dezenas de pools coexistem.
pm = ondemand
pm.max_children = 20
pm.process_idle_timeout = 10sArmadilha crítica: ondemand introduz uma latência de arranque a frio no primeiro pedido após um período de inatividade. Para aplicações sensíveis à latência, dynamic é sempre a melhor escolha.
Calcular pm.max_children Corretamente
É aqui que a maioria dos administradores comete erros dispendiosos. Definir pm.max_children demasiado alto causa esgotamento de memória e kills por OOM; demasiado baixo causa filas de pedidos e erros 502 sob carga.
A fórmula correta:
pm.max_children = (Available RAM for PHP) / (Average PHP worker memory usage)Para encontrar a memória média do worker PHP:
ps --no-headers -o "rss,cmd" -C php-fpm8.2 | awk '{ sum+=$1 } END { printf "Average: %d MBn", sum/NR/1024 }'Num VPS com 2 GB de RAM onde o NGINX, MySQL e o SO consomem ~600 MB, tem aproximadamente 1.400 MB para PHP. Se cada worker usar ~70 MB, o seu pm.max_children seguro é 20. Nunca o defina com base em suposições.
Instalar o PHP-FPM
Debian / Ubuntu
sudo apt update
sudo apt install php8.2-fpm
sudo systemctl enable php8.2-fpm
sudo systemctl start php8.2-fpmCentOS / AlmaLinux / RHEL (com repositório Remi)
sudo dnf install epel-release
sudo dnf install https://rpms.remirepo.net/enterprise/remi-release-9.rpm
sudo dnf module enable php:remi-8.2
sudo dnf install php-fpm
sudo systemctl enable php-fpm
sudo systemctl start php-fpmVerifique se o serviço está em execução e confirme o caminho do socket:
sudo systemctl status php8.2-fpm
ls -la /run/php/Configurar Pools do PHP-FPM
A configuração principal do PHP-FPM encontra-se em /etc/php/8.2/fpm/php-fpm.conf, mas as definições individuais de pool pertencem a /etc/php/8.2/fpm/pool.d/. Em sistemas baseados em RHEL, os ficheiros de pool residem em /etc/php-fpm.d/.
Cada pool é um ambiente de execução isolado. Executar múltiplas aplicações PHP no mesmo servidor — por exemplo, um site WordPress e uma API Laravel — significa criar ficheiros de pool separados com utilizadores, caminhos de socket e limites de recursos distintos. Esta é a arquitetura correta para configurações multi-tenant e é muito mais segura do que partilhar um único pool.
Exemplo: Configuração de Pool de Produção
[myapp]
user = myapp
group = myapp
; Unix socket — always prefer this over TCP for local communication
listen = /run/php/myapp-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
; Process manager
pm = dynamic
pm.max_children = 30
pm.start_servers = 5
pm.min_spare_servers = 3
pm.max_spare_servers = 10
pm.max_requests = 1000
; Slow log — log requests taking longer than 2 seconds
slowlog = /var/log/php-fpm/myapp-slow.log
request_slowlog_timeout = 2s
; Status and ping endpoints
pm.status_path = /fpm-status
ping.path = /fpm-ping
; Environment isolation
clear_env = yes
env[HOSTNAME] = $HOSTNAME
env[PATH] = /usr/local/bin:/usr/bin:/bin
; PHP value overrides per pool
php_admin_value[error_log] = /var/log/php-fpm/myapp-error.log
php_admin_flag[log_errors] = on
php_admin_value[memory_limit] = 256M
php_admin_value[upload_max_filesize] = 64M
php_admin_value[post_max_size] = 64MA diretiva clear_env = yes é uma configuração crítica de segurança que é frequentemente ignorada. Sem ela, os workers PHP herdam todas as variáveis de ambiente do processo master, podendo vazar dados sensíveis ao nível do sistema para o $_ENV da sua aplicação.
Integrar o PHP-FPM com o NGINX
O NGINX não tem capacidade nativa de execução PHP — depende inteiramente do FastCGI para delegar pedidos PHP. Isto é na verdade uma vantagem arquitetural: o NGINX trata ficheiros estáticos a custo quase zero enquanto o PHP-FPM trata apenas do que requer execução.
server {
listen 80;
server_name example.com;
root /var/www/myapp/public;
index index.php index.html;
# Serve static files directly, no PHP involvement
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# Delegate PHP to PHP-FPM
location ~ .php$ {
# Security: prevent executing uploaded files as PHP
try_files $uri =404;
fastcgi_split_path_info ^(.+.php)(/.+)$;
fastcgi_pass unix:/run/php/myapp-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
# Performance tuning
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
fastcgi_read_timeout 300;
}
# Block access to the FPM status page from public
location ~ ^/(fpm-status|fpm-ping)$ {
allow 127.0.0.1;
deny all;
fastcgi_pass unix:/run/php/myapp-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}Nota de segurança: A linha try_files $uri =404; antes de fastcgi_pass não é opcional. Sem ela, o NGINX encaminhará pedidos de ficheiros inexistentes para o PHP-FPM, permitindo ataques de path traversal onde um atacante carrega uma imagem contendo código PHP e engana o servidor para o executar.
Integrar o PHP-FPM com o Apache
O Apache requer mod_proxy_fcgi para comunicar com o PHP-FPM. Ao contrário de mod_php, esta abordagem permite ao Apache executar o PHP-FPM como um utilizador separado, melhorando o isolamento.
sudo a2enmod proxy_fcgi setenvif
sudo systemctl restart apache2Configuração do virtual host:
<VirtualHost *:80>
ServerName example.com
DocumentRoot /var/www/myapp/public
<Directory /var/www/myapp/public>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
<FilesMatch ".php$">
SetHandler "proxy:unix:/run/php/myapp-fpm.sock|fcgi://localhost/"
</FilesMatch>
ErrorLog ${APACHE_LOG_DIR}/myapp-error.log
CustomLog ${APACHE_LOG_DIR}/myapp-access.log combined
</VirtualHost>Ativar e Utilizar a Página de Estado do PHP-FPM
A página de estado integrada é uma das ferramentas de diagnóstico mais subutilizadas do PHP-FPM. Assim que pm.status_path estiver configurado no ficheiro de pool, consulte-o diretamente:
sudo -u www-data SCRIPT_NAME=/fpm-status SCRIPT_FILENAME=/fpm-status REQUEST_METHOD=GET cgi-fcgi -bind -connect /run/php/myapp-fpm.sockOu, de forma mais prática, via curl após expô-lo num endpoint interno restrito:
curl http://127.0.0.1/fpm-status?fullMétricas principais a monitorizar:
listen queue: Pedidos à espera de um worker livre. Qualquer valor acima de 0 sob carga sustentada significa quepm.max_childrené demasiado baixo.active processes: Workers a executar PHP atualmente. Se este valor for consistentemente igual apm.max_children, está na capacidade máxima.slow requests: Contagem cumulativa de pedidos que excederamrequest_slowlog_timeout. Um número crescente indica bottlenecks ao nível da aplicação.
Utilizar o Slow Log para Depuração de Desempenho
O slow log captura um stack trace PHP completo para qualquer pedido que exceda o limiar configurado. Isto é inestimável para identificar problemas de consultas N+1, chamadas de I/O bloqueantes ou loops ineficientes sem necessitar de um profiler completo.
slowlog = /var/log/php-fpm/myapp-slow.log
request_slowlog_timeout = 2sUma entrada do slow log tem este aspeto:
[21-Jun-2025 14:32:11] [pool myapp] pid 18432
script_filename = /var/www/myapp/public/index.php
[0x00007f3b4c001e80] PDOStatement->execute() /var/www/myapp/vendor/laravel/framework/src/Illuminate/Database/Connection.php:338
[0x00007f3b4c001d40] runQueryCallback() /var/www/myapp/vendor/laravel/framework/src/Illuminate/Database/Connection.php:295Isto indica imediatamente que o bottleneck é uma consulta à base de dados, não lógica PHP — direcionando o seu esforço de otimização com precisão.
PHP-FPM com OPcache: A Combinação Essencial
O PHP-FPM por si só trata da gestão de processos; o OPcache elimina o custo de análise e compilação de ficheiros PHP em cada pedido. Juntos, formam a pilha de desempenho completa para PHP em Linux.
Ative e ajuste o OPcache em /etc/php/8.2/fpm/php.ini ou num /etc/php/8.2/fpm/conf.d/10-opcache.ini dedicado:
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.revalidate_freq=0
opcache.validate_timestamps=0
opcache.jit_buffer_size=128M
opcache.jit=tracingDefinir validate_timestamps=0 desativa as verificações de modificação de ficheiros em cada pedido — um ganho de desempenho significativo em produção. Quando implementar novo código, acione uma reinicialização da cache explicitamente:
sudo systemctl reload php8.2-fpmNum VPS com cPanel, as definições do OPcache são frequentemente expostas na interface de configuração PHP, mas o ajuste manual via ficheiros .ini oferece sempre um controlo mais fino.
Reforço de Segurança para o PHP-FPM
Executar Cada Pool como um Utilizador de Sistema Dedicado
Nunca execute pools PHP-FPM como root ou como um utilizador www-data partilhado entre múltiplas aplicações. Crie um utilizador de sistema dedicado por aplicação:
sudo useradd --system --no-create-home --shell /usr/sbin/nologin myappEm seguida, defina user = myapp e group = myapp na configuração do pool. Isto garante que uma aplicação PHP comprometida não consiga ler ficheiros pertencentes a outras aplicações no mesmo servidor.
Restringir Funções PHP
No bloco php_admin_value do pool, desative funções que não têm utilização legítima em aplicações web:
php_admin_value[disable_functions] = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_sourceLimitar o Open Basedir
Confine o acesso a ficheiros do PHP ao diretório da aplicação:
php_admin_value[open_basedir] = /var/www/myapp:/tmpUtilizar Unix Sockets com Permissões Restritas
Os TCP sockets (127.0.0.1:9000) são acessíveis a qualquer processo no servidor. Os Unix sockets com listen.mode = 0660 restringem o acesso apenas ao utilizador e grupo proprietários.
Verificar a Pilha Completa
Após configurar o PHP-FPM e o seu servidor web, verifique toda a cadeia antes de entrar em produção.
Recarregue todos os serviços:
sudo systemctl reload php8.2-fpm
sudo systemctl reload nginx
# or
sudo systemctl reload apache2Teste a sintaxe da configuração do NGINX antes de recarregar:
sudo nginx -tCrie um ficheiro de informação temporário (remova-o após a verificação — expõe dados sensíveis do servidor):
echo "<?php phpinfo();" | sudo tee /var/www/myapp/public/phpinfo.phpAbra http://example.com/phpinfo.php num browser e confirme:
- Server API mostra
FPM/FastCGI - PHP Version corresponde à versão instalada
- A secção OPcache está presente e ativada
Em seguida, remova imediatamente o ficheiro:
sudo rm /var/www/myapp/public/phpinfo.phpPHP-FPM em Ambientes Multi-Aplicação e de Alto Tráfego
Num Servidor Dedicado que aloja dezenas de aplicações PHP, a arquitetura multi-pool torna-se essencial. Cada aplicação obtém o seu próprio pool com pm.max_children, limites de memória e caminhos de slow log ajustados de forma independente. Uma aplicação com mau comportamento que esgote o seu pool de workers não afeta outras aplicações.
Para cenários de alto tráfego, combine o PHP-FPM com:
- Cache FastCGI do NGINX (
fastcgi_cache) para servir respostas PHP em cache como ficheiros estáticos, contornando completamente o PHP-FPM para pedidos repetidos - Redis ou Memcached para armazenamento de sessões PHP, substituindo as sessões baseadas em ficheiros predefinidas que criam contenção de I/O sob carga
- Escalonamento horizontal executando o PHP-FPM em servidores de aplicação atrás de um load balancer, com o NGINX num nó front-end separado
Se a sua pilha inclui terminação SSL, combinar o PHP-FPM com Certificados SSL devidamente configurados na camada NGINX garante que os handshakes TLS são tratados antes de os pedidos chegarem ao PHP-FPM, mantendo os workers PHP focados exclusivamente na lógica da aplicação.
Para cargas de trabalho PHP computacionalmente intensivas — inferência de machine learning via bindings PHP, processamento de imagens ou transcodificação de vídeo — considere GPU Hosting onde o PHP-FPM pode delegar computação pesada para bibliotecas aceleradas por GPU enquanto mantém o tratamento padrão de pedidos para a camada web.
Matriz de Decisão e Checklist Técnica
Antes de implementar o PHP-FPM em produção, verifique cada item nesta checklist:
Seleção do Gestor de Processos
- Use
pm = dynamicpara cargas de trabalho VPS de uso geral - Use
pm = staticapenas em servidores dedicados com tráfego previsível e sustentado - Use
pm = ondemandapenas para pools de baixo tráfego ou de desenvolvimento
Planeamento de Capacidade
- Meça a memória real do worker com
psantes de definirpm.max_children - Reserve pelo menos 20% da RAM total para o SO, servidor web e base de dados
- Defina
pm.max_requestsentre 500–1000 para prevenir acumulação de fugas de memória
Segurança
- Cada pool de aplicação é executado com o seu próprio utilizador de sistema
clear_env = yesestá definido em cada poolopen_basedirrestringe o acesso a ficheiros ao diretório da aplicaçãodisable_functionsbloqueia funções de execução de shell- São utilizados Unix sockets em vez de TCP sockets
Observabilidade
pm.status_pathestá configurado e acessível apenas a partir do localhostslowlogestá ativado com umrequest_slowlog_timeoutde 2–5 segundos- A rotação de logs está configurada para todos os ficheiros de log do PHP-FPM
Desempenho
- O OPcache está ativado com
validate_timestamps=0em produção - A cache FastCGI do NGINX está configurada para endpoints cacheáveis
- O handler de sessões PHP está definido para Redis ou Memcached, não para ficheiros
Operacional
sudo systemctl reload php8.2-fpmé utilizado para alterações de configuração sem tempo de inatividade (nãorestart)phpinfo.phpé removido da raiz do documento imediatamente após a verificação- A configuração do pool está sob controlo de versões juntamente com o código da aplicação
FAQ
Qual é a diferença entre PHP-FPM e mod_php?
mod_php incorpora o interpretador PHP em cada processo worker do Apache, consumindo memória mesmo ao servir ficheiros estáticos e acoplando fortemente o PHP ao Apache. O PHP-FPM é executado como um serviço completamente separado, comunica via FastCGI, funciona com qualquer servidor web incluindo NGINX, e permite isolamento de processos por aplicação com limites de recursos independentes.
Como escolho entre um Unix socket e um TCP socket para o PHP-FPM?
Use um Unix socket (listen = /run/php/app-fpm.sock) sempre que o PHP-FPM e o servidor web estejam na mesma máquina física ou virtual. Os Unix sockets contornam a pilha TCP/IP, reduzindo a latência e eliminando conflitos de portas. Use um TCP socket (listen = 127.0.0.1:9000) apenas quando o PHP-FPM estiver num host diferente do servidor web.
Por que estou a obter erros 502 Bad Gateway sob carga?
Um erro 502 do NGINX apontando para o PHP-FPM significa quase sempre que a fila de escuta está cheia — todos os workers estão ocupados e novas ligações estão a ser recusadas. Verifique pm.status_path para um valor listen queue diferente de zero. A solução é aumentar pm.max_children (se a RAM permitir) ou otimizar scripts PHP lentos identificados via slow log.
Como recarrego o PHP-FPM sem perder ligações ativas?
Use sudo systemctl reload php8.2-fpm em vez de restart. O sinal reload (SIGUSR2) faz com que o processo master reinicie os workers de forma graciosa: os pedidos existentes completam normalmente enquanto os novos workers adotam a configuração atualizada. Um restart forçado termina todos os workers imediatamente, descartando pedidos em curso.
O PHP-FPM pode executar múltiplas versões PHP simultaneamente num servidor?
Sim. Instale múltiplas versões PHP (por exemplo, php7.4-fpm e php8.2-fpm) e configure cada pool de aplicação para utilizar o caminho de socket apropriado. No NGINX, aponte fastcgi_pass para o socket correto por bloco de servidor. Este é um padrão standard em infraestrutura partilhada gerida via Painéis de Controlo VPS e é totalmente suportado em VPS Hosting com acesso root.
