設定

Turnstile を設定する

Turnstile のウィジェットを作り、2 つのキーを設定して、問い合わせフォームを使えるようにします。

このページの手順で Turnstile のウィジェットを作り、サイトキーとシークレットキーを設定します。両方を設定すると、問い合わせフォームが送信を受け付けるようになります。

Turnstile は、自動プログラムによるフォームの送信を防ぐための、Cloudflare の無料の機能です。goodnight-web の問い合わせフォームには Turnstile が必要です。

ウィジェットを作る

  1. Cloudflare のダッシュボードで Turnstile を開き、Add widget を選びます。
  2. Widget name: 見分けやすい名前を付けます。たとえば会社名です。
  3. Hostnames: サイトのドメインを入れます。たとえば example.com です。試している間に workers.dev のアドレスも使うなら、それも追加します。workers.dev のアドレスを無効にするときに外してください。
  4. Widget mode: 迷ったら Managed にします。ほとんどの訪問者には短い確認が出るだけで、一部の人にはクリックを求めます。
  5. Create を選びます。

Cloudflare が 2 つの値を表示します(Cloudflare: ダッシュボードでウィジェットを作る)。

  • サイトキー(Site key): 公開してよい値です。問い合わせページがウィジェットを表示するのに使います。
  • シークレットキー(Secret key): 秘密の値です。Worker が Turnstile の検証 API(siteverify)で送信を確かめるのに使います。

キーを設定する

キー置く場所公開してよいか
サイトキーWorker の変数 TURNSTILE_SITE_KEYはい。問い合わせページが /api/contact/form から読み取ります。
シークレットキーWorker のシークレット TURNSTILE_SECRETいいえ。コミットしたり、ページに入れたりしないでください。

サイトキー

starter では、サイトキーを wrangler.jsonc に書きます。変更をコミットすると、次のデプロイで反映されます。

"vars": {
  "TURNSTILE_SITE_KEY": "0x4AAAAAAA...",
},

設定するのはここだけです。問い合わせページにはキーを書かず、Worker から読み込みます。

ダッシュボードでは設定しないでください。ダッシュボードだけで設定した値は、次のデプロイで wrangler.jsonc の値に置き換わります。wrangler deploy がファイルの変数をアップロードするためです。

シークレットキー

Cloudflare のダッシュボードで Worker を開き、変数とシークレットに TURNSTILE_SECRET を種類 Secret で追加します。プロジェクトのフォルダーでターミナルを使うなら、次のコマンドでも同じことができます。

npx wrangler secret put TURNSTILE_SECRET

設定する前の動き

goodnight-web は、必要な設定がそろうまで機能を止めます(フェイルクローズ)。Turnstile がないと、問い合わせ API はボットの送信も受け付けてしまいます。そのため、受け付けそのものを止めます。

場所設定する前の動き
POST /api/contact503 を返します。
問い合わせページ「お問い合わせフォームは準備中です」と表示します。
管理画面「お問い合わせフォームは受け付けを停止しています」というお知らせと、このページへのリンクを表示します。
管理画面のお知らせ「お問い合わせフォームは受け付けを停止しています」と、Turnstile の設定方法へのリンク管理画面のお知らせ「お問い合わせフォームは受け付けを停止しています」と、Turnstile の設定方法へのリンク
TURNSTILE_SITE_KEY と TURNSTILE_SECRET を設定するまで、管理画面にこのお知らせが出ます。

訪問者には、送れたように見えて届かないフォームではなく、準備中の表示が見えます。両方のキーを設定すれば、ほかに何も変えずにフォームが動き始めます。

Worker が確かめること

Worker は送信のたびに、フォームから届いたトークンを siteverify に送ります。次をすべて満たすときだけ受け付けます。

  • success が true である。
  • hostname があなたのサイトのホスト名である。リクエストが来たホスト名か、createGoodnightWorker() の contact.turnstileHostnames オプションに並べたホスト名のどれかです。
  • action が、問い合わせフォームで設定した action である。

トークンの有効期限は 300 秒で、検証できるのは 1 回だけです(Cloudflare: サーバー側の検証)。確認に失敗したら 400 を返し、何も保存しません。

ほかの確認は問い合わせフォームの保護で説明しています。

ローカルで開発する

wrangler dev でフォームの表示を確かめるときは、本物のキーではなく Cloudflare のテスト用キーを使います(Cloudflare: テスト)。この組み合わせでは、ウィジェットは必ず成功し、siteverify はどのトークンも受け付けます。ただし、送信は Worker の確認で拒否されます(次の節)。

site key:   1x00000000000000000000AA
secret key: 1x0000000000000000000000000000000AA

テスト用キーは、Git が無視する .dev.vars(starter の .dev.vars.example をコピーしたファイル)に書きます。wrangler.jsonc にはコミットしないでください。

テスト用キーは本番のサイトで使わないでください。すべてのリクエストを通してしまいます。

テスト用キーでは送信が拒否される

テスト用のシークレットキーでは、siteverify は hostname を example.com として返し、action を返しません(2026-10-22 に確認)。

{
  "success": true,
  "hostname": "example.com",
  "metadata": { "result_with_testing_key": true }
}

Worker は hostname と action も確かめるので、テスト用キーでの送信は拒否します。フォームには、確認に失敗したと表示します。

これは意図したものです。ローカルの開発のために、本番の確認を緩めることはしません。

starter の E2E テスト

starter の E2E テスト(npm run test:e2e)は、次の順に確かめます。

  1. テスト用キーでの送信が、上のとおり拒否されること。
  2. テスト専用の Worker e2e/worker.ts を起動し、フォームの送信から D1 への保存までが通ること。この Worker は、siteverify の応答に result_with_testing_key が付いているときに限り、hostname と action を期待どおりの値にします。

e2e/worker.ts はデプロイしないでください。

目次