WordPress lento na VPS: como otimizar

WordPress lento na VPS tem três causas principais: OPcache PHP desabilitado, ausência de cache de objetos (Redis) ou queries lentas no banco. A maioria dos sites passa de 3–4 segundos para menos de 800 ms com as otimizações descritas aqui, sem trocar de servidor ou aumentar RAM.

Medir antes de otimizar

Nunca otimize sem uma baseline. Meça o TTFB (Time To First Byte) com curl, desconta DNS e latência de rede, isola o tempo real do servidor:

bash
# Medir TTFB (3 medições para média)
for i in 1 2 3; do
  curl -o /dev/null -s -w "TTFB: %{time_starttransfer}s | Total: %{time_total}s\n" \
    https://seudominio.com.br/
done

# Forçar page não-cacheada
curl -o /dev/null -s -w "TTFB: %{time_starttransfer}s\n" \
  "https://seudominio.com.br/?nocache=1"

OPcache PHP: o ganho mais rápido

OPcache armazena o bytecode PHP compilado em memória, eliminando a recompilação a cada requisição. É desabilitado por padrão na maioria das imagens Docker. Verifique e ative:

bash
# Verificar se está ativo
docker compose exec wordpress php -r "echo opcache_get_status()['opcache_enabled'] ? 'OK' : 'DISABLED';"

# Criar configuração PHP customizada
cat > ./php-opcache.ini << 'EOF'
opcache.enable=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=10000
opcache.revalidate_freq=60
opcache.save_comments=1
EOF

# Montar no container (docker-compose.yml, serviço wordpress)
#   volumes:
#     - ./php-opcache.ini:/usr/local/etc/php/conf.d/opcache.ini

docker compose restart wordpress

Redis Object Cache

Redis elimina queries repetidas ao banco cacheando objetos PHP na memória. Adicione o serviço ao docker-compose.yml e configure o WordPress:

yaml
# No docker-compose.yml, adicionar:
  redis:
    image: redis:7-alpine
    restart: always
    command: redis-server --maxmemory 128mb --maxmemory-policy allkeys-lru
    volumes:
      - redis_data:/data

# No serviço wordpress, adicionar variável:
  wordpress:
    environment:
      WORDPRESS_REDIS_HOST: redis

volumes:
  redis_data:

Otimizar MariaDB

O banco mal configurado é gargalo em sites com muitos posts ou WooCommerce. Configure o InnoDB buffer pool para usar ~50% da RAM dedicada ao banco:

bash
cat > ./mariadb.cnf << 'EOF'
[mysqld]
innodb_buffer_pool_size = 256M
innodb_log_file_size = 64M
innodb_flush_log_at_trx_commit = 2
query_cache_type = 0
max_connections = 50
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
EOF

# Montar no container (serviço db)
#   volumes:
#     - ./mariadb.cnf:/etc/mysql/conf.d/custom.cnf

Gzip e cache de estáticos no Nginx

Compressão gzip reduz HTML/CSS/JS em 60–80%. Cache de assets evita servir o mesmo arquivo repetidamente. Adicione ao bloco server do nginx.conf:

nginx
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml application/json
           application/javascript application/xml+rss image/svg+xml;

location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
    expires 30d;
    add_header Cache-Control "public, immutable";
    access_log off;
}

Não quer configurar manualmente?

Implante o WordPress em menos de 5 minutos com a Runstack. Infraestrutura da OPEN Datacenter, com servidores em São Paulo.

Perguntas frequentes

Para simplicidade: WP Super Cache. Para controle avançado: W3 Total Cache (suporta Redis, CDN, minificação). Se você já usa Redis Object Cache na VPS, adicione WP Super Cache ou LiteSpeed Cache só para cache de páginas. Nunca instale dois plugins de cache, eles conflitam.

WooCommerce com catálogo e pedidos requer 2 GB RAM mínimo, Redis para cache de sessão de carrinho e banco otimizado com índices. Páginas de checkout e carrinho não podem ser cacheadas para usuários logados, o TTFB alto nesses casos é esperado e deve ser mitigado com otimização de queries.

A opção mais simples é Cloudflare (gratuito): aponte o DNS para o Cloudflare, ative o proxy. Assets estáticos são servidos de PoPs globais sem configuração adicional. Para mover uploads para S3/R2 use o plugin WP Offload Media.

Instale o plugin Query Monitor, ele mostra tempo por plugin, queries SQL e memória. Plugins acima de 100 ms por requisição merecem atenção. Desative-os um a um medindo o TTFB com curl para isolar o problema.

A imagem wordpress:fpm usa pm.dynamic por padrão. Para 2 GB RAM, configure pm.max_children = 10. Crie um www.conf customizado e monte em /usr/local/etc/php-fpm.d/www.conf. Regra geral: 1 worker para cada 50–80 MB de RAM livre.