使用CloudFront+S3提供静态网站Hosting

本文介绍了静态网站托管场景中,如何使用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发布点A
  • us.abc.com对应的存储桶,存放对应的网页,绑定CloudFront发布点B
  • abc.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.comwww.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.comwww.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