Saltar al contenido
cloud-webv0.1.0
Documentación

El sitio de Zonda Cloud (zondacloud.com)

El sitio público de Zonda Cloud es un directorio de archivos planos, apps/zondacloud/ (HTML y CSS, sin construcción y sin dependencias; su único JavaScript es session.js, de 1 KB y del mismo origen, que reconoce la sesión de la consola; los bloques JSON-LD son datos, no código). Es independiente del sitio de cloud-web (cloudweb.zondacloud.com: instaladores y documentación), que no cambia.

Producción corre en Cloudflare, como un Worker de solo assets (sin código de Worker): la zona zondacloud.com ya está ahí, así que el DNS se crea solo y el sitio no depende de ninguna máquina propia. La configuración está en deploy/zondacloud/wrangler.jsonc (fuera del directorio del sitio, para que no se publique con él). Las cabeceras de seguridad y la caché están en apps/zondacloud/_headers.

Desplegarlo

Opción 1 (recomendada): Workers Builds, sin credenciales en el CI

Cloudflare conecta el repositorio de GitLab (gitlab.com; las instancias autoalojadas no se admiten) y despliega en cada push.

  1. En el panel de Cloudflare: Workers & Pages → Create → Import a repository y elegí cloud-web1/cloud-web.
  2. Configuración del build (Settings → Build):
    • Root directory: vacío (la raíz del repositorio).
    • Build command: vacío. El sitio no se construye; un build de la raíz correría todo el monorepo para nada.
    • Deploy command: npx wrangler deploy --config deploy/zondacloud/wrangler.jsonc. El --config explícito es necesario: sin él, wrangler corre en la raíz de un workspace y falla con "application detection logic has been run in the root of a workspace".
  3. En Build watch paths limitá el despliegue a apps/zondacloud/* y deploy/zondacloud/* para que los demás pushes del repositorio no lo disparen.
  4. Primer despliegue: Cloudflare enlaza zondacloud.com y www.zondacloud.com (crea los registros DNS). Si ya hay un registro con ese nombre, borralo antes: el enlace no pisa registros.

Opción 2: wrangler deploy desde el CI

Sirve si preferís controlar cuándo se despliega. Hace falta un token de API de Cloudflare con permiso de editar Workers (Account → Workers Scripts → Edit) y el ID de la cuenta, cargados en Settings → CI/CD → Variables como CLOUDFLARE_API_TOKEN y CLOUDFLARE_ACCOUNT_ID, protegidas y enmascaradas (nunca en el repositorio). El job es una línea sobre una imagen de Node:

npx wrangler@4 deploy --config deploy/zondacloud/wrangler.jsonc

Para probar la configuración sin desplegar ni usar credenciales: npx wrangler@4 deploy --dry-run --config deploy/zondacloud/wrangler.jsonc.

www al dominio sin www

www.zondacloud.com queda enlazado al mismo Worker, y la URL canónica de la página es https://zondacloud.com/. Para que www redirija, creá una regla en la zona (Rules → Redirect Rules → Create rule → Single Redirect):

  • Cuando: el nombre de host es www.zondacloud.com.
  • Entonces: redirección dinámica a concat("https://zondacloud.com", http.request.uri.path) conservando la cadena de consulta, código 301.

(_redirects no distingue por nombre de host, por eso va como regla de la zona.)

Comprobar

curl -sI https://zondacloud.com | head -5          # 200, y las cabeceras de _headers (content-security-policy, x-content-type-options)
curl -sI https://www.zondacloud.com | head -3      # 301 hacia https://zondacloud.com/
curl -sI https://cloudweb.zondacloud.com/install.sh | head -1   # el instalador de cloud-web sigue donde estaba

La landing reconoce la sesión de la consola

El logo de la consola lleva a https://<dominio-base>/ (la landing) y la landing, a su vez, sabe si quien la visita ya ingresó: «Ingresar» pasa a «Mi consola» / «Ir a la consola», aparece «Hola, » y se oculta la nota «Ingresás con tu cuenta…». Sin sesión, sin conexión o ante cualquier error, la página queda como estaba (mejora progresiva).

Cómo funciona: apps/zondacloud/session.js hace una petición GET https://console.zondacloud.com/api/whoami con credenciales. La cookie de sesión es de la consola (console.zondacloud.com, sin Domain, HttpOnly, SameSite=Lax): como la landing y la consola son del mismo sitio (mismo dominio registrable), el navegador la envía en esa petición, y la consola contesta {"authenticated": true, "name": "Ana"} y nada más (ni rol, ni configuración). Para que la landing pueda leer la respuesta, esa ruta (y sólo esa) manda CORS con credenciales exclusivamente para https://<dominio-base> y https://www.<dominio-base>; nunca *, y no a los subdominios.

Por qué no se comparte la cookie con todo el dominio (Domain=zondacloud.com, que sería la forma «fácil»): las apps de los usuarios viven en <app>.zondacloud.com, así que recibirían la sesión de cualquiera que las visite, incluida la de un administrador. La cookie se queda de la consola y la landing pregunta con CORS. Por la misma razón whoami no se abre a *.zondacloud.com: una app de un usuario no puede leer si su visitante tiene sesión.

La política de seguridad del sitio (_headers) admite por eso script-src 'self' y connect-src https://console.zondacloud.com, y nada más. scripts/check-zondacloud.mjs verifica que la CSP no se abra a otros orígenes, que session.js sólo hable con /api/whoami, no use HTML dinámico ni almacenamiento y no mande cabeceras propias (para no necesitar preflight), y prueba su comportamiento en una página real: con sesión, sin sesión, ante errores y con un nombre malicioso. En una instancia sin dominio base no hay landing y la ruta no manda CORS.

Para otra instalación: la URL de la consola está escrita en session.js y en _headers (console.zondacloud.com); cámbiala en los dos lugares y en la comprobación.

SEO y GEO (que te encuentren los buscadores y que los asistentes de IA te citen bien)

Qué tiene el sitio y para qué:

  • Cinco páginas con contenido real: la portada y cuatro guías (/sitios-estaticos/, /contenedores-dockerfile/, /dominio-propio/, /ramas/). Una sola página no alcanza para posicionarse por preguntas concretas («cómo publico un sitio de Vite») ni para que un asistente tenga de dónde citar. Cada guía abre con la respuesta en una frase y usa los nombres exactos de las cosas (frameworks, variables, registros DNS).
  • Datos estructurados (JSON-LD): Organization, WebSite, SoftwareApplication y FAQPage en la portada; TechArticle y BreadcrumbList en las guías. Las preguntas frecuentes marcadas son las mismas que se ven en la página (la comprobación lo exige). No llevan precios, ofertas ni valoraciones: el producto no los ofrece.
  • Metadatos: título y descripción únicos por página, canonical, hreflang (es y x-default), Open Graph y Twitter completos, og:locale es_AR.
  • robots.txt abierto, con los rastreadores de IA y de búsqueda nombrados de forma explícita, y el sitemap. sitemap.xml con lastmod. llms.txt: resumen citable y enlaces a las guías, para los asistentes que lo leen.
  • 404.html con noindex y not_found_handling: "404-page" en el Worker: una dirección que no existe responde 404 en lugar de servir la portada con 200 (los buscadores lo penalizan).

Lo que no hay a propósito: precios, planes, «gratis», SLA, regiones, testimonios ni promesas de registro abierto (la comprobación los rechaza), y nada que el producto no haga hoy. Es lo que un asistente va a repetir como cierto.

Después de publicar, una sola vez (esto no se puede hacer desde el repositorio):

  1. Google Search Console: agregá la propiedad de dominio zondacloud.com (verificación por registro TXT en Cloudflare) y enviá https://zondacloud.com/sitemap.xml. Pedí la indexación de la portada y de las cuatro guías.
  2. Bing Webmaster Tools: importá la propiedad desde Search Console. Bing alimenta a varios asistentes de IA.
  3. Redirección de www al dominio sin www (ver arriba): sin ella hay dos sitios idénticos y se reparte la señal.
  4. Comprobá los datos estructurados con la Prueba de resultados enriquecidos de Google (https://search.google.com/test/rich-results) pegando la dirección de la portada.

Cómo mantenerlo: al cambiar una guía, actualizá su <lastmod> en sitemap.xml y el dateModified de su JSON-LD; si agregás una guía, sumala a la portada (#guias), a sitemap.xml y a llms.txt (la comprobación avisa si falta alguna). Si algo del producto cambia (por ejemplo, el registro pasa a ser abierto), corregí primero el texto y la lista de frases prohibidas de scripts/check-zondacloud.mjs.

Antes de publicar un cambio del sitio

node scripts/check-zondacloud.mjs      # axe, contraste AA, metadatos, SEO/GEO (JSON-LD, FAQ, sitemap, robots, llms.txt, enlaces), cabeceras, contenido veraz, sin scripts ni recursos remotos, peso
scripts/zondacloud/og.sh               # si cambió el titular: vuelve a generar apps/zondacloud/og.png (Chromium + ImageMagick o Pillow)

El sitio solo puede prometer lo que el producto hace hoy: la comprobación rechaza precios, planes, niveles de servicio, regiones y testimonios.