Mantengo la infraestructura de un grupo de marketing con un ecosistema de 53 sitios: 53 zonas Cloudflare, un servidor de origen con decenas de dominios y 11 Workers en el edge. A esa escala el panel de Cloudflare deja de ser una herramienta y se convierte en un riesgo: un clic fuera de contexto o una zona editada a mano de más, y un sitio de producción cae. Acá detallo el trío que sostiene esa operación: los Workers que me resuelven problemas imposibles de arreglar en el origen, el estándar SSL que uso en cada zona, y la automatización por API que me permite auditar lo que no puedo revisar a mano.
Cincuenta y tres zonas no se administran con el panel
Cuando llevé el inventario completo de la cuenta, la primera decisión fue simple: toda consulta por repetición se hace por API, no por pantalla. Tres preguntas que en el panel son 53 clics, vía REST son un loop de dos minutos:
#!/bin/bash
# Auditar modo SSL y Always Use HTTPS en todas las zonas de la cuenta
TOKEN=$CLOUDFLARE_API_TOKEN
page=1
while :; do
zonas=$(curl -s --get "https://api.cloudflare.com/client/v4/zones" \
-H "Authorization: Bearer $TOKEN" \
-d "per_page=50" -d "page=$page")
count=$(echo "$zonas" | python3 -c "import sys,json; print(len(json.load(sys.stdin)['result']))")
echo "$zonas" | python3 -c "
import sys, json
for z in json.load(sys.stdin)['result']:
print(z['name'])" >> /tmp/zonas.txt
[ "$count" -lt 50 ] && break
page=$((page+1))
done
# Para cada zona: modo SSL + redirect HTTPS activo
while read -r name; do
id=$(curl -s -H "Authorization: Bearer $TOKEN" \
"https://api.cloudflare.com/client/v4/zones?name=$name" \
| python3 -c "import sys,json; print(json.load(sys.stdin)['result'][0]['id'])")
ssl=$(curl -s -H "Authorization: Bearer $TOKEN" \
"https://api.cloudflare.com/client/v4/zones/$id/settings/ssl" \
| python3 -c "import sys,json; print(json.load(sys.stdin)['result']['value'])")
echo "$name → $ssl"
done < /tmp/zonas.txt Con ese patrón pude confirmar métricas concretas: 53 de 53 zonas con Always Use HTTPS activo y una foto instantánea de qué zonas estaban en Full contra Full (Strict). Sin API, esa auditoría existiría como "creo que lo revisé la semana pasada". Con API, existe como un dato refrescable en minutos y como insumo de un cron que lo verifica solo.
El patrón Worker que más repetí: proxy de e-commerce en el edge
De los 11 Workers en la cuenta, el patrón que uso en producción en varios sitios es el mismo: reencaminar una ruta propia del dominio hacia un e-commerce de terceros. El problema concreto: integrar el menú de la plataforma (Dispense, en los sitios de retail) en misitio.com/menu. Con rewriting de URL tradicional en el origen, el carrito se rompe: la plataforma responde con redirecciones absolutas hacia su propio dominio base y el visitante termina fuera del sitio.
La solución fue un Worker que en el edge reescribe el destino manteniendo la ruta original y fija tres headers que el e-commerce exige:
const dispenseHostname = "menus.dispenseapp.com";
const storeMenus = [
{ menuPath: '/menu', storeId: '48709' }, // storeId anonimizado
];
addEventListener("fetch", (event) => {
event.respondWith(handleRequest(event.request));
});
const matchPath = (menuPath, reqPath) => {
// match por prefijo: /menu y /menu/cualquier-cosa van al mismo menú
const menuPieces = menuPath.split("/");
const reqPieces = reqPath.split("/");
for (let i = 0; i < menuPieces.length; i++) {
if (menuPieces[i] !== reqPieces[i]) return false;
}
return true;
};
async function handleRequest(request) {
const parsedUrl = new URL(request.url);
for (const storeMenu of storeMenus) {
if (matchPath(storeMenu.menuPath, parsedUrl.pathname)) {
const originUrl = parsedUrl.toString()
.replace(parsedUrl.hostname, dispenseHostname);
const newRequest = new Request(originUrl, {
method: request.method,
headers: request.headers,
body: request.body,
});
newRequest.headers.set("dispense-store-id", storeMenu.storeId);
newRequest.headers.set("dispense-menu-path", storeMenu.menuPath);
newRequest.headers.set("x-forwarded-host", parsedUrl.hostname);
return fetch(newRequest);
}
}
return fetch(request);
} Los tres headers son el corazón del patrón: dispense-store-id identifica la tienda, dispense-menu-path le dice a la plataforma qué menú renderizar y x-forwarded-host preserva el dominio original para que sus redirecciones internas no nos expulsen del sitio. Sin el tercero, el carrito casi siempre termina rebotando al dominio del e-commerce y ahí el cliente ve una URL que no es la suya.
El otro detalle que solo se aprende desplegándolo: la sintaxis de la route. El asterisco va pegado al dominio, sin punto — *misitio.com/menu* — y el DNS del dominio debe tener el proxy activado (la nube naranja). Un Worker con la nube gris nunca dispara: no es un error, es silencio, y los silencios son lo peor de debuggear. Cada vez que conecto un sitio nuevo al patrón, la checklist es: route bien escrita, nube naranja, curl contra la ruta con -I y revisar los cf-ray hasta ver el Worker en la cadena.
SSL por capas: Full no es Full (Strict)
El estándar que aplico en cada zona de CloudPanel es doble: Origin CA de 15 años en el origen + modo Full (Strict) en la zona. El razonamiento: en esos servidores el firewall bloquea el flujo de Let's Encrypt, así que renovar certificados de origen era una tarea manual en crisis constante. La Origin CA de Cloudflare elimina esa rotación: genero el certificado una vez, lo instalo y vale 15 años — siempre que el tráfico pase por Cloudflare, que en este ecosistema es la regla.
El despliegue no fue un switch global. Empecé con los 7 sitios más críticos migrados a Full (Strict) y el resto quedó transitoriamente en Full mientras completaba la migración. Full sin Strict valida que Cloudflare hable HTTPS con el origen, pero no exige que el certificado del origen sea válido y de una CA confiable: es la puerta a un MITM entre Cloudflare y el servidor. La auditoría por API que mostré arriba es lo que me deja ver el estado exacto (7 migradas, el resto en tránsito) sin abrir 53 pestañas de dashboard.
Observabilidad: los Workers también grafican
Un día vimos un pico de tráfico en los sitios de retail desde las 9 AM. En la observabilidad de Workers, el proxy del e-commerce y su réplica para otro storefront marcaban 2x y 2.5x su tráfico normal mientras el sitio de origen, un WordPress en AWS, se veía estable. El edge estaba absorbiendo el pico sin tocar el origen: el Worker resuelve las peticiones sin cargar a los backends saturables. Ese día convertí una hipótesis en una medición: el patrón de proxy en edge no es solo conveniencia, es un piso de resiliencia.
Resultados
- 53/53 zonas con Always Use HTTPS verificado por API, no por memoria.
- 11 Workers en producción, todos centrados en el mismo patrón de reencaminamiento en edge, y cero incidentes de carrito roto desde que fijo los 3 headers.
- 7/53 zonas en Full (Strict) en el primer corte; roadmap de migración con Origin CA de 15 años para el resto, eliminando la rotación manual de certificados.
- 2x - 2.5x de pico absorbido en el edge sin tocar el origen, medido con la observabilidad del propio Worker.
- El tiempo de una auditoría completa de modos SSL bajó de "horas a mano en algún día con suerte" a un script de 2 minutos.
Si administras más de cinco zonas Cloudflare, mi consejo directo: construye primero la auditoría por API, después el patrón Worker que más repitas, y recién al final toques el panel. El panel es para excepciones; la API es para operaciones.
Más de cómo opero esta infraestructura en danieltini.dev y el código de mis proyectos en GitHub.