AWS S3教程:在S3上搭建静态网站并配置自己的域名及https


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

AWS S3
AWS 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,如果通过浏览器进行访问,你会看到一个访问拒绝的消息:

markup
<Error>
  <Code>AccessDenied</Code>
  <Message>Access Denied</Message>
  <RequestId>C4WNH6GNHA6QN19V</RequestId>
  <HostId>XWh8MvQ2rwMZ08oraA4JlU+eN8uYrZnIJqrzJnyjziH8noxsqM665cC5OKjZJVNu8wSfbjwaNO8=</HostId>
</Error>

当然,也可以上传一个React/Vue构建完的目录到S3:

bash
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:

yaml
{
    "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”

image
image

这里要求证明你对域名的所有权。如果你的域名在Route 53中,就非常方便了,直接单击“Create records in Route 53”,AWS就会自动创建对应的CNAME记录。

如果域名在其他地方管理,就需要进行相应的设置了。下面以Cloudflare为例。

在域名提供商处添加CNAME record

我用的是Cloudflare,在自己域名下按照上一步要求的信息添加对应的CNAME。

image
image

需要注意,在添加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请求定位到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

image
image

然后是Behaviors的设置:

image
image

这样所有针对 /dev/* 的访问都会被定向到 APIGateway,而其他的则会被定向到 S3。

关于CloudFront CORS

最后还有关于CORS的设定。原来所有请求会被直接发送到APIGateway,但现在不一样了,中间又多了一个CloudFront。因此,在Behaviors中需要额外的设置:

image
image

image
image

关于CloudFront中丢失header/query-string的问题

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


文章作者: 逻思
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 逻思 !