はじめに
本ブログを動かしていた EC2 インスタンスは Amazon Linux 2 (以下 AL2) で稼働していましたが、AL2 のサポート終了が 2026年6月30日 に迫っていたため、Amazon Linux 2023 (以下 AL2023) への移行を行いました。
あわせて、長らく放置していた Hexo 本体のアップグレード(3.9.0 → 7.3.0)も実施しました。本記事はその作業の流れと、途中で遭遇したトラブルおよびその対処をまとめたものです。
なお、過去のnginx関連記事については AmazonLinux2のDocker Imageにnginxをインストールする を、ローカル開発環境のNode.jsバージョン管理については hexoのテーマを設定する などの過去記事も合わせてご参照ください。
移行方針
AL2 から AL2023 への インプレースアップグレードはサポートされていません。新しい AL2023 インスタンスを別途立てて、そこに既存環境を再構築するというのが AWS 公式の推奨方法となります。
そこで以下の Blue-Green 方式で進めました:
- 旧インスタンスは稼働させたまま、新インスタンスを並行して構築
- 新インスタンス上で nginx・Hexo の動作確認
/etc/hosts書き換えで実機表示を検証- DNSを切り替え
- 旧インスタンスは数日寝かしてから停止・削除
ダウンタイムをほぼゼロにでき、問題が起きてもすぐ切り戻せるのが利点です。
新インスタンスの選定
価格と性能のバランスを考えて、Graviton(Arm)アーキテクチャを採用することにしました。
- nginx も Node.js も AL2023 標準リポジトリに arm64 ビルドあり
- Hexo は Pure JavaScript なのでアーキテクチャ非依存
- 同等の x86 インスタンスと比較して約20%安い
- ローカル開発機(Apple Silicon Mac)と環境が揃う
最終的に t4g.micro(AMI:al2023-ami-2026.X.X.X-kernel-6.1-arm64、東京リージョン)で構築しました。
インスタンスの設定として、EBSは8 GiB、セキュリティグループは以前のインスタンスに適用していた設定をそのまま流用しました。
ミドルウェアのセットアップ
1 | sudo dnf update -y |
AL2では yum が標準でしたが、AL2023では dnf に変わっている点に注意してください(yum コマンドも互換のため残されていますが、dnf の使用が推奨されています)。
旧インスタンスから以下を移行しました:
- nginx 設定(
/etc/nginx/) - Let’s Encrypt 証明書(
/etc/letsencrypt/) - Hexo のリポジトリ(Git からクローン)
遭遇したトラブルと対処
1. npm install で node-sass のビルドが失敗
最初の npm install で node-sass のビルドエラーが発生しました。
1 | gyp ERR! stack SyntaxError: invalid syntax |
原因:node-sass が依存している node-gyp@3.8.0 は Python 2 の構文(print "...")を使っていますが、AL2023 には Python 2 がインストールされておらず、Python 3 でパースできずに失敗していました。node-sass 自体も2020年に廃止(deprecated)されています。
対処:Dart Sass(sass パッケージ)ベースの hexo-renderer-sass-next に差し替えました。
1 | npm uninstall hexo-renderer-scss |
package.json の差分は以下のとおりです。
1 | "hexo-renderer-ejs": "^1.0.0", |
2. nginx が systemctl で操作できない
sudo systemctl reload nginx を実行すると以下のメッセージが出ました。
1 | nginx.service is not active, cannot reload. |
しかし ps -ef | grep nginx で確認すると nginx プロセスは動いている、という状態でした。
原因:以前テスト時に sudo nginx を直接叩いて起動していたため、systemd の管理外プロセスになっていました。
対処:手動起動の nginx を一度停止し、systemctl から起動し直しました。
1 | sudo kill -QUIT <マスターPID> |
3. SELinux による 403 エラー
コンテンツを所定の場所に配置後、directory index of "..." is forbidden というエラーが出ました。
💡 SELinuxとは:Linuxカーネルに組み込まれた強制アクセス制御(Mandatory Access Control)の仕組み。通常のファイルパーミッションとは別レイヤーで、プロセスごとのアクセスを細かく制御します。AL2023ではデフォルトで有効(enforcingモード)になっており、適切なファイルコンテキストが設定されていないとnginxからアクセスできません。
原因:AL2023 はデフォルトで SELinux が enforcing モード になっています。AL2 では多くの場合 disabled / permissive で運用していたため気にしていませんでしたが、AL2023 ではこれが実効的に機能してきます。
対処:restorecon コマンドでデフォルトのSELinuxコンテキストを復元します。
1 | sudo restorecon -Rv /usr/share/nginx/html/book-reviews |
これで403が解消できました。
4. index.html が 0 バイトになる問題(最大の難所)
403 が解消した後、今度は 真っ白な画面 が表示されるようになりました。確認すると:
1 | -rw-r--r--. 1 root root 0 ... index.html |
トップページの index.html だけ 0 バイト、個別記事ページや /page/2/ などは正常に生成されている、という不思議な状態でした。
原因:hexo-generator-index@0.2.1(2017年リリース)が Node.js 18 で silent fail していました。Hexo 3.9.0 系は公式サポートが Node 8〜10 までで、それより新しい Node 環境では一部プラグインが例外を投げずに空ファイルを出力してしまうケースがあります。
ここで「いっそ Hexo 本体ごと最新化しよう」と判断しました。
Hexo 3.9.0 → 7.3.0 への大型アップグレード
方針
- テーマ(landscape)は AdSense や JSON-LD などの独自カスタマイズを多数加えていたため、触らずに保持
- Hexo 本体・generator・renderer プラグインのみ最新化
- メンテ停止している
hexo-adminは削除
テーマカスタマイズ内容を upstream の最新 landscape と diff で確認したところ、layout/_partial 配下の AdSense 連携・JSON-LD・Amazon 検索ボックスなど、収益化と SEO に直結する機能が多数含まれていました。これらを再適用するコストを考えると、テーマは現状維持が現実的でした。
package.json の更新内容
主要な変更は以下のとおりです:
| パッケージ | 旧 | 新 |
|---|---|---|
| hexo | 3.9.0 | 7.3.0 |
| hexo-generator-index | 0.2.1 | 3.x |
| hexo-generator-archive | 0.1.5 | 2.x |
| hexo-generator-category | 0.1.3 | 2.x |
| hexo-generator-tag | 0.2.0 | 2.x |
| hexo-generator-sitemap | 1.2.0 | 3.x |
| hexo-renderer-ejs | 0.3.1 | 2.x |
| hexo-renderer-marked | 1.0.1 | 6.x |
| hexo-renderer-stylus | 0.3.3 | 3.x |
| hexo-server | 0.3.3 | 3.x |
| hexo-admin | 2.3.0 | (削除) |
package.json は最終的に以下のようになりました。
1 | { |
結果
public/index.htmlが約 120KB で正常生成- 生成ファイル数 371 個(旧 Hexo 時代と完全一致)
- ビルド時のエラー・警告ゼロ
- テーマカスタマイズ(AdSense、JSON-LD、Amazon 検索ボックス)すべて動作維持
- 表示崩れなし
カスタマイズしていた古いテーマが新しい Hexo でそのまま動いたのは正直驚きました。EJS テンプレートの後方互換性が良く保たれていたおかげだと思います。
SSL 証明書
Let’s Encrypt の証明書は旧インスタンスから /etc/letsencrypt/ 一式をコピーし、AL2023 では certbot の自動更新を systemd timer で運用する形にしました:
1 | sudo dnf install -y certbot python3-certbot-nginx |
DNS 切り替え
- 切り替え前に DNS の TTL を短く設定(300秒)
- A レコードを新インスタンスのパブリック IP に更新
- 旧インスタンスは 1 週間ほど起動状態でスタンバイ
ドメインはValue-Domain(バリュードメイン)で取得しており、DNSもValue-DomainのDNSを利用しています。
久しぶりの作業だったので少し手間取りましたが、ログインしてAレコードを編集しました。
タイムゾーンの修正
切り替え後、nginx のアクセスログを確認したところ時刻が UTC(JST から9時間ずれ)になっていることに気づきました。AL2023 のデフォルトタイムゾーンは UTC のためです。
1 | sudo timedatectl set-timezone Asia/Tokyo |
ポイント:nginx は起動時にタイムゾーンをキャッシュするため、reload ではなく restart が必要です。
学んだこと
今回の移行作業を通じて得られた知見は以下のとおりです。
- AL2023ではSELinuxがデフォルトで有効になっており、コンテンツ配置や権限設計時に意識する必要がある
node-sassのような廃止(deprecated)されたパッケージは早めに後継へ移行しておくべき。後回しにするとランタイムアップグレード時にビルド地獄に陥る- 古いまま動かしているソフトウェアは、Node.jsなどのランタイムを上げた瞬間にサイレントに壊れることがある(今回の
index.html0バイト問題はその典型例) - Graviton (Arm) は静的サイト配信のような軽量ワークロードと相性が良く、x86インスタンスに比べて約20%のコスト削減効果がある
- nginxは起動時にタイムゾーンをキャッシュするため、
timedatectlで変更したらreloadではなくrestartが必要
おわりに
Amazon Linux 2 の EOL 対応をきっかけに、放置していた Hexo のバージョンも一気に最新化することができました。
特に Hexo 3.9.0 系は2019年リリースの6年以上前のバージョンで、Node.js 18 上では一部プラグインがサイレントに失敗するという危険な状態でした。EOL 対応とプラットフォームのアップグレードを同時に行えたのは、結果的に良いタイミングだったと思います。
しばらくブログの運用は止まってしまっていましたが、やはり自分の学びやログを残すことはとても重要ですし、ブログを書くというアウトプットの目的があるからこそ、インプットが捗ると改めて感じています。
今後の課題としては以下を予定しています。
- 記事を
git pushすると自動でデプロイ・HTML生成される CI/CDパイプラインの構築 - 今回のように長期間放置してアップグレードコストが膨らまないよう、定期的なチェック・アップデート機構の整備
これらの仕組みも整えながら、技術記事と投資記事の両方を継続的にアウトプットしていきたいと思います。
📌 関連記事



