はじめに

Astroで作成した静的ブログサイトをCloudflare Pagesで公開し、カスタムドメインを設定するまでに、いくつか思わぬ落とし穴にハマってしまいました。

今回は、ビルドが通らなかったり、デプロイは成功しているのにサイトが「404 Not Found」になってしまったりしたトラブルとその解決のプロセスを技術記事としてまとめます。

この記事でわかること:

  • Cloudflare WorkersPages のデプロイ挙動の違い
  • @astrojs/cloudflare アダプターが静的サイトのビルド出力に与える影響と404エラーの対策

1. 最初の罠:WorkersプロジェクトとPagesプロジェクトの混同

発生したトラブル

GitHubへのプッシュを検知してビルドが走る設定にしたところ、デプロイ時に以下のようなエラーが発生し、ビルド全体が失敗してしまいました。

 [ERROR] A request to the Cloudflare API (/accounts/.../storage/kv/namespaces) failed.
  a namespace with this account ID and title already exists [code: 10014]
Failed: error occurred while running deploy command

原因

静的サイトをデプロイするつもりだったのですが、Cloudflareダッシュボードでプロジェクトを作成する際、誤って 「Workers」 プロジェクトとして作成し、そこにGit統合を設定していました。

  • Workersプロジェクトの場合: ビルド後にデプロイコマンド(デフォルトでは npx wrangler deploy)が実行されます。この時、プロジェクト内にKVの設定などが競合していると、重複エラーなどでデプロイ自体が落ちてしまいます。

試したこととさらなる罠

エラーを回避するため、デプロイコマンドを echo done(何もしないコマンド)に一時的に変更しました。 結果としてビルドは「成功(Success)」するようになりましたが、今度はどれだけプッシュしてもサイトの内容が更新されなくなりました。

理由は簡単で、Workersプロジェクトにおいて Deploy commandecho done にしたことで、ビルドはするものの実際のアップロード(デプロイ)処理がスキップされてしまったからです。

解決策

Cloudflareダッシュボードでプロジェクトを一度削除し、正しく 「Pages」 プロジェクトとして新規作成し直してGitHubと再連携しました。

Pagesプロジェクトであれば「デプロイコマンド」という設定項目自体が存在せず、ビルド後に自動的にファイルがアップロードされるため、余計なKVエラーに悩まされることがなくなります。


2. 第2の罠:デプロイ成功したのに「HTTP ERROR 404」

発生したトラブル

Pagesとしてプロジェクトを作り直し、デプロイも無事に「成功(Success)」になり、カスタムドメインの設定も「Active」になりました。 しかし、いざデフォルトドメイン(xxx.pages.dev)やカスタムドメインにアクセスすると、無情にも 「HTTP ERROR 404(見つかりません)」 と表示され、サイトが開けませんでした。

原因

プロジェクトの astro.config.mjs に、初期設定の段階でなんとなく追加していた @astrojs/cloudflare アダプター が有効になっていたことでした。

// astro.config.mjs (修正前)
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';
import cloudflare from '@astrojs/cloudflare';

export default defineConfig({
  site: 'https://...',
  integrations: [sitemap()],
  adapter: cloudflare(), // ← これが原因!
});

Astroで output: "static"(デフォルトの静的モード)のまま Cloudflare アダプターを有効にすると、Astroはビルド成果物を dist/ 直下ではなく、dist/client/ ディレクトリの中に格納します。

しかし、Cloudflare Pagesのビルド出力ディレクトリ設定はデフォルトで dist になっています。 Cloudflare Pagesは dist/index.html を探しますが、実際には dist/client/index.html に入っているため、ファイルが見つからず 404 エラーを返していたのです。

解決策

このブログは完全に静的なコンテンツのみで構成されているため、サーバーサイド機能(SSR)用のアダプターは不要です。

設定ファイル astro.config.mjs から @astrojs/cloudflare のインポートと adapter オプションを削除しました。

// astro.config.mjs (修正後)
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';

export default defineConfig({
  site: 'https://...',
  integrations: [sitemap()],
  // adapter は削除!
});

この修正により、Astroは通常の静的ビルド(SSG)を行い、成果物を直接 dist/ 直下に出力するようになります。これをプッシュしたところ、Pagesの出力ディレクトリ設定(dist)と完全に一致し、無事にサイトが表示されるようになりました!


まとめ

今回のトラブルから学んだ教訓は以下の2点です。

  1. 静的サイトを公開するなら、Cloudflareでは「Workers」ではなく「Pages」を選択する。
  2. 完全な静的サイト(ブログなど)の場合、Astroの設定に不要なアダプター(@astrojs/cloudflareなど)は含めない。(含めてしまうと、出力ディレクトリ構造が変わり404エラーの原因になります)

Cloudflare Pagesは非常に高速で使いやすいサービスですが、Workersとの連携周りで少し設定が複雑に見える部分もあります。同じようにAstroのデプロイで404エラーに悩んでいる方の参考になれば幸いです。