从 0 到 1 部署你的博客
0️⃣ 前言
一直以来用阿里云的 ecs 部署了一个博客应用,但是自从进入阿里之后就一直没更新,应用也无法访问了。
本身搞博客应用就是为了端到端(从前端到后端),系统地了解项目工程和流水线工作原理的,趁着有时间重新梳理一下整个过程。
1️⃣ 环境准备
博客项目技术方案:采用 Hexo + Node.js + Nginx 来搭建。
Hexo 其实是一个静态博客框架,其实不依赖 Node.js, Hexo + Nginx 就部署出来博客,这里 Node.js 主要是为了部署 Webhooks 的服务进行自动更新,后面会展开。
2️⃣ 搭建 Hexo 博客
1. 初始化博客
没有特殊需求的情况下,建议采用 hexo-cli 来初始化你的博客。
1 | npm install hexo-cli -g |
目前初始化的 hexo 是 7.x 的版本,依赖使用 pnpm 管理,你也可以安装下 pnpm:
1 | npm install pnpm -g |
本地测试使用下面命令,默认会在 4000 端口起一个服务:
1 | hexo server |
不过实际上我们部署博客不需要使用 server,可以用生成的静态 html 来访问,server 更多的是给基于 hexo 需要开发插件等使用的,比如主题。
2. 发布新文章
hexo 的文章是 markdown 的,你可以使用命令行来创建文章,它会在 source/_posts
目录下创建对应文件:
1 | hexo new "my-first-post" |
3. 博客主题
具体的博客主题可以参考:Hexo 博客主题,实际上已经很少有人维护了,毕竟 hexo 本身也比较老了。
我这边用了一个 replica 的仿 github 风格,实际上默认主题也是 ok 的,具体配置参考文档即可,难度不高。
Hexo 部署
hexo 会提供一些部署方案供你选择,我这边主要介绍两种:一种是部署到 Github Pages 的,适合没有自己站点,白嫖 github 的;另外一种是自己建服务器,可以部署到自己的站点,用自定义域名的。
3️⃣ Github Pages 部署
hexo 提供了 hexo deploy
命令来部署到 Github Pages,但是需要配置下 _config.yml
。
1 | ## 前面配置省略... |
repo 的地址可以是 ssh,也可以是 https(需要提供 token),我因为本地 mac 和 ecs 服务器都会添加 ssh key 到 github 上,所以直接用了 ssh 的形式。
其他更多的用法可以参考插件配置:hexo-deployer-git
此外,你也需要安装在插件的 npm 依赖:
1 | npm install hexo-deployer-git -S |
运行 hexo deploy
命令,它会在你根目录创建一个 .deploy_git
的目录,里面会生成你的博客静态 html,然后推送到你指定的分支,这里我用了 gh-pages
。
然后我们看一下对应仓库的 Pages 配置,让他变成一个可访问的站点:
选择 Deploy from branch
,分支选择 gh-pages
,没有的话需要创建一下,当然你也可以直接选择 main
分支。
后续推送 gh-pages
分支就会自动部署了,一般地址会根据你仓库来生成,比如:
https://excaliburhan.github.io/hexo-blog
当然你用 hexo deploy
之后,会自动帮你更新 gh-pages
分支内容的,实现自动更新。
4️⃣ 阿里云 ECS 部署
一般想要玩一下个人网站的话,可以参考下 ECS 这个方案,首先你得有一台 ECS 服务器:阿里云 ECS。
进入购买页面,个人站点没啥特别要求的,建议直接买这个配置:
目前是有 2C2G 3M 带宽 99 元的套餐的,还是比较划算的,而且第二年续费也能享受 99 元活动。我因为已经续费过了,现在界面不显示对应活动了。
镜像我就直接选了 Alibaba Cloud Linux,是基于 CentOS 继续维护的(CentOS 后续不维护了)。
登录 ECS
登录 ECS 有很多种选择,你可以通过通过 ECS 的控制台直接进入,比如 Workbench 方式:
进入之后就是一个 Web 版的 SSH 终端,当然你也可以通过 SSH 登录,那我建议你参考一下这个 SSH 免登文档。
默认 ECS 的安全组应该是开放了 80、443 端口的,这是后续访问 HTTP、HTTPS 必须配置的。如果没有的话,你也可以通过 安全组 - 快速添加
直接生成一个安全组策略。
安装必要依赖
1. 安装 git
安装一下必要的环境和依赖,首先安装下 git:
1 | yum install -y git |
2. 安装 nvm 和 node
安装 node,我这里安装了 nvm 来进行 node 版本管理:
1 | curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash |
然后安装 node,推荐使用 lts 版本:
1 | nvm install --lts |
顺便安装在 pnpm:
1 | npm install -g pnpm |
3. 安装 zsh
安装一下 zsh:
1 | yum install -y zsh |
切换成 zsh
1 | chsh -s /bin/zsh |
当然也可以考虑安装 oh-my-zsh:
1 | sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" |
安装和配置 Nginx
安装一下 Nginx
来做 HTTP 和反向代理的管理:
1 | yum install -y nginx |
配置 Nginx,这里我直接使用默认配置,然后启动 Nginx:
1 | systemctl start nginx |
这时候你可以用公网 IP 访问 80 端口,如果能访问到 Nginx 页面,说明配置成功。
结合 acme.sh 生成 ssl 证书
现在网站一般都需要 https 了,需要生成 ssl 证书,这里我使用 acme.sh
来生成。
acme.sh 是一个免费、开源的证书生成工具,可以自动生成证书,然后自动更新证书。
1. 安装 acme.sh
1 | curl https://get.acme.sh | sh |
可以设置一下 alias,方便以后使用:
1 | echo 'alias acme.sh=~/.acme.sh/acme.sh' >> ~/.zshrc && source ~/.zshrc |
2. 设置默认 CA
acme.sh
现在被 zeroSSL 收购了,而 zeroSSL 需要注册账号,我还是比较习惯 letsencrypt,所以默认 CA 设置成 letsencrypt
1 | acme.sh --set-default-ca --server letsencrypt |
3. 验证签发证书
生成 ssl 证书有多种方式,比如 webroot
、nginx
、dns
等,可以参考这个 issue 证书文档
不过实践下来,感觉还是 webroot 比较方便,一方面我们因为 http 的访问地址一般都会 rewrite 到 https,nginx
可能会因此失败;另一方面需要自动更新,dns
方案比较麻烦,尤其是 aliyun 的 api 我试了经常失败。
我需要配置的域名是: excaliburhan.com
、 www.excaliburhan.com
和 api.excaliburhan.com
。我们先修改下创建一下 web 文件目录:
1 | mkdir -p /home/www/letsencrypt |
修改下 nginx 的配置:
1 | # http 配置 |
签发证书:
1 | acme.sh --issue -d excaliburhan.com -d www.excaliburhan.com -d api.excaliburhan.com -w /home/www/letsencrypt |
-w
的地址可以根据你的需要做对应调整。
最后签发成功之后如图:
4. 安装证书到 nginx 目录
一般我们会安装证书到 nginx 目录,后续自动更新也会自动执行这个过程:
1 | acme.sh --install-cert -d excaliburhan.com -d www.excaliburhan.com -d api.excaliburhan.com \ |
key-file
这些的目录地址可以根据你实际需要去修改。
5. 修改 nginx https 的配置
1 | server { |
然后重启一下 nginx systemctl restart nginx
。
6. acme.sh 自动更新
1 | acme.sh --auto-upgrade |
acme.sh 默认会给你创建一条 crontab 的任务:
1 | crontab -l |
letsencrypt 证书有效期是 90 天,acme.sh 默认自动更新是 60 天后更新,如果没到则会直接跳过,你可以在通过下面命令具体 Renew 的时间:
1 | acme.sh --list |
DNS 解析配置
你需要 DNS 的服务商来进行 DNS 解析,从而可以通过你的域名来访问网站,我这里用了阿里云的 DNS 服务。你可以参考:DNS 解析
一般来说,你需要 3 条记录,*
、@
和 www
,记录值就是你的公网 IP:
。
这时候,你就可以用 https 的方式访问你的网站了。
5️⃣ Github Webhooks 自动更新
上面阿里云 ECS 部署篇幅比较长,所以这部分自动更新的单独放在一起说了。
首先你可以简单了解下文档:Github Webhooks。
1. 创建 Webhooks
通过 仓库 - Settings - Webhooks
,创建一个新的 Webhook,创建完成后,后续你 push 仓库的时候就会触发这个 Webhook。
利用触发的 Webhook 自动拉取最新代码和你的博客内容,从而实现自动更新的效果。
2. API Server
你需要一个自己的 api server 应用,可以使用 Express
或者简单的 Node Http Server
,这里具体逻辑就不展开了,推荐两种方案:
Express 这类需要自己处理的,可以借助 @octokit/webhooks 来完成验签这类工作,会轻松很多
Node Http Server 可以使用 github-webhook,直接安装依赖启动即可,比如:
1 | github-webhook \ |
对应的 echo "yay!"
更换成你需要执行的 sh
脚本即可,比如这样,进入对应目录,拉取最新代码,然后执行 npm run build
:
1 | cd /home/hexo-blog |
当然最好的还是自己写 API Server,可以定制自己的一些逻辑。
3. PM2 守护进程
无论是何种方式,Webhooks 本质都是一个 Node 的服务,最好使用 PM2
这样的守护进程:
- 服务挂了之后自动重启
- 自带一些日志能力
6️⃣ 图片资源处理
为了更好的体验,常规上我们会把图片放在 OSS 或者 CDN 来进行一些资源优化,下面我主要介绍一下 阿里云 OSS
和 七牛云 CDN
的方案。
阿里云 OSS
开通 OSS 服务之后,配置一下 OSS Bucket:
几个要点:
- 地域:选择有地域属性,计费会更低一点,国内场景够用了
- 存储类型:标准存储,当然你也可以选择
低频访问
、归档存储
,能力和计费上都有一点区别 - 存储冗余类型:本地冗余存储足够了
上传图片你会得到类似的 oss 地址:https://xp-assets.oss-cn-hangzhou.aliyuncs.com/gakki.jpg
。
当然 oss 是不支持图片压缩的,也无法根据用户所在地提供最近的地址,这些需要开启 CDN 服务。阿里云的 CDN 现在基本没有白嫖证书了,下面介绍七牛云的方案。
七牛云 CDN + 自定义域名 + 免费证书
开启 CDN 前提是需要 OSS 存储服务的,七牛云也有类似的服务,这里就不展开了,可以直接参考 七牛云 Kodo。
如果需要通过类似自定义域名访问:https://static.excaliburhan.com/gakki.jpg
,首先你需要一个 CA 证书。七牛云是可以白嫖这种证书的,但是有效期只有 90 天。
1. 购买证书
选择 TrustAisa 的 DV 限免证书,0 元下单:
购买之后需要你填写对应的信息,我这里验证方式选了 DNS
,加密算法选了 RSA,ECC 会有一些兼容性的情况:
2. DNS 验证
当你填写完基本信息之后,需要你去 DNS 解析增加记录,保证能够完整验证,否则就会一直审核中了。
主机记录和记录值都会在你的购买订单里显示给你,创建一个 TXT
记录,验证成功后等待订单生效即可:
3. 配置域名
然后你可以通过域名管理,新增刚才申请的域名,按照要求填写信息即可:
对应的源站选择你的七牛云存储即可。等待七牛云域名管理生效之后,就可以使用类似地址进行访问了:
https://static.excaliburhan.com/gakki.jpg
。
4. 自动更新免费证书?
查了一下七牛云的 API 和相关页面,貌似没有自动更新免费证书的能力(或者说复杂度太高)。
当然在域名管理里看到可以授权七牛云代申请免费证书的入口:域名管理 - HTTPS 配置 - 修改配置
这种方式需要你在 DNS 解析添加一条 CNAME
的记录,看起来并没有自动更新的能力,所以大概率 90 天后你还需要手动执行这个过程。
7️⃣ 总结
整个过程下来还是踩了不少坑,一方面是因为太久没搞这种从前到后的工程了,另外一方面 acme.sh 的证书签发方式按照文档也会遇到一些实际问题。
不过整体弄完效果还是可以的,但大概率这一篇博客之后,又会进入长期休眠状态了 😃