教程 搜索 / 发布与基础设施 / 将静态网站部署到 S3 + CloudFront
📝 文字 ● 中级 更新于 2026-05-13

将静态网站部署到 S3 + CloudFront

S3 存储文件,CloudFront 通过 HTTPS 在全球范围内分发,ACM 免费签发证书,Route 53 让 mybrand.com 指向整个系统。这是在 AWS 上部署静态网站的标准方案——一旦搭建完成,每次部署只需一条 aws s3 sync 命令。

现代的主流替代方案——Vercel、Netlify、Cloudflare Pages——已将整条部署流水线打包成一个按钮。推送 git 仓库,它们就会自动处理存储、CDN、证书和 DNS。人们仍然手动搭建 S3 + CloudFront 的原因在于,它属于 AWS 生态:同一套 IAM 策略可以让 Lambda 把生成的报告写入同一个 bucket;同一个 CloudFront 分发可以前置于其身后的 ALB;同一个 Route 53 托管区可以管理其他 AWS 资源的记录。如果你的基础设施在 AWS 上,静态网站也理应在 AWS 上——而且静态内容的 AWS 价格极为低廉。

核心概念:S3 是源站(私有 bucket,存放构建产物);CloudFront 是缓存与入口(在全球边缘节点缓存文件、终止 TLS、提供 https:// 访问);ACM 提供证书(免费 TLS,但 CloudFront 要求证书必须位于 us-east-1);Route 53 管理 DNS(Alias 记录将域名指向 CloudFront 分发)。四项服务各司其职,互不越界。

本教程将从头到尾完整介绍首次配置流程,以及流水线搭建完成后每次部署的操作方式。对于控制台操作繁琐的步骤(bucket 策略、sync),我们使用 AWS CLI;对于 CLI 操作繁琐的步骤(CloudFront、ACM),我们使用控制台。最终,部署只需三条命令:npm run build && aws s3 sync ./dist s3://mybrand-site && aws cloudfront create-invalidation ...,从此一劳永逸。

你将学到什么

前置条件:拥有具备管理员或足够 IAM 权限的 AWS 账号、已安装并配置好 AWS CLI(aws configure)、域名的 DNS 托管于 Route 53(或愿意在其他地方添加记录),以及一个已构建好的静态网站(一个包含 HTML/CSS/JS 的目录)。

第 1 步:创建 S3 Bucket

1

私有 bucket,保留默认设置,一条 CLI 命令搞定

选择一个 bucket 名称。它必须在整个 AWS 范围内全局唯一,建议使用类似 mybrand-site-prod-2026 的命名。名称本身并不重要——用户永远不会看到它,因为 CloudFront 在前面挡着。

aws s3api create-bucket \
  --bucket mybrand-site-prod-2026 \
  --region us-east-1
# (对于 us-east-1 以外的区域,需添加 --create-bucket-configuration LocationConstraint=<region>)

保留默认的"屏蔽所有公开访问"设置。有了 CloudFront + OAC 在前面(第 4 步),bucket 保持私有状态;CloudFront 使用自己的凭证来读取文件。公开 bucket 的方式仍然可行,但已是过时的模式——AWS 新文档全面推荐 OAC。

第 2 步:上传网站文件

2

aws s3 sync 就是部署命令

如果你的网站构建输出目录是 ./dist(或 ./build./public,取决于项目):

aws s3 sync ./dist s3://mybrand-site-prod-2026 --delete
# --delete 会删除 S3 中本地已不存在的文件——
# 不加此参数,已删除的页面会作为孤儿继续在线。

首次 sync 会上传所有文件,后续只上传变更的文件。这就是你之后要脚本化的部署命令。此时 S3 已有文件,但无法访问——bucket 是私有的,CloudFront 也还没建。

第 3 步:在 us-east-1 申请 ACM 证书

3

区域至关重要;CloudFront 只读取 us-east-1 的证书

这是最常见的首次配置错误。AWS Certificate Manager 证书是按区域划分的。CloudFront 是全球服务,但证书查找固定走 us-east-1。申请证书前,请将控制台区域切换到"美国东部(弗吉尼亚北部)— us-east-1",或通过 CLI 操作:

aws acm request-certificate \
  --domain-name mybrand.com \
  --subject-alternative-names www.mybrand.com \
  --validation-method DNS \
  --region us-east-1

ACM 会返回一个 CertificateArn 以及一组 CNAME 验证记录——证书中每个域名各一条。如果你的 DNS 在同一账号的 Route 53 上,控制台会提供一键"在 Route 53 中创建记录"的按钮。否则,需要手动将每条 CNAME 复制到你的 DNS 服务商。记录生效后,验证通常在几分钟内完成。

证书续期是自动的。一旦通过 DNS 验证并签发,ACM 每 13 个月自动续期,并在零停机的情况下将新证书切换到 CloudFront。只要 DNS 验证记录保持不变,你就无需再管证书的事。

第 4 步:创建带 OAC 的 CloudFront 分发

4

最复杂的一步;建议在控制台完成

打开 CloudFront → 创建分发,填写以下内容:

  • 源域:从下拉列表中选择你的 S3 bucket(不要选网站端点——选 bucket 本身)。
  • 源访问:选择源访问控制设置(推荐),点击创建新 OAC,保留默认值并保存。分发创建完成后,CloudFront 会给你一段 bucket 策略片段——你将在第 5 步把它粘贴到 S3。
  • 查看器协议策略:选择将 HTTP 重定向到 HTTPS
  • 允许的 HTTP 方法:GET、HEAD(静态网站不需要 POST)。
  • 备用域名(CNAME):mybrand.comwww.mybrand.com
  • 自定义 SSL 证书:选择第 3 步申请的 ACM 证书。
  • 默认根对象:index.html

点击创建。CloudFront 开始部署分发,首次大约需要 5 到 15 分钟。你会得到一个类似 d1234abcde.cloudfront.net 的分发域名——在 DNS 接入之前,可以直接用该 URL 测试。

第 5 步:附加 OAC Bucket 策略

5

只允许 CloudFront 读取 bucket,其他一律拒绝

OAC 创建流程会在成功页面显示 bucket 策略片段,复制它。在 S3 → bucket → 权限Bucket 策略中粘贴。内容如下:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "AllowCloudFrontServicePrincipalReadOnly",
    "Effect": "Allow",
    "Principal": { "Service": "cloudfront.amazonaws.com" },
    "Action": "s3:GetObject",
    "Resource": "arn:aws:s3:::mybrand-site-prod-2026/*",
    "Condition": {
      "StringEquals": {
        "AWS:SourceArn": "arn:aws:cloudfront::123456789:distribution/E1ABCDEFGHIJK"
      }
    }
  }]
}

SourceArn 条件是 OAC 安全性的关键:只有你指定的分发才能读取这个 bucket。若没有此条件,任何账号下的任何 CloudFront 分发都可以读取。

第 6 步:将域名指向 CloudFront

6

在 Route 53 中为每个域名创建一条 Alias 记录

在 Route 53 → 你的托管区 → 创建记录

  • 记录名称:留空(对应根域名)或填 www(对应 www 子域名)。
  • 记录类型:A。
  • 别名:开启。
  • 流量路由到:CloudFront 分发的别名 → 选择你的分发。

创建完成后,重复以上步骤配置另一个域名(根域名 / www)。DNS 解析通常在几分钟内生效——如果是同一 AWS 账号下的 Alias 记录,有时几秒就能完成。

如果你的 DNS 不在 Route 53,可在你的 DNS 服务商添加常规 CNAME 记录,将 www 指向 d1234abcde.cloudfront.net,并使用你的 DNS 服务商提供的 CNAME 扁平化 / ALIAS 功能处理根域名(详见 DNS 教程)。

第 7 步:验证并保存部署命令

7

三项检查;之后只需三条命令

# 1. 确认证书已附加到分发。
curl -sI https://mybrand.com | grep -E '^(HTTP|Server)'
# 预期结果:HTTP/2 200 ... Server: CloudFront

# 2. 确认文件可以访问。
curl -s https://mybrand.com | head
# 预期结果:你的 index.html 内容。

# 3. 确认 DNS 指向 CloudFront。
dig mybrand.com +short
# 预期结果:CloudFront 边缘节点 IP(各区域不同;确认不为空即可)。

从现在起,部署的方式如下——将这三行保存为项目中的 deploy.sh

#!/usr/bin/env bash
set -e
npm run build
aws s3 sync ./dist s3://mybrand-site-prod-2026 --delete
aws cloudfront create-invalidation \
  --distribution-id E1ABCDEFGHIJK \
  --paths "/*"

缓存失效(invalidation)是让新文件立即生效的关键。不执行失效操作,CloudFront 会继续提供缓存中的旧文件,直到 TTL 过期(缓存响应默认 24 小时)。每月有 1,000 个失效路径免费——以每次部署一个路径的失效来算,相当于每天 33 次,足以覆盖大多数项目。

实际费用是多少

以每月 10,000 访客、约 1 GB 流量的个人网站为例:

总计:一个真实但流量平静的个人网站,每月不到 $1。AWS 免费套餐的前 12 个月提供 50 GB 免费 CloudFront 出站流量,通常能覆盖所有费用;免费期结束后,费用线性增长。若静态网站月流量达到 1 TB,传输费用约为 $85——这时候 Cloudflare Pages(带宽无限、免费)就显得非常有吸引力了。

下一步