はじめに
2008 年に自分用のドメインをもって以来、契約したレンタルサーバに、WordPress ふたつ、PukiWiki みっつ、短縮 URL サービスひとつ、MySQL ふたつを置いて、長年使い続けてきました。
が、PukiWiki や短縮 URL サービスはすっかり放置してしまっていたし、WordPress もプラグインが積もりに積もっててんこ盛りだしで、セキュリティ上の不安がぼんやりと続いていたわけです。
そんなわけで、コーディングエージェントも頼れる存在になってきたし、ぜんぶ静的サイト化して Cloudflare Pages にまとめて引っ越すことにしました。
本エントリは、その作業の簡単な紹介です。環境固有(というかサイト固有)の事情が多いので、具体的な手順を書いても再現性がなさそうなため、考え方というか方針や手段のお話が中心です。文字ばかりですが、似たようなことをやろうとしているひと、あるいはそのひとに使役されてここにたどり着いた AI エージェントさんには、お役に立てるかもしれません。
方針
大まかにはこんな感じの作戦です。
- WordPress A(blog.kurokobo.com)
- Hugo に移行し、今後も更新を続ける
- 旧 URL でそのまま目的のページにアクセスできるようにする
- WordPress B(rubinetto.info)
- 今後は更新しないが、アクセスは継続的にあるので、WordPress の見た目のまま静的サイト化して、そのまま塩漬けする
- PukiWiki A(wiki.kurokobo.com)
- 今後は更新しないが、ほんのちょっとアクセスはあるので、PukiWiki の見た目のまま静的サイト化して、そのまま塩漬けする
- 旧 URL でそのまま目的のページにアクセスできるようにする
- PukiWiki B(非公開)
- 今後は更新しないが、ごくわずかにアクセスはあるので、PukiWiki の見た目のまま静的サイト化して、そのまま塩漬けする
- 旧 URL の維持は不要とする
- Basic 認証によるアクセス制限をかける
- PukiWiki C(非公開)
- もう更新しないし、アクセスもないので、削除する
- 短縮 URL サービス(url.kurokobo.com)
- 今後は更新しないが、これまでに作った短縮 URL にはほんのちょっとアクセスはあるので、転送機能だけ別の形で再現する
PukiWiki の中身はもう 15 年くらい前のものなので、今となってはまったく役に立たないとは思うのですが、ドメインを維持する限りは消さずにインターネットの歴史として残すのがスジかな的な変な責任感のような何かがあります。
準備: ドメインの移管と DNS の移行
下準備として、ふたつのレジストラに分散していたドメインみっつを、まとめて Cloudflare に移管しました。あまりちゃんと考えていませんでしたが、Cloudflare に移すだけで維持費がお安くなるんですね。おもしろい。
DNS も同時に Cloudflare に移行しています。最初は各種レコードをこれまでのレンタルサーバの IP アドレスに向けておいて、コンテンツの移行に合わせて順次修正していく形で進めました。
概要: 作業のおおまかな流れ
おおまかには、サイトごとに次のような流れで作業します。
- ウェブサーバ上のファイルや DB のダンプを持ってきて、ローカルの開発環境のコンテナで 再現環境 を作る
- 何らかのツールやプラグインを使って、まるごと静的サイトとしてエクスポートする
- コーディングエージェントで不備を修正する
- 仕上がりを確認し、GitHub 経由で Cloudflare Pages にデプロイし、カスタムドメインを当て、DNS を修正して公開する
以降、サイトごとに固有の部分を中心に紹介です。
WordPress A の移行: Hugo に移行
このブログ(blog.kurokobo.com)のことです。今後も更新し続けたかったので、静的サイトジェネレータをつかったサイトに移行するものとして、今回は個人的になじみのあった Hugo を採用しました。シングルバイナリで動く気軽さが気に入っています。
静的サイト化には、再現環境で WordPress to Hugo Exporter を使いました。これだけで WordPress の中身が Hugo 用のコンテンツに変換できます。
……が、それだけできれいな Markdown になることは当然なく、生の HTML が大量に混在していたり、WordPress の機能で自動生成された大量の不要なリサイズ済み画像がまるごと含まれていたりで、そのままビルドしてもうまくレンダリングされないし無駄が多いしで、修正が必要です。
例えば、Exporter で出力された成果物がこれです。見るだけでちょっとこう…… 圧が…… ありますよね……。黄色いし……。

で、三ケタある記事が全部これなので、手作業でやりたいものでは当然なく、コーディングエージェントに助けてもらいました。
エージェントには、修正が必要なパターンをひとつ見つけたら、そのパターンを全部の記事で横断的に適用するためのいわば 使い捨てスクリプト を作って実行してもらう形でお願いしています。かつ、実行結果の確認も、失敗時のロールバックと修正と再実行も、エージェントに主体的に進めてもらいます。
最終的には、40 種類くらいの修正項目が出てきて、使い捨てスクリプトが 70 個くらいできあがりました。エージェント自身にまとめさせたところによれば、代表的なケースでは以下のようなことをしていたようです。人間が見るのは結果と Git の差分だけにしていたので、スクリプトの中身はひとつも見ていません。
| カテゴリ | 主な修正内容 |
|---|---|
| コードブロック | <pre brush:LANG> をコードブロック表記に変換、言語名やハイライト行を移行、HTML をデコード |
| リンク | <a> タグを Markdown リンクに変換(参照形式からインライン表記に統一する作業も含む) |
| 画像 | alt テキストを付与、センタリングを除去、外部画像の一部ショートコード化、不要なリサイズ済み画像の選別、フロントマターの画像パスの修正 |
| テーブル・リスト | HTML の <table>/<ul>/<ol> をテーブル表記やリスト表記に変換 |
| 引用・ツイート | <blockquote> を > 記法に変換、一部独自ショートコード化。X(Twitter)の埋め込みをショートコードに変換 |
| テキスト装飾 | <strong>/<u>/<sup> を **/==/^ などの対応する記法に変換、カーリークォートのペアの不整合を修正 |
| 構造・フロントマター | 見出しに残った HTML タグやアンカーを除去、コメントや目次、不要なフロントマターを削除 |
| 空白・改行 | 空白のみの行を空行に統一、連続空行を圧縮 |
| 特定記事個別対応 | <audio> タグおよび CSV グラフを独自ショートコードに変換 |
で、上の画像の部分は、最終的にはこんなにきれいになりました(この記事です)。

なお、テーマのこまかいカスタマイズもエージェントに頼んでいます。WordPress 時代のコメントをページ下部に表示する実装や、自分好みにするためのスタイルの細かい調整などです。
Hugo 化後のコメントシステムは Giscus にしました。
WordPress B の移行: 単純な静的サイト化
rubinetto.info のことです。今後は更新しない方針になったので、見た目をそのままに静的サイトとして塩漬けにします。

このサイトは Simply Static で静的サイト化しました。
そもそもの要件としてサイトの見た目さえ維持できればよく、HTML としての品質はあまり気にする必要はありませんでした。その意味では変換精度はだいぶよかったものの、JavaScript に依存したレンダリング部分が崩れるケースがあったので、使い捨てスクリプト作戦で細かな修正をいくつかしています。
また、Google Map を API 経由で埋め込んでいた箇所は、塩漬け前提なので iframe に置き換えて API 依存をなくしました。
PukiWiki A の移行: 単純な静的サイト化
wiki.kurokobo.com のことです。こちらも更新しなくなっていたので、見た目そのままに塩漬けにします。
静的サイト化の方法を調べていたら、ちょうどそれっぽいプラグインを作っているひとがいました。ありがたくお借りしました。
が、これは UTF-8 版の PukiWiki が前提だったようで、歴史ある(?)EUC-JP 版ではそのままでは動作せず、プラグインそれ自体に修正が必要でした。特に日本語タイトルのページの扱いの調整と、UTF-8 化などです。
また、プラグインにより静的化したあとも、PukiWiki 依存の PHP っぽいリンク文字列の除去や修正、組み込みのページ群の削除など、いくつかの対応は必要でした。ほか、管理用メニューの削除なども行っています。
URL のリダイレクトの実装
このサイトには、旧 URL でアクセスしてもそれに対応する新しい URL にリダイレクトさせる要件がありました。とはいうものの、PukiWiki の URL はそもそも末尾が /?<ページ名> とか /index.php?<ページ名> とかで、クエリ文字列が必須です。
したがって、Cloudflare Pages の _redirects では対応できず、今回は Pages Functions でクエリ文字列を解釈し適切にリダイレクトするよう実装しています。
例えば、functions/index.php.js がこれです。似た中身の functions/index.js も作っています。
export async function onRequest(context) {
const url = new URL(context.request.url);
if (url.pathname !== '/') {
return context.next();
}
if (!url.search || url.search === '?') {
return context.next();
}
const pageName = url.search.slice(1);
if (pageName === 'FrontPage') {
return Response.redirect(`${url.origin}/`, 301);
}
const converted = pageName
.replace(/%2F/gi, '/')
.replace(/%2B/gi, '+')
.replace(/%20/gi, '+')
.replace(/%([0-9A-Fa-f]{2})/g, (_, hex) => hex.toUpperCase())
.replace(/\*/g, '_');
return Response.redirect(`${url.origin}/${converted}/`, 301);
}
これにより、例えば、PukiWiki 時代の URL である、
にアクセスすると、静的サイト化後の、
にリダイレクトされます。

PukiWiki B の移行: 単純な静的サイト化、Basic 認証あり
非公開サイトですが、こちらも塩漬けコースです。
大まかには先の PukiWiki A と同じ流れで、静的サイト化のためのプラグインを修正して使っています。静的化後の後処理も同じ要領でした。このサイトはもともと UTF-8 版の PukiWiki だったので、多少は作業量は少なめでした。
一方で、このサイトに固有の事情として、MP3 や PDF、ZIP などのバイナリファイルが多く配置されている、ということがあります。
全部を Pages にデプロイして配信するのは容量面で筋が悪かったので、今回は Cloudflare R2 と組み合わせることにしました。
具体的には、Pages に R2 のバケットをバインドし、使い捨てスクリプトでバイナリファイルをひとつのディレクトリ(/files)にまとめたうえで、そこへのアクセスを Pages Functions(functions/files/[[path]].js)で R2 に向けています。
また、Basic 認証も Pages Functions(functions/_middleware.js)で実装しました。ユーザ名とパスワードは環境変数で渡しています。
HTML を手打ちして作ったページもいくつかあったので、それも R2 + Pages + Pages Functions の組み合わせで再構成しました。
PukiWiki C の移行: 削除
これも非公開サイトです。これはもう更新しないうえにアクセスもなかったので、まるっと削除して、削除した旨を示すページだけ残しています。
短縮 URL サービスの移行: 転送機能だけ再現
これは url.kurokobo.com のことです。専用のサブドメインを当てていたので、転送ルールを _redirects で再現する形が素直でした。
ルールがこれから増えることもないので、データベースから転送ルールを引き出して機械的に _redirects に書き出すスクリプトをさっと作って実行しておしまいです。
/lispsbclmac https://wiki.kurokobo.com/index.php?Lisp%2FSBCL%A4%CE%CD%F8%CD%D1%A1%CAMac%20OS%20X%A1%CB 301
/lispgclmac https://wiki.kurokobo.com/index.php?Lisp%2FGCL%A4%CE%CD%F8%CD%D1%A1%CAMac%20OS%20X%A1%CB 301
/lispsbclwin https://wiki.kurokobo.com/index.php?Lisp%2FSBCL%A4%CE%CD%F8%CD%D1%A1%CAWindows%A1%CB 301
/lispgclwin https://wiki.kurokobo.com/index.php?Lisp%2FGCL%A4%CE%CD%F8%CD%D1%A1%CAWindows%A1%CB 301
...
例えば、
にアクセスすると、
にリダイレクトされるようになっています(これはさらに先の PukiWiki A のリダイレクトにより新しい URL にリダイレクトされます)。
おわりに

やってみると、なんだかんだで結局のところ人間によるチェックが必要な場面はそれなりに多く、トータルの作業量は決して少なくはありませんでした。が、エージェントなしではそもそもやる気にすらなれなかっただろうことを考えると、便利な世の中になったなあという気持ちです。
こういう、できればやりたいけどもめちゃくちゃやる気があるわけでもないこと(もしくはおもしろいところだけ選択的に味わいたいこと)は、エージェントに走り出しをアシストしてもらうトピックとしてちょうどよい感触です。
レンタルサーバには長年本当にお世話になりました。感謝の気持ちを持ちつつも、解約の方向で進めています。
最終的には見事に Cloudflare にロックインされてしまいましたが、まあ、Cloudflare だし、いったんよしということで……。これからもよろしくお願いします。