作为AWS众多云服务的核心成员之一,S3得到了非常广泛的应用。下面来介绍一下如何在S3上搭建静态网站。

创建并配置S3 bucket
创建S3 bucket
首先在自己的AWS账户中创建一个bucket,比如填入如下信息:
- Bucket name: demo.lcoding.club
- 不要选择“Block all public access”
- 建议选择Bucket Versioning
单击”Create bucket”来创建这个bucket。
上传测试文件index.html
上传一个index.html到这个bucket。此时还不能直接访问这个index.html,如果通过浏览器进行访问,你会看到一个访问拒绝的消息:
<Error>
<Code>AccessDenied</Code>
<Message>Access Denied</Message>
<RequestId>C4WNH6GNHA6QN19V</RequestId>
<HostId>XWh8MvQ2rwMZ08oraA4JlU+eN8uYrZnIJqrzJnyjziH8noxsqM665cC5OKjZJVNu8wSfbjwaNO8=</HostId>
</Error>
当然,也可以上传一个React/Vue构建完的目录到S3:
aws s3 sync build/ s3://YOUR_BUCKET_NAME --profile YOUR_AWS_PROFILE_NAME --delete
Bucket的进一步配置
选择S3 Bucket => “Properties” => “Static website hosting”,
- Static website hosting: Enable
- Index document: index.html
单击“Save changes”
选择“Permissions”,添加如下的Bucket policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": [
"s3:GetObject"
],
"Resource": [
"arn:aws:s3:::demo.lcoding.club/*"
]
}
]
}
至此为止:我们能够通过http (而不是https) 来访问这个静态网站了:
http://demo.lcoding.club.s3-website-eu-west-1.amazonaws.com/
下面的目标有两个:第一是使用https,第二是使用自定义域名: https://demo.lcoding.club
AWS Certificate Manager中的设置
注意,Region一定要选择us-east-1 (N. Virginia)
单击“Request a certificate”
- 选择:”Request a public certificate”
- Fully qualified domain name: demo.lcoding.club
- Select validation method: DNS validation - recommended
单击“Request”,这时就会看到这个certificate的状态为”Pending validation”

这里要求证明你对域名的所有权。如果你的域名在Route 53中,就非常方便了,直接单击“Create records in Route 53”,AWS就会自动创建对应的CNAME记录。
如果域名在其他地方管理,就需要进行相应的设置了。下面以Cloudflare为例。
在域名提供商处添加CNAME record
我用的是Cloudflare,在自己域名下按照上一步要求的信息添加对应的CNAME。

需要注意,在添加CNAME的时候,
- Name:_xxxxxxxxxxxxxxxxxxx.api (没有后面的.lcoding.club.)
- Content: xxxxxxxxxxxxxxxx.xxxxxxx.acm-validations.aws. (不要忘记后面的.)
这部做完后需要等待几个小时,一旦AWS通过了验证,就可以进入到下一步了。
CloudFront中的设置
选择“Create a CloudFront distribution”
- Origin domain: demo.lcoding.club.s3.eu-west-1.amazonaws.com (注意这一步可以从下拉列表框中选择,但有些时候AWS似乎不能及时更新,可能看不到最新的bucket名字,因此建议去bucket那里复制名字然后粘贴过来)
- Viewer Protocol Policy: Redirect HTTP to HTTPS
- Alternate Domain Names: demo.lcoding.club
- SSL Certificate: Custom SSL Certiciate 并选择刚创建的certificate。
然后单击“Create distribution”。
Cloudflare中的进一步设置
在CloudFront中,Domain Name的格式为: xxxxxxxxxxx.cloudfront.net,下面就需要回到Cloudflare域名设置中,添加一条CNAME,将demo.lcoding.club指向CloudFront的域名。
- Route traffice to: Alias to CloudFront distribution
- 选择CloudFront Domain Name
这时如果在Chrome Developer Tool中查看HTTP Response,就会看到:
- server: AmazonS3
- via: 1.1 xxxxxxxxxxxxxxxxxxx.cloudfront.net (CloudFront)
CloudFront缓存问题
如果页面更改后在浏览器中仍看不到,需要考虑清空CloudFront的缓存。
进入CloudFront Distributions -> 对应的 XXXXXXXXXXX
选择:Invalidations
单击:Create Invalidation,在Object Paths中选择“/**/*”,但后单击”Invalidate”
如何在CloudFront中的一个Distribution对应到API和前端两个域名
在最终部署的时候,可能会有这个问题:
- 前端代码会部署到S3 bucket
- 后端API则会通过API Gateway访问
这样的话:
- 前端对应的域名为:YOUR_BUCKET_NAME.s3-website-YOUR_REGION.amazonaws.com
- 后端API对应的域名为:xxxxxxxxxx.execute-api.eu-west-1.amazonaws.com
但我们最终想要的访问URL则是:
要想解决这个问题,就可以有两个不同的选择:
- 首先,针对后台API,单独启用一个子域名,比如:https://api.lcoding.club,这有可能会造成CORS的问题。
- 还可以使用CloudFront中不同的origin / behavior来解决
第一种方案比较简单,就不再说了。
将所有/api请求定位到API Gateway,其余的则定位到S3
对于第二种方案,可以进行如下设置,进入CloudFront对应的Distributions,自己的distribution => Origins:
添加APIGateway对应的设置:
- Origin name: xxxxxxxxx.execute-api.eu-west-1.amazonaws.com
- Origin domain: xxxxxxxxx.execute-api.eu-west-1.amazonaws.com
添加S3对应的设置:
- Origin name: xxxxxxxxx.s3-website-eu-west-1.amazonaws.com
- Origin domain: xxxxxxxxx.s3-website-eu-west-1.amazonaws.com

然后是Behaviors的设置:

这样所有针对 /dev/* 的访问都会被定向到 APIGateway,而其他的则会被定向到 S3。
关于CloudFront CORS
最后还有关于CORS的设定。原来所有请求会被直接发送到APIGateway,但现在不一样了,中间又多了一个CloudFront。因此,在Behaviors中需要额外的设置:



关于CloudFront中丢失header/query-string的问题
另外,在默认设置下,CloudFront会忽略所有的header及query string,这样在后台就无法获得前台传递过来的数据了。如果要解决这个问题,可以在CloudFront中创建一个自定义policy,然后在Distribution中使用这个policy:
