Aprenda a otimizar o WordPress em servidor próprio com Nginx e PHP-FPM: WP-CLI, Redis, cache de página, proteção do login e rotina de atualização.
Para que serve
Num servidor dedicado o WordPress tem CPU e memória de sobra, mas isso não garante um site rápido nem seguro. Este artigo mostra como otimizar o WordPress com os ajustes que mais fazem diferença numa instalação própria com Nginx, PHP-FPM e MariaDB: instalação via WP-CLI, permissões corretas, cache, proteção do login e rotina de atualização.
Pré-requisitos
- Nginx e PHP-FPM configurados com um usuário e um pool por site (veja o artigo sobre Nginx + PHP-FPM desta base). Nos exemplos: usuário
exemplo, raiz/srv/exemplo/public. - MariaDB ou MySQL instalado (
apt install -y mariadb-server). - Certificado TLS emitido (artigo sobre Let's Encrypt).
Passo a passo para otimizar o WordPress
1. Crie o banco de dados
mariadb -e "CREATE DATABASE wp_exemplo CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'wp_exemplo'@'localhost' IDENTIFIED BY 'SENHA-FORTE-AQUI';
GRANT ALL PRIVILEGES ON wp_exemplo.* TO 'wp_exemplo'@'localhost';"
Um usuário de banco por site: se um WordPress for comprometido, o invasor não alcança os bancos dos outros.
2. Instale o WP-CLI e o WordPress
curl -o /usr/local/bin/wp https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
chmod +x /usr/local/bin/wp
cd /srv/exemplo/public
sudo -u exemplo wp core download --locale=pt_BR
sudo -u exemplo wp config create --dbname=wp_exemplo --dbuser=wp_exemplo --dbpass='SENHA-FORTE-AQUI'
sudo -u exemplo wp core install --url=https://exemplo.com.br --title="Meu Site" \
--admin_user=gestor --admin_email=ti@exemplo.com.br
O último comando mostra a senha gerada para o administrador. Evite o usuário admin, que é o primeiro alvo de ataques de força bruta.
3. Endureça o wp-config.php
Acrescente antes da linha /* That's all, stop editing! */:
define( 'DISALLOW_FILE_EDIT', true ); // remove o editor de temas/plugins do painel
define( 'WP_AUTO_UPDATE_CORE', 'minor' );
define( 'DISABLE_WP_CRON', true ); // o cron será executado pelo sistema (passo 6)
define( 'WP_MEMORY_LIMIT', '256M' );
Ajuste as permissões:
find /srv/exemplo/public -type d -exec chmod 755 {} \;
find /srv/exemplo/public -type f -exec chmod 644 {} \;
chmod 640 /srv/exemplo/public/wp-config.php
Como o PHP roda com o usuário dono dos arquivos, as atualizações pelo painel funcionam sem precisar de 777 em lugar algum.
4. Regras de segurança no Nginx
No bloco http de /etc/nginx/nginx.conf, crie uma zona de limite de requisições:
limit_req_zone $binary_remote_addr zone=wplogin:10m rate=10r/m;
No server block do site, antes do location ~ \.php$:
# Limita tentativas de login
location = /wp-login.php {
limit_req zone=wplogin burst=5 nodelay;
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/exemplo.sock;
}
# XML-RPC é usado em ataques de força bruta; bloqueie se não usa o app móvel ou o Jetpack
location = /xmlrpc.php { deny all; }
# Impede execução de PHP na pasta de uploads
location ~* /wp-content/uploads/.*\.php$ { deny all; }
# Arquivos que não devem ser públicos
location ~* /(wp-config\.php|readme\.html|license\.txt)$ { deny all; }
nginx -t && systemctl reload nginx
Para uma camada extra contra injeção de SQL, XSS e varreduras, veja também o artigo «Como instalar um WAF no servidor: ModSecurity com OWASP CRS e Cloudflare».
5. Cache: onde está o ganho de velocidade
- OPcache: já vem ativo com o pacote
php-opcache; ajuste o tamanho conforme o artigo sobre configuração do PHP. - Cache de objetos com Redis: reduz consultas repetidas ao banco, principalmente em WooCommerce e áreas logadas.
Em servidores com vários sites, defina em cadaapt install -y redis-server php-redis systemctl reload php8.4-fpm sudo -u exemplo wp plugin install redis-cache --activate sudo -u exemplo wp redis enablewp-config.phpum prefixo diferente:define( 'WP_REDIS_PREFIX', 'exemplo_' );. - Cache de página: entrega HTML pronto para visitantes não logados. Um plugin de cache de página bem mantido resolve para a maioria dos sites; para tráfego alto, o
fastcgi_cachedo próprio Nginx é ainda mais eficiente, mas exige regras para não guardar carrinho, checkout e áreas logadas. - Banco de dados: se o site continuar lento mesmo com cache, o gargalo costuma ser consulta pesada. Veja também o artigo «MySQL lento: como achar as consultas culpadas com slow query log e EXPLAIN».
- Imagens: sirva em WebP/AVIF e com carregamento tardio. O WordPress atual já aplica
loading="lazy"automaticamente.
6. Cron do sistema no lugar do WP-Cron
O WP-Cron padrão roda a cada visita, o que é lento em site movimentado e não roda em site sem visitas. Com DISABLE_WP_CRON ativo, agende no crontab do usuário do site (crontab -u exemplo -e):
*/5 * * * * cd /srv/exemplo/public && /usr/local/bin/wp cron event run --due-now --quiet
7. Atualizações e backup
sudo -u exemplo wp core update
sudo -u exemplo wp plugin update --all
sudo -u exemplo wp theme update --all
Plugins desatualizados são a principal porta de entrada em sites WordPress invadidos. Remova os que não usa (wp plugin delete nome), em vez de só desativar. Antes de atualizar, faça backup de arquivos e banco (wp db export) e mantenha cópias fora do servidor: o backup é responsabilidade sua.
Se suspeitar que o site já foi comprometido, veja também o artigo «WordPress invadido: como descobrir, limpar e evitar que aconteça de novo».
Como saber se funcionou
sudo -u exemplo wp redis statusmostra Connected.- Em Ferramentas > Saúde do site, não devem aparecer alertas críticos.
- Repita mais de 15 tentativas rápidas em
/wp-login.phpe o Nginx deve passar a responder503. curl -I https://exemplo.com.br/xmlrpc.phpretorna403.- Meça o tempo até o primeiro byte:
curl -o /dev/null -s -w "%{time_starttransfer}\n" https://exemplo.com.br. Com cache de página, fica abaixo de 0,2 s.
Problemas comuns
- WordPress pede dados de FTP para atualizar: o PHP não roda como dono dos arquivos. Confira
user/groupno pool do PHP-FPM e o dono em/srv/exemplo/public. - Loop de redirecionamento após ativar HTTPS atrás de proxy ou Cloudflare: confira as URLs em Configurações > Geral e o modo SSL da Cloudflare (deve ser Full (strict)).
- Erro "Error establishing a database connection": teste o usuário com
mariadb -u wp_exemplo -p wp_exemplo. - Bloqueio do xmlrpc quebrou o Jetpack ou o app: libere apenas os IPs do serviço ou remova a regra.
Perguntas frequentes
Qual o melhor cache para WordPress em servidor próprio?
A combinação que mais rende é OPcache ativo, cache de objetos com Redis e um cache de página (plugin ou fastcgi_cache do Nginx). O cache de página é o que mais reduz o tempo de resposta para visitantes não logados.
Devo bloquear o xmlrpc.php?
Sim, se você não usa o aplicativo móvel do WordPress nem o Jetpack. Ele é muito usado em ataques de força bruta. Se precisar dele, libere apenas os IPs do serviço.
O WordPress precisa de permissão 777 para atualizar?
Não. Com o PHP-FPM rodando com o usuário dono dos arquivos, diretórios em 755 e arquivos em 644 bastam, e o wp-config.php pode ficar em 640.
Desativar o WP-Cron causa problema?
Não, desde que você agende wp cron event run --due-now no crontab do usuário do site. Assim as tarefas rodam no horário, mesmo sem visitas.
Como saber se meu WordPress foi invadido?
Sinais comuns são redirecionamentos estranhos, usuários administradores desconhecidos e arquivos PHP na pasta de uploads. O passo a passo está no artigo «WordPress invadido: como descobrir, limpar e evitar que aconteça de novo».
Leitura complementar
Precisa de ajuda?
Se ficar com alguma dúvida, abra um ticket na área do cliente ou fale com o suporte pelo WhatsApp.
