AWS S3 + CloudFront 静态网站托管实战:从零到全球加速完整指南

📅 · 海外服务器线路与网络实测 - ChengziCloud

一句话结论

在现代 Web 架构中,静态网站托管已经成为一种高效、安全且成本极低的部署方案。

本文要点
  • 引言
  • 架构总览与核心概念
  • 环境准备与 AWS CLI 配置
  • S3 存储桶配置详解
  • CloudFront CDN 配置与优化
  • HTTPS 与域名配置
  • 自动化部署脚本
  • 性能监控与故障排查

引言

在现代 Web 架构中,静态网站托管已经成为一种高效、安全且成本极低的部署方案。相比传统的服务器渲染模式,将 HTML、CSS、JavaScript 等静态资源托管在 Amazon S3 上,并通过 CloudFront CDN 进行全球加速分发,不仅能获得近乎无限的横向扩展能力,还能将运维成本降低 90% 以上。本文将带你从零开始,一步步完成一个生产级别的 S3 + CloudFront 静态网站部署,涵盖域名配置、HTTPS 证书、缓存策略和自动化部署。

无论你是前端开发者想快速上线作品集,还是 DevOps 工程师需要为团队搭建文档站点,本文提供的完整命令和配置文件都可以直接复制使用。我们将避开空洞的理论,聚焦于可操作的命令行实践和生产环境的最佳配置。读完本文后,你将掌握从域名解析到缓存策略优化的完整技能链,并拥有一套可以直接应用于生产环境的部署模板。


一、架构总览与核心概念

在动手之前,我们先理解整体架构。一个典型的 S3 + CloudFront 静态网站架构由以下组件构成:


用户请求 → Route 53(DNS) → CloudFront(CDN) → S3(源站)
                ↓                    ↓
           ACM(SSL证书)      Lambda@Edge(可选)

各组件职责如下:

组件作用是否必需
S3 存储桶存储静态文件(HTML/CSS/JS/图片)并作为 CloudFront 源站✅ 必需
CloudFront全球 CDN 加速,缓存内容到边缘节点,提供 HTTPS 终端✅ 必需
ACM(证书管理器)提供免费的公共 SSL/TLS 证书✅ 必需(HTTPS)
Route 53DNS 域名解析,将域名指向 CloudFront 分配推荐
Lambda@Edge在边缘节点执行自定义逻辑(如 URL 重写、安全头注入)可选

S3 静态网站托管 vs 传统服务器托管对比

维度S3 + CloudFront传统 EC2/Nginx
可用性99.99%(S3 SLA)取决于架构(单机无 SLA)
全球延迟CloudFront 边缘节点 < 20ms取决于服务器地理位置
并发能力近乎无限(AWS 自动扩展)受限于服务器配置
成本(100GB/月)~$15/月~$30-50/月(含 EC2 + 带宽)
运维负担几乎为零需要系统更新、监控、扩容
HTTPS 配置ACM 一键证书 + 自动续期需手动配置 Let's Encrypt 或付费证书
DDoS 防护AWS Shield Standard(免费)需额外配置

二、环境准备与 AWS CLI 配置

2.1 确认 CLI 版本


# 检查 AWS CLI 版本(需要 v2.0+)
aws --version
# 输出示例:aws-cli/2.15.0 Python/3.11.6 Linux/x86_64

# 如未安装,使用以下命令安装
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip && sudo ./aws/install

2.2 配置访问凭证


# 交互式配置(需要 Access Key ID 和 Secret Access Key)
aws configure
# AWS Access Key ID: AKIAXXXXXXXXXXXX
# AWS Secret Access Key: xxxxxxxxxxxxxxxxxxxxxxxx
# Default region name: us-east-1
# Default output format: json

# 验证配置
aws sts get-caller-identity
# 输出应包含你的 Account ID 和 ARN

2.3 设定变量

在后续命令中,我们将使用以下环境变量,请根据实际情况替换:


export AWS_REGION="us-east-1"
export S3_BUCKET="my-static-site-$(aws sts get-caller-identity --query Account --output text)"
export DOMAIN_NAME="example.com"

三、S3 存储桶配置详解

3.1 创建存储桶并启用静态网站托管


# 创建 S3 存储桶(桶名必须全局唯一)
aws s3api create-bucket \
  --bucket $S3_BUCKET \
  --region $AWS_REGION \
  --create-bucket-configuration LocationConstraint=$AWS_REGION

# 启用静态网站托管
aws s3api put-bucket-website \
  --bucket $S3_BUCKET \
  --website-configuration '{
    "IndexDocument": {"Suffix": "index.html"},
    "ErrorDocument": {"Key": "error.html"}
  }'

3.2 配置存储桶策略(仅允许 CloudFront 访问)

这是生产环境的关键安全配置:S3 存储桶不应直接公开,而应该只允许来自 CloudFront 的请求。


# 创建存储桶策略文件
cat > /tmp/s3-bucket-policy.json << 'POLICY'
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudfront.amazonaws.com"
      },
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::BUCKET_NAME/*",
      "Condition": {
        "StringEquals": {
          "AWS:SourceArn": "arn:aws:cloudfront::ACCOUNT_ID:distribution/DISTRIBUTION_ID"
        }
      }
    }
  ]
}
POLICY

# 应用策略(等 CloudFront 创建后再替换变量并执行)
aws s3api put-bucket-policy --bucket $S3_BUCKET --policy file:///tmp/s3-bucket-policy.json

3.3 上传静态网站文件


# 假设你的网站文件在 ./dist 目录下
aws s3 sync ./dist s3://$S3_BUCKET/ \
  --delete \
  --cache-control "max-age=3600" \
  --exclude "*.html" \
  --exclude "*.json"

# HTML 文件使用较短的缓存时间(或不缓存)
aws s3 sync ./dist s3://$S3_BUCKET/ \
  --delete \
  --exclude "*" \
  --include "*.html" \
  --cache-control "no-cache,must-revalidate"

3.4 S3 高级配置:版本控制与生命周期策略


# 启用版本控制(保护文件不被误删)
aws s3api put-bucket-versioning \
  --bucket $S3_BUCKET \
  --versioning-configuration Status=Enabled

# 配置生命周期策略(旧版本自动清理)
aws s3api put-bucket-lifecycle-configuration \
  --bucket $S3_BUCKET \
  --lifecycle-configuration '{
    "Rules": [{
      "Id": "cleanup-old-versions",
      "Status": "Enabled",
      "NoncurrentVersionExpiration": {
        "NoncurrentDays": 30
      },
      "AbortIncompleteMultipartUpload": {
        "DaysAfterInitiation": 7
      }
    }]
  }'

四、CloudFront CDN 配置与优化

4.1 创建 CloudFront 分配


# 创建 CloudFront 分发配置文件
cat > /tmp/cloudfront-config.json << 'EOF'
{
  "CallerReference": "static-site-20260720",
  "Aliases": {
    "Quantity": 1,
    "Items": ["www.example.com"]
  },
  "DefaultRootObject": "index.html",
  "Origins": {
    "Quantity": 1,
    "Items": [{
      "Id": "S3-origin",
      "DomainName": "BUCKET_NAME.s3-website-us-east-1.amazonaws.com",
      "CustomOriginConfig": {
        "HTTPPort": 80,
        "HTTPSPort": 443,
        "OriginProtocolPolicy": "http-only",
        "OriginSslProtocols": {
          "Quantity": 1,
          "Items": ["TLSv1.2"]
        }
      }
    }]
  },
  "DefaultCacheBehavior": {
    "TargetOriginId": "S3-origin",
    "ViewerProtocolPolicy": "redirect-to-https",
    "AllowedMethods": {
      "Quantity": 2,
      "Items": ["GET", "HEAD"],
      "CachedMethods": {
        "Quantity": 2,
        "Items": ["GET", "HEAD"]
      }
    },
    "Compress": true,
    "CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6"
  },
  "PriceClass": "PriceClass_100"
}
EOF

# 创建分发
aws cloudfront create-distribution \
  --distribution-config file:///tmp/cloudfront-config.json \
  --query 'Distribution.Id' \
  --output text

4.2 CloudFront 缓存策略深度优化

CloudFront 提供了多种缓存策略选项,合理配置能大幅提升命中率并降低源站负载:

缓存策略适用场景TTL 配置建议
Managed-CachingOptimized图片、CSS、JS 等不常变的静态资源最小 TTL: 1s, 默认 TTL: 86400s, 最大 TTL: 31536000s
Managed-CachingDisabled需要实时更新的内容(如 API 响应)按需自定义
自定义缓存策略HTML 页面(需要兼顾缓存和新鲜度)最小 TTL: 0s, 默认 TTL: 300s, 最大 TTL: 600s

# 创建自定义缓存策略(适用于 HTML 页面)
aws cloudfront create-cache-policy \
  --cache-policy-config '{
    "Name": "StaticSiteHTMLPolicy",
    "DefaultTTL": 300,
    "MinTTL": 0,
    "MaxTTL": 600,
    "ParametersInCacheKeyAndForwardedToOrigin": {
      "EnableAcceptEncodingGzip": true,
      "EnableAcceptEncodingBrotli": true,
      "HeadersConfig": {
        "HeaderBehavior": "whitelist",
        "Headers": {"Quantity": 1, "Items": ["CloudFront-Viewer-Country"]}
      },
      "CookiesConfig": {"CookieBehavior": "none"},
      "QueryStringsConfig": {"QueryStringBehavior": "none"}
    }
  }'

4.3 CloudFront 价格等级选择

CloudFront 提供三个价格等级,适合不同预算和覆盖需求:

价格等级边缘节点覆盖适用场景月度成本(1TB)
Price Class 100北美 + 欧洲目标用户集中于欧美~$85
Price Class 200100类 + 亚洲、中东、非洲部分地区全球业务但预算有限~$110
Price Class All全球所有边缘节点需要最佳全球性能~$130

4.4 自定义错误页面


# 配置 SPA (Single Page Application) 的错误响应
# 将所有 404/403 错误重定向到 index.html
aws cloudfront update-distribution \
  --id $DISTRIBUTION_ID \
  --distribution-config '{
    ...,
    "CustomErrorResponses": {
      "Quantity": 2,
      "Items": [
        {
          "ErrorCode": 403,
          "ResponsePagePath": "/index.html",
          "ResponseCode": "200",
          "ErrorCachingMinTTL": 10
        },
        {
          "ErrorCode": 404,
          "ResponsePagePath": "/index.html", 
          "ResponseCode": "200",
          "ErrorCachingMinTTL": 10
        }
      ]
    }
  }'

五、HTTPS 与域名配置

5.1 申请 ACM 公共证书


# 在 us-east-1 申请证书(CloudFront 要求证书在 us-east-1)
aws acm request-certificate \
  --domain-name www.example.com \
  --subject-alternative-names example.com \
  --validation-method DNS \
  --region us-east-1

# 获取 DNS 验证记录
aws acm describe-certificate \
  --certificate-arn $CERT_ARN \
  --query 'Certificate.DomainValidationOptions[0].ResourceRecord' \
  --region us-east-1

5.2 Route 53 DNS 配置


# 创建 A 记录别名指向 CloudFront
aws route53 change-resource-record-sets \
  --hosted-zone-id $HOSTED_ZONE_ID \
  --change-batch '{
    "Changes": [{
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "Name": "www.example.com",
        "Type": "A",
        "AliasTarget": {
          "HostedZoneId": "Z2FDTNDATAQYW2",
          "DNSName": "CLOUDFRONT_DOMAIN_NAME",
          "EvaluateTargetHealth": false
        }
      }
    }]
  }'

六、自动化部署脚本

将上述步骤整合为可复用的部署脚本,实现一键部署与更新:


#!/bin/bash
# deploy-static-site.sh — S3 + CloudFront 静态网站自动化部署
set -euo pipefail

# ============ 配置区 ============
DIST_DIR="./dist"
S3_BUCKET="my-static-site-prod"
CLOUDFRONT_ID="E1ABCDEFGHIJKL"
AWS_REGION="us-east-1"

echo "🚀 开始部署静态网站..."

# 1. 构建项目(如需要)
if [ -f "package.json" ]; then
  echo "📦 执行项目构建..."
  npm run build
fi

# 2. 上传到 S3
echo "📤 上传静态文件到 S3..."
# 长缓存资源(带 hash 的文件名)
aws s3 sync $DIST_DIR s3://$S3_BUCKET/ \
  --delete \
  --exclude "*.html" \
  --exclude "service-worker.js" \
  --exclude "asset-manifest.json" \
  --cache-control "public,max-age=31536000,immutable"

# 短缓存资源(HTML 等入口文件)
aws s3 sync $DIST_DIR s3://$S3_BUCKET/ \
  --delete \
  --exclude "*" \
  --include "*.html" \
  --include "service-worker.js" \
  --cache-control "public,max-age=0,must-revalidate"

# 3. 失效 CloudFront 缓存(使旧内容立即过期)
echo "🔄 创建 CloudFront 缓存失效..."
INVALIDATION_ID=$(aws cloudfront create-invalidation \
  --distribution-id $CLOUDFRONT_ID \
  --paths "/*" \
  --query 'Invalidation.Id' \
  --output text)

# 4. 等待失效完成
echo "⏳ 等待缓存失效完成..."
aws cloudfront wait invalidation-completed \
  --distribution-id $CLOUDFRONT_ID \
  --id $INVALIDATION_ID

echo "✅ 部署完成!网站已更新。"
echo "🌐 访问地址: https://www.example.com"

七、性能监控与故障排查

7.1 CloudFront 关键指标监控


# 查看 CloudFront 分发的近期请求统计
aws cloudfront get-distribution \
  --id $CLOUDFRONT_ID \
  --query 'Distribution.DistributionConfig.Enabled'

# 通过 CloudWatch 查看缓存命中率
aws cloudwatch get-metric-statistics \
  --namespace AWS/CloudFront \
  --metric-name CacheHitRate \
  --dimensions Name=DistributionId,Value=$CLOUDFRONT_ID \
  --start-time $(date -d '24 hours ago' -u +%Y-%m-%dT%H:%M:%SZ) \
  --end-time $(date -u +%Y-%m-%dT%H:%M:%SZ) \
  --period 3600 \
  --statistics Average

7.2 常见问题与解决方案

问题现象可能原因排查命令解决方案
返回 403 Access DeniedS3 存储桶策略未授权 CloudFrontaws s3api get-bucket-policy --bucket $BUCKET检查 OAC/OAI 配置
更新文件后仍然看到旧内容CloudFront 缓存未失效aws cloudfront list-invalidations --distribution-id $ID创建失效请求或使用文件版本化
HTTPS 证书错误ACM 证书未在 us-east-1 申请aws acm list-certificates --region us-east-1在 us-east-1 重新申请证书
首次访问慢边缘节点未缓存(冷启动)查看 x-cache: Miss from cloudfront 响应头进行预热或接受首次 Miss 延迟
跨域请求被拦截缺少 CORS 响应头curl -I https://cdn.example.com/file.js在 S3 上配置 CORS 规则

7.3 S3 CORS 配置

当前端应用需要直接从浏览器访问 S3 上的资源(例如通过 JavaScript Fetch API 加载 JSON 数据或字体文件),必须正确配置跨域资源共享策略,否则浏览器会阻止这些跨域请求。以下是完整的配置方法。


# 如果前端需要跨域访问 S3 资源
aws s3api put-bucket-cors --bucket $S3_BUCKET --cors-configuration '{
  "CORSRules": [{
    "AllowedHeaders": ["*"],
    "AllowedMethods": ["GET", "HEAD"],
    "AllowedOrigins": ["https://www.example.com"],
    "ExposeHeaders": ["ETag", "x-amz-meta-custom-header"],
    "MaxAgeSeconds": 3600
  }]
}'

八、成本分析与优化建议

月度成本明细(中小型网站,100GB 流量/月)

费用项用量单价月费用
S3 存储(Standard)5GB$0.023/GB$0.12
S3 PUT/COPY 请求1,000 次$0.005/千次$0.01
S3 GET 请求10,000 次$0.0004/千次$0.004
CloudFront 数据传输100GB$0.085/GB(美国)$8.50
CloudFront HTTP 请求500,000 次$0.0075/万次$0.38
Route 53 托管区1 个$0.50/月$0.50
ACM 证书1 个免费$0.00
合计~$9.51/月

优化建议

除了上述基本的成本控制手段之外,以下进阶优化措施能够帮助你在大流量场景下进一步压缩开支,同时提升用户体验:

  1. 启用 Gzip/Brotli 压缩:已在 CloudFront 配置中启用,可减少 60-80% 传输量
  2. 使用 S3 Intelligent-Tiering:如果文件访问模式不确定,可自动优化存储成本
  3. 合理设置缓存 TTL:静态资源设置较长 TTL(一年),HTML 设置较短 TTL
  4. 启用 Origin Shield:在高流量场景下,增加一层集中缓存减少回源请求,可将回源请求降低至原来的十分之一
  5. 按需选择 Price Class:如果用户主要集中在特定地区,选择对应的价格等级可以有效降低边缘传输成本
  6. 使用 Lambda@Edge 进行响应压缩:对于动态生成的内容,可以在边缘节点实时压缩后再返回给用户

九、总结与最佳实践

通过本文的完整实践,我们成功搭建了一个基于 S3 + CloudFront + ACM + Route 53 的生产级静态网站托管方案。这个架构不仅成本低廉(月均不到 10 美元),而且性能卓越,借助 CloudFront 全球 400 多个边缘节点,无论用户身处哪个大洲都能获得低延迟的访问体验。回顾整个过程,以下最佳实践值得你在实际项目中坚持:

  1. S3 绝不直接公开:始终通过 CloudFront OAC(Origin Access Control)代理 S3 请求,避免存储桶直接暴露在公网
  2. 文件版本化 + 缓存失效组合:对静态资源使用内容哈希命名(如 main.abc123.js),结合 Cache-Control: immutable 实现永久缓存;HTML 文件使用短 TTL 或 must-revalidate
  3. 监控缓存命中率:将 CloudFront 的 CacheHitRate 指标接入 CloudWatch Dashboard,设定低于 85% 的告警阈值
  4. 自动化部署:将部署流程集成到 CI/CD 流水线中,每次代码提交自动触发 S3 同步和 CloudFront 失效
  5. 成本可控:中小型网站每月成本不到 10 美元,随着流量增长成本呈线性增长而非指数级

AWS S3 与 CloudFront 的组合不仅是静态网站托管的最优解,也是现代 Jamstack 架构的基石。掌握这套技术栈,你将能够以极低的成本、极高的可靠性为数百万用户提供闪电般的网页加载体验。

本文由 6.chengzicloud.cloud 提供,点击访问首页了解更多