Hexo博客开发(1)
为什么
- 不想要开源博客的代码
- 主要是为了配置简单, 用AWS S3来储存Hexo生成的静态文件, CloudFront做CDN,还有Route53做域名管理。再加上用CodeBuild的webhook用来监听Github的源码更新。
Hexo初始设置
根据官网来初始化Hexo项目 (默认nodejs和yarn环境)
1 | hexo init my-blog |
使用hexo-theme-butterfly来写博客。把_config.yml里把Hexo的主题改成butterfly
1 | # Extensions |
然后根据butterfly快速开始把本地node_modules/hexo-theme-butterfly下的_config.butterfly.yml复制到项目根目录下。之后就可以根据需求开启/关闭博客的一些功能。
运行 hexo serve -p 4000, 然后在浏览器打开localhost:4000预览结果.
AWS CodeBuild
登陆AWS console, 在顶部搜索CodeBuild服务。点击”Create build project”,
- 填构建的工程名称
- 在”Source”栏
- 点击选择Github作为代码的源
- 勾选Rebuild every time a code change is pushed to this repository, 这样就注册了一个webhook, 可以让CodeBuild在Github代码更新的时候自动重新编译/发布博客
- 点击选择Github作为代码的源
- “Environment”栏依次选择
- OS: Amazon Linux 2
- Runtime(s): Standard
- Image: aws/codebuild/amazonlinux2-x86_64-standard:5.0
- 最后选择或者创建一个service role.
- 备注一下: 在AWS中role主要包含了当前服务可以调用其他AWS服务的**权限(Permission)**。比如CodeBuild需要在打包阶段将结果写入S3, 那么被挂载到CodeBuild的Role应该包含有写入S3的权限.
- “Buildspec”使用默认选项,具体描述在源码目录下的buildspec.yml中, 下面是当前博客使用的buildspec.yml, 具体配置参考AWS CodeBuild的官方文档
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22version: 0.2
phases:
# 安装所需要的包
install:
runtime-versions:
nodejs: 18 # 使用nodejs 18
commands:
- npm install
- npm install -g hexo-cli
build:
on-failure: ABORT # 错误发生将自己停止编译
commands:
- echo Start building website
- hexo generate # 使用hexo generate生成网站(public目录)
artifacts: #生成目录在CodeBuild中指定为S3
# 下面两个选项可以理解为:
# 拷贝public目录下的所有文件到S3.
files:
- '**/*'
base-directory: public - “Artifact”栏选择
- Amazon S3为输出地址, 选择目标Bucket
- Name还有path分别填”/“和”./“, 否则的话CodeBuild最后会将结果打包成一个文件夹放到S3根目录下, 而不是直接在根目录下。
- 在”Additional configuration”下填入从AWS KMS的加密密匙。具体方法在下面说明。
- 这里不使用AWS S3默认的密匙是因为, S3的密匙是用于当前账户下的所有S3 Bucket. 自己创建的密匙可以提供更精细(fine grained)的配置
AWS Key Management Service (KMS)
简单来说, KMS就是一个提供了集中管理/储存加密密匙的服务. 比如说:
- S3需要从KMS获取密匙来加密上传的对象
- CloudFront需要在用户发送网络请求的时候从KMS获取密匙来解密S3的对象,然后再将结果返回给用户.
这样的话, 就不需要硬编码密匙, 同时KMS也提供了每年进行密匙的更新。下面就创建一个KMS密匙 (默认选项).
点击新创建的密匙, 查看并编辑Key Police. Key Police决定了那些AWS服务可以使用这个密匙
1 | { |
CloudFront
AWS CloudFront可以用于缓存应用层面的数据和对象, 并加速对客户端的请求的响应. 登陆AWS创建一个新的CloudFront分布节点
- “Origin”一栏选择S3为源. 这里选择推荐OAC (Origin Access Control), 即所有的网络请求只有通过CloudFront来获取资源, 并且S3将无法直接从网络访问.
- 备注: 当前S3的website endpoint不支持 OAC, 所以不在这里使用.
- “Default cache behavior”中, 为了数据传输安全,把Viewer protocol policy改成Redirect HTTP to HTTPS
- “Web Application Firewall (WAF)”中, 可以勾选打开网络防火墙, 基础为每个月$8
创建为新的CloudFront节点以后, 可以得到一个CloudFront的URL如,d3lx8t3p3ypfbh.cloudfront.net, 在这之后需要更新S3的访问权限只让CloudFront访问
S3
如果CodeBuild配置成功的话, 目标S3下应该会出现以下文件,
- 到“Property”下打开”Static website hosting”,
- 将“Index document” 设置为”index.html”
- 到”Permission”下修改S3访问权限, 可以根据官网文档配置, 或者直接在CloudFront的Origin中直接复制:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17{
"Version": "2012-10-17",
"Statement": {
"Sid": "AllowCloudFrontServicePrincipalReadOnly",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::<S3 bucket name>/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::<AWS account ID>:distribution/<CloudFront distribution ID>"
}
}
}
}
注意, 在这时S3的”Block public access”还是启用的(绿色on).
Route53 & ACM (AWS Certificate Manager)
这里将配置一个域名并将网络流量定向到CloudFront.
- 首先先申请一个域名, 一般申请成功的话AWS会自动帮你创建一个Hosted Zone. 这里要注意的是要把申请完域名的名称服务器 (Name Server)改成Hosted Zone的.
- 点击进入Hosted Zone, 可以看到有4个名称服务器的地址
- 打开左边菜单, 点击”Registered Domain”, 点击自己的域名, 然后在页面左上角”Action”下拉菜单中选择”Edit name servers”并更新名称服务器。
- 点击进入Hosted Zone, 可以看到有4个名称服务器的地址
- 接下来需要通过自己的域名将网络流量导给CloudFront.
首先要同过AWS Certificate Manager申请一个SSL/TLS证书, 这个证书可以让不同计算机系统在网络上安全地相互通信。
- ***.ryon49.com**将映射在ryon49.com下的所有子域名, 如www.ryon49.com, blog.ryon49.com等等。
- 创建完后点击进入, 选择”Create records in Route53”, 将自动把证书导入Route53. 返回Hosted Zone, 可以看到新增加了一条cname记录
关联Route53和CloudFront:
- 返回CloudFront的节点配置页面, 在setting一栏点击Edit
- 在”Alternate domain name (CNAME)”下填写www.ryon49.com和blog.ryon49.com, 这样对这两个地址的网络访问都会被导向个CloudFront节点
- 在”Custom SSL certificate”中下拉选择刚刚创建过的SSL证书.
- 保存并等待CloudFront更新节点
返回Route53自己域名的Hosted Zone
- 点击”Create record”创建新的记录, 创建两条记录并同时指向CloudFront, 可以看到两条记录的名称都跟上面的对应.
这样的话就可以通过在浏览器访问 www.ryon49.com 和 **blog.ryon49.com**看到最初显示的Hexo界面了.
Troubleshoot (错误Debug)
正常情况下当我们访问博客的时候, 如wwww.ryon49.com, 实际上我们访问的是www.ryon49.com/**index.html**这个页面. 但是CloudFront只会根据路径名找资源, 并不会找到index.html. 这种情况下
- 登陆AWS,点击进入自己的CloudFront. 打开CloudFront左边的菜单并进入Functions,
- 创建一个新的函数, 名字就叫append-index-html
- 函数代码可以在官方文档找到
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15function handler(event) {
var request = event.request;
var uri = request.uri;
// // Check whether the URI is missing a file name.
if (uri.endsWith('/')) {
request.uri += 'index.html';
}
// Check whether the URI is missing a file extension.
else if (!uri.includes('.')) {
request.uri += '/index.html';
}
return request;
} - 保存更改, 然后点击发布(Publish), 发布以后可以在”Associated distributions”标签下于CloudFront进行关联. 点击”Add association”, 选中当前CloudFront的节点
- “Event type”为Viewer request, 代表URL将在进入CloudFront时, 到达S3之前进行处理, 跟具体的资料可以在官网文档进行查看
- “Cache behavior勾选Default就行。
- 查看改变, 回到CloudFront节点设置页面. 在Behaviors标签下编辑(Edit)优先级为0的行为(behavior), 下拉找到”Function associations”就可以看到Viewer request已经关联了刚刚创建的CloudFront函数了.
一般由两种情况
CodeBuild在UPLOAD_ARTIFACTS的阶段发生错误,
图片说明CodeBuild没有获取加密密匙的权限, 无法生成密匙. 这种情况一般是上面KMS关于CodeBuild的Policy没有配置号导致,根据目录第4个AWS Key Management Service (KMS)检查一遍。CloudFront在解密S3的对象上发生错用, 可能有两个原因
1. 跟上面一样KMS的配置发生了错误
2. CodeBuild在Artifact一栏没有配置正确KMS Arn,是CloudFront用于解密的密匙与CodeBuild用来加密的密匙不一样. 回到CodeBuild更改配置.