--- title: "Cómo configurar Cloudflare CDN para un VPS con Nginx" description: "Pon tu VPS con Nginx detrás de Cloudflare: DNS con proxy, SSL Full (strict) con Let's Encrypt, IP real del visitante, reglas de caché, WAF y firewall de origen." category: "Integración Cloud" language: es source: https://cubepath.com/es/docs/integración-cloud/configuracion-de-cloudflare-cdn-para-vps updated: 2026-09-25 --- # Cómo configurar Cloudflare CDN para un VPS con Nginx Cloudflare es un proxy inverso con CDN que se coloca entre los visitantes y tu servidor: sirve el contenido estático desde su red, filtra ataques y oculta la IP de origen. En este tutorial pondrás detrás de Cloudflare un sitio servido por Nginx en Ubuntu 24.04, con cifrado de extremo a extremo en modo Full (strict), la IP real del visitante en los logs, una regla de caché, una regla de WAF y el firewall del servidor abierto solo a Cloudflare. Todo funciona con el plan gratuito. ## Requisitos previos Para seguir esta guía necesitas: - Un VPS con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath, con un usuario no root con privilegios `sudo`. - Nginx instalado y sirviendo tu sitio en el puerto 80 con un bloque `server` para `your_domain` y `www.your_domain`. - UFW activo con SSH permitido (`sudo ufw allow OpenSSH`). - Un dominio propio (`your_domain`) y acceso al panel de su registrador para cambiar los servidores de nombres. - Una cuenta gratuita de Cloudflare. En los ejemplos, `your_server_ip` es la IP pública del VPS. ## Paso 1: Añadir el dominio a Cloudflare En el panel de Cloudflare, añade tu dominio con la opción de incorporar un dominio (**Add a domain**), elige el plan Free y deja que Cloudflare importe los registros DNS existentes. Revisa la lista importada en **DNS > Records** y asegúrate de que existen estos registros: | Tipo | Nombre | Contenido | Estado del proxy | |------|--------|-----------|------------------| | A | `@` | `your_server_ip` | Solo DNS (nube gris), de momento | | CNAME | `www` | `your_domain` | Solo DNS (nube gris), de momento | | MX | `@` | tu servidor de correo | Siempre solo DNS | Deja el proxy desactivado hasta tener el certificado en el paso 2. Los registros de correo (MX y el A o CNAME al que apuntan) nunca deben ir por el proxy, porque Cloudflare solo reenvía tráfico HTTP y HTTPS. Cloudflare te asignará dos servidores de nombres, del tipo `xxx.ns.cloudflare.com`. Sustituye los actuales por esos dos en el panel de tu registrador. Cuando el cambio se haya propagado, Cloudflare mostrará el dominio como activo. Puedes comprobarlo desde el servidor: ```bash dig +short NS your_domain ``` ```output ava.ns.cloudflare.com. cole.ns.cloudflare.com. ``` La propagación suele tardar menos de una hora, aunque puede llegar a 24 horas. ## Paso 2: Obtener un certificado válido en el origen El modo SSL recomendado, Full (strict), exige que el servidor tenga un certificado válido para el dominio. Obtén uno de Let's Encrypt mientras los registros siguen en modo solo DNS, para que la validación HTTP llegue directamente a Nginx: ```bash sudo apt update sudo apt install certbot python3-certbot-nginx sudo ufw allow 'Nginx Full' sudo certbot --nginx -d your_domain -d www.your_domain ``` Certbot modifica el bloque `server` de Nginx, añade la escucha en el puerto 443 y configura la renovación automática con un timer de systemd. Comprueba que la renovación funciona: ```bash sudo certbot renew --dry-run ``` ```output Congratulations, all simulated renewals succeeded: /etc/letsencrypt/live/your_domain/fullchain.pem (success) ``` Las renovaciones posteriores seguirán funcionando con el proxy activo, porque Cloudflare reenvía las peticiones a `/.well-known/acme-challenge/` al origen. ## Paso 3: Activar el proxy y el modo Full (strict) Vuelve a **DNS > Records** y activa el proxy (nube naranja) en los registros `@` y `www`. Después, en **SSL/TLS > Overview**, configura el modo de cifrado en **Full (strict)**. Los modos disponibles son: | Modo | Visitante a Cloudflare | Cloudflare a origen | Uso | |------|-----------------------|---------------------|-----| | Flexible | HTTPS | HTTP sin cifrar | No recomendado; causa bucles de redirección | | Full | HTTPS | HTTPS sin validar el certificado | Solo con certificado autofirmado | | Full (strict) | HTTPS | HTTPS con certificado válido | Recomendado | En **SSL/TLS > Edge Certificates**, activa **Always Use HTTPS** para que Cloudflare redirija HTTP a HTTPS en su red. Comprueba que el dominio ya resuelve a IPs de Cloudflare y que las respuestas pasan por su proxy: ```bash dig +short your_domain curl -sI https://your_domain | grep -iE '^(server|cf-ray|cf-cache-status)' ``` ```output 104.21.48.77 172.67.155.12 server: cloudflare cf-ray: 8c1f2a3b4d5e6f70-MAD cf-cache-status: DYNAMIC ``` `DYNAMIC` significa que la respuesta (HTML) no se ha cacheado, que es el comportamiento por defecto. ## Paso 4: Registrar la IP real del visitante en Nginx Con el proxy activo, Nginx ve la IP de Cloudflare en cada conexión. Cloudflare envía la IP original en la cabecera `CF-Connecting-IP`, y el módulo `realip` de Nginx puede usarla siempre que la petición venga de un rango de Cloudflare. Genera el archivo de configuración a partir de las listas oficiales de rangos: ```bash { for ip in $(curl -fsS https://www.cloudflare.com/ips-v4) $(curl -fsS https://www.cloudflare.com/ips-v6); do echo "set_real_ip_from $ip;" done echo "real_ip_header CF-Connecting-IP;" } | sudo tee /etc/nginx/conf.d/cloudflare-realip.conf ``` ```output set_real_ip_from 173.245.48.0/20; set_real_ip_from 103.21.244.0/22; ... set_real_ip_from 2c0f:f248::/32; real_ip_header CF-Connecting-IP; ``` Ubuntu incluye `/etc/nginx/conf.d/*.conf` dentro del bloque `http`, así que la configuración se aplica a todos los sitios. Valida y recarga Nginx: ```bash sudo nginx -t sudo systemctl reload nginx ``` Visita el sitio desde tu navegador y revisa el log de acceso: ```bash sudo tail -n 3 /var/log/nginx/access.log ``` La primera columna debe mostrar tu IP pública, no una IP de Cloudflare como `172.68.x.x` o `162.158.x.x`. ## Paso 5: Cachear los recursos estáticos Por defecto Cloudflare cachea por extensión (imágenes, CSS, JavaScript, fuentes) y nunca cachea HTML. Para contenido estático con nombres versionados puedes alargar el tiempo en la red de Cloudflare con una regla de caché. En la sección **Cache Rules** del panel, crea una regla: - **Nombre**: `estaticos`. - **Condición**: campo **URI Path**, operador **starts with**, valor `/static/`. - **Cache eligibility**: **Eligible for cache**. - **Edge TTL**: ignorar la cabecera de caché del origen y usar 1 mes. Crea una segunda regla con **Bypass cache** para las rutas que nunca deben cachearse, como `/wp-admin/` o `/api/`. Comprueba el resultado pidiendo dos veces el mismo recurso: ```bash curl -sI https://your_domain/static/app.css | grep -i cf-cache-status curl -sI https://your_domain/static/app.css | grep -i cf-cache-status ``` ```output cf-cache-status: MISS cf-cache-status: HIT ``` Tras desplegar cambios, purga la caché desde **Caching > Configuration > Purge Cache**, o por API con un token que tenga el permiso **Zone > Cache Purge**. El ID de la zona aparece en la página **Overview** del dominio: ```bash curl -X POST "https://api.cloudflare.com/client/v4/zones/your_zone_id/purge_cache" \ -H "Authorization: Bearer your_api_token" \ -H "Content-Type: application/json" \ --data '{"files":["https://your_domain/static/app.css"]}' ``` La respuesta incluye `"success": true`. Usa `{"purge_everything":true}` como cuerpo para vaciar toda la zona. ## Paso 6: Proteger el sitio con el WAF En **Security > WAF > Custom rules** puedes bloquear tráfico antes de que llegue al VPS; el plan gratuito permite cinco reglas personalizadas. Por ejemplo, para permitir el acceso a `/wp-admin` solo desde la IP de tu oficina, crea una regla con acción **Block** y esta expresión (editor de expresiones): ```text (starts_with(http.request.uri.path, "/wp-admin") and not ip.src in {203.0.113.10}) ``` Sustituye `203.0.113.10` por tu IP. Otras expresiones útiles son `(ip.src.country in {"XX" "YY"})` para bloquear países o `(http.user_agent contains "sqlmap")` para herramientas de escaneo conocidas. En la sección de bots activa **Bot Fight Mode**, incluido en el plan gratuito. Si sufres un ataque de capa 7 en curso, activa **I'm Under Attack Mode** desde la página de resumen del dominio: Cloudflare mostrará un desafío a cada visitante hasta que lo desactives. Comprueba la regla del WAF desde una IP distinta a la permitida: ```bash curl -s -o /dev/null -w '%{http_code}\n' https://your_domain/wp-admin/ ``` ```output 403 ``` El evento aparece en **Security > Events** con el nombre de la regla. ## Paso 7: Aceptar solo tráfico web de Cloudflare Aunque el DNS apunte a Cloudflare, cualquiera que conozca `your_server_ip` puede atacar el servidor directamente y saltarse el WAF. Permite los puertos 80 y 443 solo desde los rangos de Cloudflare: ```bash for ip in $(curl -fsS https://www.cloudflare.com/ips-v4) $(curl -fsS https://www.cloudflare.com/ips-v6); do sudo ufw allow proto tcp from "$ip" to any port 80,443 comment 'Cloudflare' done ``` Elimina después la regla que abría los puertos web a todo el mundo y revisa el resultado: ```bash sudo ufw delete allow 'Nginx Full' sudo ufw status numbered ``` Debes ver `OpenSSH` permitido desde cualquier origen y los puertos `80,443/tcp` solo desde los rangos de Cloudflare. Comprueba que el origen ya no responde de forma directa desde otra máquina: ```bash curl -m 5 -sI http://your_server_ip ``` El comando debe agotar el tiempo de espera, mientras que `https://your_domain` sigue funcionando. Cloudflare cambia sus rangos con muy poca frecuencia; si publica rangos nuevos, repite este paso y el paso 4. ## Solución de problemas **Error 521 (Web server is down)**: Cloudflare no consigue conectar con el origen. Comprueba `sudo systemctl status nginx` y que UFW permite los rangos de Cloudflare en los puertos 80 y 443. **Error 522 (Connection timed out)**: la conexión se abre pero no se completa, normalmente por un firewall externo o porque el registro A apunta a una IP equivocada. Revisa el registro en **DNS > Records**. **Error 526 (Invalid SSL certificate)**: el modo es Full (strict) y el certificado del origen está caducado o no cubre el nombre. Compruébalo en el servidor con `sudo certbot certificates`. **ERR_TOO_MANY_REDIRECTS**: el modo SSL está en Flexible y Nginx redirige a HTTPS. Cloudflare pide la página por HTTP, Nginx responde con una redirección a HTTPS, y el ciclo se repite. Cambia el modo a Full (strict). **Los cambios no se ven**: el recurso está en la caché de Cloudflare o del navegador. Purga la URL como en el paso 5. ## Conclusión Tu sitio se sirve ahora a través de Cloudflare con HTTPS verificado en los dos tramos, los estáticos se cachean en su red, el WAF filtra el tráfico no deseado y el VPS solo acepta conexiones web de Cloudflare. Como siguientes pasos puedes activar Authenticated Origin Pulls para que Nginx exija un certificado de cliente de Cloudflare, sustituir el certificado de Let's Encrypt por un certificado Cloudflare Origin CA de larga duración, o exponer servicios internos sin abrir puertos con Cloudflare Tunnel.