Cloudflare Workers のプレビュー URL を自動で無効化する

Cloudflare Workers のプレビュー URL は、PR をマージしても自動で無効化されません。バージョンの削除ではアクセスを止められないため、Subdomain API の previews_enabled を GitHub Actions で自動制御する方法を実装しました。

公開日
読了まで
6 分

/ 6 分

目次

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を自動デプロイするzenn.dev

ただ、Cloudflare に勤めていて Hono(軽量な Web フレームワーク)の作者でもある Yusuke Wada 氏は、X で以下のように説明しています。

これからは理由がない限りCloudflare PagesではなくCloudflare Workersを使ってください。
  • Pagesと同じくアセットへのアクセスは無料です
  • Pagesではできない機能が使えます > Durable Objects/Workers Logs etc.
  • フロントエンドフレームワークが動きます
Yusuke Wada (@yusukebe) on Xx.com

これを見てこのブログは Workers を選択しましたが、プレビュー URL の管理でハマりました。

プレビュー URL のしくみ

警告

本記事の内容は 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 にするだけのシンプルな方法です。

警告

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-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-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 中のみプレビューを公開できる

参考

Version URLsdevelopers.cloudflare.comworkers.devdevelopers.cloudflare.comSubdomaindevelopers.cloudflare.comVersionsdevelopers.cloudflare.comInfrastructure as Code (IaC)developers.cloudflare.comPotential Security Concerns with Workers & Pagescommunity.cloudflare.comMigrate from Pages to Workersdevelopers.cloudflare.comwrangler-actionを使ってCloudflare Pagesを自動デプロイするzenn.dev

おまけ 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 を個別に管理できるようなエンドポイントが追加されるとうれしいですね!

脚注

  1. 本番デプロイ前に動作確認するための一時的なバージョン。固有の URL が発行され、PR 単位で確認用の環境として利用する。 ↩本文へ戻る

  2. Cloudflare Zero Trust の一部で、Web アプリケーションに認証・認可ポリシーを適用するサービス。プレビュー URL へのアクセスを特定のユーザーやグループに限定できる。 ↩本文へ戻る

この記事を Markdown で取得