本文介绍了静态网站托管场景中,如何使用CloudFront将一个处于非公开状态的S3存储桶对外发布为静态网站。
一、使用S3直接提供静态网站的挑战
S3提供静态网站Hosting的方式是官方使用S3提供网站托管的推荐主要方式,此时直接对外暴露S3存储桶,也就是必须将S3存储桶设置为Public可见。如果本AWS账户内仅有一个S3存储桶并配置为公开,可能问题不大。但是对于大部分企业用户,尤其是混合多种业务数据管理的场景、一个账号内有许多存储桶,将存储桶设置为Public会遇到安全挑战问题。
针对S3存储桶开启保护的配置。如下截图。
大部分企业的安全管理团队会要求将本AWS账号的S3全局设置Block public access
配置为启用,也就是阻止本账号内所有S3存储桶公开,这样的安全要求与S3静态网站托管需要对外设置Public产生了矛盾,无法满足需求。这时候就需要在CloudFront上进行静态网站配置来满足安全需求。
此时,可以用CloudFront配置在S3之前并通过OAC(Origin Access Control)授权访问S3存储桶,让S3存储桶继续保持非Public的私有状态,然后通过CloudFront Function进行默认页跳转,即可在无需设置Public的要求下满足网站发布需求。
本文以abc.com
域名为例,通常网站服务是绑定在www.abc.com
这样的域名上,或者是us.abc.com
这样的二级子域名上。这里需要注意的是,名字以www
开头的www.abc.com
,本质上也是一个二级域名。因此每个独立的网站都必须有独立的配置。如果还希望abc.com
域名也能对外提供服务,那么总计需要配置3个独立的S3存储桶和3个独立的CloudFront发布点。它们分别是:
www.abc.com
对应的存储桶,存放对应的网页,绑定CloudFront发布点Aus.abc.com
对应的存储桶,存放对应的网页,绑定CloudFront发布点Babc.com
对应的存储桶,存放对应的网页,绑定CloudFront发布点C,可以配置自动跳转到www.abc.com
下面继续进行配置。
二、创建针对www域名/二级域名的静态网站服务
1、创建S3存储桶
正常创建S3存储桶,在创建向导页面,所有类型都是用默认设置。取名时候可以任意取名,这里不需要向使用S3提供静态网站一样,对S3存储桶名字有特定命名规范的要求。这里可以任意选用名字。例如使用my-s3-static-hosting-demo-01
的名字。
创建时候注意您的Region是否正确,如果Region不是需要的Region,请从右上角的位置切换Region。然后在选择类型的位置选择General Purpose
通用型,在Object Ownership
位置选择ACLs disabled。如下截图。
在Block Public Access settings for this bucket
选项位置,选中之。如下截图。
点击创建Bucket完成创建。
2、配置CloudFront发布点
现在进入CloudFront服务,创建发布点。从2025年起,CloudFront控制台发布了新版本UI交互界面,本文以新界面进行介绍。
在创建向导第一步,输入发布点的名称,然后填写要绑定的域名。在Distribution type
位置,选择Distribution type
。在Custom domain
位置,输入要绑定的域名,首先配置以www
开头的域名。点击Check domain
按钮,此时CloudFront向导会检查此域名是否经由Amazon Route53托管。一般情况下,您可能是有自己独立的域名解析服务商,就会看到提示您需要稍后自行管理域名。点击Skip domain setup
跳过。如下截图。
在向导第二步,Origin type
位置选择S3存储桶作为源站。在Origin
位置,点击浏览存储桶,选择上一步创建的存储桶。在Origin path - optional
路径位置留空。在Settings
位置,选择默认的Allow private S3 bucket access to CloudFront - Recommended
。下边两个选项也保持默认。这将使得您的S3存储桶不会公开,CloudFront会使用自己的Policy授权来访问S3存储桶,这一功能也被称为OAC即Origin Access Control
。然后点击下一步继续。
在向导第三步安全配置界面,选择不需要配置WAF防火墙。因为这是一个静态网站,且由S3进行托管,所以默认情况下不使用WAF防火墙也没有问题。如果您有特殊的安全或者运营需求,例如检查Http访问请求中的特定Header、IP地址限制、访问频率限制等特殊需要,那么在创建CloudFront发布点之后,再手工打开WAF防火墙实现这些功能。如下截图。
在向导第四步,选择对应的SSL证书。在Amazon Certificate Manager(以下简称ACM)服务中,可生成免费的SSL证书用于CloudFront服务。这里需要注意的是,证书服务是严格区分名称的,针对abc.com
的证书是根域名的证书;针对www.abc.com
的证书是二级子域名证书,通常用*.abc.com
的通配符证书来代替。但是二级子域名的证书是不能给根域名使用的。因此这里请参考ACM服务文档,提前配置好证书。如下截图。
最后一步回顾刚才的配置,点击下一步创建发布点。如下截图。
创建完成后,要等待大约5分钟,配置才会生效。如下截图。
CloudFront发布点创建完成。
3、将域名指向CloudFront发布点
在上一步创建完成的界面上,可以看到Distribution domain name
位置有一个类似d3xxxxxxx.cloudfront.net
的域名。这就是发布点的别名。现在需要添加一个域名解析指向到这个Endpoint。配置信息如下:
- 要解析的子域名:www.abc.com
- 解析类型:CNAME
- 解析目标:d3xxxxxxx.cloudfront.net
- TTL:300秒
以上配置根据您的域名解析服务商来完成,配置界面有所不同,请参考相应文档。
如果您的域名使用了Amazon Route53进行解析,那么以上的域名解析记录配置填写如下截图。
域名解析配置完成。
4、设置CloudFront的根目录默认页
在CloudFront发布点配置成功后,如果您访问https://www.abc.com/index.html
,可正常访问。但如果用户输入的是根目录https://www.abc.com/dir01
,会遇到如下错误:
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>AccessDenied</Code><Message>Access Denied</Message></Error>
这就是由于CloudFront不能提供默认页面造成的。在CloudFront发布点的默认配置下,CloudFront是不会查找某个目录内的默认页的。您的S3存储桶作为网站发布目录,里边通常有index.html
等页面。但不管这些文件是否存在,不管默认页是叫做index.html
还是叫做default.html
,CloudFront都是无法感知的。因此需要为CloudFront设置默认页。
接下来配置CloudFront针对根目录的默认页。在创建好的发布点页面上,点击编辑按钮。如下截图。
在编辑页面上,找到Default root object
位置,输入index.html
,然后点击保存。如下截图。
配置修改后,需要等待5~10分钟让全球的CloudFront发布点进行同步。之后再访问https://www.abc.com/
即可看到显示正常。
5、创建CloudFront Function函数实现子目录的默认页跳转
上一步配置了针对根目录的默认页,但是这个配置仅针对顶层目录生效。现在如果测试针对子目录https://www.abc.com/dir1/
的访问,可以看到也会遇到报错,因为CloudFront不能自动查找这个子目录内默认页。因此,要实现任意一个子目录的默认页跳转,需要引入CloudFront Function功能。
进入CloudFront的控制台,在左侧找到Functions
菜单,点击右上角Create按钮。如下截图。
在函数名称位置,输入redirect-for-index
,也可以使用自己的名称。在版本方面选择Cloudfront-js-2.0
。点击右下角的Create function
按钮。如下截图。
在Build
标签页下,添加如下代码。
function handler(event) {
var request = event.request;
var uri = request.uri;
// 检查URI是否以斜杠'/'结尾
if (uri.endsWith('/')) {
// 将请求URI修改为添加'index.html'
request.uri = uri + 'index.html';
}
// 返回修改后的请求对象
return request;
}
点击右下角的保存按钮。如下截图。
切换到Test
标签页。点击右上角的Test function
按钮。将URL path
中的请求网址从/index.html
修改为/
,然后点击Test function
测试访问效果。如下截图。
将页面移动到最下方,可以看到针对/
路径的访问,被自动修改为/index.html
,实现了跳转。如下截图。
在测试通过后,点击Publish
标签页,将函数发布并绑定到CloudFront的发布点。如下截图。
在发布点位置选择上一步创建的发布点,然后点击Publish
按钮。如下截图。
在弹出窗口内,分别选择上一步创建的CloudFront的发布点的名称;在Event type
位置,选择Viewer request
;在Cache behavior
位置的下拉框中,选择默认的Default(*)
标签页。最后点击绑定按钮。如下截图。
在修改完成后,CloudFront可能需要5~10分钟将函数同步到全球的POP点。此时在函数列表页面上,函数的Status
位置会显示Updating
。如下截图。
在发布成功后,对目录https://www.abc.com/dir01
发起访问,可看到默认页被正常的显示。
至此针对www.abc.com
的静态网站发布配置完成
三、针对顶级域名的跳转配置
在本文第一章题到,abc.com
根域名和www.abc.com
是两个独立的域名,需要分别配置。通常,abc.com
顶级域名会需要自动跳转到www.abc.com
。那么这里就来配置一个自动跳转。
1、创建独立的ACM证书、S3存储桶、发布点、绑定域名、设置发布点默认页
配置过程和上一章节配置www.abc.com
的配置过程相同。需要注意的是,ACM需要独立的顶级域名证书。在CloudFront发布点配置选项中,设置默认页为index.html
。
上一章节的最后的CloudFront Function子目录的跳转功能就不需要了。因为这里实现的abc.com
到www.abc.com
跳转,不涉及子目录。
2、放置跳转页面
在abc.com
对应的S3存储桶内,放置一个index.html
页面。内容如下。
<!DOCTYPE html>
<html>
<head>
<script>
window.location.href = "https://www.abc.com/";
</script>
</head>
<body>
</body>
</html>
由此即可实现abc.com
到www.abc.com
跳转。
四、使用CloudFront发布静态网站的最佳实践
1、使用CloudFront OAC(Origin Access Control)策略实现对私有S3存储桶的访问
在上文的配置过程中,CloudFront最新的向导配置会自动给S3的存储桶配置存储策略。这个功能被称为OAC(Origin Access Control)。OAC策略是由CloudFront自动配置。此时进入S3存储桶,进入Permissions
标签页,在S3存储桶策略中可以看到如下一段。
{
"Version": "2008-10-17",
"Id": "PolicyForCloudFrontPrivateContent",
"Statement": [
{
"Sid": "AllowCloudFrontServicePrincipal",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-s3-static-hosting-demo-01/*",
"Condition": {
"ArnLike": {
"AWS:SourceArn": "arn:aws:cloudfront::123456789012:distribution/E1234ABCDEFG"
}
}
}
]
}
以上就是CloudFront向导自动添加的S3存储桶策略。如果需要修改存储桶策略,请保持以上内容不要删除,否则将导致CloudFront访问源站失败。
2、开启Origin Shield优化回源流量提升缓存命中率
CloudFront的回源默认是从离用户最近的POP点发起直接访问,因此当访问者分布在全球时候,回源路径是分布在全球的POP点的。使用Origin Shield功能,可以让整个CloudFront所有POP点的回源先汇聚在一个地点,然后从这个单一地点回源。此时网络流量的传输将借助AWS骨干网,有效改善访问延迟。使用Origin Shield之后,源站可以设置安全规则组,仅对Origin Shield回源特定的IP地址放行,由此大大提升安全性。
针对使用私有S3存储桶作为静态网页存储的场景,因为本身S3存储桶已经是私有状态,不涉及安全规则组,因此本选项不涉及安全性提升。此时,开启Origin Shield可提升缓存命中率。下面介绍如何打开。
在CloudFront发布点的配置页面上,点击Origins
标签页,点击S3源站,编辑按钮。如下截图。
在源站设置界面,将页面移动到最下方,开启Origin Shield选项,然后将回源的区域改为和S3存储桶相同的区域。然后点击保存按钮。如下截图。
由此即可通过Origin Shield提升缓存命中率。
3、为静态网站托管设置自定义错误页面
使用CloudFront+S3提供静态网站后,一个主要的变化就是不再有404错误类型,所有找不到文件的类型都将返回403错误。这是因为S3存储的文件是以键值(Key)来标识的,当访问/abc.html
的时候,如果这个文件不存在,S3返回的是找不到这个Key/或者这个Key存在但是没有权限
的错误。这个时候CloudFront返回的错误代码是403。这就是没有404错误的原因。如果不修改自定义错误页面的配置,当用户输入了错误地址时候,会显示没权限错误,可能引起访问者的误解,误以为是网站故障而不是自己输入错误的地址。
为此,建议自定义错误页面,将404和403错误都指向到自己的自定义页面。
进入CloudFront发布点,点击Error pages
标签页,点击右上角的创建自定义错误响应按钮。如下截图。
在自定义错误响应页面上,点击HTTP error code
下拉框,首先选中403错误,然后将下方的Customize error response
的打开设置为Yes
。在下方自定义错误页面路径的位置,输入/errorpage.html
,这个就是自定义的错误页面,然后把最下方的错误代码设置为403错误。如下截图。
由此403错误的页面配置完成。再次重复以上设置,将404错误也指向/errorpage.html
。
4、使用多条行为规则细化缓存管理
CloudFront创建发布点向导时候,选择源站是S3将会自动配置缓存优化规则。因此如果要刷新,要强制进行过期操作。
首先我们先看下默认的规则。进入发布点,点击Behaviors
标签页,选择默认的行为,点击编辑按钮。如下截图。
在Cache key and origin requests
选项位置上,可看到CloudFront向导推荐的设置是Cache policy and origin request policy (recommended)
,并且配置的是CachingOptimized
规则。点击View Policy
按钮,即可查看规则。如下截图。
点击View Policy
按钮后,跳到查看规则界面。这就是默认规则。如果需要自定义规则,可以新建规则、并重新配置到本CloudFront发布点。如下截图。
如果希望清除所有CloudFront的POP点上的缓存,那么可以通过在发布点的Invalidations
界面上发起过期的请求。如下截图。
在创建新的规则位置,输入/*
即可将全站的缓存清除。
此外,转向静态化之后,不同的网站内容类型、不同的栏目、包括首页、和详细文章内容页,可能分别有不同的缓存策略,此处建议创建多条行为规则,匹配不同的路径和扩展名,分别管理缓存规则。
5、设置CloudFront Response Policy屏蔽S3文件暴露的标签
存储在S3存储桶上的文件是包含特定的标签,包括加密方式、ETAG、存储级别等。当通过自己的应用程序访问S3时候并不是问题,但如果通过CloudFront对S3进行发布,这些Tag会被CloudFront透传出来。
下边以访问某图片文件为例。
curl -I https://www.abc.com/image01.png
访问结果如下:
HTTP/2 200
content-type: image/png
content-length: 633839
date: Tue, 19 Aug 2025 06:41:39 GMT
last-modified: Tue, 19 Aug 2025 06:33:30 GMT
etag: "2c68345ecca3488e69827fd8f2b0eafb"
x-amz-server-side-encryption: AES256
accept-ranges: bytes
server: AmazonS3
x-cache: Hit from cloudfront
via: 1.1 692ffa98ef111ee24bd6eed0db7ec1de.cloudfront.net (CloudFront)
x-amz-cf-pop: NRT57-P2
x-amz-cf-id: dHptv9Izf1d6TP8-HyUbDA3CvoUDnTaSifPTX-GzL7dc0cDcTI8tEQ==
age: 925
以上信息中,可以看到文件创建时间、etag、S3存储加密方式、Server、POP点等信息。去掉CloudFront对外提供服务正常的Header(如POP点、缓存命中率),其中一些信息可能是不希望暴露给用户的。如果使用了Storage Gateway对S3进行读写,那么Storage Gateway也会添加大量的Header,例如如下。
x-amz-meta-user-agent: aws-storage-gateway x-amz-meta-user-agent-id: sgw-C06FECA9
x-amz-meta-aws-sgw: b41bb85f0944738dd9d125b2307a42420b7acd28106d5c68b3335df81204db0b
x-amz-meta-file-ctime: 1754985929434000000ns
x-amz-meta-file-owner: 1000
x-amz-meta-file-permissions: 0664
x-amz-meta-file-group: 1000
x-amz-meta-file-mtime: 1754985929434000000ns
以上信息就是通过Storage Gateway对S3进行读写时候,会额外添加的Header。
对于使用CloudFront进行发布的用户来说,这些信息可能是不希望对外暴露的,此时可以通过修改CloudFront Policy规则进行修改。具体屏蔽方法如下。
进入cloudFront的Policy规则界面,点击第三个标签页Response headers
,点击右下角的创建按钮。如下截图。
在名称位置,输入自定义名称。如下截图。
在Remove headers
位置,输入要被CloudFront去除的header。然后点击创建按钮。如下截图。
由此,即可移除不想对外展示的header。
需要注意的是,这里不能添加无限数量的header,处理能力总数有一定限制,最大可以输入10个。
6、使用WAF进行流量控制
由于原始网站是静态内容并且使用S3托管,因此不需要对安全方面有所担心,在CloudFront上默认不开启WAF也可以确保基本的安全。如果希望通过WAF进行更多检查,例如控制流量,检查Refer,检查特定Header等。
具体WAF配置过程,这里不再详细描述,请参考WAF服务相关文档。
7、使用S3存储桶生命周期删除过期页面
全静态化网站意味着内容的管理仅靠文件版本来进行,无法像动态网站那样决定显示数据库中的哪一条。因此,可打开存储桶的Versioning版本管理功能,并设置S3 Lifecycle生命周期规则,将过期的旧版本过期删除。
在存储分层管理方面,因为S3自动分层对小于128KB大小的对象无效,且S3IA不频繁访问层也不会生效,因此对于以HTML页面为主的全静态网站场景,无须使用自动分层。如果网站中包含大量图片、引用素材,他们平均体积远大于128KB,那么建议上传文件时候就把所有文件的存储层设置为自动分层,或者使用S3 Lifecycle将存量文件转换为S3自动分层存储类型
8、网站备份
静态化网站的备份可通过应用端读取S3存储桶的方式实现,不过这样会导致大量对S3的遍历访问。另一种办法是,开启S3的复制规则,将S3所有文件复制到另一个区域、甚至另一个账号的存储桶。由此在作为生产环境的当前存储桶受到错误删除或者其他破坏时候,就可以从远端的存储桶恢复文件。
五、参考文档
Use an Amazon CloudFront distribution to serve a static website
https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/getting-started-cloudfront-overview.html
S3 CORS配置
https://docs.aws.amazon.com/AmazonS3/latest/userguide/cors.html
最后修改于 2025-08-19