Protegendo seu WordPress com Cloudflare
Este guia une o processo de entrada no Cloudflare com uma camada prática de hardening para WordPress. Primeiro organizamos DNS, proxy e TLS. Depois criamos regras de WAF com critérios claros, ação definida e espaço para testar antes de bloquear algo legítimo.
Da criação da conta até regras que reduzem a superfície exposta do WordPress.
O que o Cloudflare muda na proteção do WordPress
O Cloudflare fica entre o visitante e o servidor de origem. Quando o registro web está em Proxied, as requisições HTTP e HTTPS passam pela rede da Cloudflare antes de chegar à hospedagem. É nesse ponto que entram cache, proteção contra DDoS, regras de WAF, limitação de requisições e outros controles de borda.
Menos exposição direta
Com o proxy ativo, o visitante recebe endereços da Cloudflare em vez do IP público do servidor. Isso não substitui firewall de origem, mas reduz a exposição do host web.
Filtro antes do WordPress
Regras personalizadas e regras gerenciadas podem bloquear, desafiar ou limitar requisições antes que PHP, plugins e banco de dados precisem processá-las.
Decisão por contexto
Host, caminho, método, IP, país, bot verificado e User-Agent ajudam a definir uma política que combina com o tipo de site e com o público real.
Criar conta e adicionar o domínio
Os painéis da Cloudflare evoluem com frequência, mas a sequência continua a mesma: criar a conta, informar o domínio, revisar os registros DNS importados e apontar os nameservers no registrador. As imagens abaixo preservam o passo a passo original como referência visual.
Criar uma conta no Cloudflare
Acesse o site da Cloudflare, crie a conta com um e-mail corporativo ou controlado pela empresa e use uma senha forte. Assim que a conta existir, ative MFA antes de configurar domínios ou permissões de equipe.
Adicionar seu site
No painel, escolha adicionar um site e informe somente o domínio raiz, sem caminho ou protocolo. Exemplo: lluciox.space, e não https://lluciox.space/wp-admin. Depois selecione o plano adequado e revise a zona DNS importada.
Trocar os nameservers no registrador
O Cloudflare exibirá dois nameservers próprios para sua zona. A alteração acontece no registrador do domínio, não no provedor de hospedagem. Copie os dois endereços exatamente como aparecem no painel e não remova registros DNS necessários durante a migração.
DNS, origem e Proxy Status
Crie ou valide os registros que levam o site para a hospedagem. Para o site WordPress, normalmente isso significa um registro A, AAAA ou CNAME para o hostname público. E-mail, verificações de domínio e serviços que não aceitam proxy devem permanecer em DNS-only.
Validar a origem primeiro
Enquanto prepara o certificado no servidor, o modo DNS-only ajuda a testar se a origem responde pelo hostname em HTTPS. Ele não recebe WAF, cache ou proteção de borda e revela o IP de origem em consultas DNS.
Colocar o host web atrás do Cloudflare
Depois de validar a origem em HTTPS, ative a nuvem laranja para os hostnames que servem o site. A partir daí, as regras WAF passam a ser avaliadas antes de a requisição alcançar o WordPress.
SSL/TLS: a conexão precisa estar protegida até a origem
O cadeado no navegador cobre apenas a conexão entre visitante e Cloudflare. Para evitar que a segunda etapa fique fraca, entre Cloudflare e hospedagem, a configuração recomendada é Full (strict): HTTPS na origem, certificado válido, não expirado e compatível com o hostname.
Off e Flexible
Off deixa as conexões sem HTTPS. Flexible cifra até a Cloudflare, mas usa HTTP entre Cloudflare e origem. Para WordPress com login, dados pessoais ou painel administrativo, não é o modo adequado.
Full
Usa HTTPS para a origem, mas não valida o certificado apresentado. É útil apenas enquanto você corrige a origem para atender os requisitos de modo estrito.
Full (strict)
Exige certificado de origem válido, não expirado, emitido por autoridade pública ou Cloudflare Origin CA e com CN ou SAN correspondente ao hostname.
Edge Certificates, HTTPS e HSTS
Ative redirecionamento para HTTPS somente depois de confirmar que o site responde corretamente com certificado válido. HSTS merece atenção especial: uma vez publicado com subdomínios e preload, erros de certificado ficam mais difíceis de contornar do lado do visitante.
Versão mínima de TLS e instalação do WordPress
Defina TLS 1.2 ou superior para reduzir compatibilidade com protocolos antigos. Depois, com DNS e TLS organizados, finalize a instalação do WordPress. A partir daqui o ambiente está pronto para receber as regras de camada 7.
Criando regras no WAF para proteger seu WordPress
Daqui em diante, deixamos os prints de lado e trabalhamos com a configuração atual da Cloudflare. No painel novo, procure Security rules; no menu clássico, o caminho pode aparecer como Security → WAF → Custom rules. Crie cada política, cole a expressão em Edit expression, escolha a ação e defina a ordem com intenção.
GEOBLOCK_HIGH_RISK
Esta política é uma postura de risco contextual, não uma lista universal de países “maliciosos”. No exemplo, o bloqueio de determinados continentes, Tor e países foi escolhido conforme o perfil de acesso e os IPs que vinham gerando ruído no ambiente. Para sites com audiência internacional, e-commerce ou usuários viajando, comece com Managed Challenge ou monitore antes de bloquear.
lower(http.host) in {"lluciox.space" "www.lluciox.space"}
and
not cf.client.bot
and
not lower(http.request.uri.path) contains "/.well-known/acme-challenge/"
and
(
(
ip.src.continent in {"AF" "AS" "T1"}
and not ip.src.country in {"AO" "MZ"}
)
or ip.src.country in {"RU" "IE"}
)
BAD_USER_AGENTS
Esta regra intercepta User-Agents vazios e assinaturas comuns de scanners, frameworks de automação e ferramentas de enumeração. Ela também bloqueia as rotas /cdn-cgi/trace e /cli neste exemplo. É uma camada de redução de ruído: um atacante pode alterar o User-Agent, portanto ela não substitui as demais políticas.
lower(http.host) in {"lluciox.space" "www.lluciox.space"}
and
(
lower(http.request.uri.path) eq "/cdn-cgi/trace"
or lower(http.request.uri.path) eq "/cli"
or
(
not cf.client.bot
and
(
http.user_agent eq ""
or lower(http.user_agent) contains "wpscan"
or lower(http.user_agent) contains "sqlmap"
or lower(http.user_agent) contains "nmap"
or lower(http.user_agent) contains "masscan"
or lower(http.user_agent) contains "nikto"
or lower(http.user_agent) contains "acunetix"
or lower(http.user_agent) contains "nessus"
or lower(http.user_agent) contains "metasploit"
or lower(http.user_agent) contains "hydra"
or lower(http.user_agent) contains "zgrab"
or lower(http.user_agent) contains "gobuster"
or lower(http.user_agent) contains "dirbuster"
or lower(http.user_agent) contains "ffuf"
or lower(http.user_agent) contains "fuzzer"
or lower(http.user_agent) contains "nuclei"
or lower(http.user_agent) contains "whatweb"
or lower(http.user_agent) contains "scrapy"
or lower(http.user_agent) contains "scraper"
or lower(http.user_agent) contains "libwww-perl"
or lower(http.user_agent) contains "python-requests"
or lower(http.user_agent) contains "aiohttp"
or lower(http.user_agent) contains "go-http-client"
or lower(http.user_agent) contains "curl"
or lower(http.user_agent) contains "wget"
or lower(http.user_agent) contains "headlesschrome"
or lower(http.user_agent) contains "phantomjs"
or lower(http.user_agent) contains "selenium"
)
)
)
curl, wget e bibliotecas HTTP podem ser usados por health checks e automações legítimas.LOCKDOWN_WP_CORE
A terceira regra concentra caminhos e parâmetros que normalmente não precisam ficar abertos ao público. Ela bloqueia XML-RPC, enumeração de autores, rotas de usuários da REST API, tentativa de executar PHP em diretórios sensíveis e caminhos usuais de backup.
lower(http.host) in {"lluciox.space" "www.lluciox.space"}
and
(
lower(http.request.uri.path) eq "/xmlrpc.php"
or lower(http.request.uri.query) contains "author="
or lower(http.request.uri.path) contains "/wp-json/wp/v2/users"
or lower(http.request.uri.query) contains "rest_route=/wp/v2/users"
or (
lower(http.request.uri.path) contains "/wp-content/uploads/"
and lower(http.request.uri.path) contains ".php"
)
or (
lower(http.request.uri.path) contains "/wp-includes/"
and lower(http.request.uri.path) contains ".php"
)
or starts_with(lower(http.request.uri.path), "/wp-content/backup")
or starts_with(lower(http.request.uri.path), "/wp-content/backups")
or starts_with(lower(http.request.uri.path), "/wp-content/backup-db")
or starts_with(lower(http.request.uri.path), "/wp-content/db-backup")
or starts_with(lower(http.request.uri.path), "/wp-content/mu-plugins")
)
BLOCK_WPADMIN: restrinja administração sem se bloquear
A expressão abaixo é o bloqueio completo de acesso público a /wp-login.php e /wp-admin, preservando apenas /wp-admin/admin-ajax.php para reduzir quebra de recursos no front-end. Sozinha, ela também bloqueia você. Use-a apenas quando o painel for acessado por uma camada alternativa, como VPN, Cloudflare Access ou uma política de exceção anterior validada.
lower(http.host) in {"lluciox.space" "www.lluciox.space"}
and
(
lower(http.request.uri.path) eq "/wp-login.php"
or lower(http.request.uri.path) eq "/wp-login"
or starts_with(lower(http.request.uri.path), "/wp-login/")
or lower(http.request.uri.path) eq "/wp-admin"
or
(
starts_with(lower(http.request.uri.path), "/wp-admin/")
and lower(http.request.uri.path) ne "/wp-admin/admin-ajax.php"
)
)
Permitir somente acessos do Brasil
Útil para uma operação local. Quem estiver fora do Brasil, inclusive você em viagem ou usando VPN de outro país, será bloqueado no login e no painel.
lower(http.host) in {"lluciox.space" "www.lluciox.space"}
and
ip.src.country ne "BR"
and
(
lower(http.request.uri.path) eq "/wp-login.php"
or lower(http.request.uri.path) eq "/wp-login"
or starts_with(lower(http.request.uri.path), "/wp-login/")
or lower(http.request.uri.path) eq "/wp-admin"
or
(
starts_with(lower(http.request.uri.path), "/wp-admin/")
and lower(http.request.uri.path) ne "/wp-admin/admin-ajax.php"
)
)
Permitir somente seus IPs confiáveis
É a opção mais restritiva. Troque os IPs de documentação pelos seus IPv4 e IPv6 públicos reais. Se seu provedor muda o IP frequentemente, mantenha um método alternativo de recuperação antes de ativar.
lower(http.host) in {"lluciox.space" "www.lluciox.space"}
and
not ip.src in {203.0.113.10 2001:db8:1234::/48}
and
(
lower(http.request.uri.path) eq "/wp-login.php"
or lower(http.request.uri.path) eq "/wp-login"
or starts_with(lower(http.request.uri.path), "/wp-login/")
or lower(http.request.uri.path) eq "/wp-admin"
or
(
starts_with(lower(http.request.uri.path), "/wp-admin/")
and lower(http.request.uri.path) ne "/wp-admin/admin-ajax.php"
)
)
WP-CRON: manter público ou bloquear?
/wp-cron.php não é um arquivo de configuração nem uma página administrativa. Ele é o ponto usado pelo WordPress para processar tarefas agendadas. Publicações programadas, verificações de atualização, e-mails, limpezas de cache, rotinas de backup e jobs de plugins podem depender dessa fila. No comportamento padrão, o WordPress verifica eventos vencidos durante as visitas ao site e pode iniciar uma chamada não bloqueante para /wp-cron.php. Portanto, bloquear a rota sem substituir esse mecanismo pode fazer tarefas pararem sem um erro visível para quem navega no site.
wp-cron.php. A decisão aqui é sobre permitir ou bloquear o acesso HTTP à rota.Quando não há um agendador real pronto, mantenha a rota funcional.
Esta é a escolha adequada para hospedagens compartilhadas sem cron de sistema confiável, ambientes em que você não tem acesso a WP-CLI ou situações em que ainda não foi possível testar os plugins que usam tarefas agendadas. Nesse cenário, não adicione /wp-cron.php à regra de arquivos sensíveis e não use uma regra Block para a rota.
http.host in {"lluciox.space" "www.lluciox.space"}
and
http.request.uri.path eq "/wp-cron.php"
Conta chamadas repetidas do mesmo endereço de origem.
Janela inicial para identificar repetição anormal.
Valor inicial para conter abuso sem bloquear a operação comum.
Bloqueio temporário para a origem que ultrapassar o limite.
Substitua o disparo por visitas por um cron real e só então bloqueie o endpoint público.
Essa é a arquitetura mais previsível para VPS, servidores dedicados e hospedagens que liberam tarefas agendadas. O cron do sistema chama o WordPress em um intervalo definido, mesmo quando não há visitantes. Primeiro teste o comando manualmente. Depois agende-o. Somente no final desative o disparo padrão e bloqueie a rota pública.
cd /var/www/seu-site && wp cron event run --due-now
*/5 * * * * cd /var/www/seu-site && /usr/local/bin/wp cron event run --due-now --quiet >/dev/null 2>&1
define( 'DISABLE_WP_CRON', true );
lower(http.host) in {"lluciox.space" "www.lluciox.space"}
and
lower(http.request.uri.path) eq "/wp-cron.php"
BLOCK_SENSITIVE_FILES
Esta regra impede a leitura de arquivos que nunca deveriam ser públicos: arquivos de configuração, logs, repositórios de versionamento, manifestos de dependências e cópias de backup. Ela também identifica arquivos compactados associados a nomes que costumam indicar backup, banco de dados ou diretório antigo. /wp-cron.php fica fora desta lista porque exige uma decisão de arquitetura própria: mantenha a rota enquanto usa WP-Cron padrão ou bloqueie-a somente depois de migrar para um agendador real e validar as tarefas.
lower(http.host) in {"lluciox.space" "www.lluciox.space"}
and
(
lower(http.request.uri.path) in {"/wp-load.php" "/wp-settings.php" "/.htaccess" "/.htpasswd" "/.env" "/wp-config.php" "/composer.json" "/composer.lock" "/package.json" "/package-lock.json" "/yarn.lock" "/pnpm-lock.yaml" "/debug.log" "/error_log" "/php_errorlog" "/php-errors.log" "/readme.html" "/readme.txt" "/readme.md" "/license.txt" "/license.md" "/licence.txt" "/licence.md" "/changelog.txt" "/changelog.md"}
or lower(http.request.uri.path) contains "/.env"
or lower(http.request.uri.path) contains "/.git"
or lower(http.request.uri.path) contains "/.svn"
or lower(http.request.uri.path) contains "/.hg"
or lower(http.request.uri.path) contains "/.idea"
or lower(http.request.uri.path) contains "/.vscode"
or lower(http.request.uri.path) contains "/wp-config.php"
or lower(http.request.uri.path) contains "/composer.json"
or lower(http.request.uri.path) contains "/composer.lock"
or lower(http.request.uri.path) contains "/debug.log"
or lower(http.request.uri.path) contains "/error_log"
or ends_with(lower(http.request.uri.path), ".sql")
or ends_with(lower(http.request.uri.path), ".bak")
or ends_with(lower(http.request.uri.path), ".bkp")
or ends_with(lower(http.request.uri.path), ".backup")
or ends_with(lower(http.request.uri.path), ".bk")
or ends_with(lower(http.request.uri.path), ".old")
or ends_with(lower(http.request.uri.path), ".orig")
or ends_with(lower(http.request.uri.path), ".save")
or ends_with(lower(http.request.uri.path), ".swp")
or ends_with(lower(http.request.uri.path), ".tmp")
or (
(
lower(http.request.uri.path) contains "/backup"
or lower(http.request.uri.path) contains "/dump"
or lower(http.request.uri.path) contains "/database"
or lower(http.request.uri.path) contains "/db"
or lower(http.request.uri.path) contains "/banco"
or lower(http.request.uri.path) contains "/mysql"
or lower(http.request.uri.path) contains "/public_html"
or lower(http.request.uri.path) contains "/site"
or lower(http.request.uri.path) contains "/wordpress"
or lower(http.request.uri.path) contains "/wp-content"
or lower(http.request.uri.path) contains "/old"
or lower(http.request.uri.path) contains "/antigo"
)
and
(
ends_with(lower(http.request.uri.path), ".zip")
or ends_with(lower(http.request.uri.path), ".tar")
or ends_with(lower(http.request.uri.path), ".tgz")
or ends_with(lower(http.request.uri.path), ".gz")
or ends_with(lower(http.request.uri.path), ".7z")
or ends_with(lower(http.request.uri.path), ".rar")
)
)
)
RATE_LIMIT_CRITICAL_WP
Rate limiting não avalia uma requisição isolada; ele mede repetição dentro de uma janela de tempo. Essa política aponta para login, XML-RPC, envio de comentários, enumeração de usuários e caminhos de plugin que costumam ser sondados. Configure a característica por IP source, a janela, o número de requisições e a duração da mitigação de acordo com o comportamento normal do seu site.
http.host in {"lluciox.space" "www.lluciox.space"}
and
(
http.request.uri.path eq "/wp-login.php"
or http.request.uri.path eq "/xmlrpc.php"
or http.request.uri.path eq "/wp-comments-post.php"
or http.request.uri.path contains "/wp-json/wp/v2/users"
or
(
http.request.uri.path contains "/wp-content/plugins/"
and
(
http.request.uri.path contains ".php"
or http.request.uri.path contains "readme.txt"
or http.request.uri.path contains "changelog"
or http.request.uri.path contains ".bak"
or http.request.uri.path contains ".old"
or http.request.uri.path contains ".txt"
)
)
)
Conta requisições por endereço de origem.
Janela inicial simples para observar o comportamento.
Ponto de partida conservador para endpoints críticos.
Tempo de bloqueio depois que o limite for atingido.
Validar a política antes de chamar de proteção
O resultado esperado não é apenas ver eventos bloqueados. Uma configuração madura mantém o site, formulários, login autorizado, cache, renovação de certificado e integrações funcionando, enquanto reduz caminhos desnecessários e tráfego automatizado de baixo valor.
Fontes oficiais para manter a configuração atualizada
As telas do Cloudflare podem mudar, mas as regras devem ser revisadas com a documentação oficial. Consulte principalmente as páginas de custom rules, rate limiting, status de proxy, modos SSL/TLS e regras gerenciadas.