Site search / サイト内検索

必要な情報を探す

ページ内の言葉を探す検索と、意味が近い内容を探す検索を使い分けられます。

「検索する」を実行すると、入力した検索語をCloudflare Workers AIで数値表現に変換し、その数値表現をCloudflare Vectorizeで当サイトの公開情報と照合します。あわせて、Acecore共通検索API(acecore.net)へ送信し、 Acecore関連サイトの公開情報を下部に表示することがあります。個人情報や機密情報は入力しないでください。個人情報の取り扱い

Insights / 技術解説

Astro + Cloudflareで公式サイトを機能拡張する全体設計

AstroとCloudflare Pagesを土台に、問い合わせAI、Sveltia CMS、多言語ブログ、サービスCTA、Markdown安全描画、Cloudflareだけのコメント機能をどう組み合わせて公式サイトを育てたかを、他サイトにも転用しやすい全体設計として整理します。

  • 技術
  • Astro
  • Cloudflare
  • Webサイト
  • AI
  • CMS
Astro + Cloudflareで公式サイトを機能拡張する全体設計
この記事の目次
  1. 結論
  2. 1. まず静的サイトとして強くする
  3. 2. 動的機能はCloudflare側の小さなAPIにする
  4. 3. CMSは編集入口、公開判断はPRにする
  5. 4. 多言語はUI翻訳ではなく静的ページにする
  6. 5. 問い合わせ導線は会話、CTA、フォームで分ける
  7. 6. AI出力はHTMLとして信頼しない
  8. 7. コメント機能はCloudflareだけで閉じる
  9. 8. 検索対象と交流機能を分ける
  10. 9. 目的別に読む
  11. おすすめの導入順
  12. 他サイトへ転用するときの最小構成
  13. まとめ
  14. 補足:Workersの本番・検証環境とビルド設定を分ける
  15. 補足:外部フィードの再試行と障害を入力元ごとに分ける
  16. 2026年10月6日追記:API契約と添付の確認範囲

AstroとCloudflareでCMSや検索を追加するときは、更新担当者、公開データ、利用者ごとの処理を書き分けてから構成を選びます。記事表示は静的生成、投稿や外部API呼び出しはFunctionsという分担を起点に、必要な接続だけをCloudflare Pages: Bindingsで確認すると導入範囲を絞れます。

2026年9月26日追記: 以下は2026年6月の構成を記録した記事です。その後のコードでは、CMS保存は権限・内容・HEADを検証したうえでGitHub Appによるmain直接commitに変わり、翻訳はOpenAI Batchと翻訳PR、問い合わせAIはService Binding先の共通Workerを利用します。図・表・コード中のCopilot翻訳、CMSのPR保存、AIの直接API呼び出しは当時の実装としてお読みください。現在の各方式はCMS導入記録、多言語運用、問い合わせAIに分けて記載しています。

AstroとCloudflare Pagesで静的サイトを作ると、最初はページを速く安全に配信できれば十分です。

しかし運用を続けると、CMSで更新したい、多言語で出したい、AIチャットで訪問者を案内したい、フォームに文脈を渡したい、コメント欄も置きたい、という機能追加が出てきます。

この記事は、それらを どの順番で入れるか、どのレイヤーに置くか、どの記事を読めばよいか をまとめるインデックスです。Acecore公式サイトの実装を例にしながら、他のAstro + Cloudflare構成にも真似しやすい形で整理します。

結論

公式サイトを育てるときは、最初に「どこまでを静的HTMLにするか」「どこからをAPIにするか」「誰がコンテンツを更新するか」を分けるのが大事です。

Acecoreでは、次のように分担しました。

レイヤー 担当するもの
Astro ページ生成、ブログ、OGP、RSS、sitemap、UI
Cloudflare Pages配信、Pages Functions、D1、Turnstile
GitHub PRレビュー、CMS編集差分、翻訳差分、履歴
Sveltia CMS 日本語source、著者、タグ、画像、ページ文言
OpenAI API 問い合わせAIの回答生成
Pagefind 静的HTMLに含める検索対象の索引

この分け方にすると、機能を増やしても「全部をCMSに入れる」「全部を外部SaaSに投げる」「全部をクライアント側で頑張る」状態になりません。

1. まず静的サイトとして強くする

土台はAstroです。

公式サイトの大半は、毎リクエストでサーバー処理をする必要がありません。

  • サービス紹介
  • 会社概要
  • 制作事例
  • ブログ記事
  • 著者ページ
  • タグページ
  • RSS
  • sitemap
  • OGP

これらはbuild時に静的HTMLとして生成できます。

静的HTMLで出せるものは、なるべく静的に出します。これにより、表示速度、キャッシュ、検索エンジンへの渡しやすさ、障害時の影響範囲が安定します。

一方で、問い合わせAIやコメント投稿のように、リクエストごとの処理が必要なものだけをCloudflare Pages Functionsへ出します。

ここを最初に分けておくと、機能追加のたびに「これはAstroのbuild時に解決するのか」「Cloudflare側のAPIにするのか」を判断しやすくなります。

2. 動的機能はCloudflare側の小さなAPIにする

静的サイトにも、どうしても動的な処理はあります。

  • 問い合わせAIチャット
  • コメントの読み込みと投稿
  • Turnstile検証
  • Originチェック
  • レート制限
  • D1への保存

これらはCloudflare Pages Functionsへ寄せました。

Astro側に置くのはUIです。APIキー、D1 binding、Turnstile secret、hash salt、Origin判定はブラウザへ出しません。

この方針は、問い合わせAIチャットの技術設計 と Cloudflareだけで作るブログコメント機能 の両方で同じです。

機能 UI API境界 保存先・外部API
問い合わせAI Astro /api/ai-contact OpenAI API
コメント Astro /api/comments Cloudflare D1
bot対策 Turnstile Pages Functionsで検証 Cloudflare Siteverify
rate limit なし Pages Functionsで判定 メモリ、D1、必要ならWAF/KV/DO

大事なのは、動的機能を足しても「サイト全体がアプリケーションサーバーになる」わけではないことです。

静的サイトの強みを残し、必要な境界だけをAPI化します。

3. CMSは編集入口、公開判断はPRにする

Sveltia CMSは、静的サイトに編集画面を足すために入れました。

ただし、CMSを入れたからといって、CMSを本番DBのように扱うわけではありません。

Acecoreでは、CMSは日本語sourceを編集する入口です。

  • ブログ記事
  • 著者情報
  • タグ定義
  • 日本語source JSON
  • 画像アップロード

編集結果はGitHub上の差分になります。そこからPR、build、レビューを通してmainへ入れます。

この設計は Sveltia CMS導入ガイド に詳しく書きました。

CMSの役割を「公開DB」ではなく「Git差分を作るUI」と捉えると、静的サイトとの相性がよくなります。

4. 多言語はUI翻訳ではなく静的ページにする

多言語対応は、CMS画面で全言語を直接編集する運用にはしませんでした。

日本語sourceを正として、翻訳はGitHub CopilotのPRに分けています。

理由は単純です。

  • 言語別URLを持てる
  • title、description、OGP、JSON-LDを言語別にできる
  • sitemap、RSS、hreflangに出せる
  • 翻訳差分をレビューできる
  • CMS画面を複雑にしすぎない

この考え方は Sveltia CMSで多言語ブログを運用する方法 にまとめています。

UI上で翻訳できることと、検索エンジンに言語別ページとして渡せることは別です。

だから、翻訳は表示時の処理ではなく、公開前のコンテンツ生成処理として扱います。

5. 問い合わせ導線は会話、CTA、フォームで分ける

問い合わせ周りは、全部をAIに寄せないようにしました。

訪問者の状態によって、適した導線が違うからです。

訪問者の状態 使う導線
どのサービスに合うか迷っている 問い合わせAI
すでにサービスページを読んだ サービスCTA
正式に相談内容を送りたい 問い合わせフォーム
LINEで軽く相談したい LINE導線

問い合わせAIは、公開済みサイト情報を使って案内します。個人情報をAIへ渡す場所にはしません。

サービスCTAは、ユーザーが読んでいたサービス文脈をURLパラメータでフォームへ渡します。フォーム側では、問い合わせ種別と件名を初期化します。

この部分は サービスCTAから問い合わせフォームへ文脈を引き継ぐ技術設計 で掘り下げています。

導線を増やすときは、役割を分けることが重要です。

AIチャットもフォームもLINEも、同じ「問い合わせボタン」ではありません。訪問者の迷い方に合わせて配置します。

6. AI出力はHTMLとして信頼しない

問い合わせAIを入れると、次に問題になるのが回答の描画です。

AIが 詳しくは[サービス一覧](/services/)をご覧ください のようなMarkdownを返すなら、リンクとして表示したくなります。

しかし、AI回答をそのまま innerHTML に入れてはいけません。

そこで、AIチャット回答のMarkdownリンク安全描画 では、次の方針にしました。

  • AI回答はテキストとして受け取る
  • 必要なMarkdownだけを小さく拾う
  • URLはtrimしてから許可リストで判定する
  • 許可できるURLだけDOM APIでリンク化する
  • 許可できないURLはテキストとして残す

AI機能をサイトに入れるときは、モデルの精度だけでなく、出力をどう表示するかまで設計対象です。

7. コメント機能はCloudflareだけで閉じる

コメント機能は、外部コメントサービスを使わずに作りました。

これは今回の構成の中でも、特に分かりやすい判断です。

すでにCloudflare Pagesで配信しているなら、軽いコメント機能はCloudflare内で完結できます。

  • Pages FunctionsでGET/POSTを受ける
  • D1にコメントを保存する
  • Turnstileをserver-side validationする
  • Originとhostname allowlistを見る
  • URL、メール、HTML、Markdownリンク、宣伝語句を拒否する
  • D1の実体名とbindingをWranglerで明示する

詳しくは CloudflareだけでAstroブログにコメント機能を作る方法 にまとめています。

コメント欄は便利ですが、荒らされやすい場所でもあります。

だから「コメント機能を足す」ではなく、「どこまで投稿を許すか」「何を検索indexに入れないか」「削除運用をどうするか」を最初に決めます。

8. 検索対象と交流機能を分ける

ブログ本文は検索対象です。

一方、コメントはPagefind対象から外しています。

これは、静的サイトに交流機能を足すときの重要な判断です。

公式サイトの本文はレビュー済みコンテンツです。コメントは訪問者の投稿です。コメント本文まで検索対象やSEO対象にするなら、承認制、静的HTMLへの再生成、moderationが必要になります。

最初の実装では、コメントは交流機能として扱い、検索対象にはしません。

同じように、AIチャットの会話ログもブログ本文ではありません。問い合わせフォームの入力も公開コンテンツではありません。

サイト内にある情報をすべて検索対象にするのではなく、公開コンテンツ、操作UI、ユーザー投稿、管理画面を分けて扱う必要があります。

コンテンツ・投稿・管理画面の公開境界 レビュー済み本文は静的検索の対象、訪問者投稿と管理面は別境界です。Previewと本番は別に確認します。
  1. レビュー済みの静的本文 レビュー済みの本文を静的HTMLとして公開し、サイト内検索Pagefindの対象として索引化する。
  2. 訪問者の投稿 コメントは動的APIと保存先で扱い、フォーム等の訪問者入力を静的検索へ混ぜない。対象化には承認と再生成が必要。
  3. 管理面・環境確認 管理画面は公開検索から分離する。Previewと本番を別々に確認し、環境設定の列挙だけで稼働を判断しない。

9. 目的別に読む

全部を一度に読む必要はありません。自分のサイトで足したい機能から入ると、判断しやすくなります。

やりたいこと 先に読む記事
ブラウザから記事や画像を更新したい Sveltia CMS導入ガイド
多言語ブログを検索対象として出したい Sveltia CMSで多言語ブログを運用する方法
AIチャットで訪問者を案内したい Astroサイトに問い合わせAIチャットを組み込む技術設計
AI回答に安全なリンクを出したい AIチャット回答のMarkdownリンクを安全に描画する実装設計
サービスページからフォームへ送客したい サービスCTAから問い合わせフォームへ文脈を引き継ぐ技術設計
外部コメントサービスなしでコメント欄を作りたい CloudflareだけでAstroブログにコメント機能を作る方法

おすすめの導入順

これから同じような構成を他サイトへ入れるなら、実装順はこうです。

  1. 静的ページ、ブログ、RSS、sitemap、OGPをAstroで固める
  2. Sveltia CMSで日本語sourceを編集できるようにする
  3. 多言語ページを静的HTMLとして生成する
  4. AIチャットとサービスCTAで相談導線を整える
  5. AI回答のMarkdownリンクやフォームprefillの安全境界を固める
  6. 必要になってからCloudflare内でコメント機能を足す

最初にCMSと多言語を固めると、後から記事を増やしやすくなります。

問い合わせAIやサービスCTAは、問い合わせ導線を強くしたいタイミングで入れます。

コメント機能は、ブログが読まれ始めてから足すくらいで十分です。

他サイトへ転用するときの最小構成

すべてを一度に入れる必要はありません。

最小構成はこうです。

Astro
  - 静的ページ
  - ブログ
  - RSS / sitemap / OGP

Cloudflare Pages
  - 静的配信
  - preview環境

GitHub
  - PRレビュー
  - build check

次に、必要に応じて足します。

CMSが必要
  -> Sveltia CMS + GitHub backend + CMS PR

多言語が必要
  -> locale別Markdown + 翻訳PR + hreflang

問い合わせ導線を強くしたい
  -> AIチャット + サービスCTA + フォームprefill

交流機能が必要
  -> Pages Functions + D1 + Turnstile + moderation方針

この順番なら、機能を足しても土台を壊しにくいです。

まとめ

Astro + Cloudflareの公式サイトは、静的サイトのままでもかなり機能拡張できます。

重要なのは、すべてを一つの仕組みに押し込まないことです。

Astroは公開HTMLを作る。Cloudflareは配信と小さなAPI境界を受け持つ。Sveltia CMSは日本語sourceを編集する。翻訳はPRで作る。AIチャットは相談導線の整理に使う。コメントはCloudflare内に閉じる。検索対象はレビュー済みコンテンツに絞る。

このようにレイヤーを分けると、公式サイトは単なる会社案内ではなく、更新、翻訳、相談、交流まで扱える運用基盤になります。

このページを入口にすると、必要な機能だけを選びながら、静的サイトの土台を崩さずに拡張できます。

補足:Workersの本番・検証環境とビルド設定を分ける

2026年9月30日追記。関連するビルド設定の整理を、固有サービス名や内部設定を使わず設計原則として補足します。複数Workerを同じリポジトリで管理する場合、WorkerごとのWrangler設定、ソースのルート、ビルド・デプロイ対象を対応させます。設定ファイルを分けるだけでは環境分離の証明になりません。

本番・検証ごとに変数、秘密情報、D1・R2・Service Bindingなどの接続先を確認します。Workersの環境設定ではbindingsと変数は自動継承されないため、環境ごとに明示します。必要な設定がないときは、本番接続先へ黙って切り替えず処理を止める設計にします。永続的なstaging環境と、ブランチ・PRごとのPreviewも同じものとして扱いません。

本番の反映経路を一つに定め、事前検証後に本番ブランチから反映します。非本番のビルドやversionの作成は確認用とし、成功しただけで本番へ昇格したとは扱いません。Git連携のビルドでは、対象ブランチ・commit、ルート、選択する設定・環境、デプロイコマンドを確認します。Pagesの公開が成功しても、別Workerの反映まで完了したとは限りません。CI、本番ビルド、稼働中のバージョン・接続先、公開ドメインの動作をそれぞれ確認します。これらは転用時の確認項目であり、全サービスの環境分離を実証したという意味ではありません。

詳細はCloudflare公式のWorkers環境設定、Workers Buildsの複数Worker構成、ビルド設定を参照してください。Pages FunctionsはPages用のWrangler設定として区別します。

補足:外部フィードの再試行と障害を入力元ごとに分ける

2026年9月30日追記。RSSなどの公開フィードを取り込む処理は、RSSを出力する処理とは別の運用です。取得には待ち時間と再試行回数の上限を設け、一時的な失敗を再確認しても、無期限に処理を続けないようにします。

複数の入力元は失敗を個別に扱います。一つの取得に失敗しても、独立して更新できるほかの入力まで停止させない構成にします。一部成功を全件成功とせず、入力元ごとの結果と残る失敗をジョブの報告へ残します。取得の成功、生成データ、本番ビルド、公開ページの確認も分けます。これは一般的な設計確認であり、すべての障害条件や将来の入力元への適用を実証したという意味ではありません。

2026年10月6日追記:API契約と添付の確認範囲

匿名化した改修では、frontend/backendのsessionやlimitの契約のずれにより、処理が成功した後でも応答を503へ変えてしまう経路を修正しました。HTTP結果、保存された状態、UI表示を分けて照合し、クライアントの再送が二重の書き込みにならないように扱います。

添付欄が表示されることと、実ファイルの転送・保存・再取得まで確認できたことも別です。UIやAPIの改修だけで後者を完了扱いにはしません。静的公開サイトから非公開管理画面への境界はダッシュボードの認証と集計、決済の外部状態照合はWebhookの状態管理に分けて記載しています。

Site Architecture

公式サイトを機能拡張するレイヤー

静的サイトを土台にしつつ、必要な部分だけ動的にしていきます。

  1. 配信する

    Astroで静的HTMLを生成し、Cloudflare Pagesで配信する。

  2. 更新する

    Sveltia CMSで日本語sourceを編集し、GitHub PRで確認する。

  3. 翻訳する

    翻訳はCMS画面ではなく、CopilotのPR運用に分離する。

  4. 案内する

    問い合わせAIとサービスCTAで、訪問者を適切なフォームへ送る。

  5. 受ける

    Pages FunctionsでAPI境界を作り、D1やTurnstileを必要な箇所だけ使う。

  6. 守る

    Markdown描画、Origin、rate limit、noindex、Pagefind対象を分けて制御する。

ただ機能を足す場合と、全体設計として足す場合

機能ごとに足す

  • AI、CMS、コメント、フォームがそれぞれ別の設計思想になる
  • 外部サービスのscriptや管理画面が増え、説明責任が分散する
  • 多言語URL、検索index、preview環境でズレが起きやすい
  • 機能同士の関係が見えず、導入順を決めにくい

レイヤーで足す

  • Astro、Cloudflare、GitHub、OpenAI APIの役割を分けて説明できる
  • 動的APIはPages Functionsに集め、保存先はD1などCloudflare側に寄せられる
  • CMS更新、多言語翻訳、検索、RSS、sitemapを同じコンテンツ構造で扱える
  • 用途別・導入順のインデックスとして読み進めやすい

他サイトへ転用するときの設計チェック

  • 静的に出せるものと、APIが必要なものを分ける
  • CMSは編集入口、翻訳はPR、公開判断はbuildに分離する
  • 問い合わせAIには個人情報を渡さず、公開済み情報だけを案内させる
  • フォーム導線はURLパラメータで文脈を渡し、受信値は安定した分類にする
  • コメントなど投稿データはD1の実体名とbindingを設定で明示する
  • AI出力やユーザー投稿は、HTMLとして信頼せず許可リストで扱う

よくある質問

どこから導入すべきですか?

まずAstroの静的ページ、ブログ、RSS、sitemap、OGPを固めます。次にCMSと多言語を入れ、相談導線が必要になってからAIチャット、サービスCTA、コメント機能を足す順番が扱いやすいです。

すべてCloudflareだけで作るべきですか?

いいえ。問い合わせAIのようにOpenAI APIを使う部分もあります。ポイントは、配信、API境界、DB、bot対策をCloudflareへ寄せ、外部サービスを入れる場所と入れない場所を意識して分けることです。

小規模サイトでもここまで必要ですか?

最初から全部は不要です。ただ、CMS、問い合わせ導線、多言語、コメントのどれかを足す予定があるなら、URL、データ保存先、preview環境、検索indexの扱いを早めに決めると後から楽になります。