Skip to content

非公式本サイトは非公式の日本語ドキュメントであり、Cloudflare 公式サイトではありません。最新情報はdevelopers.cloudflare.comをご確認ください。

デプロイの引き継ぎ(一時アカウント)

最終更新 Markdown で表示Agent セットアップ

一時プレビューアカウントを使うと、Cloudflare に認証する前に Workers をデプロイしてテストできます。その後、アカウントを引き継いで、デプロイと対応リソースを保持できます。

Cloudflare Drop は、静的サイト向けに、このプレビューと引き継ぎのライフサイクルを示しています。プラットフォームは REST API を使い、生成したアプリケーションに同様の体験を提供できます。

設計の背景は Temporary Cloudflare Accounts for AI agents を参照してください。

AI エージェントが一時アカウントで Worker をデプロイ、確認、再デプロイし、ユーザーが認証してアカウントを引き継ぎ、リソースを保持する流れの図

連携方法を選ぶ

アカウントのプロビジョニングを誰が制御するかで、連携方法を選びます。

連携 使う場面 プロビジョニングの動作
Wranglerwrangler deploy --temporary AI エージェントまたはツールが Wrangler を実行する Wrangler がアカウントを作成または再利用し、Claim URL を表示します
REST API(api.cloudflare.com/client/v4/provisioning/previews プラットフォームのバックエンドがデプロイ体験を制御する バックエンドが一時的な資格情報と Claim URL を受け取ります

本番および継続的インテグレーション / 継続的デプロイ(CI/CD)では、永続的な Cloudflare アカウントを使います。wrangler login または Cloudflare API トークン で認証します。

Wrangler でデプロイする

AI エージェントまたはツールがデプロイコマンドを実行する場合は、Wrangler を使います。Wrangler がプルーフオブワークのチャレンジ、資格情報、Claim URL を管理します。

Wrangler 4.102.0 以降は、未認証のデプロイを --temporary で再実行する案内を表示します。

  1. Wrangler をバージョン 4.102.0 以降にインストールまたは更新します。

    インストール手順は インストールと更新 を参照してください。

  2. AI エージェントにデプロイ用のプロンプトを渡します。

    例は次のとおりです。

    Make a very simple Hello World Cloudflare Worker in TypeScript and deploy it using the Wrangler CLI. Do not ask me questions.
  3. エージェントに wrangler deploy を実行させます。

    未認証かつ非対話のセッションでは、Wrangler は次のような出力を表示します。

    To continue without logging in, rerun this command with `--temporary`.
    Wrangler will use a temporary account and print a claim URL.

    この出力は、エージェントに --temporary 付きでコマンドを再実行するよう伝えます。

  4. --temporary を付けてデプロイを再実行します。

    npx wrangler deploy --temporary

    Wrangler は次のような出力を表示します。

    Continuing means you accept Cloudflare's Terms of Service (https://www.cloudflare.com/terms/) and Privacy Policy (https://www.cloudflare.com/privacypolicy/).
    
    Temporary account ready:
      Account:        example-name (created)
      Claim within:   60 minutes
      Claim URL:      https://dash.cloudflare.com/claim-preview?claimToken=<CLAIM_TOKEN>
    
    Uploaded example-worker
    Deployed example-worker triggers
      https://example-worker.example-name.workers.dev
  5. (任意)アカウントを引き継ぐ前に、変更を再デプロイします。

    資格情報と Claim URL が有効なあいだ、Wrangler はアカウントをキャッシュして再利用します。出力で、Wrangler がアカウントを作成したか再利用したかを確認できます。

    wrangler login または wrangler logout を実行すると、Wrangler はキャッシュしたアカウントをクリアします。

    Wrangler はこれらの一時的な値を、現在の OS ユーザーのグローバル設定ディレクトリに保存します。このディレクトリをプラットフォーム利用者間で共有しないでください。

REST API で連携する

プラットフォームのバックエンドがデプロイを制御する場合は、REST API を使います。バックエンドは、ユーザーが認証する前にアカウントをプロビジョニングし、対応リソースをデプロイします。

プロビジョニングとデプロイの呼び出しは、すべてバックエンドから行います。プロビジョニングのレスポンスには、機密の資格情報と Claim URL が含まれます。

次の図は、ユーザーがプレビューしてデプロイを引き継ぐあいだ、プラットフォームが一時的な資格情報をバックエンドに保持する流れです。

flowchart LR
    accTitle: プラットフォームのプレビューと引き継ぎの構成
    accDescr: ユーザーが Cloudflare のポリシーに同意し、プラットフォーム UI でプレビューを要求します。信頼できるプラットフォームバックエンドが一時アカウントを作成し、account.apiToken を非公開のまま保持して Worker をデプロイし、プレビュー URL と Claim URL だけを UI に返します。Claim URL は、対象ユーザーにだけ見せるベアラー資格情報です。ユーザーは Cloudflare ダッシュボードでアカウントを引き継ぎます。以降のプラットフォームからのデプロイには、別の OAuth フローが必要です。

    USER((ユーザー))

    subgraph PLATFORM["プラットフォーム"]
        direction TB
        UI["プラットフォーム UI<br/>一時 API トークンなし"]
        BACKEND["信頼できるプラットフォームバックエンド<br/>account.apiToken を保存"]
        UI -->|"2. プレビューを要求"| BACKEND
        BACKEND -->|"10. プレビュー URL とベアラーの Claim URL のみ"| UI
    end

    subgraph CLOUDFLARE["Cloudflare"]
        direction TB
        API["Cloudflare API"]
        DASHBOARD["Cloudflare ダッシュボード<br/>アカウントを引き継ぐ"]
    end

    USER -->|"1. ポリシーに同意し、アプリケーションを生成"| UI
    BACKEND -->|"3. チャレンジを要求"| API
    API -->|"4. チャレンジパラメーター"| BACKEND
    BACKEND -->|"5. チャレンジをローカルで解く"| BACKEND
    BACKEND -->|"6. 解とともに一時アカウントを作成"| API
    API -->|"7. アカウント ID、API トークン、Claim URL"| BACKEND
    BACKEND -->|"8. Worker をデプロイし、サブドメインを要求"| API
    API -->|"9. workers.dev サブドメイン"| BACKEND
    UI -->|"11. ライブプレビューと対象ユーザー限定の Claim リンクを表示"| USER
    USER -->|"12. サインインして引き継ぎを完了"| DASHBOARD
    DASHBOARD -.->|"引き継ぎ後は任意"| OAUTH["以降のプラットフォームデプロイ用の<br/>別の OAuth フロー"]

チャレンジを要求する

一時アカウントを作成する前に、プルーフオブワークのチャレンジを要求します。

curl "https://api.cloudflare.com/client/v4/provisioning/previews/challenge" \
  -X POST \
  -H "Content-Type: application/json" \
  --data '{}'

レスポンスには、チャレンジトークン、シード、難易度パラメーターが含まれます。

{
	"success": true,
	"result": {
		"challengeToken": "<CHALLENGE_TOKEN>",
		"seed": "<BASE64URL_32_BYTE_SEED>",
		"k": 8000,
		"g": 2000
	},
	"errors": [],
	"messages": []
}

プルーフオブワークを解く

連続する SHA-256 のチェックポイントチェーンを計算して、チャレンジを解きます。

  1. seed を Base64URL としてデコードします。32 バイトになる必要があります。
  2. checkpoint[0] = SHA-256(seed) を計算します。
  3. 0 から k - 1 までの各セグメントについて、直前のチェックポイントから g 回の連続 SHA-256 ハッシュを計算し、結果を追加します。
  4. すべての k + 1 個のチェックポイントを連結します。各チェックポイントは 32 バイトです。
  5. 連結したバイト列を標準 Base64 でエンコードします。その値を solution.checkpoints として送ります。

チャレンジを解く前に、kg が正の整数であることを確認します。seed が 32 バイトにデコードできない場合、または k * g64,000,000 を超える場合は、チャレンジを拒否します。

次の Node.js の例は、これらの上限を適用し、作成リクエストで必要なオブジェクトを返します。

solve-preview-challenge.jsjs
import { createHash } from "node:crypto";

function sha256(value) {
	return createHash("sha256").update(value).digest();
}

export function solvePreviewChallenge({ challengeToken, seed, k, g }) {
	const seedBytes = Buffer.from(seed, "base64url");
	if (seedBytes.length !== 32) {
		throw new Error("seed must decode to 32 bytes");
	}
	if (!Number.isInteger(k) || k <= 0) {
		throw new Error("k must be a positive integer");
	}
	if (!Number.isInteger(g) || g <= 0) {
		throw new Error("g must be a positive integer");
	}
	if (k * g > 64_000_000) {
		throw new Error("k * g must not exceed 64,000,000");
	}

	const checkpoints = [];
	let hash = sha256(seedBytes);

	checkpoints.push(hash);

	for (let segment = 0; segment < k; segment++) {
		for (let iteration = 0; iteration < g; iteration++) {
			hash = sha256(hash);
		}

		checkpoints.push(hash);
	}

	return {
		challengeToken,
		solution: {
			checkpoints: Buffer.concat(checkpoints).toString("base64"),
		},
	};
}
solve-preview-challenge.tsts
import { createHash } from "node:crypto";

type PreviewChallenge = {
	challengeToken: string;
	seed: string;
	k: number;
	g: number;
};

function sha256(value: Uint8Array): Buffer {
	return createHash("sha256").update(value).digest();
}

export function solvePreviewChallenge({
	challengeToken,
	seed,
	k,
	g,
}: PreviewChallenge) {
	const seedBytes = Buffer.from(seed, "base64url");
	if (seedBytes.length !== 32) {
		throw new Error("seed must decode to 32 bytes");
	}
	if (!Number.isInteger(k) || k <= 0) {
		throw new Error("k must be a positive integer");
	}
	if (!Number.isInteger(g) || g <= 0) {
		throw new Error("g must be a positive integer");
	}
	if (k * g > 64_000_000) {
		throw new Error("k * g must not exceed 64,000,000");
	}

	const checkpoints: Buffer[] = [];
	let hash = sha256(seedBytes);

	checkpoints.push(hash);

	for (let segment = 0; segment < k; segment++) {
		for (let iteration = 0; iteration < g; iteration++) {
			hash = sha256(hash);
		}

		checkpoints.push(hash);
	}

	return {
		challengeToken,
		solution: {
			checkpoints: Buffer.concat(checkpoints).toString("base64"),
		},
	};
}

一時アカウントを作成する

アカウント作成の前に、ユーザーに Cloudflare の 利用規約プライバシーポリシー への同意を求めます。ユーザーが両方に同意したあとでのみ、acceptTermsOfService"yes" に設定します。

その後、必須のポリシーフィールドとともに、プルーフオブワークの解を送ります。

curl "https://api.cloudflare.com/client/v4/provisioning/previews" \
  -X POST \
  -H "Content-Type: application/json" \
  --data '{
    "termsOfService": "https://www.cloudflare.com/terms/",
    "privacyPolicy": "https://www.cloudflare.com/privacypolicy/",
    "acceptTermsOfService": "yes",
    "challengeToken": "<CHALLENGE_TOKEN>",
    "solution": {
      "checkpoints": "<BASE64_CHECKPOINTS>"
    }
  }'

レスポンスには、一時的な資格情報と Claim URL が含まれます。

{
	"success": true,
	"result": {
		"account": {
			"id": "<TEMPORARY_ACCOUNT_ID>",
			"name": "<TEMPORARY_ACCOUNT_NAME>",
			"type": "standard",
			"apiToken": "<TEMPORARY_ACCOUNT_API_TOKEN>",
			"tokenId": "<TEMPORARY_TOKEN_ID>",
			"expiresAt": "<ACCOUNT_EXPIRES_AT>"
		},
		"claim": {
			"token": "<CLAIM_TOKEN>",
			"url": "https://dash.cloudflare.com/claim-preview?claimToken=<CLAIM_TOKEN>",
			"expiresAt": "<CLAIM_EXPIRES_AT>"
		}
	},
	"errors": [],
	"messages": []
}

レスポンスを使う前に、successtrue であることを確認します。account.idaccount.apiTokenaccount.expiresAtclaim.urlclaim.expiresAt が存在することも確認します。

対応リソースをデプロイする

対応する Cloudflare API エンドポイントでは、account.idaccount.apiToken を使います。一時的な値は、対応するリソース操作にだけ使います。

一時アカウントのトークンは、永続アカウントのすべての API 権限を持ちません。非対応の操作は認可エラーを返します。

次の例は、Workers Script Upload API で Worker をアップロードしてデプロイし、その後アカウントの workers.dev サブドメインを取得します。

curl "https://api.cloudflare.com/client/v4/accounts/$CLOUDFLARE_ACCOUNT_ID/workers/scripts/$SCRIPT_NAME" \
  -X PUT \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  -F 'metadata={"main_module":"worker.mjs","compatibility_date":"<YYYY-MM-DD>"};type=application/json' \
  -F '[email protected];type=application/javascript+module'

一時的な資格情報で Get Subdomain エンドポイント を呼び出します。

curl "https://api.cloudflare.com/client/v4/accounts/$CLOUDFLARE_ACCOUNT_ID/workers/subdomain" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN"

workers.dev で公開するスクリプトでは、result.subdomain とスクリプト名を組み合わせてデプロイ URL を作ります。形式は https://<SCRIPT_NAME>.<SUBDOMAIN>.workers.dev です。

一時アカウントをプロビジョニングしたあと、対応するリソース操作には Cloudflare TypeScript SDK を使います。

import Cloudflare from "cloudflare";

export async function deployWorker(
	accountId: string,
	apiToken: string,
	scriptName: string,
	compatibilityDate: string,
	scriptContent: string,
) {
	const client = new Cloudflare({ apiToken });
	const workerModule = new File([scriptContent], "worker.mjs", {
		type: "application/javascript+module",
	});

	await client.workers.scripts.update(scriptName, {
		account_id: accountId,
		metadata: {
			main_module: "worker.mjs",
			compatibility_date: compatibilityDate,
		},
		files: [workerModule],
	});

	const { subdomain } = await client.workers.subdomains.get({
		account_id: accountId,
	});

	return `https://${scriptName}.${subdomain}.workers.dev`;
}

デプロイ URL と claim.url は、対象ユーザーに渡します。

アカウントを引き継ぐ

対象ユーザーは、60 分以内に引き継ぎを完了する必要があります。期限前に Claim URL を開いただけでは足りません。

URL を開き、Cloudflare にサインインするかアカウントを作成し、ダッシュボードの案内を完了します。

ユーザーが引き継ぎを完了しない場合、Cloudflare はアカウントとそのリソースを削除します。

Wrangler を使う場合、一時的な資格情報または Claim URL が期限切れになったら、wrangler deploy --temporary を再実行します。Wrangler は新しいアカウントをプロビジョニングし、新しい Claim URL を表示します。

REST 連携では、引き継ぎ前に account.expiresAt または claim.expiresAt を過ぎた場合、新しいチャレンジとアカウントを要求します。

引き継ぎ後、Worker と対応リソースは、引き継いだアカウントに残ります。

Wrangler を続けて使う場合は wrangler login を実行し、--temporary なしでデプロイします。引き継ぎによって、プラットフォームがアカウントへ永続的にアクセスできるようになるわけではありません。

以降のデプロイでは、Cloudflare OAuth クライアント など、通常の認証済みフローで、引き継いだアカウントを接続します。

対応リソース

次の表は、対応する機能と上限の概要です。一時的な資格情報は、これらのリソースのすべての操作を許可するわけではありません。

対応するプロダクトまたはリソース 対応する機能または上限
Workers workers.dev へのデプロイ
Workers Static Assets 最大 1,000 ファイル。各アセットは最大 5 MiB
Workers KV 名前空間の作成、一覧、名前変更、削除。キーの put、get、list、delete。一括の put、get、delete
D1 データベース 1 つ。データベースあたり最大 100 MB、合計 100 MB
Durable Objects Durable Object のバインディングとマイグレーション付きで Workers をデプロイ
Hyperdrive データベース設定は最大 2 つ、接続は 10
Queues キューは最大 10
mTLS と CA 証明書 wrangler cert のアップロード、一覧、削除

セキュリティと制限

一時的な値を保護する

  • account.apiToken は、対応するリソース操作を認可します。ブラウザーのレスポンスやクライアント側のコードに出さないでください。
  • claim.url はベアラー資格情報として扱います。URL を持つ人はだれでも、一時アカウントの所有権を引き継げます。
  • 両方の値は、対象ユーザーにスコープしたバックエンドストレージまたはサーバー側セッションストレージにだけ保存します。claim.url はそのユーザーにだけ渡します。
  • 両方の値をログ、分析、サポート用テレメトリから除外します。不要になったら保存したコピーを削除し、返されたいずれかの有効期限を過ぎないようにします。

制限

  • Cloudflare は、アカウント作成前にプルーフオブワークの確認を求めます。Wrangler はこの確認を処理します。REST 連携では解を送信する必要があります。
  • Cloudflare は一時アカウントの作成をレート制限します。再試行する前に待つか、永続アカウントで認証してください。
  • --temporary は未認証の利用だけをサポートします。既存の OAuth、API トークン、またはグローバル API キーの資格情報があるとエラーになります。
  • --temporary はグローバルフラグではありません。一時的な資格情報に対応するコマンドだけがこのフラグを持ちます。
  • 一時アカウントのプロビジョニングは、デフォルトの公開 API エンドポイント経由でのみ利用できます。FedRAMP High API エンドポイントでは利用できません。
  • 追加の不正利用防止チェックに失敗したリクエストは、Cloudflare が拒否することがあります。

関連リソース

wrangler deploy

Workers をデプロイするコマンドの完全なリファレンスです。

プロンプト

AI プロンプトと MCP サーバーで Workers アプリを構築します。

役に立ちましたか?