15%

Poupe 15% em todos os serviços

Teste as suas habilidades e obtenha Desconto em qualquer plano

Utilizar o código:

Skills
Começar a trabalhar
10.10.2024

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.

FuncionalidadeCGImod_phpPHP-FPM
Modelo de processoNovo processo por pedidoIncorporado no ApachePool de workers persistente
Eficiência de memóriaMuito fracaModeradaExcelente
Acoplamento ao servidor webForteForte (apenas Apache)Desacoplado (qualquer servidor)
Isolamento por siteNenhumNenhumTotal (pools separados)
Recarga sem interrupçõesNãoNãoSim
Slow log / profilingNãoNãoSim
Escalonamento dinâmico de processosNãoNãoSim
Suporte a Unix socketNãoNãoSim
Compatível com NGINXNãoNãoSim

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.

  1. Um browser envia um pedido HTTP para um recurso .php.
  2. O servidor web (NGINX ou Apache) recebe o pedido e compara-o com um bloco de localização ou diretiva FilesMatch.
  3. 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).
  4. O processo master do PHP-FPM encaminha o pedido para um worker disponível do pool configurado.
  5. O worker executa o script PHP, escreve em stdout e devolve a resposta ao servidor web.
  6. O servidor web entrega o HTML renderizado ao cliente.
  7. 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 = 20

pm = 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 = 500

pm = 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 = 10s

Armadilha 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-fpm

CentOS / 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-fpm

Verifique 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] = 64M

A 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 apache2

Configuraçã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.sock

Ou, de forma mais prática, via curl após expô-lo num endpoint interno restrito:

curl http://127.0.0.1/fpm-status?full

Métricas principais a monitorizar:

  • listen queue: Pedidos à espera de um worker livre. Qualquer valor acima de 0 sob carga sustentada significa que pm.max_children é demasiado baixo.
  • active processes: Workers a executar PHP atualmente. Se este valor for consistentemente igual a pm.max_children, está na capacidade máxima.
  • slow requests: Contagem cumulativa de pedidos que excederam request_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 = 2s

Uma 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:295

Isto 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=tracing

Definir 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-fpm

Num 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 myapp

Em 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_source

Limitar o Open Basedir

Confine o acesso a ficheiros do PHP ao diretório da aplicação:

php_admin_value[open_basedir] = /var/www/myapp:/tmp

Utilizar 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 apache2

Teste a sintaxe da configuração do NGINX antes de recarregar:

sudo nginx -t

Crie 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.php

Abra 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.php

PHP-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 = dynamic para cargas de trabalho VPS de uso geral
  • Use pm = static apenas em servidores dedicados com tráfego previsível e sustentado
  • Use pm = ondemand apenas para pools de baixo tráfego ou de desenvolvimento

Planeamento de Capacidade

  • Meça a memória real do worker com ps antes de definir pm.max_children
  • Reserve pelo menos 20% da RAM total para o SO, servidor web e base de dados
  • Defina pm.max_requests entre 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 = yes está definido em cada pool
  • open_basedir restringe o acesso a ficheiros ao diretório da aplicação
  • disable_functions bloqueia funções de execução de shell
  • São utilizados Unix sockets em vez de TCP sockets

Observabilidade

  • pm.status_path está configurado e acessível apenas a partir do localhost
  • slowlog está ativado com um request_slowlog_timeout de 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=0 em 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ão restart)
  • 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.

15%

Poupe 15% em todos os serviços

Teste as suas habilidades e obtenha Desconto em qualquer plano

Utilizar o código:

Skills
Começar a trabalhar