Cloudflare Workers
Redirige las solicitudes de /docs a través de un Cloudflare Worker a tu sitio de documentación Jamdesk. Configuración del Worker, rutas y caché.
Un Cloudflare Worker intercepta las solicitudes en /docs de tu dominio, las reescribe hacia tu subdominio de Jamdesk y devuelve la respuesta, todo en el edge sin necesidad de un servidor de origen. Puedes generar el Worker automáticamente con npx jamdesk deploy-proxy cloudflare o configurarlo manualmente a continuación.
Cómo funciona
El Worker reenvía las solicitudes a tu subdominio de Jamdesk y envía tu dominio en el encabezado X-Jamdesk-Forwarded-Host, que Jamdesk usa para verificar el dominio y aplicar su configuración. Es una configuración única: si más adelante cambias tu dominio o la configuración en el dashboard, no es necesario actualizar el Worker.
Requisitos previos
- Una cuenta de Cloudflare con tu dominio configurado
- Wrangler CLI v3.0+ instalado
- Tu subdominio de Jamdesk (lo encuentras en la configuración del dashboard)
- Tu dominio personalizado añadido a tu proyecto en el dashboard de Jamdesk (el Worker devuelve un 403 hasta que el dominio esté registrado y verificado)
- Un registro DNS proxeado (nube naranja) en el nombre de host que sirve tu documentación. Los Workers solo se ejecutan en registros proxeados, así que un dominio que no aloja nada más también necesita uno: añade un registro
AAAAde marcador que apunte a100::y actívalo como proxeado.
Configuración rápida con la CLI
La forma más rápida de configurar tu Cloudflare Worker:
npx jamdesk deploy-proxy cloudflare
Este comando interactivo hará lo siguiente:
- Comprobar que wrangler 3.0+ esté instalado
- Verificar tu cuenta de Cloudflare y mostrar los dominios disponibles
- Resolver tu subdominio de Jamdesk a partir del proyecto vinculado en
docs.json - Permitirte seleccionar tu dominio de destino entre tus zonas de Cloudflare
- Generar todos los archivos necesarios
- Desplegar a Cloudflare de forma opcional
Si tienes acceso a varias cuentas de Cloudflare (algo común en agencias o equipos), la CLI te pedirá elegir una antes de seleccionar la zona. Elige la cuenta propietaria del dominio al que vas a desplegar: las rutas de Workers solo se pueden crear para dominios de la cuenta seleccionada.
Configuración no interactiva
Para ejecutarlo sin preguntas — en CI o desde un script — pasa las respuestas como flags:
jamdesk deploy-proxy cloudflare --slug myproject --domain example.com --yes
--yes genera los archivos del Worker y se detiene. Nunca despliega: la zona se deduce de tu dominio en lugar de confirmarse contra tu cuenta de Cloudflare, así que publicar esa configuración sigue siendo un paso explícito. Termina con:
cd cloudflare-worker
npx wrangler deploy
Con --yes la CLI no puede preguntar, así que necesita conocer tu subdominio. Lo obtiene del proyecto vinculado en docs.json; si falta ese vínculo (ejecuta jamdesk deploy una vez para añadirlo), pasa --slug explícitamente, o el comando se detiene en lugar de adivinar.
Si el directorio de salida ya existe, --yes se detiene en lugar de reemplazarlo. Añade --force para sobrescribirlo, o --output-dir para generarlo en otro sitio.
| Opción | Descripción |
|---|---|
--slug | Tu subdominio de Jamdesk, la X en X.jamdesk.app (omite la detección automática) |
--domain | Dominio de destino (p. ej., yoursite.com) |
--path | Prefijo de ruta; debe coincidir exactamente con el subpath configurado en tu panel (por defecto: /docs) |
--output-dir | Directorio de salida (por defecto: cloudflare-worker/) |
--skip-deploy | Omite la pregunta «¿desplegar ahora?» en una ejecución interactiva (--yes nunca despliega) |
--force | Sobrescribe el directorio de salida si ya existe |
--yes | Responde cada pregunta con su valor por defecto (modo CI). Nunca despliega ni sobrescribe un directorio existente — combínalo con --force para eso |
Si prefieres la configuración manual, continúa con los siguientes pasos.
Configuración manual
Paso 1: Crear un Worker
Crea un nuevo directorio para tu Worker e inicialízalo:
mkdir docs-proxy && cd docs-proxy
npm init -y
Paso 2: Añadir el código del Worker
Crea index.js con el siguiente código:
/**
* Jamdesk Documentation Proxy Worker
*
* Generated by: jamdesk deploy-proxy cloudflare
* Proxies /docs/* requests AND their assets to YOUR_SLUG.jamdesk.app
*
* Assets under /_jd/* (images, fonts, branding, analytics) must also be proxied
* since they use absolute paths in the HTML.
*/
const JAMDESK_HOST = "YOUR_SLUG.jamdesk.app";
// Paths that are always proxied to Jamdesk
const PROXY_PATHS = [
"/docs", // Documentation pages
"/_jd/", // All Jamdesk assets (images, fonts, branding, analytics)
];
function shouldProxy(pathname) {
return PROXY_PATHS.some(prefix => {
// For the docs path, require exact match or prefix with slash (not /docs.json)
if (prefix === "/docs") {
return pathname === "/docs" || pathname.startsWith("/docs/");
}
return pathname.startsWith(prefix);
});
}
function proxyToJamdesk(request, url) {
// Rewrite the request to Jamdesk
const proxyUrl = new URL(request.url);
proxyUrl.hostname = JAMDESK_HOST;
// Pin the scheme: an http:// visitor proxied as http:// gets a 308 from
// Vercel's edge pointing at JAMDESK_HOST, and redirect:"manual" hands that
// redirect straight to the browser — bouncing the visitor off this domain.
proxyUrl.protocol = "https:";
// Setting .protocol leaves a non-default .port in place, so :8787 (wrangler
// dev) or Cloudflare's alternate http ports (8080, 8880, 2052…) would follow
// us to the https upstream and fail there.
proxyUrl.port = "";
// Clone headers and add proxy headers
const headers = new Headers(request.headers);
headers.set("Host", JAMDESK_HOST);
headers.set("X-Forwarded-Host", url.hostname);
headers.set("X-Forwarded-Proto", "https");
// Custom header for domain verification (Vercel strips standard forwarding headers)
headers.set("X-Jamdesk-Forwarded-Host", url.hostname);
// Don't follow redirects — let the browser handle them so the URL updates.
// Without this, redirects happen internally and the browser URL doesn't change,
// which causes the sidebar to mis-highlight the active page.
const proxyRequest = new Request(proxyUrl, {
method: request.method,
headers,
body: request.body,
redirect: "manual",
});
// Cache all content types at Cloudflare edge (CF doesn't cache HTML by default).
// Cache duration is controlled by upstream Cache-Control headers.
// Never cache redirects or errors — they must always hit origin.
return fetch(proxyRequest, {
cf: {
cacheEverything: true,
cacheTtlByStatus: { "300-399": 0, "400-499": 0, "500-599": 0 },
},
});
}
export default {
async fetch(request) {
const url = new URL(request.url);
if (shouldProxy(url.pathname)) {
return proxyToJamdesk(request, url);
}
// /_next/ is ambiguous: the customer's root site may itself be a Next.js app
// serving its own /_next/ assets. Try the origin first and fall back to
// Jamdesk when the origin doesn't have it (404) or can't answer at all
// (5xx — a docs-only domain has no real origin, so Cloudflare returns 522).
// Hashed asset filenames never collide between the two apps.
if (url.pathname.startsWith("/_next/")) {
let originResponse;
try {
originResponse = await fetch(request);
} catch (err) {
// Log rather than swallow: a genuine platform fault and a domain with
// no origin at all are indistinguishable in `wrangler tail` otherwise.
console.warn("origin fetch threw, serving from Jamdesk:", err);
return proxyToJamdesk(request, url);
}
if (originResponse.status !== 404 && originResponse.status < 500) {
return originResponse;
}
return proxyToJamdesk(request, url);
}
return fetch(request);
},
};Reemplaza YOUR_SLUG por tu subdominio real de Jamdesk (por ejemplo, acme si tu documentación está en acme.jamdesk.app).
El encabezado X-Jamdesk-Forwarded-Host es obligatorio, y si falta, el fallo es silencioso: las solicitudes siguen teniendo éxito, pero las páginas se sirven con noindex y enlaces canónicos que apuntan a YOUR_SLUG.jamdesk.app en lugar de tu dominio, por lo que los motores de búsqueda nunca indexan tu documentación. Un 403 es el problema opuesto: el encabezado sí está presente, pero indica un dominio que no está registrado ni activo para este proyecto.
Paso 3: Configurar wrangler.toml
Crea wrangler.toml para configurar tu Worker:
name = "docs-proxy"
main = "index.js"
compatibility_date = "2024-01-01"
# Serve only via the routes below, not on the public <name>.workers.dev URL —
# that URL is a second way into the same proxy and is worth closing.
workers_dev = false
# Single catch-all route; the worker handles path filtering internally
routes = [
{ pattern = "yoursite.com/*", zone_name = "yoursite.com" },
]Si tu inicio de sesión de Cloudflare tiene acceso a más de una cuenta, añade también account_id = "<tu id de cuenta>" — de lo contrario wrangler deploy se detiene en lugar de adivinar en qué cuenta desplegar. npx wrangler whoami lista tus ID de cuenta.
Si tu sitio también recibe tráfico en www.yoursite.com, añade una segunda ruta para que el Worker gestione ambas:
routes = [
{ pattern = "yoursite.com/*", zone_name = "yoursite.com" },
{ pattern = "www.yoursite.com/*", zone_name = "yoursite.com" },
]Paso 4: Desplegar
Despliega tu Worker en Cloudflare:
npx wrangler deploy
Paso 5: Verificar
Visita https://yoursite.com/docs para confirmar que tu documentación se sirve correctamente.
Solución de problemas
Si renombraste tu subpath en el panel (por ejemplo, /docs → /help) pero el array PROXY_PATHS de tu Worker sigue listando solo /docs, las solicitudes a /help/* nunca llegan a Jamdesk: caen en fetch(request) y devuelven un 404 desde tu propio origen. Mientras tanto /docs/* sigue funcionando (Jamdesk sirve ambos prefijos), que es justo lo que hace fácil pasarlo por alto.
Solución: añade tu nuevo subpath a PROXY_PATHS. Vuelve a ejecutar jamdesk deploy-proxy cloudflare --path <subpath> si el Worker sigue siendo una plantilla sin modificar, o edita el array a mano si lo has personalizado.
Wrangler da prioridad a CLOUDFLARE_API_TOKEN sobre su inicio de sesión OAuth, y no puede iniciar sesión con OAuth mientras ese token esté definido. Este comando necesita OAuth para listar las zonas de tu cuenta, así que se detiene indicando de dónde viene el token en lugar de fallar dentro de wrangler.
Wrangler también lee el archivo .env del directorio actual, así que el token puede estar definido para wrangler sin estar en tu shell — que echo $CLOUDFLARE_API_TOKEN no muestre nada no lo descarta. Comprueba también si hay un .env en el directorio actual.
Solución: concede al token los permisos account:read y zone:read y vuelve a ejecutarlo, o ejecuta el comando sin él:
env -u CLOUDFLARE_API_TOKEN jamdesk deploy-proxy cloudflareSi el token viene de un .env, env -u no servirá — ejecuta el comando desde un directorio sin ese .env, o aparta el archivo temporalmente.
La CLI muestra tus dominios disponibles antes de seleccionar la zona. Si ves "No domains found":
- Verifica que iniciaste sesión en la cuenta de Cloudflare correcta
- Comprueba que tu dominio esté añadido y activo en el dashboard de Cloudflare
- Vuelve a ejecutar la CLI y selecciona "No" cuando te pregunte si deseas continuar con la cuenta actual, para cambiar de cuenta
Si tienes varias cuentas de Cloudflare:
- Ejecuta
jamdesk deploy-proxy cloudflare - Cuando se te pida seleccionar una cuenta, elige la que tiene tu dominio
- Si necesitas iniciar sesión con una cuenta completamente distinta, selecciona "Switch to different login"
- La CLI cerrará tu sesión y te pedirá iniciar sesión con las credenciales correctas
Este error significa que la zona seleccionada no coincide con tu cuenta de Cloudflare. Puede deberse a:
- Seleccionaste una zona que pertenece a otra cuenta
- La zona fue eliminada de Cloudflare
Solución: vuelve a ejecutar la CLI y selecciona la zona correcta de la lista, o cambia a la cuenta propietaria de la zona.
Asegúrate de que tu patrón de ruta use un catch-all: yoursite.com/* (no solo yoursite.com/docs*). La función interna shouldProxy() del Worker se encarga del filtrado de rutas.
Dos causas comunes:
- El Worker no se está ejecutando. Asegúrate de que tu registro DNS esté configurado como Proxied (nube naranja) en Cloudflare. Los Workers solo se ejecutan en registros proxied.
- Falta el encabezado
X-Forwarded-Host. El Worker debe establecer este encabezado para que Jamdesk genere correctamente las URLs de los recursos.
Si ves "Domain is not authorized to serve this content":
- Verifica que tu dominio esté registrado en el dashboard de Jamdesk
- Completa la verificación DNS (registro TXT) de tu dominio
- Asegúrate de que el encabezado
X-Jamdesk-Forwarded-Hostesté configurado en el código de tu Worker - Comprueba que tu dominio esté asignado al proyecto correcto
El dominio debe estar verificado antes de que el Worker pueda servir la documentación.
Los Workers solo se ejecutan en registros DNS proxied (nube naranja). Si tu registro A está configurado como "DNS only" (nube gris), las solicitudes van directamente al origen y omiten el Worker por completo.
Solución: cambia el registro A a proxied (nube naranja) en el DNS de Cloudflare. Lo mismo aplica a los subdominios: cualquier registro con una ruta de Worker debe estar en modo proxied.
Jamdesk verifica la propiedad leyendo directamente los valores de tus registros DNS. El proxy de Cloudflare (nube naranja) enmascara estos valores, por lo que la verificación no puede completarse.
Solución:
- Configura el registro DNS como DNS only (nube gris)
- Espera a que se complete la verificación (el estado cambia a active en el dashboard)
- Vuelve a Proxied (nube naranja) para que el Worker funcione
Resumen: nube gris para verificar → nube naranja para servir.
Jamdesk sirve el HTML de la documentación con Cache-Control: no-store, por lo que Cloudflare no almacena en caché las páginas en el edge (cf-cache-status: BYPASS). Cada solicitud renderiza la versión actual, y los cambios publicados aparecen de inmediato, sin demora de caché.
Los recursos estáticos bajo /_next/ y /_jd/ (JavaScript, CSS, fuentes, imágenes) se sirven con encabezados de caché immutable de larga duración, por lo que Cloudflare los almacena en caché en el edge. Sus nombres de archivo llevan un hash del contenido, así que cada build genera nuevas URLs y los recursos actualizados se recogen automáticamente. No es necesario purgar la caché.
cacheEverything: true permite que Cloudflare almacene en caché esos recursos estáticos en la ruta proxied; no anula el no-store del HTML. Para limpiar la caché del edge manualmente, usa Purge Cache de Cloudflare (Caching → Configuration → Purge Everything).
La CLI requiere wrangler 3.0+. Actualízala con:
npm install -g wrangler@latest