このブログを作った技術構成 — Astro × GitHub × Cloudflare Pages
個人ブログを Astro と Cloudflare Pages で立ち上げ、GitHub に push すれば公開される構成にした記録。
このブログをどう作ったかをまとめておきます。Markdown でメモを書き、git push したら勝手に公開される。それを無料で長く続けられる構成を選びました。
なぜこの構成にしたか
私が個人ブログでまず気にしたのは「お金をかけずに続けられること」と「執筆だけに集中できること」です。WordPress のように DB とサーバーを運用するのは面倒で、毎月の費用もずっと気になり続けます。
そこで採用したのが 静的サイト + Git + 静的ホスティング の組み合わせです。
- 静的サイトジェネレータ(Astro)でビルドし、できあがった HTML / CSS / JS を配信するだけにする
- ソースを GitHub に置き、記事もリポジトリに
.mdとして追加する - Cloudflare Pages にリポジトリを繋ぎ、push のたびに自動ビルド・自動公開させる
これで自分は Markdown を書いて push するだけ、サーバーの面倒は見ない、という運用に近づきます。3 つのサービスはどれも無料枠で十分回ります。
Astro の基本
Astro は最近よく見るようになった静的サイトジェネレータで、デフォルトで全ページを HTML に書き出してくれます。
ディレクトリ構成はおおまかにこんな形になりました。
src/
├── pages/ # ファイルベースルーティング
│ ├── index.astro
│ └── posts/[...slug].astro
├── layouts/ # 共通レイアウト
│ └── BaseLayout.astro
├── content/
│ └── blog/*.md # 記事の本体(Markdown)
└── content.config.ts # 記事のスキーマ(zod)
特に便利だったのが Content Collections で、Markdown の frontmatter に型を付けられます。私のブログでは次のようにタイトル・カテゴリ・タグを縛っています。
// src/content.config.ts
import { defineCollection, z } from "astro:content";
const blog = defineCollection({
type: "content",
schema: z.object({
title: z.string(),
description: z.string(),
publishedAt: z.coerce.date(),
category: z.enum(["education", "research", "game", "misc"]).default("misc"),
tags: z.array(z.string()).default([])
})
});
export const collections = { blog };
スキーマで弾かれるとビルドが落ちるので、frontmatter の書き間違いを公開前に必ず検知できるのがありがたい部分です。
GitHub での記事運用
GitHub の使い方はシンプルで、リポジトリを 1 つ作って、それをそのままブログのソースにしています。
新しい記事を書くときの流れは次のとおりです。
src/content/blog/<slug>.mdを新規作成する- frontmatter を書く(タイトル、カテゴリ、公開日など)
- 本文を Markdown で書く
git add→git commit→git push
個人運用なら main ブランチに直 push でも問題ありません。私は試しに大きめの変更のときだけ feature branch を切って Pull Request を作るようにしてみましたが、履歴が見やすくなる以外は大きな違いはありませんでした。
公開を取り下げたい記事は frontmatter に draft: true を入れておけば、一覧から自動で除外されます(getCollection("blog", ({ data }) => !data.draft) で絞り込めるため)。
Cloudflare Pages で公開
Cloudflare Pages は静的サイト向けの無料ホスティングで、GitHub と連携しておけば push をフックに自動でビルド・デプロイしてくれます。
設定は次の手順でした。
- Cloudflare ダッシュボードから Workers & Pages → Create → Pages → Connect to Git を選ぶ
- GitHub の Cloudflare Pages App をインストール(リポジトリ単位で許可することも可能)
- 連携したいリポジトリを選択
- ビルド設定を入力
私が入力したビルド設定はこれだけです。
| 項目 | 値 |
|---|---|
| Framework preset | Astro |
| Build command | npm run build |
| Build output directory | dist |
| Production branch | main |
初回ビルドが終わると <project>.pages.dev という URL が割り当てられ、すぐに公開されます。
CI/CD として動くこと
連携が終わったあとは、git push がそのままデプロイ操作になります。
mainへの push → 本番デプロイ。<project>.pages.dev(またはカスタムドメイン)が更新される- その他のブランチへの push → プレビュー用 URL が発行される(例:
<branch>.<project>.pages.dev) - Pull Request を開く → その PR に対するプレビュー URL が自動でコメントされる
プレビュー URL には Cloudflare 側で自動的に X-Robots-Tag: noindex が付くので、書きかけの記事や試行錯誤中のレイアウトが検索結果に紛れ込む心配がありません。
ビルドログは Cloudflare のダッシュボードに残り、失敗したときも何が落ちたか追えます。たとえば npm run build の出力で Cannot find package のようなエラーがあれば NODE_VERSION の問題、TypeScript の型エラーなら frontmatter の不足、というように原因を辿りやすくなっています。
ここまでくると、
- 記事を書く → push する → ビルドが走る → 数十秒で公開される
というループが完成し、運用に頭を使う場面はかなり減りました。CI/CD を意識せずとも、自然に「Markdown を書いて push するだけ」になっています。