Cloudflare Workers
Redirige las solicitudes /docs a tu sitio de documentación Jamdesk mediante un Cloudflare Worker. Cubre la configuración, las rutas y el 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 borde 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 transmite 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 configuración en el dashboard, el Worker no necesita actualizarse.
Requisitos previos
- Una cuenta de Cloudflare con tu dominio configurado
- Wrangler CLI v3.0+ instalada
- Tu subdominio de Jamdesk (disponible en la configuración del dashboard)
- Tu dominio personalizado agregado a tu proyecto en el dashboard de Jamdesk (el Worker devuelve un 403 hasta que el dominio esté registrado y verificado)
- Un registro DNS con proxy (nube naranja) en el nombre de host que sirve tu documentación. Los Workers solo se ejecutan en registros con proxy, así que un dominio que no aloja nada más también necesita uno — agrega un registro
AAAAde marcador de posición que apunte a100::y configúralo con proxy.
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 en Cloudflare, opcionalmente
Si tienes acceso a varias cuentas de Cloudflare (algo común en agencias o equipos), la CLI te pide elegir una antes de la selección de zona. Elige la cuenta propietaria del dominio al que estás desplegando — las rutas de Workers solo pueden crearse para dominios de la cuenta seleccionada.
Configuración no interactiva
Para ejecutarlo sin solicitudes interactivas — 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 asume a partir 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 lee del proyecto vinculado en docs.json; si ese enlace falta (ejecuta jamdesk deploy una vez para agregarlo) 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. Agrega --force para sobrescribirlo, o --output-dir para escribir en otro lugar.
| Option | Description |
|---|---|
--slug | Tu subdominio de Jamdesk, la X en X.jamdesk.app (omite la detección automática) |
--domain | Dominio de destino (por ejemplo, yoursite.com) |
--path | Prefijo de ruta; debe coincidir exactamente con la subruta de tu dashboard (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 predeterminado (modo CI). Nunca despliega, y nunca sobrescribe un directorio existente — combínalo con --force para eso |
Si prefieres una configuración manual, continúa con los pasos a continuación.
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: Agregar 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 con tu subdominio real de Jamdesk (por ejemplo, acme si tu documentación está en acme.jamdesk.app).
Si usas una subruta personalizada desde el dashboard en lugar de la predeterminada /docs, reemplaza "/docs" por tu subruta en PROXY_PATHS y en la verificación de coincidencia exacta dentro de shouldProxy(). El flag --path de la CLI hace esto por ti al generar el archivo, pero solo sobre un template sin modificar; regenerarlo sobrescribe cualquier entrada personalizada que hayas agregado a mano en PROXY_PATHS. Si has personalizado este Worker, edita las entradas /docs directamente en su lugar.
El encabezado X-Jamdesk-Forwarded-Host es obligatorio, y si falta el fallo es silencioso — las solicitudes siguen teniendo éxito, pero las páginas sirven noindex con 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 nombra un dominio que no está registrado y 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, agrega también account_id = "<your account id>" — de lo contrario wrangler deploy se detiene en lugar de adivinar en qué cuenta desplegar. npx wrangler whoami lista los IDs de tus cuentas.
Si tu sitio también sirve tráfico en www.yoursite.com, agrega una segunda ruta para que el Worker gestione ambos:
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 está sirviendo correctamente.
Solución de problemas
Si renombraste tu subruta en el dashboard (por ejemplo, /docs → /help) pero el PROXY_PATHS de tu Worker todavía solo lista /docs, las solicitudes a /help/* nunca llegan a Jamdesk: caen en fetch(request) y devuelven 404 en tu propio origen. /docs/* sigue funcionando mientras tanto (Jamdesk sirve ambos prefijos), que es exactamente por qué es fácil pasarlo por alto.
Solución: agrega tu nueva subruta a PROXY_PATHS. Vuelve a ejecutar jamdesk deploy-proxy cloudflare --path <subpath> si el Worker sigue siendo un template sin modificar, o edita el array a mano si lo has personalizado.
Wrangler prefiere CLOUDFLARE_API_TOKEN sobre su inicio de sesión OAuth, y no puede iniciar un inicio de sesión OAuth mientras ese token esté definido. Este comando necesita OAuth para listar las zonas de tu cuenta, así que se detiene indicando la ubicación del token en lugar de fallar dentro de wrangler.
Wrangler también lee .env desde el directorio en el que lo ejecutas, 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. Revisa también si hay un .env en el directorio actual.
Solución: otorga al token los permisos account:read y zone:read y vuelve a ejecutar, o ejecútalo sin él:
env -u CLOUDFLARE_API_TOKEN jamdesk deploy-proxy cloudflareSi el token proviene de un .env, env -u no ayudará — ejecuta el comando desde un directorio que no tenga ese .env, o mueve el archivo temporalmente para esta ejecución.
La CLI muestra tus dominios disponibles antes de la selección de zona. Si ves «No domains found»:
- Verifica que hayas iniciado sesión en la cuenta de Cloudflare correcta
- Comprueba que tu dominio esté agregado y activo en el dashboard de Cloudflare
- Vuelve a ejecutar la CLI y selecciona «No» cuando se 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 un inicio de sesión completamente diferente, 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 ser que:
- 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 comodín global: yoursite.com/* (no solo yoursite.com/docs*). La función interna shouldProxy() del Worker gestiona el filtrado de rutas.
Dos causas comunes:
- El Worker no se está ejecutando. Asegúrate de que tu registro DNS esté configurado en Proxied (nube naranja) en Cloudflare. Los Workers solo se ejecutan en registros con proxy.
- Falta el encabezado
X-Forwarded-Host. El Worker debe establecer este encabezado para que Jamdesk genere URLs de recursos correctas.
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é vinculado 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 con proxy (nube naranja). Si tu registro A está configurado en «DNS only» (nube gris), las solicitudes van directamente al origen y omiten el Worker por completo.
Solución: cambia el registro A a con proxy (nube naranja) en el DNS de Cloudflare. Lo mismo aplica a los subdominios: cualquier registro con una ruta de Worker debe tener proxy activado.
Jamdesk verifica la propiedad leyendo directamente los valores de tu registro DNS. El proxy de Cloudflare (nube naranja) oculta estos valores, por lo que la verificación no puede completarse.
Solución:
- Configura el registro DNS en DNS only (nube gris)
- Espera a que la verificación se complete (el estado cambia a active en el dashboard)
- Vuelve a Proxied (nube naranja) para que el Worker funcione
Versión corta: 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 borde (cf-cache-status: BYPASS). Cada solicitud muestra la versión actual, y los cambios publicados aparecen de inmediato sin retraso 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 borde. Sus nombres de archivo tienen hash según el contenido, así que cada build produce nuevas URLs y los recursos actualizados se recogen automáticamente. No se requiere purga.
cacheEverything: true permite que Cloudflare almacene en caché esos recursos estáticos en la ruta con proxy; no anula el no-store en el HTML. Para vaciar el caché del borde manualmente, usa Purge Cache de Cloudflare (Caching → Configuration → Purge Everything).
La CLI requiere wrangler 3.0+. Actualiza con:
npm install -g wrangler@latest