個人ブログをCloudflareで公開するまでの2日間の記録


このブログの最初のコミットは2026年8月7日の9時54分で、一般公開が翌8日の9時14分でした。23時間20分。手際がよかったから短いのではありません。記事21本はその前に書き溜めてあり、Astroでのサイト生成も手元で動いていました。残っていたのは、それを外に出す作業だけです。ところが、その「出すだけ」の工程で立て続けにつまずきました。何につまずき、どう判断したかをGitの履歴から起こしておきます。同じ構成で始める人が、23時間のうち無駄だった数時間を飛ばせるように。

静的ブログの公開作業でつまずくのはサイト本体ではなく、「見せない・見せる」の切り替えと配信の設定でした。

全体像:何をどこに置いたか

先に構成を一覧にします。ここは公開の前後で変わっていません。

役割使ったもの補足
サイト生成Astro 5完全な静的サイト。ビルドでHTMLを全部生成する
記事Markdownファイルsrc/content/blog/ にfrontmatter付きで置く
管理画面Sveltia CMSGitベースのヘッドレスなオープンソースの管理画面※1。記事はGitHubに保存される
配信Cloudflare Workers(静的アセット)ビルド済みの dist/ をWorkerから配信
ビルドと配信の自動化Workers BuildsGitHubにpushすると自動でビルドして配信する※2
ドメインyohakulab.comCloudflareで取得し、Workerに割り当て
サイト内検索Pagefindビルド時に索引を作る。ビルドコマンドは astro build && pagefind --site dist

Astro公式にはCloudflareへの配信手順があり※3、それに沿って作っています。ここまでは何も難しくありません。難しかったのは、この構成のまま「まだ誰にも見せない」状態を作ることでした。

最初につまずいたのはPagesとWorkersの違い

公開前にレビューしてもらうため、サイト全体にBasic認証をかけることにしました。8月7日10時25分、functions/_middleware.js というファイルを足しています。これはCloudflare Pagesの「Functions」の書き方で、Pagesではこのフォルダに置いたコードがリクエストの前後で動きます※4。

4分後の10時29分に、それを消して書き直しました。このサイトを置いていたのはPagesではなく、Workersの静的アセット機能だったからです。PagesとWorkersはどちらもCloudflareで静的サイトを配信できて、GitHub連携で自動ビルドもできる。頭の中では同じ棚に入っていたのですが、ミドルウェアの書き方は別物でした。Workers側では、worker/index.jsfetch でヘッダーを見て、通すか401を返すかを自分で書きます。

// worker/index.js(公開前)
export default {
  async fetch(request, env) {
    const auth = request.headers.get('Authorization') || '';
    const expected = 'Basic ' + btoa(`${USER}:${PASS}`);
    if (auth === expected) {
      return env.ASSETS.fetch(request);
    }
    return new Response('Authentication required', {
      status: 401,
      headers: { 'WWW-Authenticate': 'Basic realm="yohaku-lab preview"' },
    });
  },
};

これで終わりだと思ったら、まだ抜け穴がありました。16分後の10時45分に、wrangler.jsonc へ1行足しています。

"assets": {
  "directory": "./dist",
  "binding": "ASSETS",
  "run_worker_first": true   // 全リクエストをWorker経由にする
}

Cloudflareのドキュメントによれば、静的アセットとWorkerの両方を設定している場合、まず静的アセットに一致するものがあればそれを配信します※5。つまり既定では、HTMLや画像に一致するリクエストはWorkerを通りません。認証コードを書いても、肝心のページはその手前で配られてしまう。run_worker_first は、Workerを先に走らせるための設定です※5。速さを捨てて認証を優先する、公開前だけの切り替えでした。

10時25分から10時45分までの20分で、Basic認証を3回書き直したことになります。あとから見れば、ドキュメントの「Routing」の章を先に読んでいれば1回で済んだ話です。

公開の朝:ドメインを取り、CMSをつなぎ、認証を外す

翌8月8日の朝は、公開に必要な残りを順に片づけています。

時刻(日本時間)やったこと
8:31yohakulab.com を取得(レジストラの登録記録より)
8:47Sveltia CMSの認証を有効化(GitHubログイン用の認証Workerを別に用意)
9:14Basic認証を外し、run_worker_first を消して公開

ドメインを取ったのが公開の43分前です。これは計画的ではなく、前日まで名前を決めかねていたからです。取得したドメインはWorkerのカスタムドメインとして割り当てました※6。Workersには最初から *.workers.dev のURLが付いているので、独自ドメインがなくても公開はできます。

公開の操作そのものは拍子抜けするほど小さく、fetch を1行に戻し、設定から run_worker_first を消しただけです。

// worker/index.js(公開後)
export default {
  async fetch(request, env) {
    return env.ASSETS.fetch(request);
  },
};

この時点で記事のファイルは22本(うち数本は公開日を先にした予約投稿)。前日の夜に1本足していました。

やり直すなら、ここを変える

23時間の中で「次はこうする」と思った点を、正直に並べておきます。

やったこと問題次はこうする
Basic認証のユーザー名とパスワードをコードに直書き非公開リポジトリだから許したが、履歴に残るWorkersのシークレットに入れる
Pages向けのミドルウェアを先に書いた4分で気づいたが、配信先を決めてから書けば無駄がない「PagesかWorkersか」を最初にメモに書く
run_worker_first を後から足した16分間、静的ファイルが認証を通らずに配られていた可能性がある(公開前なので実害はなし)ドキュメントの「Routing」を先に読む
公開後も *.workers.dev のURLが生きたまま独自ドメインと同じ内容が二重に配信されているworkers_dev: false で止める。この記事の時点でまだやっていない
予約投稿の自動再ビルドを設定した「つもり」実は動いていなかった別の記事に書いた

最後の2行は、この記事を書いている時点で未解決です。二重配信のほうは、canonicalが独自ドメインを指しているので検索エンジン上の実害は小さいと判断して後回しにしましたが、「後回し」がそのまま10日経ちました。片づけたら、この表を更新します。

公開作業を振り返って残った感想はひとつで、静的サイトは「作る」より「見せ方を切り替える」ほうに落とし穴が多い、ということです。作る側の情報は豊富にありますが、公開前に隠す、公開する、古いURLを閉じる、といった運用の切り替えは、自分でドキュメントを読んで組み立てるしかありませんでした。その手順を残しておけば、次のサイトは23時間かかりません。

参考文献・出典

※1 : 「GitHub - sveltia/sveltia-cms: Leading Git-based headless CMS. Successor to Netlify/Decap CMS.」 |GitHub https://github.com/sveltia/sveltia-cms

※2 : 「Builds · Cloudflare Workers docs」 |Cloudflare Docs https://developers.cloudflare.com/workers/ci-cd/builds/

※3 : 「AstroサイトをCloudflareにデプロイする」 |Astro Docs https://docs.astro.build/ja/guides/deploy/cloudflare/

※4 : 「Functions · Cloudflare Pages docs」 |Cloudflare Docs https://developers.cloudflare.com/pages/functions/

※5 : 「Worker script · Cloudflare Workers docs」 |Cloudflare Docs https://developers.cloudflare.com/workers/static-assets/routing/worker-script/

※6 : 「Custom Domains · Cloudflare Workers docs」 |Cloudflare Docs https://developers.cloudflare.com/workers/configuration/routing/custom-domains/

よくある質問

AstroのブログはCloudflareのPagesとWorkersのどちらで公開できますか?

どちらでも公開できます。このブログはWorkersの静的アセット機能を使い、GitHubにpushするとWorkers Buildsが自動でビルドして配信する構成にしました。ただし、Pages向けの書き方(functionsフォルダのミドルウェアなど)はWorkersでは動かないので、どちらに置いているかを最初に決めておく必要があります。

公開前のサイトにBasic認証をかけるには?

Workersの静的アセット構成では、Workerのfetchハンドラーで Authorization ヘッダーを検査し、wrangler.jsoncのassetsに run_worker_first を設定します。この設定がないと、静的ファイルに一致するリクエストはWorkerを通らずに配信されるため、認証をすり抜けます。

公開したあとに残った作業はありますか?

このブログでは、公開前に使っていた workers.dev のURLが公開後もそのまま生きていて、独自ドメインと同じ内容が二重に配信されています。canonicalは独自ドメインを指しているので実害は小さいものの、workers.devの配信を止める設定を後回しにしたままです。