如何:使用 AWS S3 + CloudFront 建立高效能 CDN

為什麼選擇 AWS S3 + CloudFront?

如何:使用 AWS S3 + CloudFront 建立高效能 CDN

前言

在現代 Web 開發中,內容傳遞網路(CDN)已成為提升網站效能和使用者體驗的關鍵技術。AWS 提供的 S3 + CloudFront 組合,不僅能大幅提升網站載入速度,還能有效降低伺服器負載和頻寬成本。

本文將帶你從零開始,建立一個完整的 CDN 架構,包括自動化部署流程,讓你的靜態網站或應用程式能夠快速、安全地服務全球用戶。

為什麼選擇 AWS S3 + CloudFront?

架構優勢

價格優勢

最便宜的方案免費起。

第一步:建立 S3 Bucket

1.1 基本設定

  1. 登入 AWS Console
  2. 搜尋並進入 S3 服務
  3. 點擊 “Create bucket”

Bucket 命名規則

  • 必須全球唯一
  • 只能包含小寫字母、數字、連字號(-)
  • 長度限制:3–63 個字元
  • 建議格式:your-project-cdn-assets

1.2 區域選擇

選擇合適的 AWS 區域對於成本和效能都至關重要:
相比起香港和新加坡,台北的S3價錢會相對便宜一點。

1.3 安全設定

Object Ownership(物件擁有權)

Block Public Access(封鎖公開存取)

所有選項都應該啟用,這是 AWS 推薦的安全設定:

  • ✅ 封鎖透過新的 ACL 授予的公開存取權
  • ✅ 封鎖透過任何 ACL 授予的公開存取權
  • ✅ 封鎖透過新的公開政策授予的公開存取權
  • ✅ 封鎖透過任何公開政策授予的公開存取權

重要:即使封鎖公開存取,CloudFront 仍可透過 Origin Access Control (OAC) 存取檔案。

Bucket Versioning(版本控制)

Default Encryption(預設加密)

選擇 “Enable” → “SSE-S3”,免費且足夠安全。

第二步:建立 CloudFront Distribution

2.1 Origin 設定

Origin Domain

  • 選擇你建立的 S3 bucket
  • 格式:your-bucket-name.s3.region.amazonaws.com
  • ⚠️ 不要選擇 *.s3-website-*.amazonaws.com 格式

Origin Access Control (OAC)

  1. 選擇 “Origin access control settings (recommended)”
  2. 點擊 “Create control setting”
  3. 設定名稱(例如:s3-cdn-oac
  4. 選擇你建立的 OAC 設定

2.2 Cache Behavior 設定

Viewer Protocol Policy

自動壓縮

✅ 啟用 “Compress objects automatically”,可節省頻寬成本。

2.3 Distribution 設定

Default Root Object

設定為 index.html,讓用戶訪問根路徑時自動顯示首頁。

Web Application Firewall (WAF)

初期可使用監聽模式觀察 1–2 週。

2.4 部署與驗證

  1. 點擊 “Create distribution”
  2. 等待 5–15 分鐘,狀態由 “In Progress” 變為 “Deployed”
  3. 記下 Distribution ID(格式:E1234567890ABC

2.5 更新 S3 Bucket Policy

(目前AWS已自動化處理,無需人手複製貼上)


接下來,如果你想在 GitHub 自動同步到 S3+Cloudfront,就跟隨以下內容繼續吧!

第三步:設定自動化部署

3.1 建立 IAM User

權限政策

建立一個 IAM policy,授予以下權限:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:GetObject",
        "s3:DeleteObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::your-bucket-name",
        "arn:aws:s3:::your-bucket-name/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "cloudfront:CreateInvalidation"
      ],
      "Resource": "*"
    }
  ]
}

建立 Access Keys

  1. 建立 IAM user
  2. 附加上述 policy
  3. 建立 Access Key(選擇 “Application running outside AWS”)
  4. ⚠️ 立即儲存 Access Key ID 和 Secret Access Key(只顯示一次)

3.2 設定 GitHub Secrets

在 GitHub Repository → Settings → Secrets and variables → Actions 中新增:

3.3 GitHub Actions Workflow

建立 .github/workflows/s3.yml
假設你是使用 next.JS 可跟隨以下template。

name: Deploy to S3 and CloudFront

on:
  push:
    branches: [main, master]
  workflow_dispatch:

env:
  AWS_REGION: ${{ secrets.AWS_REGION }}
  S3_BUCKET: ${{ secrets.S3_BUCKET }}
  CLOUDFRONT_DISTRIBUTION_ID: ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }}

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Bun
        uses: oven-sh/setup-bun@v1
        with:
          bun-version: latest
      
      - name: Install dependencies
        run: bun install --frozen-lockfile
      
      - name: Build Next.js app
        run: bun run build
      
      - name: Configure AWS credentials
        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: ${{ env.AWS_REGION }}
      
      - name: Deploy to S3
        run: |
          aws s3 sync ./out s3://${{ env.S3_BUCKET }} \
            --delete \
            --cache-control "public, max-age=31536000, immutable" \
            --exclude "*.html" \
            --exclude "*.json"
          
          aws s3 sync ./out s3://${{ env.S3_BUCKET }} \
            --cache-control "public, max-age=3600, must-revalidate" \
            --exclude "*" \
            --include "*.html" \
            --include "*.json"
      
      - name: Invalidate CloudFront
        run: |
          aws cloudfront create-invalidation \
            --distribution-id ${{ env.CLOUDFRONT_DISTRIBUTION_ID }} \
            --paths "/*"

第四步:測試與驗證

4.1 觸發部署

  1. 推送程式碼到 mainmaster 分支
  2. 或手動觸發:GitHub → Actions → “Deploy to S3 and CloudFront” → Run workflow

4.2 驗證結果

常見問題與解決方案

Q1: CloudFront 狀態一直顯示 “In Progress”

原因:CloudFront 需要時間部署到全球邊緣節點。

解決方案:

  • 正常現象,通常需要 5–15 分鐘
  • 首次部署可能需要更長時間
  • 耐心等待狀態變為 “Deployed”

Q2: 訪問網站出現 “Access Denied” 錯誤

原因:S3 bucket policy 未正確設定。

解決方案:

  1. 檢查 CloudFront Origin Access Control 是否正確設定
  2. 確認 S3 bucket policy 已更新
  3. 確保 Block Public Access 仍然全部啟用
  4. 使用 CloudFront 自動生成的 policy(最簡單)

Q3: 檔案上傳但無法訪問

可能原因:

  • CloudFront 尚未部署完成
  • S3 bucket policy 未更新
  • Cache 未清除

解決方案:

  1. 等待 CloudFront 部署完成
  2. 檢查並更新 bucket policy
  3. 手動清除 CloudFront cache(或等待自動清除)

Q4: 如何設定自訂網域?

步驟:

  1. 在 DNS 供應商設定 CNAME 記錄,指向 CloudFront domain
  2. 在 CloudFront 設定 Alternate domain name (CNAME)
  3. 使用 AWS Certificate Manager (ACM) 申請 SSL 憑證
  4. 在 CloudFront 附加 SSL 憑證

安全性最佳實踐

結論

透過 AWS S3 + CloudFront 建立 CDN,不僅能大幅提升網站效能,還能有效控制成本。結合自動化部署流程,你可以專注於開發,而不用擔心基礎設施管理。

關鍵要點總結

  1. ✅ 安全性優先:保持 S3 bucket 私有,使用 OAC 控制存取
  2. ✅ 成本優化:選擇合適的區域和 Price Class,啟用壓縮
  3. ✅ 自動化部署:使用 GitHub Actions 實現 CI/CD
  4. ✅ 監控與優化:定期檢查效能指標和成本

下一步

  • 設定自訂網域和 SSL 憑證
  • 啟用 CloudWatch 監控和告警
  • 優化快取策略和檔案大小
  • 考慮使用 AWS WAF 進階功能

開始建立你的高效能 CDN,讓全球用戶享受快速、安全的網站體驗!

謝謝閱讀 :)