INTEGRITY Dokumentace

Tunnels

sandbox.tunnels jmenný prostor zpřístupňuje službu běžící uvnitř sandboxu na veřejném internetu prostřednictvím Cloudflare Tunnel. SDK spouští cloudflared uvnitř kontejneru a otevře trvalé QUIC připojení k edge síti Cloudflare.

K dispozici jsou dvě varianty:

Požadavky

Obě varianty tunelu vyžadují:

Pojmenované tunely navíc vyžadují token Cloudflare API, účet a zónu, podrobnosti viz Pojmenované tunely: předpoklady.

Metody

tunnels.get()

Vrátí záznam tunelu pro port. SDK vytvoří nový cloudflared proces v kontejneru, pokud ještě neběží. Metoda je idempotentní: opakovaná volání se stejným (port, options) vrátí stejný záznam.

const tunnel = await sandbox.tunnels.get(
  port: number,
  options?: { name?: string }
): Promise<TunnelInfo>

Parametry:

Vrací: Promise<TunnelInfo> : záznam tunelu. Viz TunnelInfo.

Volání get(port) s jiným options na portu, který už má tunel, vyvolá výjimku. Zavolejte destroy(port) nejprve.

import { getSandbox } from "@cloudflare/sandbox";

export { Sandbox } from "@cloudflare/sandbox";

export default {
	async fetch(request, env) {
		const sandbox = getSandbox(env.Sandbox, "my-sandbox");

		await sandbox.startProcess("python -m http.server 8080");

		const tunnel = await sandbox.tunnels.get(8080);
		console.log(tunnel.url);
		// → https://random-words-here.trycloudflare.com

		// Repeated calls for the same port return the same record.
		const same = await sandbox.tunnels.get(8080);
		console.log(same.url === tunnel.url); // true

		return Response.json({ url: tunnel.url });
	},
};
import { getSandbox } from "@cloudflare/sandbox";

export { Sandbox } from "@cloudflare/sandbox";

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const sandbox = getSandbox(env.Sandbox, "my-sandbox");

    await sandbox.startProcess("python -m http.server 8080");

    const tunnel = await sandbox.tunnels.get(8080);
    console.log(tunnel.url);
    // → https://random-words-here.trycloudflare.com

    // Repeated calls for the same port return the same record.
    const same = await sandbox.tunnels.get(8080);
    console.log(same.url === tunnel.url); // true

    return Response.json({ url: tunnel.url });

},
};

tunnels.list()

Vrátí všechny tunely aktuálně sledované pro tento sandbox.

const tunnels = await sandbox.tunnels.list(): Promise<TunnelInfo[]>

Vrací: Promise<TunnelInfo[]> : pole TunnelInfo záznamy. Prázdné, pokud není aktivní žádný tunel.

const tunnels = await sandbox.tunnels.list();

for (const tunnel of tunnels) {
	console.log(`port ${tunnel.port} → ${tunnel.url}`);
}
const tunnels = await sandbox.tunnels.list();

for (const tunnel of tunnels) {
console.log(`port ${tunnel.port} → ${tunnel.url}`);
}

tunnels.destroy()

Zrušení tunelu. Přijímá buď číslo portu, nebo TunnelInfo záznam vrácený get(). Idempotentní: zrušení neznámého portu proběhne úspěšně.

await sandbox.tunnels.destroy(portOrInfo: number | TunnelInfo): Promise<void>

Parametry:

const tunnel = await sandbox.tunnels.get(8080);

// Tear down by port number...
await sandbox.tunnels.destroy(8080);

// ...or by the record.
await sandbox.tunnels.destroy(tunnel);
const tunnel = await sandbox.tunnels.get(8080);

// Tear down by port number...
await sandbox.tunnels.destroy(8080);

// ...or by the record.
await sandbox.tunnels.destroy(tunnel);

Typy

TunnelInfo

Quick Tunnels vynechávají name; pojmenované tunely nesou popisek předaný přes options.name.

Pole Typ Popis
id string Identifikátor tunelu. quick-<random> pro rychlé tunely, respektive UUID tunelu Cloudflare Tunnel pro pojmenované tunely.
port number Číslo portu uvnitř sandboxu, na které tunel přesměrovává provoz.
url string Veřejná URL: https://<random>.trycloudflare.com (rychlé) nebo https://<name>.<your-zone> (s názvem).
hostname string Součást hostname v url.
createdAt string Časové razítko ISO-8601 udávající, kdy byl tunel vytvořen.
name string Pouze pojmenované tunely. Popisek předaný přes options.name. U rychlých tunelů chybí.
type TunnelInfo = QuickTunnelInfo | NamedTunnelInfo;

interface QuickTunnelInfo {
  id: string;
  port: number;
  url: string;
  hostname: string;
  createdAt: string;
  name?: never;
}

interface NamedTunnelInfo {
  id: string;
  port: number;
  url: string;
  hostname: string;
  createdAt: string;
  name: string;
}

Pojmenované tunely

Pojmenované tunely váží hostname určený uživatelem: <name>.<your-zone> : postavené na spravovaném Cloudflare Tunnel a proxovaný CNAME záznam ve vaší zóně. Na rozdíl od quick tunnelů je URL adresa stabilní i po restartu kontejneru a sdílené mezi sandboxy které volají get(port, { name }) se stejným name.

Čím se liší od quick tunnels

Aspekt Quick tunnel Pojmenovaný tunel
Hostname Náhodný *.trycloudflare.com, přidělené společností Cloudflare <name>.<your-zone>, který zvolíte vy
Stabilita Mění se při každém restartu kontejneru Stabilní; zachovává se i po restartu a v průběhu celého životního cyklu sandboxu
účet Cloudflare Není vyžadováno Povinné (API token + zóna)
Zdroje na straně Cloudflare Žádné Spravovaný Cloudflare Tunnel + proxované DNS CNAME
Záruka dostupnosti Žádné (pomůcka pro ladění) Kryto standardním Cloudflare SLA vaší zóny
Certifikát TLS Wildcard ve vlastnictví Cloudflare Universal SSL na <name>.<your-zone> (pouze jeden štítek DNS)
Server-Sent Events Nepodporováno (edge ukládá do vyrovnávací paměti text/event-stream) Podporováno

Předpoklady

Chcete-li zřídit pojmenovaný tunel, potřebujete:

  1. A účet Cloudflare s zóna (doména, kterou spravujete v Cloudflare DNS).
  2. A Token Cloudflare API se správnými scopes.
  3. ID účtu a ID zóny : SDK dokáže obojí odvodit z tokenu, pokud je token omezen přesně na jedno z každého.

Vytvořte API token

Vytvořte token z My Profile > API Tokens > Create Token > Custom token s následujícími oprávněními:

Rozsah Použito pro
Účet · Cloudflare Tunnel · Úprava Vytvářejte, vyhledávejte a odstraňujte tunely.
Zóna · DNS · Úprava Vytvoření nebo aktualizace a odstranění proxovaného CNAME pro <name>.<your-zone>.
Zóna · Zóna · Čtení Vyhledejte název zóny a odvoďte z něj <name>.<your-zone>.
Účet · Nastavení účtu · Čtení (volitelné) Umožňuje SDK odvodit ID účtu z tokenu, pokud není nastaveno výslovně.

V části Prostředky účtu, omezte rozsah tokenu na účet, kterému bude tunel patřit. V části Zone Resources, omezte jeho rozsah na konkrétní zónu, ke které jej chcete připojit.

Obojí Uživatelské API tokeny a API tokeny účtu (tajný klíč s předponou cfat_) jsou podporovány, přičemž SDK rozpozná druh tokenu a použije odpovídající introspekční koncový bod.

Vytvořte token pomocí REST API

Token můžete vytvořit i bez dashboardu. ID skupin oprávnění jsou stabilní. Ukázka níže používá zástupné hodnoty, aktuální ID získáte z GET /user/tokens/permission_groups.

curl -X POST "https://api.cloudflare.com/client/v4/user/tokens" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "sandbox-named-tunnels",
    "policies": [
      {
        "effect": "allow",
        "resources": { "com.cloudflare.api.account.<ACCOUNT_ID>": "*" },
        "permission_groups": [{ "id": "<TUNNEL_EDIT_GROUP_ID>" }]
      },
      {
        "effect": "allow",
        "resources": { "com.cloudflare.api.account.zone.<ZONE_ID>": "*" },
        "permission_groups": [
          { "id": "<DNS_EDIT_GROUP_ID>" },
          { "id": "<ZONE_READ_GROUP_ID>" }
        ]
      }
    ]
  }'

Připojte token a ID k Workeru

SDK čte CLOUDFLARE_API_TOKEN z prostředí Workeru a pokusí se z tokenu automaticky odvodit ID účtu a ID zóny. Pokud je token přiřazen k více účtům nebo zónám, SDK nedokáže jednoznačně vybrat jeden z nich a musíte nastavit CLOUDFLARE_ACCOUNT_ID a/nebo CLOUDFLARE_ZONE_ID explicitně.

Proměnná Povinné? Poznámky
CLOUDFLARE_API_TOKEN Ano Uložte jako tajný klíč pomocí wrangler secret put.
CLOUDFLARE_ACCOUNT_ID Pouze pokud token vidí více účtů Jinak se odvodí z tokenu.
CLOUDFLARE_ZONE_ID Pouze pokud token vidí více zón Jinak se odvodí z tokenu.
npx wrangler secret put CLOUDFLARE_API_TOKEN

Pro lokální vývoj umístěte proměnné do .dev.vars (vyloučeno v .gitignore). Pro produkci nastavte neutajovaná ID (pokud jsou potřeba) v části vars v konfiguraci Wrangler:

{
  "vars": {
    "CLOUDFLARE_ACCOUNT_ID": "<account-id>",
    "CLOUDFLARE_ZONE_ID": "<zone-id>"
  }
}

Když se rozpoznávání nezdaří, SDK vyvolá jasnou chybu s uvedením proměnné, kterou je třeba nastavit.

Příklad

import { getSandbox } from "@cloudflare/sandbox";

export { Sandbox } from "@cloudflare/sandbox";

export default {
	async fetch(request, env) {
		const sandbox = getSandbox(env.Sandbox, "my-sandbox");

		// Reuse an existing app process across container restarts, or start it.
		let proc = await sandbox.getProcess("app");
		if (!proc) {
			try {
				proc = await sandbox.startProcess("python -m http.server 8080", {
					processId: "app",
				});
			} catch (err) {
				if (err?.code !== "PROCESS_ALREADY_EXISTS") throw err;
				proc = await sandbox.getProcess("app");
			}
		}

		// Provision (or reuse) https://app.example.com pointing at port 8080.
		const tunnel = await sandbox.tunnels.get(8080, { name: "app" });
		console.log(tunnel.url); // → https://app.example.com

		return Response.json({ url: tunnel.url });
	},
};
import { getSandbox } from "@cloudflare/sandbox";

export { Sandbox } from "@cloudflare/sandbox";

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const sandbox = getSandbox(env.Sandbox, "my-sandbox");

    // Reuse an existing app process across container restarts, or start it.
    let proc = await sandbox.getProcess('app');
    if (!proc) {
      try {
        proc = await sandbox.startProcess('python -m http.server 8080', { processId: 'app' });
      } catch (err) {
        if ((err as { code?: string })?.code !== 'PROCESS_ALREADY_EXISTS') throw err;
        proc = await sandbox.getProcess('app');
      }
    }

    // Provision (or reuse) https://app.example.com pointing at port 8080.
    const tunnel = await sandbox.tunnels.get(8080, { name: "app" });
    console.log(tunnel.url); // → https://app.example.com

    return Response.json({ url: tunnel.url });
  },
};

Životní cyklus

Pojmenované tunely jsou navržené tak, aby přežily kontejner, který je vytvořil:

  1. První volání na sandbox.tunnels.get(port, { name }):
    • Vyřeší se <name>.<your-zone> z nakonfigurovaného ID zóny.
    • Vytvoří Cloudflare Tunnel prostředek s názvem sandbox-<sandbox-id>-<name> otagovaný pomocí ID sandboxu.
    • Vytvoří nebo aktualizuje proxovaný CNAME z <name>.<your-zone> na <tunnel-id>.cfargotunnel.com.
    • Spouští cloudflared uvnitř kontejneru s tokenem tunelu.
  2. Následná volání se stejným (port, name) vrátí záznam z mezipaměti, aniž by kontaktovaly Cloudflare.
  3. Restart kontejneru (vyřazení Durable Object, nasazení, pád):
    • cloudflared zanikne spolu s kontejnerem, ale Cloudflare Tunnel a DNS záznam zůstávají zachovány.
    • Při dalším get(port, { name }), SDK znovu vyhledá označený tunel prostřednictvím API Cloudflare a znovu spustí cloudflared. Hostname zůstává beze změny.
  4. Explicitní ukončení hodnotou sandbox.tunnels.destroy(port):
    • Zastaví cloudflared uvnitř kontejneru.
    • Odstraní prostředek Cloudflare Tunnel.
    • Odstraní proxované CNAME záznam.
  5. Zničení sandboxu hodnotou sandbox.destroy() před zastavením kontejneru zruší všechny tunely vytvořené sandboxem, včetně prostředků na straně Cloudflare.

Pokud destroy() se nepodaří dosáhnout Cloudflare API (například byl token zneplatněn mezi get() a destroy()), SDK zaznamená upozornění s názvem osiřelého tunnelId a dnsRecordId abyste mohli provést úklid ručně z dashboardu.

Zdroje Cloudflare a jejich štítkování

Pojmenované tunely vytvářejí prostředky ve vašem účtu Cloudflare, mimo kontejner sandboxu. Neukládají se do úložiště Durable Object a nezapočítávají se do kvót sandboxu, objeví se však v Cloudflare dashboardu a spotřebovávají kvóty tunelů a DNS vašeho účtu.

Pro každý (sandbox, name) dvojice SDK vytvoří:

Prostředek Název / umístění Identifikátor
Cloudflare Tunnel Sítě > Tunnels sandbox-<sandbox-id>-<name>
Proxovaný DNS záznam Vaše zóna, DNS > Záznamy CNAME <name>.<zone> → <tunnel-id>.cfargotunnel.com

Oba prostředky jsou označeny tagy, takže je můžete auditovat, dotazovat se na ně a hromadně je čistit z dashboardu nebo přes API:

U plánů, které nejsou Enterprise, Cloudflare odmítá tagy prostředků; SDK to rozpozná a požadavek zopakuje bez tagů. Komentář DNS a metadata tunelu se přesto použijí, takže prostředek můžete vždy dohledat zpět k jeho sandboxu.

Chcete-li vypsat všechny tunely vytvořené SDK pro daný účet:

curl "https://api.cloudflare.com/client/v4/accounts/$CLOUDFLARE_ACCOUNT_ID/cfd_tunnel?name=sandbox-" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN"

Omezení

Obě varianty tunelu:

Pouze Quick Tunnels:

Pouze pojmenované tunely: