きっかけは些細な話だった。
あるお客様から「サイトが重い」と言われたのが最初だった。Lighthouseで計測すると、Performanceスコアが60点台。プラグインが増えるたびに重くなり、WordPressコアのアップデートが来るたびに「今回は何か壊れないか」とヒヤヒヤしながら作業する。そういう運用が数年続いていた。
正直なところ、最初は「WordPress側を最適化すればいい」と思っていた。キャッシュプラグインを入れ、画像を最適化し、不要なプラグインを削除する。一通りやってみたが、スコアは70点台に上がった程度で、根本的な改善にはならなかった。
そこで問い直したのが「そもそも、このコーポレートサイトに動的処理は本当に必要か?」という点だった。
コーポレートサイトを静的にできる条件
このサイトのコンテンツは会社情報、ニュース、事例紹介、採用情報の4カテゴリ。更新頻度は週に1〜2回程度で、リアルタイムのデータ取得やユーザー認証は一切不要だった。
こうした条件を整理すると、静的サイトジェネレータとCDN配信で十分対応できると判断した。ビルド時に全ページをHTMLとして生成してしまうアプローチだ。
技術選定でAstroを選んだのは「コンテンツ中心のサイトとの相性の良さ」が理由だった。ReactのようなSPAフレームワークはインタラクションが豊富なアプリケーション向けに最適化されている。コーポレートサイトのようにほぼ静的なページが中心であれば、Astroのように「デフォルトでJavaScriptをゼロに近づける」設計思想の方が実態に合っていると考えています。
---
// src/pages/news/[...slug].astro
import { getCollection } from 'astro:content';
export async function getStaticPaths() {
const posts = await getCollection('news', ({ data }) => {
return data.status === 'published';
});
return posts.map(post => ({
params: { slug: post.slug },
props: { post },
}));
}
---
ビルド時にZodスキーマでフロントマターを検証するため、不正なコンテンツが混入していればビルド自体が失敗する。WordPressで発生しがちな「なぜか本番だけ表示が崩れる」問題を構造的に防いでくれる点は、運用を考えると非常に安心感がある。
CloudFront + S3の構成で詰まったところ
インフラ構成はシンプルで、AstroのビルドアウトプットをS3バケットに配置し、CloudFrontのオリジンに設定する。ただ、最初に詰まったのはOAC(Origin Access Control)の設定だった。
S3バケットをパブリックアクセス可能にしてしまうと、CloudFrontを経由せずに直接S3のURLでアクセスできてしまう。セキュリティと運用を考えると、OACを使ってCloudFront経由のアクセスのみを許可するのが正しい構成だ。最初にこの設定を省略したら、キャッシュが意図通りに効かない問題が出て、原因の特定に半日かかってしまった。
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "AllowCloudFrontServicePrincipal",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::your-bucket-name/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::123456789:distribution/XXXXXX"
}
}
}]
}
キャッシュ設定も注意が必要だった。HTMLファイルはキャッシュを効かせすぎると更新が反映されない。Astroが_astro/配下に出力する静的アセット(JS/CSS)はファイル名にコンテンツハッシュが入るのでimmutableキャッシュが使えるが、HTMLはno-cacheにして毎回オリジンから取得させる方が安全だ。
# HTMLファイル
Cache-Control: no-cache, no-store, must-revalidate
# 静的アセット(ハッシュ付きファイル名)
Cache-Control: public, max-age=31536000, immutable
ここは好みが分かれるところですが、私はHTMLのキャッシュは保守的に設定する方針を取っています。コンテンツの鮮度より確実な配信を優先したい場面の方が多いため。
コスト比較
移行前後のコストを並べると、差は一目瞭然だった。
| 項目 | WordPress(VPS) | Astro + S3 + CloudFront |
|---|---|---|
| 月額インフラ費 | 約1.5〜3万円 | 約数百円 |
| Lighthouse Performance | 60〜70点 | 95〜100点 |
| SSL証明書 | 別途管理 | ACM(無料) |
| デプロイ作業 | 手動またはプラグイン | GitHub Actions(自動) |
| セキュリティパッチ対応 | 月数時間 | ほぼ不要 |
移行後の唯一のランニングコストはS3のストレージ料金とCloudFrontのデータ転送料のみだ。アクセス数にもよるが、コーポレートサイト規模であれば月数百円に収まる。
私が重視したのは「見えないコスト」の削減でもある。WordPressの更新作業、プラグインの互換性確認、セキュリティパッチの適用——これらは金銭コストには現れないが、エンジニアの時間を確実に消費していた。マネージドサービスを使うか自前で管理するかを判断するとき、こういった間接コストまで含めて比較することが重要だと考えています。
振り返って
移行後、Lighthouseのパフォーマンススコアは安定して90〜100点を維持している。サーバー監視のアラートが飛んでくることもない。
今思えば、最初にWordPress側の最適化に時間をかけたのは遠回りだったかもしれない。ドキュメントにはキャッシュプラグインの設定方法が丁寧に書いてあるが、そもそもサーバーサイドレンダリングが必要かどうかを先に問い直すべきだったと思っています。
もちろん、この構成が向かないケースもある。ユーザー固有のコンテンツ配信、リアルタイム更新、Eコマースの在庫管理などは別途バックエンドが必要だ。ただ、コーポレートサイトのような「ほぼ読み取り専用」のコンテンツであれば、静的サイト+CDNの構成を最初に検討することを今後も推奨していきたいと考えています。