Jamdesk Documentation logo

Cloudflare Workers

Redirigez les requêtes /docs vers votre site de documentation Jamdesk via un Cloudflare Worker. Couvre la configuration, les routes et le cache.

Un Cloudflare Worker intercepte les requêtes sur /docs de votre domaine, les réécrit vers votre sous-domaine Jamdesk, et retourne la réponse, le tout en périphérie sans serveur d'origine requis. Vous pouvez générer le Worker automatiquement avec npx jamdesk deploy-proxy cloudflare ou le configurer manuellement ci-dessous.

Comment ça fonctionne

Le Worker transmet les requêtes à votre sous-domaine Jamdesk et transmet votre domaine dans l'en-tête X-Jamdesk-Forwarded-Host, que Jamdesk utilise pour vérifier le domaine et appliquer ses paramètres. Il s'agit d'une configuration unique — si vous modifiez ultérieurement votre domaine ou votre configuration dans le dashboard, le Worker n'a pas besoin d'être mis à jour.

Prérequis

  • Un compte Cloudflare avec votre domaine configuré
  • Wrangler CLI v3.0+ installée
  • Votre sous-domaine Jamdesk (dans les paramètres du dashboard)
  • Votre domaine personnalisé ajouté à votre projet dans le dashboard Jamdesk (le Worker renvoie une erreur 403 tant que le domaine n'est pas enregistré et vérifié)
  • Un enregistrement DNS proxifié (nuage orange) sur le nom d'hôte qui sert votre documentation. Les Workers ne s'exécutent que sur les enregistrements proxifiés, donc un domaine qui n'héberge rien d'autre en a quand même besoin d'un — ajoutez un enregistrement AAAA de remplacement pointant vers 100:: et définissez-le comme proxifié.

Configuration rapide avec la CLI

Le moyen le plus rapide de configurer votre Cloudflare Worker :

npx jamdesk deploy-proxy cloudflare

Cette commande interactive va :

  1. Vérifier que wrangler 3.0+ est installé
  2. Vérifier votre compte Cloudflare et afficher les domaines disponibles
  3. Résoudre votre sous-domaine Jamdesk à partir du projet lié dans docs.json
  4. Vous laisser sélectionner votre domaine cible parmi vos zones Cloudflare
  5. Générer tous les fichiers requis
  6. Déployer sur Cloudflare, si vous le souhaitez

Si vous avez accès à plusieurs comptes Cloudflare (fréquent pour les agences ou les équipes), la CLI vous invite à en choisir un avant la sélection de la zone. Choisissez le compte propriétaire du domaine sur lequel vous déployez — les routes Workers ne peuvent être créées que pour des domaines appartenant au compte sélectionné.

Configuration non interactive

Pour exécuter sans invites — dans la CI ou depuis un script — passez les réponses sous forme d'options :

jamdesk deploy-proxy cloudflare --slug myproject --domain example.com --yes

--yes génère les fichiers du Worker puis s'arrête. Elle ne déploie jamais : la zone est déduite de votre domaine plutôt que confirmée par rapport à votre compte Cloudflare, donc la mise en production de cette configuration reste une étape explicite. Terminez avec :

cd cloudflare-worker
npx wrangler deploy

Avec --yes, la CLI ne peut pas afficher d'invites, elle doit donc connaître votre sous-domaine. Elle le lit à partir du projet lié dans docs.json ; si ce lien est absent (exécutez jamdesk deploy une fois pour l'ajouter), passez --slug explicitement, sinon la commande s'arrête plutôt que de deviner.

Si le répertoire de sortie existe déjà, --yes s'arrête plutôt que de le remplacer. Ajoutez --force pour l'écraser, ou --output-dir pour écrire ailleurs.

OptionDescription
--slugVotre sous-domaine Jamdesk, le X dans X.jamdesk.app (ignore la détection automatique)
--domainDomaine cible (par ex. yoursite.com)
--pathPréfixe de chemin ; doit correspondre exactement au sous-chemin de votre dashboard (par défaut : /docs)
--output-dirRépertoire de sortie (par défaut : cloudflare-worker/)
--skip-deployIgnore l'invite « déployer maintenant ? » lors d'une exécution interactive (--yes ne déploie jamais)
--forceÉcrase le répertoire de sortie s'il existe déjà
--yesRépond à chaque invite avec sa valeur par défaut (mode CI). Ne déploie jamais et n'écrase jamais un répertoire existant — combinez avec --force pour cela

Si vous préférez une configuration manuelle, poursuivez avec les étapes ci-dessous.


Configuration manuelle

Étape 1 : Créer un Worker

Créez un nouveau répertoire pour votre Worker et initialisez-le :

mkdir docs-proxy && cd docs-proxy
npm init -y

Étape 2 : Ajouter le code du Worker

Créez index.js avec le code suivant :

index.js
/**
 * 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);
  },
};

Remplacez YOUR_SLUG par votre sous-domaine Jamdesk réel (par ex. acme si votre documentation se trouve à acme.jamdesk.app).

Si vous utilisez un sous-chemin personnalisé depuis le dashboard au lieu du /docs par défaut, remplacez "/docs" par votre sous-chemin dans PROXY_PATHS et dans la vérification de correspondance exacte à l'intérieur de shouldProxy(). L'option --path de la CLI le fait pour vous lors de la génération du fichier, mais uniquement sur un template non modifié ; régénérer écrase toute entrée personnalisée que vous avez ajoutée manuellement à PROXY_PATHS. Si vous avez personnalisé ce Worker, modifiez plutôt les entrées /docs sur place.

L'en-tête X-Jamdesk-Forwarded-Host est obligatoire, et un en-tête manquant échoue silencieusement — les requêtes réussissent quand même, mais les pages servent noindex avec des liens canoniques pointant vers YOUR_SLUG.jamdesk.app au lieu de votre domaine, si bien que les moteurs de recherche n'indexent jamais votre documentation. Un 403 est le problème inverse : l'en-tête est présent, mais désigne un domaine qui n'est pas enregistré et actif pour ce projet.

Étape 3 : Configurer wrangler.toml

Créez wrangler.toml pour configurer votre Worker :

wrangler.toml
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 votre connexion Cloudflare a accès à plusieurs comptes, ajoutez également account_id = "<your account id>" — sinon wrangler deploy s'arrête plutôt que de deviner dans quel compte déployer. npx wrangler whoami liste vos identifiants de compte.

Si votre site sert également du trafic sur www.yoursite.com, ajoutez une seconde route afin que le Worker gère les deux :

routes = [
  { pattern = "yoursite.com/*", zone_name = "yoursite.com" },
  { pattern = "www.yoursite.com/*", zone_name = "yoursite.com" },
]

Étape 4 : Déployer

Déployez votre Worker sur Cloudflare :

npx wrangler deploy

Étape 5 : Vérifier

Visitez https://yoursite.com/docs pour confirmer que votre documentation est correctement servie.

Dépannage

Si vous avez renommé votre sous-chemin dans le dashboard (par exemple, /docs → /help) mais que le PROXY_PATHS de votre Worker ne liste toujours que /docs, les requêtes vers /help/* n'atteignent jamais Jamdesk : elles retombent sur fetch(request) et renvoient une erreur 404 sur votre propre origine. /docs/* continue de fonctionner entre-temps (Jamdesk sert les deux préfixes), ce qui explique pourquoi c'est facile à manquer.

Solution : ajoutez votre nouveau sous-chemin à PROXY_PATHS. Relancez jamdesk deploy-proxy cloudflare --path <subpath> si le Worker est toujours un template non modifié, ou modifiez le tableau à la main si vous l'avez personnalisé.

Wrangler privilégie CLOUDFLARE_API_TOKEN par rapport à sa connexion OAuth, et ne peut pas démarrer une connexion OAuth tant que ce token est défini. Cette commande a besoin d'OAuth pour lister les zones de votre compte, donc elle s'arrête en indiquant l'emplacement du token plutôt que d'échouer à l'intérieur de wrangler.

Wrangler lit également .env dans le répertoire depuis lequel vous l'exécutez, donc le token peut être défini pour wrangler sans être présent dans votre shell — le fait que echo $CLOUDFLARE_API_TOKEN n'affiche rien ne l'exclut pas. Vérifiez aussi la présence d'un .env dans le répertoire courant.

Solution : accordez au token les permissions account:read et zone:read puis relancez, ou exécutez sans lui :

env -u CLOUDFLARE_API_TOKEN jamdesk deploy-proxy cloudflare

Si le token provient d'un .env, env -u ne servira à rien — exécutez la commande depuis un répertoire sans un tel .env, ou déplacez temporairement le fichier pour cette exécution.

La CLI affiche vos domaines disponibles avant la sélection de la zone. Si vous voyez « No domains found » :

  1. Vérifiez que vous êtes connecté au bon compte Cloudflare
  2. Vérifiez que votre domaine est ajouté et actif dans le dashboard Cloudflare
  3. Relancez la CLI et sélectionnez « No » lorsqu'on vous demande de continuer avec le compte actuel, pour changer de compte

Si vous avez plusieurs comptes Cloudflare :

  1. Exécutez jamdesk deploy-proxy cloudflare
  2. Lorsqu'on vous invite à sélectionner un compte, choisissez celui qui contient votre domaine
  3. Si vous avez besoin d'une connexion complètement différente, sélectionnez "Switch to different login"
  4. La CLI vous déconnectera et vous invitera à vous reconnecter avec les identifiants corrects

Cette erreur signifie que la zone sélectionnée ne correspond pas à votre compte Cloudflare. Soit :

  • Vous avez sélectionné une zone appartenant à un autre compte
  • La zone a été supprimée de Cloudflare

Solution : relancez la CLI et sélectionnez la bonne zone dans la liste, ou basculez vers le compte propriétaire de la zone.

Assurez-vous que votre schéma de route utilise un caractère générique global : yoursite.com/* (pas seulement yoursite.com/docs*). La fonction interne shouldProxy() du Worker gère le filtrage des chemins.

Deux causes courantes :

  1. Le Worker ne s'exécute pas. Assurez-vous que votre enregistrement DNS est défini sur Proxied (nuage orange) dans Cloudflare. Les Workers ne s'exécutent que sur les enregistrements proxifiés.
  2. En-tête X-Forwarded-Host manquant. Le Worker doit définir cet en-tête pour que Jamdesk génère des URL de ressources correctes.

Si vous voyez « Domain is not authorized to serve this content » :

  1. Vérifiez que votre domaine est enregistré dans le dashboard Jamdesk
  2. Terminez la vérification DNS (enregistrement TXT) pour votre domaine
  3. Assurez-vous que l'en-tête X-Jamdesk-Forwarded-Host est défini dans le code de votre Worker
  4. Vérifiez que votre domaine correspond au bon projet

Le domaine doit être vérifié avant que le Worker puisse servir la documentation.

Les Workers ne s'exécutent que sur des enregistrements DNS proxifiés (nuage orange). Si votre enregistrement A est défini sur « DNS only » (nuage gris), les requêtes vont directement à l'origine et contournent entièrement le Worker.

Solution : basculez l'enregistrement A sur proxifié (nuage orange) dans le DNS Cloudflare. La même règle s'applique aux sous-domaines : tout enregistrement associé à une route Worker doit être proxifié.

Jamdesk vérifie la propriété en lisant directement les valeurs de votre enregistrement DNS. Le proxy de Cloudflare (nuage orange) masque ces valeurs, donc la vérification ne peut pas aboutir.

Solution :

  1. Définissez l'enregistrement DNS sur DNS only (nuage gris)
  2. Attendez que la vérification se termine (le statut passe à active dans le dashboard)
  3. Revenez à Proxied (nuage orange) pour que le Worker fonctionne

Version courte : nuage gris pour vérifier → nuage orange pour servir.

Jamdesk sert le HTML de la documentation avec Cache-Control: no-store, donc Cloudflare ne met pas les pages en cache en périphérie (cf-cache-status: BYPASS). Chaque requête affiche la version actuelle, et les modifications publiées apparaissent immédiatement sans délai de cache.

Les ressources statiques sous /_next/ et /_jd/ (JavaScript, CSS, polices, images) sont servies avec des en-têtes de cache immutable à longue durée de vie, donc Cloudflare les met en cache en périphérie. Leurs noms de fichiers sont hachés en fonction du contenu, donc chaque build produit de nouvelles URL et les ressources mises à jour sont automatiquement prises en compte. Aucune purge n'est nécessaire.

cacheEverything: true permet à Cloudflare de mettre en cache ces ressources statiques sur la route proxifiée ; cela ne remplace pas le no-store sur le HTML. Pour vider manuellement le cache en périphérie, utilisez Purge Cache de Cloudflare (Caching → Configuration → Purge Everything).

La CLI nécessite wrangler 3.0+. Mettez à jour avec :

npm install -g wrangler@latest

Et ensuite ?

Domaine personnalisé uniquement

Empêchez votre sous-domaine de répondre directement

Domaines personnalisés

Vérifiez le DNS et dépannez

Hébergement par sous-chemin

Servez la documentation à /docs