チュートリアル
Astro を Cloudflare Workers にデプロイする(2026年版)
· 更新 · 読了まで約12分
目次
長いあいだ「Astro を Cloudflare にデプロイする」といえば Cloudflare Pages のことでしたが、その前提はもう古くなりました。Cloudflare は Workers の静的アセット(static assets) に軸足を移し、新規プロジェクトには Workers を勧め、Pages への新機能追加も止めています。
とはいえ悪い話ではありません。静的な Astro サイトを載せる手順で言えば、Workers のほうが Pages 時代よりむしろ簡単です。設定ファイル1つとコマンド1つで、Cloudflare のエッジにサイトが乗ります。
このブログ(astro.p4ni.com)も、販売している商用 Astro テーマも、この構成で動かしています。扱うのは次の5点です。
- なぜ Workers なのか(「静的アセット」とは何か)
- 静的 Astro サイトのための最小の
wrangler.jsonc wrangler deployでのデプロイ- 独自ドメインの接続(国内レジストラで取ったドメインを使うときの注意点も)
- 落とし穴: 404 ページ、末尾スラッシュ、Cloudflare アダプタが本当に必要になる場面
なぜ Pages ではなく Workers なのか
先に結論だけ表にしておきます。
| 作ろうとしているもの | 選ぶべきもの |
|---|---|
| 新規の静的 Astro サイト | Workers(この記事) |
| SSR ルートを含む新規 Astro サイト | Workers + @astrojs/cloudflare(最後の落とし穴を参照) |
| すでに Pages で動いている既存サイト | Pages のままで動く。移行は都合のよいときに |
| Cron Triggers・Queue コンシューマ・段階的デプロイが要る | Workers(Pages はここが同等になりませんでした) |
Pages がいらなくなったのは、Workers に「静的アセット」機能が入ったからです。Worker がファイルの入ったディレクトリ(つまり dist/)をそのまま同梱できるようになり、Cloudflare がそれを CDN から直接配信してくれます。完全な静的サイトなら Worker のコードは1行も書きませんし、課金もされません。静的アセットから返したリクエストは、Free プランを含む全プランで無料・無制限です。
上限があるのはトラフィックではなくファイル数のほうで、Free で 20,000 ファイル、有料プランで 100,000 ファイル、1ファイルあたり 25MiB です。ブログでここに当たるとしたら、ページごとに何か(たとえば OG 画像)を生成している場合ですが、それでもすぐには届きません。
日本からのアクセスについても補足しておくと、Cloudflare は東京と大阪にエッジを持っていて、静的アセットもそこから配信されます。国内向けのサイトが海外リージョンまで往復する、といった構成にはなりません。
Step 0: Astro サイトを用意する
静的な Astro プロジェクトなら何でも構いません。ゼロから始めるなら次の2行から。
pnpm create astro@latest my-site -- --template minimal
cd my-site
Astro はデフォルトで静的なので、アダプタは要りません。pnpm build を叩けば dist/ に素の HTML/CSS/JS が出てきます。これがそのままデプロイ対象になります。
Step 1: Wrangler を入れる
Wrangler は Cloudflare の CLI です。誰が叩いても同じ結果になるよう、開発依存として入れておきます。
pnpm add -D wrangler
Step 2: wrangler.jsonc を書く
プロジェクトのルートに wrangler.jsonc を作ります。静的サイトの設定はこれで全部です。
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "my-site",
"compatibility_date": "2026-07-27",
"assets": {
"directory": "./dist",
"not_found_handling": "404-page"
}
}
押さえておきたいのは3点です。
nameがそのまま Worker 名になり、無料のプレビュー URLmy-site.<自分のサブドメイン>.workers.devにもなります。assets.directoryは Astro のビルド出力を指します。効いているのは、mainフィールドを書いていないことです。実行する Worker スクリプトが無いので、Cloudflare はディレクトリをそのまま配信します。not_found_handling: "404-page"を入れると、dist/404.html(Astro がsrc/pages/404.astroから生成したもの)を 404 ステータス付きで返してくれます。SPA をデプロイするなら、ここは"single-page-application"に変えます。
Step 3: デプロイする
一度認証すれば、あとはデプロイするだけです。
pnpm exec wrangler login
pnpm build
pnpm exec wrangler deploy
Wrangler が dist/ をアップロードすると、数秒で https://my-site.<自分のサブドメイン>.workers.dev が見られるようになります。ビルド忘れを防ぐため、package.json にスクリプトを足しておきましょう。
{
"scripts": {
"deploy": "astro build && wrangler deploy"
}
}
これ以降、公開作業は pnpm run deploy の一手です。run を省くと動きません。pnpm は pnpm deploy をワークスペース用の組み込みコマンドとして予約しているので、こちらのスクリプトまで呼び出しが届かないのです。毎回 run を打つのが煩わしければ、pnpm が押さえていない名前(ship など)に変えてしまうのが早いと思います。
Step 4: 独自ドメインを繋ぐ
ドメインの DNS がすでに Cloudflare にある(つまりゾーンが同じアカウントにある)なら、ダッシュボードを触る必要はありません。wrangler.jsonc にドメインを書くだけで済みます。
{
// …ここまでの設定はそのまま…
"routes": [
{
"pattern": "blog.example.com",
"custom_domain": true
}
]
}
次に wrangler deploy を打つと、Cloudflare が DNS レコードを作り、TLS 証明書も自動で発行してくれます。いま読んでいるこのサイトも、この書き方で astro.p4ni.com に繋いでいます。設定を数行足して、デプロイし直すだけです。
お名前.com などで取ったドメインを使う場合
ここが日本で詰まりやすいところです。Workers の独自ドメイン(Custom Domains)は、Cloudflare がネームサーバーを管理しているゾーンにしか設定できません。 お名前.com、ムームードメイン、さくらのドメインといった国内レジストラで取ったドメインは、レジストラの DNS に置いたままでは使えません。
とはいえ必要なのはドメインの移管(トランスファー)ではなく、ネームサーバーの変更だけです。
- Cloudflare のダッシュボードでドメインをゾーンとして追加する(Free プランで構いません)
- Cloudflare が割り当てるネームサーバー2つを控える
- レジストラの管理画面で、ネームサーバーをその2つに変更する
- 反映を待つ(数分〜48時間。実際には数十分で終わることが多い)
- 反映後に
wrangler deployを実行すると、DNS レコードと証明書が自動で作られる
ドメインの登録自体はレジストラに残るので、更新や請求先は変わりません。気をつけたいのは既存のメールです。そのドメインでメールを受け取っているなら、ネームサーバーを切り替える前に MX レコードを Cloudflare 側へ移しておいてください。ここを飛ばすとメールが止まります。
Astro に本番 URL を教える
canonical URL やサイトマップ、RSS のリンクを絶対 URL にするため、Astro 側にも本番 URL を伝えておきます。
// astro.config.mjs
export default defineConfig({
site: 'https://blog.example.com',
});
site を設定してしまえば、ついでに片付けられるものがあります。Workers の静的アセットは dist/ の中身なら何でも配信するので、ページごとの OG 画像もビルド時に生成して、ただの PNG として置いておけば済みます。サーバーレス関数も実行時のコストも要りません。手順は Astro と Satori で OG 画像を自動生成するにまとめてあります。site が与えてくれる絶対 URL は各ページの JSON-LD にも必要になるので、どちらを書くにしても先に設定しておくと楽です。
すでに Pages で動いているサイトを移行する
Astro 側のソースは何も変わりません。Pages も Workers の静的アセットも、同じ dist/ を配信しているにすぎません。書き換えるのは設定だけです。
- ビルド出力: Pages の
pages_build_output_dirが、Workers ではassets.directoryになります。パスは同じで、キーの名前だけが変わります。 - 404 の扱い: Pages は自動で判定していましたが、Workers では上記の
not_found_handlingで明示します。 - 環境変数: 引き継がれません。
[vars]に書き直すか、wrangler secret putで入れ直してください。CI でビルドしているなら、Workers Builds が Pages のビルド時変数を継承せず独自に持つ点にも注意が要ります。 _headersと_redirects: そのまま使えます(後述)。
切り替える前に知っておきたいことが2つあります。ひとつはドメインの制約です。Workers が独自ドメインを配信できるのは、Cloudflare がネームサーバーを管理しているゾーンに限られます。Pages より条件が厳しいので、外部 DNS のドメインを Pages プロジェクトに向けていた場合、その構成はそのままでは移せません。
もうひとつ、ドメインの移動は一度きりの切り替えになります。新旧を並行して走らせ、様子を見ながら寄せていく進め方はできません。まず Worker をデプロイして workers.dev の URL で動作を確かめ、それからホスト名を移します。
ローカル開発の細かい話もひとつ。wrangler dev が使うポートは 8787 です。wrangler pages dev に慣れていると 8788 を開いて首をかしげることになります。
知っておきたい落とし穴
末尾スラッシュ。 静的アセットの HTML 処理はデフォルトが auto で、/about/ には about/index.html を返し、/about は /about/ へ 307 で飛ばします。Astro のデフォルト(ディレクトリ形式の出力)と噛み合うのでそのまま動きますが、内部リンクの書き方だけは統一しておいたほうが安全です。開発と本番で挙動を合わせたいので、私は astro.config.mjs に trailingSlash: 'always' を書いています。
_headers と _redirects。 Pages 形式のこの2ファイルは Workers の静的アセットでもそのまま効きます。public/ に置けば Astro が dist/ にコピーしてくれるので、フォントのキャッシュヘッダーを足したり、移行後に旧 URL を飛ばしたりするのに使えます。
デプロイ前にプレビューする。 wrangler dev を使うと、本番と同じアセット配信ルールでビルド済みのサイトがローカルに立ちます。リダイレクトや 404 の挙動は astro preview だと少しずれるので、ここで確かめておけます。
アダプタが本当に必要になる場面。 ここまでは全ページをプリレンダリングする前提の話でした。パーソナライズやフォーム処理、D1 を叩く API ルートなど、SSR が要る要件が出てきた時点で @astrojs/cloudflare を足します。それでも静的ページは無料の静的アセットのまま配信され、サーバーでレンダリングするルートだけが Worker を呼ぶ形になります。私のディレクトリテーマ Almanac がこのハイブリッド構成で、閲覧まわりは静的、検索・投稿・管理画面だけ D1 を使って Worker 側で動かしています。
似た構成を考えているなら、無料・有料を問わず、見つけられる限りのテーマを比べたディレクトリテーマ比較も置いてあります。Worker 側の仕組みが要るかどうかは、結局どんなデータ層を選ぶかで決まります。
まとめ
pnpm add -D wrangler # 1. CLI を入れる
# 2. wrangler.jsonc に assets.directory = ./dist を書く
pnpm exec wrangler login # 3. 一度だけ認証する
pnpm run deploy # 4. astro build && wrangler deploy
静的な Astro を Workers に載せるのに要るのは、暗記できる長さの設定ファイル1つだけ。これで Cloudflare のエッジに、無料・従量課金なしでサイトが置けます。しかも「ただの静的サイト」では収まらなくなったときには、D1 や SSR へそのまま進む道が残ったままです。