Skip to content

Cloudflare a fondo ​

Ya tienes mitienda.com en Cloudflare con SSL en Full (strict). Ahora vamos a sacarle todo el jugo al plan gratuito: caché para que el sitio vuele, redirecciones sin tocar el servidor, un escudo contra bots y ataques, la IP real de tus visitantes, y una probada de las herramientas avanzadas (Workers, Pages, API, DNSSEC, túneles).

Los menús cambian

Cloudflare rediseña su panel con frecuencia. Las rutas de esta lección describen dónde suele estar cada opción; si no la encuentras, usa el buscador del panel (arriba) escribiendo el nombre de la función: "Cache Rules", "Redirect Rules", "Bot Fight Mode"...

1. Caché: qué guarda Cloudflare y cuándo ​

Concepto ​

Con nube naranja, Cloudflare puede guardar copias de tus archivos en cada uno de sus centros de datos. Cuando otro visitante de la misma región pide el mismo archivo, Cloudflare lo entrega sin molestar a tu servidor.

txt
Primer visitante en Guadalajara:
  Visitante → Cloudflare GDL (no lo tiene: MISS) → tu hosting → Cloudflare guarda copia → visitante

Segundo visitante en Guadalajara:
  Visitante → Cloudflare GDL (lo tiene: HIT) → visitante        (tu hosting ni se entera)

Qué se cachea por defecto ​

Cloudflare cachea por extensión de archivo: imágenes (jpg, png, webp, gif, svg, ico), css, js, fuentes (woff, woff2), pdf, zip, video y similares. No cachea HTML por defecto, porque el HTML suele ser dinámico (carrito, sesión, contenido personalizado).

Lo puedes comprobar con la cabecera cf-cache-status:

bash
curl -sI https://mitienda.com/wp-content/themes/tema/style.css | grep -i cf-cache-status
# cf-cache-status: HIT

curl -sI https://mitienda.com/ | grep -i cf-cache-status
# cf-cache-status: DYNAMIC   ← HTML, no se cachea
ValorSignificado
HITServido desde la caché de Cloudflare.
MISSNo estaba; se pidió al origen (la próxima vez será HIT).
EXPIREDEstaba pero venció; se volvió a pedir.
REVALIDATEDEstaba vencido, el origen confirmó que sigue igual.
BYPASSUna regla o cabecera (ej. cookie, Cache-Control: private) indicó no cachear.
DYNAMICNo es cacheable según la configuración (típico del HTML).

Purgar caché ​

Subiste un nuevo logo.png con el mismo nombre y sigues viendo el viejo. Ruta: Caching → Configuration → Purge Cache:

  • Custom Purge / Purgar personalizado: pegas las URLs exactas (https://mitienda.com/img/logo.png). Es lo ideal.
  • Purge Everything / Purgar todo: borra todo. Úsalo con moderación: el siguiente minuto tu servidor recibirá todas las peticiones de golpe.

Modo de desarrollo ​

Caching → Configuration → Development Mode: desactiva temporalmente la caché (se apaga solo después de 3 horas). Útil mientras haces cambios de diseño. No olvides que existe: si se queda activo durante una campaña, pierdes la ventaja de la CDN.

Reglas de caché (Cache Rules) ​

Ruta: Caching → Cache Rules (o Rules → Cache Rules). Permiten decir "esto sí se cachea, esto no, y por cuánto tiempo". Ejemplo: cachear el HTML de un sitio WordPress de información, excepto el panel y usuarios con sesión.

txt
Nombre: Cachear HTML público

Cuando la petición coincida con (expresión personalizada):
  (http.host eq "mitienda.com"
   and not starts_with(http.request.uri.path, "/wp-admin")
   and not starts_with(http.request.uri.path, "/wp-login.php")
   and not http.cookie contains "wordpress_logged_in"
   and not http.cookie contains "woocommerce_items_in_cart")

Entonces:
  Cache eligibility:  Eligible for cache (Apto para caché)
  Edge TTL:           Ignorar cabecera del origen → 2 horas
  Browser TTL:        Respetar el origen

Nunca caches páginas personalizadas

Carrito, checkout, "mi cuenta", paneles. Si cacheas HTML con sesión, el visitante B puede ver la página del visitante A (¡con su nombre y pedido!). Ante la duda, no caches HTML; con la caché de estáticos ya ganas mucho.

2. Redirecciones sin tocar el servidor ​

Ruta: Rules → Redirect Rules (Reglas de redireccionamiento). Funcionan solo si el nombre tiene un registro DNS en nube naranja, porque es Cloudflare quien responde.

www → raíz ​

Cloudflare suele ofrecer una plantilla ("Redirect from WWW to root"). A mano:

txt
Nombre: www a raíz

Cuando: (http.host eq "www.mitienda.com")

Entonces:
  Tipo:      Dinámico (Dynamic)
  Expresión: concat("https://mitienda.com", http.request.uri.path)
  Código:    301
  Conservar cadena de consulta (Preserve query string): ✓

Resultado: http://www.mitienda.com/productos?cat=2 → https://mitienda.com/productos?cat=2.

Dominio viejo → dominio nuevo ​

La tienda cambió de nombre: viejatienda.com → mitienda.com. Agrega viejatienda.com como otra zona en Cloudflare (gratis), crea un registro "de relleno" en naranja para que el tráfico llegue a Cloudflare, y una regla:

txt
DNS de viejatienda.com:
  AAAA  @    100::    🟠 Proxied     (dirección "de descarte": nunca se usa, solo activa el proxy)
  AAAA  www  100::    🟠 Proxied

Redirect Rule en viejatienda.com:
  Cuando: (http.host eq "viejatienda.com" or http.host eq "www.viejatienda.com")
  URL:    concat("https://mitienda.com", http.request.uri.path)    301, conservar query

Así cada página vieja lleva a su equivalente nueva y Google transfiere el posicionamiento. Si tienes cientos de dominios o URLs sueltas, usa Bulk Redirects (listas de redirecciones).

Error común: bucles por redirigir en dos lugares

Si el .htaccess manda mitienda.com → www y Cloudflare manda www → mitienda.com, tienes ERR_TOO_MANY_REDIRECTS. Decide un solo lugar y una sola dirección canónica.

3. Page Rules, Configuration Rules y compañía ​

Las Page Rules eran la forma antigua de hacer "si la URL es X, cambia Y" (redirigir, cachear todo, cambiar nivel de seguridad). Cloudflare las está reemplazando por reglas especializadas, más flexibles:

Antes (Page Rule)Ahora
Forwarding URLRedirect Rules
Cache Level, Edge Cache TTLCache Rules
Security Level, SSL, Rocket Loader por rutaConfiguration Rules
Cambiar cabecerasTransform Rules
Cambiar puerto o host de origenOrigin Rules

Ejemplo de Configuration Rule: subir la seguridad y desactivar optimizaciones de JavaScript en el panel de WordPress.

txt
Cuando: (starts_with(http.request.uri.path, "/wp-admin"))
Entonces:
  Security Level: High
  Rocket Loader:  Off
  Email Obfuscation: Off

Si heredas un sitio con Page Rules, funcionan; al crear nuevas, prefiere las reglas modernas.

4. Seguridad ​

WAF: reglas administradas y personalizadas ​

Ruta: Security → WAF (puede aparecer como "Security rules").

  • Managed rules (gratuitas): Cloudflare incluye un conjunto de reglas contra vulnerabilidades de alto impacto (por ejemplo, fallas famosas tipo Log4Shell). Déjalas activas.
  • Custom rules: el plan Free permite unas cuantas. Ejemplos útiles:
txt
Regla 1: proteger el login de WordPress fuera de México
  Cuando:  (http.request.uri.path eq "/wp-login.php" and ip.src.country ne "MX")
  Acción:  Managed Challenge (desafío administrado)

Regla 2: bloquear países a los que no vendes (solo si estás seguro)
  Cuando:  (ip.src.country in {"KP" "IR"})
  Acción:  Block

Regla 3: bloquear acceso a archivos sensibles
  Cuando:  (http.request.uri.path contains "/.env" or http.request.uri.path contains "/.git")
  Acción:  Block

Acciones disponibles: Block (bloquear), Managed Challenge (Cloudflare decide si mostrar verificación; recomendado), JS Challenge, Interactive Challenge, Skip (saltarse otras reglas, útil para tu propia IP o webhooks).

No bloquees a Google ni a tus pagos

Bloquear países o "todo lo que parezca bot" puede impedir que Googlebot indexe tu sitio o que la pasarela de pagos (Stripe, Mercado Pago, PayPal) avise de un cobro por webhook. Usa Managed Challenge en vez de Block cuando dudes, y revisa Security → Events para ver qué estás bloqueando.

Bot Fight Mode ​

Security → Bots → Bot Fight Mode: desafía tráfico de bots conocidos. Es gratis y útil, pero es "todo o nada": no puedes hacer excepciones. Si tienes integraciones (webhooks, apps móviles, monitoreo) que dejan de funcionar al activarlo, apágalo y usa reglas WAF más finas.

Under Attack Mode ​

En Overview (acciones rápidas) o Security → Settings: muestra una verificación de unos segundos a todos los visitantes. Úsalo solo durante un ataque (DDoS a nivel de aplicación, el servidor saturado); luego vuelve al nivel normal. Si lo dejas activo, rompes APIs, webhooks y empeoras la experiencia de usuarios reales.

Rate limiting (limitar frecuencia) ​

Security → WAF → Rate limiting rules. El plan Free incluye una regla básica, suficiente para frenar ataques de fuerza bruta al login:

txt
Nombre: Limitar login
Cuando:  (http.request.uri.path eq "/wp-login.php" and http.request.method eq "POST")
Contar por: IP
Límite: 5 peticiones en 10 segundos
Acción: Block durante 10 segundos

Turnstile: captcha gratis y sin "semáforos" ​

Turnstile reemplaza a reCAPTCHA: verifica que el visitante es humano casi siempre sin que tenga que hacer nada. Es gratis y funciona aunque tu dominio no use Cloudflare.

  1. En el panel de la cuenta: Turnstile → Add widget. Nombre, dominio mitienda.com, modo Managed.
  2. Copia la Site Key (pública) y la Secret Key (privada, va en tu servidor).

En el formulario:

html
<form action="/contacto.php" method="POST">
  <input name="nombre" required>
  <input name="correo" type="email" required>
  <textarea name="mensaje" required></textarea>

  <!-- Aquí aparece el widget de Turnstile -->
  <div class="cf-turnstile" data-sitekey="TU_SITE_KEY"></div>

  <button type="submit">Enviar</button>
</form>

<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>

En el servidor, siempre valida el token (sin esto, el captcha no protege nada):

php
<?php
// contacto.php
$token = $_POST['cf-turnstile-response'] ?? '';

$ch = curl_init('https://challenges.cloudflare.com/turnstile/v0/siteverify');
curl_setopt_array($ch, [
    CURLOPT_POST           => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POSTFIELDS     => http_build_query([
        'secret'   => getenv('TURNSTILE_SECRET'), // nunca escribas la llave en el código
        'response' => $token,
    ]),
]);
$respuesta = json_decode(curl_exec($ch), true);
curl_close($ch);

if (empty($respuesta['success'])) {
    http_response_code(400);
    exit('Verificación fallida. Intenta de nuevo.');
}

// ...aquí envías el correo o guardas el mensaje
echo 'Gracias, te contactaremos pronto.';

5. La IP real del visitante ​

El problema ​

Con nube naranja, quien se conecta a tu servidor es Cloudflare. En tus logs, en WordPress, en tu sistema de comentarios o en tu límite de intentos de login, todas las visitas parecen venir de IPs como 172.68.x.x. Si bloqueas "esa IP", bloqueas a medio país.

Cloudflare agrega la IP original en la cabecera CF-Connecting-IP (y también en X-Forwarded-For).

Solución en el servidor ​

Apache con acceso a la configuración (VPS): módulo mod_remoteip.

apache
# /etc/apache2/conf-available/cloudflare.conf
# Activar con: sudo a2enmod remoteip && sudo a2enconf cloudflare && sudo systemctl reload apache2
RemoteIPHeader CF-Connecting-IP
# Confía en la cabecera SOLO si la petición viene de Cloudflare.
# Lista completa y actualizada: https://www.cloudflare.com/ips/
RemoteIPTrustedProxy 173.245.48.0/20 103.21.244.0/22 103.22.200.0/22 103.31.4.0/22
RemoteIPTrustedProxy 141.101.64.0/18 108.162.192.0/18 190.93.240.0/20 188.114.96.0/20
RemoteIPTrustedProxy 197.234.240.0/22 198.41.128.0/17 162.158.0.0/15 104.16.0.0/13
RemoteIPTrustedProxy 104.24.0.0/14 172.64.0.0/13 131.0.72.0/22

En Nginx se hace con set_real_ip_from y real_ip_header CF-Connecting-IP (ya lo viste en Rendimiento y CDN).

Hosting cPanel compartido: muchos hostings ya tienen mod_remoteip configurado para Cloudflare; pregúntale a soporte. Si no, hazlo en tu código PHP, validando que la petición venga de Cloudflare:

php
<?php
// Devuelve la IP real del visitante solo si la petición vino de un rango de Cloudflare.
function ipEnRango(string $ip, string $cidr): bool {
    [$red, $bits] = explode('/', $cidr);
    $mascara = -1 << (32 - (int) $bits);
    return (ip2long($ip) & $mascara) === (ip2long($red) & $mascara);
}

function ipVisitante(): string {
    $remota = $_SERVER['REMOTE_ADDR'] ?? '';
    $rangosCloudflare = ['173.245.48.0/20', '103.21.244.0/22', '141.101.64.0/18',
        '108.162.192.0/18', '162.158.0.0/15', '104.16.0.0/13', '104.24.0.0/14',
        '172.64.0.0/13', '188.114.96.0/20', '190.93.240.0/20', '197.234.240.0/22',
        '198.41.128.0/17', '131.0.72.0/22', '103.22.200.0/22', '103.31.4.0/22'];

    if (filter_var($remota, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
        foreach ($rangosCloudflare as $rango) {
            if (ipEnRango($remota, $rango) && !empty($_SERVER['HTTP_CF_CONNECTING_IP'])) {
                return $_SERVER['HTTP_CF_CONNECTING_IP'];
            }
        }
    }
    return $remota; // no vino de Cloudflare: no confíes en la cabecera
}

Nunca confíes en CF-Connecting-IP sin validar

Cualquiera puede enviar una cabecera CF-Connecting-IP: 1.2.3.4 si se conecta directo a tu IP de origen. Solo es confiable cuando la conexión viene de un rango oficial de Cloudflare. En Laravel, configura el middleware de proxies de confianza con esos rangos.

6. Analíticas ​

  • Analytics & Logs → Traffic / Tráfico: solicitudes totales, porcentaje servido desde caché, ancho de banda ahorrado, países, códigos de estado (¿muchos 404 o 5xx?).
  • Security → Events / Eventos: qué se bloqueó o desafió, con qué regla, desde qué país e IP. Es lo primero que revisas cuando "un cliente no puede entrar".
  • Web Analytics: estadísticas de visitas sin cookies (respetuosas de la privacidad), gratis. Se activa con un clic si usas el proxy o con un pequeño script si no.

Las analíticas de Cloudflare cuentan peticiones, no personas: no las compares 1 a 1 con Google Analytics.

7. Cloudflare Pages y Workers (introducción) ​

  • Pages: hosting gratuito para sitios estáticos y frameworks (Astro, Vite, VitePress, Next.js con adaptador). Conectas tu repositorio de GitHub, defines el comando de compilación y la carpeta de salida, y cada git push publica. Luego en Custom domains agregas mitienda.com y Cloudflare crea los registros solo (porque ya administra tu DNS).
  • Workers: código JavaScript que corre en los servidores de Cloudflare, antes de llegar a tu origen. Sirve para APIs pequeñas, redirecciones complejas, pruebas A/B, cabeceras. El plan gratuito incluye un número generoso de peticiones diarias.

Un Worker mínimo:

js
// Responde directamente desde el borde de Cloudflare, sin servidor propio
export default {
  async fetch(request) {
    const url = new URL(request.url);
    if (url.pathname === '/salud') {
      return new Response('ok', { status: 200 });
    }
    return fetch(request); // todo lo demás pasa al origen normal
  },
};

8. Tokens de API ​

Si automatizas (Certbot con DNS-01, scripts de despliegue, Terraform), no uses la Global API Key: da acceso total a toda tu cuenta. Crea un API Token con permisos mínimos:

  1. Ícono de perfil → My Profile → API Tokens → Create Token.
  2. Plantilla Edit zone DNS.
  3. Zone Resources: Include → Specific zone → mitienda.com.
  4. Opcional: filtrar por IP del servidor y fecha de expiración.
  5. Copia el token (se muestra una vez).
bash
export CF_TOKEN="pega_aqui_tu_token"

# Verificar que el token funciona
curl -s https://api.cloudflare.com/client/v4/user/tokens/verify \
  -H "Authorization: Bearer $CF_TOKEN"

# Obtener el ID de la zona
curl -s "https://api.cloudflare.com/client/v4/zones?name=mitienda.com" \
  -H "Authorization: Bearer $CF_TOKEN"

# Crear un registro A proxeado (ttl 1 = automático)
curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records" \
  -H "Authorization: Bearer $CF_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{"type":"A","name":"app","content":"198.51.100.20","proxied":true,"ttl":1}'

9. DNSSEC con un clic ​

DNSSEC firma digitalmente las respuestas DNS para que nadie pueda falsificarlas en el camino (envenenamiento de caché). Es como un sello holográfico en cada respuesta.

  1. Cloudflare: DNS → Settings → DNSSEC → Enable.
  2. Te muestra un registro DS (Key Tag, Algoritmo 13, Digest Type 2, Digest).
  3. Cópialo en el registrador (sección DNSSEC). Si tu dominio está registrado en Cloudflare Registrar, se hace solo.
  4. En unas horas el estado cambia a Success / Activo.

Antes de cambiar de nameservers, quita DNSSEC

Si mueves el dominio fuera de Cloudflare con el DS todavía en el registrador, el dominio deja de resolver en todos los resolvers que validan (Google, Cloudflare, muchos ISP). Orden correcto: quitar DS en registrador → esperar → desactivar DNSSEC en Cloudflare → cambiar nameservers.

10. Cloudflare Registrar ​

Cloudflare también vende y renueva dominios a precio de costo (lo que cobra el registro del TLD, sin margen), sin "precio de promoción el primer año" ni cargos ocultos.

  • Requisito: el dominio debe usar los nameservers de Cloudflare.
  • No soporta todas las terminaciones (por ejemplo, .mx no está disponible: se queda en Akky u otro registrador acreditado).
  • Para transferir: desbloquea el dominio en el registrador actual, pide el código de autorización (EPP), y en Cloudflare ve a Domain Registration → Transfer Domains. Se cobra un año de renovación (que se suma al tiempo que ya tenías).
  • Un dominio no puede transferirse en los 60 días siguientes a su registro o a una transferencia previa.

11. Zero Trust y túneles (introducción) ​

Cloudflare Tunnel (cloudflared) conecta tu servidor con Cloudflare desde dentro hacia fuera: no necesitas abrir puertos ni exponer la IP. Ideal para un servidor en casa, una Raspberry Pi o un VPS donde quieres cerrar todo el firewall.

bash
# Prueba rápida (sin cuenta): publica tu localhost:3000 en una URL temporal *.trycloudflare.com
cloudflared tunnel --url http://localhost:3000

Para algo permanente, crea el túnel desde el panel (Zero Trust → Networks → Tunnels → Create a tunnel): te da un comando con un token para instalar cloudflared como servicio, y ahí mismo asignas app.mitienda.com → http://localhost:3000. Cloudflare crea el registro DNS (un CNAME a <id>.cfargotunnel.com) automáticamente.

Cloudflare Access (también en Zero Trust) pone una puerta de inicio de sesión delante de una URL: por ejemplo, admin.mitienda.com solo abre para correos @mitienda.com que reciban un código. El plan gratuito cubre equipos pequeños.

Ejercicios ​

  1. Después de un despliegue, https://mitienda.com/css/estilos.css sigue mostrando la versión anterior. Escribe el comando para comprobar si viene de caché y explica cómo purgar solo ese archivo.
  2. Escribe la Redirect Rule para mandar tienda-vieja.mx y www.tienda-vieja.mx a https://mitienda.com conservando la ruta. ¿Qué registros DNS necesita tienda-vieja.mx?
  3. Tu formulario de contacto recibe 200 mensajes de spam al día. Propón dos medidas con Cloudflare (gratis).
  4. En los logs de WordPress todos los intentos de login vienen de 172.70.x.x y un plugin de seguridad bloqueó esa IP: ahora nadie puede iniciar sesión. ¿Qué pasó y cómo se corrige?
  5. Vas a mudar mitienda.com de Cloudflare a otro proveedor DNS y tiene DNSSEC activo. Escribe el orden de pasos.
Ver solución
bash
curl -sI https://mitienda.com/css/estilos.css | grep -i cf-cache-status

Si dice HIT, viene de caché. Caching → Configuration → Purge Cache → Custom Purge y pega https://mitienda.com/css/estilos.css. A futuro, usa nombres con versión (estilos.v2.css o estilos.css?v=2).

  1. DNS de tienda-vieja.mx (zona propia en Cloudflare):
txt
AAAA  @    100::   Proxied
AAAA  www  100::   Proxied

Regla:

txt
Cuando: (http.host eq "tienda-vieja.mx" or http.host eq "www.tienda-vieja.mx")
URL dinámica: concat("https://mitienda.com", http.request.uri.path)
Código 301, conservar query string
  1. Agregar Turnstile al formulario (y validar el token en el servidor) y una rate limiting rule para POST a /contacto.php. Opcional: regla WAF con Managed Challenge para países de donde no esperas clientes.
  2. Con el proxy, el servidor ve la IP de Cloudflare y no la del visitante; el plugin bloqueó un nodo de Cloudflare. Desbloquea esa IP y restaura la IP real: mod_remoteip con CF-Connecting-IP y los rangos oficiales (o pide al hosting que lo active), o configura el plugin para leer CF-Connecting-IP solo desde rangos de Cloudflare.
  3. (1) Quitar el registro DS en el registrador. (2) Esperar a que expire (al menos el TTL del DS; en la práctica 24–48 h). (3) Desactivar DNSSEC en Cloudflare. (4) Copiar la zona al nuevo proveedor. (5) Cambiar nameservers. (6) Cuando esté estable, activar DNSSEC en el nuevo proveedor y poner su DS en el registrador.

Resumen ​

  • Cloudflare cachea estáticos por defecto, no HTML. Mira cf-cache-status, purga por URL y usa Cache Rules con cuidado.
  • Redirect Rules resuelven www→raíz y dominio viejo→nuevo sin tocar el servidor (requieren nube naranja).
  • Page Rules son legado: usa Redirect, Cache, Configuration, Transform y Origin Rules.
  • Seguridad gratis: WAF administrado + reglas propias, Bot Fight Mode, Under Attack solo en emergencias, rate limiting y Turnstile.
  • Restaura la IP real con CF-Connecting-IP, validando que venga de Cloudflare.
  • Pages/Workers para sitios y código en el borde; API Tokens con permisos mínimos.
  • DNSSEC en un clic (y quítalo antes de mudarte); Registrar a precio de costo; Tunnel sin abrir puertos.
  • Siguiente: Escenarios reales.

Academia Web — aprende, copia y construye.