これまでClaude Codeを利用して、Cloudflare Pagesでブログを作成・運用してきました。作り始めて2週間は、試行錯誤しながら夢中で運用してきたのですが、1日1記事ペースでアップするようなルーティンができてきたため、現状のブログ運用の仕組みを整理したくなりました。
Claude Codeにこんなことやりたい、あんなことやりたいと相談して、今の仕組みが出来上がりました。その中で、何回もClaude Codeが思ったように動いてくれないこともあり、一度、「仕組みが悪いんじゃないか。全体の仕組みを見直して。」とお願いしたこともあります。このように、Claude Codeに仕組み構築をお願いしていたこともあって、自身でも全体像をぼんやりとしかわかっていませんでした。そこで今回、それをClaude Codeに整理してもらいました。
整理していく中で、以下のような課題が今の仕組みで対処されていることが改めてわかりました。
- 記事を書いてすぐ公開するのは怖い。確認してからアップしたい
- 外出先からでも記事の内容を確認したい
- 「毎朝8時に投稿」みたいな予約投稿が静的サイトでできるか分からない
Draft環境と本番環境を分けた2段階フローを持つことで、これらの課題をすべて解決しています。 ファイルの置き場所だけで公開先が変わるシンプルな仕組みなので、一度作ってしまえば運用はほぼ自動です。
このフローが機能しているのは、GitとCloudflare Pagesの組み合わせが「ファイルを動かす=公開状態を変える」という単純な構造で動いているからです。本記事では、このブログ「金融エンジニアの資産運用実験室」で実際に運用している仕組みをベースに確認していきます。
※本記事は個人の運用体験をもとにした仕組み紹介です。構成の詳細は環境によって異なります。
この記事の位置づけ:本記事はブログ記事の公開フロー(Draft確認・投稿予約)の仕組みに特化しています。このブログをClaude Codeで開設した経緯の全体は「Claude Codeでブログを作った話 ── シミュレーターから始まったこのサイトの開設記」で紹介しています。
この記事でわかること
- このブログが採用している2段階公開フローの全体像
- Draft環境をGoogle検索からブロックしている理由と方法
- frontmatterの公開日時フィールドとCloudflare Workersを組み合わせた予約投稿の仕組み
- Claude Codeとの組み合わせで回るサイクル
まず全体像を把握しておきましょう。このブログでは以下の3ステップで記事を公開しています。
左:記事を書いてアップロード 中:Draft環境で確認 右:確認OKで本番に公開
各ステップで登場するツール・サービスの名前に馴染みがない方も多いと思います。次のセクションで登場人物を整理してから、詳細の説明に入ります。
登場人物:ブログ運営に出てくるツール・サービス
この仕組みには、聞き慣れない名前がいくつか出てきます。本題に入る前に、それぞれの役割を簡単に整理しておきます。
ローカルPCで記事を書き、GitHubへアップロード。GitHub上でHugoとGitHub Actionsが動き、Cloudflare Pagesへ送信してブログが公開される
ローカルPC
記事を書いたり編集したりする、手元の自分のパソコンのことです。「ローカル」とは「手元・自分の環境」という意味で、インターネット上のサービス(クラウド)と対比して使われます。このブログでは、Claude Codeを使った記事の執筆・修正はすべてローカルPCで行っています。
GitHub(ギットハブ)
クラウド上のファイル管理サービスです。Wordでいう「変更履歴の保存」を強化したもの、とイメージしてもらうと近いです。「いつ・誰が・何を変えたか」を記録しながらファイルを管理でき、変更をアップロードする操作を「push(プッシュ)」と呼びます。このブログの記事ファイルはすべてGitHubで管理しています。
Cloudflare Pages(クラウドフレア ページズ)
Cloudflareは、Webサイトの高速配信やセキュリティ対策を提供する世界規模のインターネットインフラ企業です。その中の「Pages」というサービスが、Webサイトのファイルを受け取ってインターネット上に公開・配信する機能を担っています。皆さんがブラウザで見ているこのブログは、Cloudflare Pages上に置かれています。このブログはDraft(確認用)と本番の2環境をCloudflare Pages上に持っています。
Hugo(ヒューゴ)
Markdownという書きやすい形式で書いた記事ファイルを、ブラウザで見られるHTML形式に変換するソフトです。「記事を書く作業」と「Webサイトとして見せる作業」を分けてくれる変換エンジンです。このブログでは、HugoはCloudflare上ではなく、GitHub Actions(GitHubのサーバー)上で動いています。
GitHub Actions(ギットハブ アクションズ)
GitHub上で動く自動化機能です。「ファイルが更新されたら○○する」「決まった時刻に○○の処理を実行する」といった条件付き・定時実行の仕組みを設定できます。この定時実行の仕組みのことを特に cron(クロン) と呼びます。このブログでは、記事をHTMLに変換して公開する処理(後述のビルド・デプロイ)をGitHub Actionsが担当しています。なお、予約投稿の「決まった時刻に処理を起こす」役目は、最初はこのGitHub Actions自身のcronに任せていましたが、うまくいかず作り直しました。その経緯は後半の「公開日時の予約投稿はどう実現しているか」で紹介します。
Cloudflare Workers(クラウドフレア ワーカーズ)
Cloudflare上で動く小さなプログラムを動かせるサービスです。「決まった時刻にきっかけの合図を送る」といった軽い自動処理に向いています。このブログでは、予約投稿のために「決まった時刻にビルドを起こす合図」を送る役目を担っています(後半で詳しく紹介します)。
Claude Code(クロード コード)
AnthropicのAI「Claude」をターミナル(コマンド操作画面)から使えるツールです。記事の執筆・修正はもちろん、GitHub Actionsのワークフロー設定ファイルのような技術的な実装もClaude Codeに依頼しながら作ってきました。このブログ運営の実質的な共同作業者です。
このブログの記事は、Claude Codeにベースとなる下書きを作成してもらい、そこに私自身の経験や知見をClaude Codeと対話しながら追加・修正してもらう形で作成しています。
記事がCloudflare Pagesで公開されるまでの基本の流れ
Draft環境の話に入る前に、まず「ブログ記事がどういう流れで公開されるのか」という基本から整理します。
① 記事ファイルの作成(ローカルPC上)
記事の執筆はClaude Codeで始めます。執筆の起点は2パターンあります。
- ニュースから探すパターン:Claude Codeにブログの趣旨に合うニュースや話題を探してもらい、その中から筆者がテーマを選んで執筆を依頼する
- テーマ先行パターン:筆者がテーマを思いついたとき、記事の大まかな流れをClaude Codeに説明して書いてもらう
どちらのパターンも、ブログ記事の最初の執筆はClaude Codeが担当しています。その後、筆者が自身の経験や知見を加えながらClaude Codeと対話して仕上げていきます。
そうして作成した記事は、Markdown形式(.mdファイル)としてローカルPC上に保存されます。ファイルの先頭には frontmatter(フロントマター)という設定ブロックがあり、タイトル・公開日・公開状態などを記述します。
---
title: "記事のタイトル"
date: 2026-05-01T08:00:00+09:00
draft: false
---
記事ファイルの公開状態(ステータス)は実質2つです。
| 状態 | 設定 | 動き |
|---|---|---|
| 下書き | draft: true |
GitHubにアップロードしても本番サイトには出ない |
| 公開対象 | draft: false |
アップロードすれば本番サイトに反映される |
date: フィールドで公開日時を指定することもできます。これを使った予約投稿の仕組みについては後半で解説します。
② ローカル確認 → GitHubへアップロード
記事ファイルはテキスト形式のため、そのまま開いてもブログとして公開されたときのレイアウトでは表示されません。そこで、ローカルPC上にHugo用の小さなサーバーを立ち上げ、ブラウザ経由でアクセスすることで、公開後に近い見た目で記事を確認することができます。難しそうに聞こえますが、Claude Codeに「ローカルで確認したい」と伝えるだけで自動的にやってくれます。問題がなければGitHubへアップロードします。
ただし、このローカルサーバーはPCが起動している間だけ、自分のPCからしか参照できません。外出先やスマホから同じURLにアクセスしても見ることはできません。
③ GitHub Actionsが起動 → 変換・公開 → ブログに反映
GitHubへアップロードすると、GitHub Actionsが変更を検知して起動します。GitHub Actionsのサーバー上でHugoがMarkdownをHTML(Webページ)に変換する処理を実行し、完成したHTMLファイルをCloudflare Pagesへ送信します。Cloudflare PagesがそのHTMLを受け取って配信することで、数十秒後には本番ブログに反映されます。この③の流れはすべて自動で、手動の操作は不要です。
ただし、Hugoのデフォルトの動作では、公開日時が未来の記事は除外されます。 記事を公開するには、公開日時をアップロード時点より過去の時間に設定するか、この除外動作を変える仕組みを別途用意するかのどちらかが必要です。このブログでの具体的な解決方法は、後半の「公開日時の予約投稿はどう実現しているか」で詳しく解説します。
人から見ると、記事が現れるのは③のタイミング
①②はいずれも筆者の手元での作業です。記事を書いてアップロードするまでの過程は読者には見えません。読者がブログを訪れて記事を目にするのは、③のCloudflareによる公開が完了したタイミングです。
基本の流れでは、②でアップロードすると③が自動で動き出し、そのまま本番に公開されます。つまりアップロードと公開はほぼ同時です。確認の間もなく公開されてしまうため、この③をより安全に運用するために設けたのが、次に説明するDraft環境を使った2段階フローです。
💡 コラム:Claude Codeがよく使う3つの言葉 — push・ビルド・デプロイ
Claude Codeと対話しながら作業していると、この3つの言葉が頻繁に出てきます。それぞれ①〜③のどこにあたるかを整理しておきます。
| 用語 | 読み方 | どこの作業か | 具体的な内容 |
|---|---|---|---|
| push | プッシュ | ② | ローカルPCで編集したファイルをGitHubへアップロードする操作 |
| ビルド | ビルド | ③前半 | HugoがMarkdownファイルをHTMLに変換する処理。pushを検知したGitHub Actionsが自動実行する |
| デプロイ | デプロイ | ③後半 | ビルド済みのHTMLをCloudflare Pagesに配置して公開する処理。ビルド完了後にGitHub Actionsが自動実行する |
「アップロードしたらビルドが走り、完了したらデプロイされる」という順番です。③の「数十秒後に反映」の中身は、実はビルドとデプロイの2ステップで構成されています。
ローカルPCからアップロード(push)→GitHubがビルド(変換)→Cloudflare Pagesにデプロイ(公開)の順で自動実行される
Cloudflare Pagesでの構成:Draft環境と本番環境を分けた2段階フロー
左:記事を書いてアップロード 中:Draft環境で確認 右:確認OKで本番に公開
このブログは「Draft環境」と「本番環境」の2つの環境で動いています。ここで言う「環境」とは、それぞれ独立したウェブサイトのことです。Cloudflare Pages 上に2つのサイトが存在していて、役割が異なります。
一方、「フォルダ」は GitHub 上のファイルの置き場のことです。この2つは別の場所にある別の話ですが、「どのフォルダに置くか」が「どの環境に出るか」を決めるという形で連動しています。
左のフォルダ(GitHub)と右の環境(Cloudflare)は別の場所にある。GitHub Actionsがアップロードのたびに両方を自動で変換・Web公開する
整理すると、次のようになります。
| 場所 | 名前 | 役割 |
|---|---|---|
| GitHub(ファイル管理) | 確認用フォルダ | 確認中の記事を置く |
| GitHub(ファイル管理) | 公開用フォルダ | 本番に出す記事を置く |
| Cloudflare Pages(ウェブサイト) | Draft環境 | 確認用・URL限定公開 |
| Cloudflare Pages(ウェブサイト) | 本番環境 | 誰でも閲覧できる公開サイト |
- 確認用フォルダに置いた記事 → Draft環境にだけ表示される
- 公開用フォルダに置いた記事 → 本番環境に表示される
本番アップしたいときは、確認用フォルダから公開用フォルダへ記事を移動するだけです。移動後にアップロードすれば、あとはGitHub Actionsが自動で変換・Web公開します。コピーではなく「移動」なので、同期ずれが起きません。
なぜDraft環境を用意したのか
ローカルサーバーの立ち上げが手間・外出先から確認できない
記事ファイルを作成したあと、ローカルで確認するにはHugoのサーバーをコマンドで起動する必要があります。毎回この手間がかかるほか、起動中も自分のPCからしかアクセスできません。「電車の中でスマホから確認したい」「外出先で最終チェックしたい」といった場面には対応できませんでした。Draft環境はURLが固定されているため、どこからでもスマホブラウザで確認できます。
ローカルでの確認には限界がある
ローカルPC上のサーバーでは、Cloudflare Pages固有の設定は再現されません。
たとえばOGP(SNSでシェアされたときのサムネイル・タイトル表示)はローカルでは確認できません。OGPはCloudflare Pages上に公開されたURLに対してSNSがアクセスして読み取る仕組みのため、ローカルサーバーのURLでは情報が取得できないからです。記事をXでシェアしたときにサムネイルが表示されない・タイトルがおかしい、といったトラブルはDraft環境で事前に防ぐことができます。「ローカルでは正しく見えていたのに、本番アップしたら壊れていた」を防ぐためにも、本番に近い環境での確認は重要です。
Draft環境はGoogle検索に引っかからない
Draft環境はURLを知っていれば誰でも見られますが、Google検索には出てきません。
仕組みはシンプルで、Draft環境(Cloudflare 上の確認用サイト)全体の robots.txt に以下を設定しています。
User-agent: *
Disallow: /
これはGoogleなどの検索エンジンのクローラー(自動巡回プログラム)に対して「このサイト全体を読み込まないでください」と伝える記述です。この指示に従ったクローラーはページをインデックス(検索データベースへ登録)しません。なお、robots.txtはあくまでクローラーへの「お願い」であり、Googleのような主要な検索エンジンは尊重しますが、悪意ある第三者のプログラムには効かない場合もあります。URLを知らなければアクセスできないという意味では非公開ですが、完全な非公開とは異なります。
この robots.txt は GitHub のフォルダに置いているファイルではなく、Web公開処理が行われるたびに GitHub Actions が自動生成して Draft 環境のサイト全体に適用するものです。確認用フォルダ・公開用フォルダという「フォルダ単位」の制御ではなく、Draft環境という「サイト丸ごと」が Google 検索対象外になっています。
実際の設定はClaude Codeに「DraftサイトはGoogleに検索されないようにして」と伝えるだけで実装してもらいました。仕組みの中身を知らなくても、やりたいことを言葉で伝えればClaude Codeが適切な設定を選んでくれます。
なぜこれが必要かというと、「本番より先にDraftの内容がGoogle検索に出てしまう」リスクを防ぐためです。
同じ内容のページが2つのURLに存在すると、Googleから重複コンテンツとみなされてSEO評価に悪影響が出る場合があります。また、確認中の未完成の状態が外部に漏れることも避けたい。robots.txt での制御はそのための最低限の対策です。
公開日時の予約投稿はどう実現しているか
静的サイトには、ブログサービス(はてなブログ、noteなど)のような「予約投稿」機能がありません。代わりに、frontmatterの公開日時フィールドと、決まった時刻に処理を起こす仕組みを組み合わせて予約投稿を実現しています。実は、この「決まった時刻に処理を起こす」部分は一度作り直しています。まず今の仕組みを説明したあと、なぜ作り直すことになったのかを紹介します。
frontmatterの公開日時で「いつ公開するか」を指定する
ブログ記事のMarkdownファイルの先頭には、frontmatterという設定ブロックがあります。
---
title: "記事タイトル"
date: 2026-05-01T08:00:00+09:00
---
Hugoはこの date フィールドを「記事の公開日時」として扱います。
- 公開日時が現在時刻より過去の場合:通常通り本番アップの対象になる
- 公開日時が現在時刻より未来の場合:Hugoが変換する際に除外され、本番アップの対象にならない
つまり date: 2026-05-01T08:00:00+09:00 と書いておけば、5月1日8時になるまでは公開されません。ここで注意したいのは、予約投稿する記事も原稿の段階から公開用フォルダに置いておくという点です。確認用フォルダから公開用フォルダへ記事を移動するような処理はどこにも存在しません。公開日時が来るまではHugoがビルド対象から自動的に除外してくれるので、フォルダを分ける必要がないのです。
frontmatterのdateが現在時刻より未来なら非公開、過去になればCloudflare Workerが5:35(メイン)・6:35(救済)に起動するビルドで自動的に本番公開される
最初はGitHub Actionsのcronで動かしていた
「公開日時が過去になったら自動でビルドし直して本番アップする」処理を起こす部分は、最初はGitHub Actionsのcron機能で動かしていました。
GitHubには「定時に処理を実行する」スケジュール実行機能があり、これをcronと呼びます。設定は以下のような記述で行います(これはYAML形式のワークフローファイルです)。
on:
schedule:
- cron: '0 * * * *' # 毎時0分に実行
このワークフローが1時間に1回動き、公開日時が過去になった記事があればHTMLへの変換・Web公開処理を自動で走らせる、という想定でした。
実際には「時間が大幅にずれる」問題が起きた
ところが実際に運用してみると、GitHub Actionsのスケジュール実行は想定通りには動いてくれませんでした。GitHub側の混雑状況によって実行タイミングが遅れたり、そのままスキップされたりすることが珍しくなかったのです。
決定的だったのは2026年6月13日の朝です。5:30に公開予約していた記事が、時間になっても本番に上がってきませんでした。結局、6:30に手動でワークフローを実行してようやく公開する、という対応になりました。「毎時0分に自動チェック」という仕組みを作ったつもりが、実際にはそこまで頼れる精度ではなかったわけです。
頻度を上げる方法も、上限の壁にぶつかった
「もっと確実に動かすため、チェックの頻度を上げられないか」も検討しました。しかしここで、Cloudflare Pages側の制約にぶつかりました。Cloudflare Pagesの無料プランは、1か月あたりのビルド(デプロイ)回数に500回という上限があります。このブログはDraft環境と本番環境の2つのサイトを運用しているため、単純に「1時間に1回ビルド」を24時間×2環境で続けると1か月で1,440回に達してしまい、上限を大きく超えてしまいます。
そもそも実際の運用では毎朝5:30固定で本番アップしていたため、それ以外の時間帯のチェックはほぼ毎回「対象記事なし」の空振りでした。ここに気づき、「毎時チェック」という発想自体を見直すことにしました。
Cloudflare Workerが決まった時刻に「公開のきっかけ」を送る仕組みに変更
そこで採用したのが、Cloudflare Workersに「決まった時刻にビルドのきっかけを送る」役目を持たせる方法です。GitHub Actions側のスケジュール実行(cron)は完全に廃止し、代わりにCloudflare WorkerがGitHub Actionsのworkflow_dispatch(外部からの起動命令)を使って、ビルド処理そのものを直接起動する形に変更しました。
現在動いているタイミングは以下のとおりです。
| 時刻(JST) | 役割 |
|---|---|
| 5:35 | 本番ビルド(メイン。5:30公開予約分をここで反映) |
| 6:35 | 本番ビルド(救済枠。5:35が何らかの理由で失敗した場合の保険) |
| 7:05 | X(旧Twitter)への自動投稿 |
| 21:05 | X(旧Twitter)への自動投稿 |
1日1回だった公開処理を「メイン+救済」の2回に増やしたことで、GitHub Actions側のcron遅延・スキップに悩まされることなく、5:30予約分は5:35〜6:35の間に確実に本番へ反映されるようになりました。
なお、Cloudflare Worker自体の定時実行(cronトリガー)にも、無料プランでは1つのWorkerあたり5回までという上限があります。実際に7個のcronを設定しようとしたところ反映されず、この上限に気づきました。上の表の4件(5:35・6:35・7:05・21:05)はこの上限内に収まっています。
Cloudflare Workerで定時起動する仕組み自体は、X自動投稿の記事「Xの自動投稿を自作する」でも同じ考え方を使っているので、あわせて参考にしてください。
なぜこの仕組みにしたか
もともと、記事を書き終えてから内容を確認して本番アップするまでに時間差があるため、本番アップのタイミングで公開日時を設定し直すようにしていました。ところが、操作のタイミングによっては「現在より少し未来の日時」が入ってしまい、本番アップしたはずの記事が表示されないという失敗を何度か繰り返してしまいました。
この失敗をなくしたいこと、そして今後は「毎週火曜に更新」のような定期的な投稿もしてみたいという考えもあり、Claude Codeに相談しました。その結果として提案・設定してもらったのが、この予約投稿の仕組みです。
Claude Codeとの組み合わせ
記事執筆・修正はClaude Codeで行うことが多く、このDraft→本番フローとの相性がよいと感じています。
実際のサイクルは以下のような流れです。
- Claude Codeに記事の下書きを作成・修正してもらう
- GitHubにアップロードしてDraft環境に反映させる
- Draft環境のページにアクセスして確認する
- 気になる点をClaude Codeに伝えて修正してもらう
- 再アップロードしてDraft環境で確認。問題なければ確認用フォルダから公開用フォルダへ移動して本番公開
静的サイトを選ぶと「自由に設定できる反面、仕組みを自分で作る必要がある」という面があります。その部分をClaude Codeが補ってくれることで、エンジニアでなくても自分専用の運用フローを作れるようになっています。
まとめ
このブログの公開フローを整理すると、以下のようになります。
- GitHubへのアップロードで、Draft環境と本番環境の両方が自動で変換・Web公開される
- 確認用フォルダに置いた記事はDraft環境に表示され、公開用フォルダに置いた記事が本番に表示される
- Draft環境はサイト全体がGoogle検索の対象外に設定されている
- frontmatterの公開日時を未来日時にすることで予約投稿を実現できる
- Cloudflare Workerが決まった時刻(5:35・6:35)にビルドのきっかけを送り、公開日時が過去になった記事を自動で本番公開する
「書いたらすぐ公開」ではなく「確認してから公開」できる安心感は、継続的なブログ運営にとって思っていた以上に重要でした。
まずはDraft環境を作るところから試してみると、自分のブログ運営に合った公開フローが見えてくると思います。何かの参考になれば幸いです。
ここまで読んで「自分にも作れるだろうか」と身構える必要はありません。GitHub ActionsのYAMLもrobots.txtの書き方も、細部まで自分で理解する必要はなく、この記事をそのままClaude Codeに見せて「これと同じような公開フローを作りたい」と伝えるだけで十分です。実際、この記事で紹介した仕組み自体も、私がClaude Codeに相談しながら少しずつ作ってもらったものです。
関連記事
- X自動投稿の作り方|GitHub Actionsのcronズレを解決 — Xの自動投稿をほぼ無料で自作した記録
- Claude Codeでブログを作った話 ── シミュレーターから始まったこのサイトの開設記 — 投資シミュレーターを作ろうとしたらブログまで作っていた話
- Claude Designでブログのデザインを刷新した話 — PaperMod標準から脱却するまで — Claude Codeに「ブログをリデザインして」と丸投げするだけで完成