はじめに
難しいことは抜きにして、静的サイト(HTML/CSS/JS)を最速・低コスト・高セキュリティで公開する、1パターンだけの手順です。
サイトの中身(HTML等)は対象外。サーバまわり(公開インフラ) だけに絞ります。
ゴールと構成図
- ゴール:
https://example.comであなたのサイトが常時HTTPSで表示される - 構成:S3(コンテンツ)→ CloudFront(CDN)→ Route 53(DNS)→ ACM(証明書)
ユーザー ──[HTTPS]── CloudFront ──(OAC)── S3(静的コンテンツ)
│
├── Route 53(Aレコード/ALIAS)
└── ACM(SSL/TLS証明書)
この構成だけ覚えればOK。S3は公開ブロックONのまま 、CloudFrontからOAC(Origin Access Control) で私的アクセスします。
前提(最小限)
- AWSアカウント作成済み・請求情報登録済み
- 独自ドメインを使う(Route 53で購入 or 他社から移管/委任)
- リージョンは原則東京(ap-northeast-1)を使用
※ただしCloudFront用の証明書だけは us-east-1(後述)
手順(これだけやる)
1) Route 53:パブリックホストゾーン作成
- ドメインをRoute 53で管理する(購入 or NS委任)
- 以降の「Aレコード(ALIAS) → CloudFront」設定に使う
他社DNSを継続利用する場合は、CloudFrontのCNAME設定+他社側のA/CNAME設定でも可。ただしRoute 53の方が手順は簡潔。
2) S3:バケット作成 & コンテンツ配置
-
S3バケット作成(例:
example.com/リージョンは東京でOK)- Block Public Access=ON(既定のまま)
- 静的ウェブサイトホスティングは使わない(CloudFront経由にする)
-
index.html等をアップロード(assets/など任意構成)
ポイント:S3をインターネット公開しない。公開口はCloudFrontだけに集約する。
3) ACM:証明書を us-east-1 に発行(ここ最重要)
- マネジメントコンソールのリージョンを「バージニア北部(us-east-1)」に切替
-
example.comと*.example.comをSANに追加してDNS検証で発行 - Route 53管理なら「レコード自動作成」で一発
なぜus-east-1? → CloudFrontで使う証明書はus-east-1必須。ここでつまずく人が最も多い。
4) CloudFront:ディストリビューション作成(OACでS3を保護)
- オリジン:S3バケットを指定(バケットのリージョンエンドポイント)
- オリジンアクセス:OAC(Origin Access Control)を作成&アタッチ
-
ビヘイビア:デフォルトでOK(SPAなら後で404→
/index.htmlにフォールバック設定) -
代替ドメイン名(CNAME):
example.com(+必要なサブドメイン) - 証明書:手順3で発行したACM(us-east-1)を選択
-
Default Root Object:
index.html(トップ直叩き対策)
作成後、CloudFront画面の案内に従い、S3バケットポリシーをOAC向けに更新(ボタンひとつで自動生成可能)。
これでS3は非公開のまま、CloudFront経由のみアクセス可能に。
5) Route 53:Aレコード(ALIAS)でCloudFrontへ向ける
- ホストゾーンの
example.comにAレコード(ALIAS) を作成 - 宛先:CloudFrontのドメイン(
dXXXX.cloudfront.netを選択)
しばらくすれば
https://example.comに到達する。
※DNSとCloudFrontの伝播に数分〜数十分かかることあり。
(任意)SPAのルーティング対策
SPA(React/Vueなど)でブラウザリロード時に404になる場合:
- CloudFrontのカスタムエラーレスポンスで
- HTTP 404 → レスポンス200/エラーページパス:
/index.htmlに設定
- HTTP 404 → レスポンス200/エラーページパス:
更新フロー(反映を早く)
- ファイル更新 → S3へ再アップロード
-
即時反映したいときは CloudFront の Invalidation:
/*
GitHub Actions による自動デプロイ(最小例)
先にGitHubリポジトリのSecretsにAWSキーを設定(
AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY)。
IAMはS3/CloudFrontの最小権限を付与。
name: deploy-static
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-1
- name: Upload to S3
run: aws s3 sync ./dist s3://example.com --delete
- name: Invalidate CloudFront
run: aws cloudfront create-invalidation --distribution-id ABCDE12345 --paths "/*"
これだけチェックリスト(出せるかの最終確認)
-
S3バケット作成(公開ブロックON、
index.html配置) - ACM証明書(us-east-1) をDNS検証で発行
-
CloudFront作成:OACを必ず設定/Default Root Object=
index.html - S3バケットポリシーをOACに更新(コンソールの自動提案でOK)
- Route 53のAレコード(ALIAS) をCloudFrontに向ける
-
https://example.comで表示確認(必要ならInvalidation) -
(SPAのみ)404→
/index.htmlフォールバック設定
料金と運用ミニマム
- S3 + CloudFrontは小規模なら数百円〜(トラフィック量に依存)
- 予算アラート:AWS Budgetsで閾値メール通知
- 監査:CloudTrail(有効化は既定、保持/集約を検討)
- 権限:ルートはMFA、日常はIAMユーザー/ロールで最小権限
よくあるつまずき
-
CloudFrontに証明書が表示されない
→ ACMのリージョンがus-east-1になっているか確認。 -
403/404が出る
→ OAC設定とS3バケットポリシーの更新漏れを確認。S3をパブリックにしないこと。 -
更新が反映されない
→ CloudFrontのInvalidation実行。キャッシュTTLが残っている可能性。
まとめ(1パターンで十分)
- S3(非公開)+CloudFront(OAC) を“基本形”として固定化する
- ドメインはRoute 53、証明書はACM(us-east-1)
- これで高速・安価・安全な公開が実現する
- あとはCIで
aws s3 sync+Invalidationを回せば運用も簡単
はじめの一歩はこの形だけでOK。将来APIが必要になったら、別途API GatewayやLambda/ECSを足すだけで拡張できる。