Ghostで動かしていた2サイトをCloudflare Workersに引っ越した

Ghostで動かしていた2サイトをCloudflare Workersに引っ越した

Ghost(Pro)で動かしていた3つのサイトのうち、機械が毎朝自動で記事を書いている2つを、Cloudflare Workersへ移した。7月28日にDNSを切り替え、読者が見るサイトも、毎朝の投稿先もCloudflare側に揃った。

URLは1本も変えていない。切替後に全URLを叩いて、243/243、284/284、すべてHTTP 200(成功)を返した。RSSの購読先もそのままだ。読者から見れば、何も起きていない。それがいちばんの成果になる引っ越しだった。

なぜ移したのか

理由は3つある。

ひとつは、Ghostが個人ブログの道具から、だんだん「ニュースレター事業のプラットフォーム」の方へ寄っていったこと。使っていない機能の重さが気になり始めた。

もうひとつは、単純にCloudflare Workersを触ってみたかったこと。実のところ、こちらがいちばん大きい。;)

Ghost(Pro)は有料なのでそこの費用を抑えられればという意図もあったが、費用はまだ1円も浮いていない。Ghost(Pro)にこのブログが残っている限りコスト面の見返りはない。3サイトすべてを移して解約したときに、初めてゼロになる。段階的な移行に、コスト面のご褒美はない。

あと、生成AIとの対話でどこまでできるか試したかった。逆にAIがなければブログ(だけでなくその投稿の仕掛けの)移行なんてめんどうなことはしなかったろう。w

構成

項目

移行前

移行後

記事の置き場

Ghost

Cloudflare D1(SQLite)

サイトの配信

Ghost

Astro + Cloudflare Workers

投稿先

Ghost Admin API

Workerに立てた投稿API(トークン認証)

記事の生成

GitHub Actions

GitHub Actions

記事を作る側は変えず、出口だけを差し替えられるよう、Python側に投稿先を切り替える仕組みを入れた。環境変数ひとつで、ghostcloudflareを切り替えられる。

失敗したときに痛くない順に

一番重要な方針はひとつ、

失敗したときに痛くない順にやる。

  1. Cloudflare側に試作サイトを作り、Ghostの全記事を流し込む
  2. しばらく両方へ投稿する。Ghostが本番で、Cloudflareは影武者
  3. 毎朝の投稿先をCloudflareへ変える。読者はまだGhostを見ている
  4. 翌朝の投稿が新しい経路で成功したのを見届けてから、DNSを切り替える

どの段階からでも戻れるようにしてた。投稿先はghostに戻すだけ、DNSはTTLが300秒なので数分で元に戻る。この可逆性を保ちつつ、進めた。

ほぼ全部、AIとの対話でできた

作業の大半は、Claudeとの対話で進めた。

AIがコードを書き、データを調べ、手順を組み立てる。私は内容を確認し、違和感があれば問い返す。人間側でしかできなかったのは、目視確認と、パスキーの登録くらいだ。Touch IDを押すところまでは、さすがにエージェントには任せられない。

もうひとつ、対話の副産物として引き継ぎ書ができあがった。新しいセッションでは最初に全文を読ませ、終わるときに、その日の判断と作業結果を追記させる。決めたこと、踏んだ穴、見送った判断が、全部そこに積み上がっていく。この記事も、その引き継ぎ書をもとに書いている。書かせたものを私が編集したものだ。w

つまずいたところ

細かい穴はいくつも踏んだ。

既存のDNSレコードがあるとwrangler deploy(Cloudflareコマンドラインツール)は409で止まる。設定ファイルを直しても、ビルドし直さないと反映されない。「反映されていない」と騒いだ原因は、たいていキャッシュだった。2日で5回、同じ勘違いをした。

笑えなかったのはログだ。Cloudflareへの投稿に成功すると「Ghost: created」と出る。文言が固定されているだけで投稿先は正しいのだが、切替がうまくいったか確認している最中にこれが出ると、心臓に悪い。

ただ、いちばん厄介だったのは、そういう小さな穴ではなかった。AIの誤認が、引き継ぎ書に事実として残ったことだった。

引き継ぎ書には長らく、「Ghostを解約すると254記事の画像が全滅する」と最優先の注意事項として書かれていた。作業中のAIがデータを読み違え、それを確定事項として記録したものだった。以後のセッションのAIは、それを正しい前提として作業を組み立て続けた。引き継ぎ書は毎回冒頭で全文読ませているのだから、当然そうなる。

しかし、どうも話がおかしい。テキスト中心のニュースサイトに、画像が254件も参照されているだろうか。改めて実データを確認させると、画像は1枚も使われていなかった。Ghostが外部リンクに自動で付ける?ref=パラメータを、ドメイン名で引っかけて画像URLと誤認していただけだった。

引き継ぎ書の仕組みが悪かったわけではない。違和感を放置せずたまたま問い返したことで引継書の誤りを直せた。AIはかなりの作業を進めてくれる。ただし、間違った前提からでも、同じ勢いで進めてしまう。引き継がれるのは、正しい前提だけではない。

残っているもの

残るのは、3つめのサイト——このブログ本体をどうするかだ。

移行先の準備はできていて、実際にそちらで記事を書き始めてもいる。ただ、機械が書くサイトと、人間が書くサイトでは、道具に求めるものが違う。CloudFlare EmDash というCloudeflareが用意するヘッドレスCMSを使うのだが、安定性、投稿機能などまだまだGhostには及ばない。ただEmDashのような発展途上の新しいツールは、新しもの好きな私の大好物ではある。

Ghostを完全にやめるべきか、悩みが増えた。