Cloudflare Workers のプレビュー URL を自動で無効化する
Cloudflare Workers のプレビュー URL は、PR をマージしても自動で無効化されません。バージョンの削除ではアクセスを止められないため、Subdomain API の previews_enabled を GitHub Actions で自動制御する方法を実装しました。
目次
Cloudflare Pages は 2020 年にリリースされた静的サイトホスティングサービスですが、2024 年に Workers が静的アセット配信に対応したことで状況が変わりました。Cloudflare はWorkers への移行を推奨する方針を打ち出し、Workers では wrangler versions upload でプレビューバージョン1をアップロードでき、PR ごとにプレビュー URL で動作確認が可能です。
しかし、Workers のプレビューバージョンには構造的な課題があります。PR をマージしてブランチを削除しても、プレビューバージョンは自動削除されず、URL を知っていれば誰でもアクセスできてしまいます。Pages にはデプロイの削除 API が公開されていますが、Workers の Standard API にバージョンの DELETE エンドポイントはありません。この問題は 2025年8月ころ Cloudflare Community でも報告されています。
このブログも Cloudflare Workers でホスティングしており、同じ問題が発生しました。Vercel であればプレビューデプロイに認証をかけられますが、Workers のプレビューバージョンにはそのような認証機能がありません。個人ブログなので実害はないかもしれませんが、昨今のセキュリティ事情を考えると、放置するのも気持ちが悪いです。「まぁ試しにやってみるか」くらいの気持ちで調べ始めたところ、Subdomain API の previews_enabled でプレビュー URL を一括無効化できることが分かり、GitHub Actions で本番デプロイ後に自動で無効化するしくみを実装しました。
なぜ Pages ではなく Workers なのか
「プレビューの管理が面倒なら Pages を使えばよいのでは?」と思うかもしれません。実際、Pages であればプレビューデプロイの削除は簡単で、GitHub Actions で自動化する方法も Zenn で紹介されています。
wrangler-actionを使ってCloudflare Pagesを自動デプロイする
ただ、Cloudflare に勤めていて Hono(軽量な Web フレームワーク)の作者でもある Yusuke Wada 氏は、X で以下のように説明しています。
これからは理由がない限りCloudflare PagesではなくCloudflare Workersを使ってください。
- Pagesと同じくアセットへのアクセスは無料です
- Pagesではできない機能が使えます > Durable Objects/Workers Logs etc.
- フロントエンドフレームワークが動きます
これを見てこのブログは Workers を選択しましたが、プレビュー URL の管理でハマりました。
プレビュー URL のしくみ
WARNING
本記事の内容は 2026 年 2 月時点の API 仕様に基づいています。
Workers のプレビュー URL は、バージョンごとに {version_id}-{script_name}.{subdomain}.workers.dev の形式で発行されます。このルーティングはバージョンの存在そのものではなく、Subdomain API の previews_enabled という設定で制御されています。
GET /accounts/{account_id}/workers/scripts/{script_name}/subdomain
POST /accounts/{account_id}/workers/scripts/{script_name}/subdomain{
"enabled": true,
"previews_enabled": true
}| 設定値 | 対象 |
|---|---|
enabled |
本番の workers.dev URL({script_name}.{subdomain}.workers.dev) |
previews_enabled |
プレビュー URL({version_id}-{script_name}.{subdomain}.workers.dev) |
この 2 つは独立した設定値です。previews_enabled を false にしても本番 URL には影響しません。公式ドキュメントにも以下の記載があります。
Disabling Preview URLs will disable routing to both versioned and aliased preview URLs.
実際に previews_enabled: false に変更してみたところ、プレビュー URL は HTTP/404 を返すようになり、本番 URL は HTTP/200 のままでした。
| URL | 変更前 | 変更後 |
|---|---|---|
| プレビュー URL | HTTP/200 | HTTP/404 |
本番 URL({script_name}.workers.dev) |
HTTP/200 | HTTP/200 |
バージョン削除ではプレビュー URL は消えない
最初に試したのはバージョンの削除です。
Workers の API を調べると、Standard API にはバージョンの DELETE エンドポイントが存在しません。試しに DELETE リクエストを送ると 405 Method Not Allowed が返ります。
GET /accounts/{account_id}/workers/scripts/{script_name}/versions
POST /accounts/{account_id}/workers/scripts/{script_name}/versions調べを進めると、Beta API には DELETE エンドポイントがあることが分かりました。
GET /accounts/{account_id}/workers/workers/{worker_id}/versions
POST /accounts/{account_id}/workers/workers/{worker_id}/versions
DELETE /accounts/{account_id}/workers/workers/{worker_id}/versions/{version_id}試しに Beta API でバージョンを削除してみると、HTTP/200 が返るので削除できたように見えます。ところが、削除後もプレビュー URL にはアクセスできてしまいます。
公式ドキュメントを読むと、バージョンは不変かつ追記のみの設計で、もともと「削除する」想定になっていないそうです。wrangler にも versions delete コマンドは存在しません(upload / deploy / list / view / rollback / secret のみ)。Beta API の DELETE は後付けのエンドポイントで、プレビュー URL のルーティングとは無関係です。
Worker versions are immutable at the API level, meaning they cannot be updated after creation, only re-created with any desired changes. [...] versions are both immutable and append-only.
バージョンを消すのではなく、ルーティングを制御する previews_enabled を使うのが正解でした。
previews_enabled を切り替える
解決策として、Cloudflare Access2 でプレビュー URL に認証をかける方法と、previews_enabled を CI で切り替える方法があります。
Cloudflare Access は Zero Trust の認証基盤で、プレビュー URL へのアクセスに認証を要求できます。プレビュー URL 自体は有効なまま残りますが、認証を通過しないとアクセスできません。チーム開発ならこちらを使うべきです。
previews_enabled の切り替えは、PR デプロイ前に true、本番デプロイ後に false にするだけのシンプルな方法です。
WARNING
previews_enabled は Worker 全体の設定です。false にするとすべてのプレビュー URL が無効化されます。複数人で開発していて他の PR のプレビューも同時に使いたい場合は、Cloudflare Access を検討してください。
このブログは私一人で開発しているので、シンプルに切り替え方式を選びました。本番デプロイが走るタイミングでプレビュー URL を無効化すれば、他の PR を壊す心配はありません。
GitHub Actions での実装
PR デプロイ時(deploy-preview ジョブ)で wrangler versions upload の前に previews_enabled を true にし、本番デプロイ後に false に戻します。
- name: Enable preview URLs
run: |
SCRIPT_NAME="sui-tech-blog"
API_BASE="https://api.cloudflare.com/client/v4/accounts/$CLOUDFLARE_ACCOUNT_ID/workers"
curl -sf -X POST \
"$API_BASE/scripts/$SCRIPT_NAME/subdomain" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"enabled": true, "previews_enabled": true}'
echo "Preview URLs enabled"
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}本番デプロイ後(deploy-production ジョブ)では、プレビュー URL を無効化します。
- name: Disable preview URLs
continue-on-error: true
run: |
SCRIPT_NAME="sui-tech-blog"
API_BASE="https://api.cloudflare.com/client/v4/accounts/$CLOUDFLARE_ACCOUNT_ID/workers"
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" -X POST \
"$API_BASE/scripts/$SCRIPT_NAME/subdomain" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"enabled": true, "previews_enabled": false}')
if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 300 ]; then
echo "Preview URLs disabled (HTTP $HTTP_CODE)"
else
echo "::warning::Failed to disable preview URLs (HTTP $HTTP_CODE)"
fi
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}continue-on-error: true を設定しているので、無効化が失敗しても本番デプロイ自体は成功として扱われます。おまけの処理ですので、これが原因でデプロイが止まるのは避けたいところです。
まとめ
- Cloudflare Workers のプレビュー URL は PR をマージしても自動で無効化されず、URL を知っていれば誰でもアクセスできる状態が残る
- Beta API にバージョンの DELETE エンドポイントはあるが、HTTP/200 が返るだけでプレビュー URL のルーティングは無効化されない
- Subdomain API の
previews_enabled: falseで全プレビュー URL を無効化でき、本番 URL には影響しない - GitHub Actions で PR デプロイ前に
true、本番デプロイ後にfalseに切り替えることで、PR 中のみプレビューを公開できる
参考
Preview URLs
Preview URLs allow you to preview new versions of your project without deploying it to production.
workers.dev
Cloudflare Workers accounts come with a workers.dev subdomain that is configurable in the Cloudflare dashboard. Your workers.dev subdomain allows you getting started quickly by deploying Workers without first onboarding your custom domain to Cloudflare.
Subdomain
Versions
Infrastructure as Code (IaC)
While Wrangler makes it easy to upload and manage Workers, there are times when you need a more programmatic approach. This could involve using Infrastructure as Code (IaC) tools or interacting directly with the Workers API. Examples include build and deploy scripts, CI/CD pipelines, custom developer tools, and automated testing.
Page Not Found
Failed to fetch link preview.
Migrate from Pages to Workers
A guide for migrating from Cloudflare Pages to Cloudflare Workers. Includes a compatibility matrix for comparing the features of Cloudflare Workers and Pages.
wrangler-actionを使ってCloudflare Pagesを自動デプロイする
おまけ Workers の DELETE 系エンドポイント一覧
プレビュー URL だけを無効化できる DELETE エンドポイントは存在しません。
| エンドポイント | 効果 | プレビュー URL への影響 |
|---|---|---|
DELETE /workers/workers/{worker_id}/versions/{version_id} (Beta API) |
バージョンのメタデータ削除 | 消えない |
DELETE /workers/workers/{worker_id} |
Worker 丸ごと削除 | 本番も消える |
DELETE /workers/scripts/{script_name}/subdomain |
workers.dev 全無効化(enabled も previews_enabled も false) |
本番も消える |
DELETE /workers/scripts/{script_name}/deployments/{deployment_id} |
デプロイ履歴の削除(最新は削除不可) | 消えない |
DELETE /zones/{zone_id}/workers/routes/{route_id} |
カスタムドメインのルート削除 | 無関係 |
正直「わかりづらいな…」と思います。今後の API 設計では、プレビュー URL を個別に管理できるようなエンドポイントが追加されるとうれしいですね!
Footnotes
理解度チェック
問題1: Cloudflare Workers のプレビュー URL を無効化するために、この記事で採用した方法はどれですか?
Beta API でバージョンを DELETE する
Subdomain API の previews_enabled を false にする
Worker を丸ごと削除して再作成する
wrangler versions delete コマンドを実行する
問題2: Subdomain API の previews_enabled を false に設定した場合、本番 URL({script_name}.workers.dev)はどうなりますか?
本番 URL も HTTP/404 になる
本番 URL は HTTP/200 のまま影響を受けない
本番 URL は HTTP/301 でリダイレクトされる
本番 URL は HTTP/503 になる