Life and freedom Ge Lin ——— Draw by Razzh

acme.sh 申请 SSL 部署博客至阿里云

Feb 7 · 10 min

#写在之前

本文主要记录了作者如何申请免费的 SSL 证书并部署当前博客到云服务器的过程,分为以下两个阶段:

  • acme.shdocker 中的 Nginx 添加 SSL 证书
  • Github Actions 任务流自动上传提交代码的打包版本至服务器指定目录

整篇教程以 docker 为基础来部署博客至阿里云

#acme.sh

acme.sh是 github 上的一个开源项目,目前以有41K🌟,acme 协议是 Let’s Encrypt 和其他 CA 机构使用的一种网络交互协议,用于自动验证网站/域名并颁发 SSL/TLS 证书。

在签发证书后可同时创建定时任务,在证书将要过期时自动重新申请并部署,其还可以于 Nginx 或者 Apache 直接交互完成证书申请过程。

#docker

如果云服务器上还没安装docker,可以按照阿里云文档 提供的方法安装。

docker 的指令可以见文档

首先,我们需要使用 docker 拉取一个 Nginx 镜像:

docker container run \
  -d \
  --rm \
  --name mynginx \
  nginx
docker container cp mynginx:/etc/nginx .
mv nginx conf
mkdir ./conf/certs
mkdir html
docker stop mynginx

这一步的作用是运行 docker 容器中的 nginx,复制 nginx 的目录文件至当前目录,并创建 certs 目录和 html 目录,目的是为后续与 docker 容器内的 nginx 做数据卷(映射)。

certs 目录是用来在存放证书的目录,而 html 目录则是存放我们博客打包后资源的目录。

docker container run \
  --rm \
  --name mynginx_1 \
  --volume "$PWD/html":/usr/share/nginx/html \
  --volume "$PWD/conf":/etc/nginx \
  --label=sh.acme.autoload.domain=razzh.cn \
  -p 80:80 \
  -p 443:443 \
  -d \
  nginx

因为HTTP和HTTPS的默认端口是80和443,云服务器需要在安全组手动添加80和443端口,才能完成后续的成功访问。

接下来,我们按照 acme.sh 提供的 docker部署文档 来操作。

docker container run \
  --name mynginx_1 \
  --volume "$PWD/html":/usr/share/nginx/html \
  --volume "$PWD/conf":/etc/nginx \
  --label=sh.acme.autoload.domain=razzh.cn \
  -d \
  nginx

文档中要求我们使用 docker 运行一个 nginx,并打上 label 标签,因为后续acme.sh在部署的时候需要用 label 去找到这个容器。

#1. 向阿里云申请API

这里简单的登录后,申请一个 AccessKey IDAccess Key Secret,妥善保存。

#2. 创建 acme.sh 容器

下面的命令将在当前目录创建一个 out 目录存放一些证书文件,但我们将不会直接使用这些文件。

docker run --rm  -itd \
    -v "$(pwd)/out":/acme.sh \
    --net=host \
    --name=acme.sh   \
    -v /var/run/docker.sock:/var/run/docker.sock \
    neilpang/acme.sh daemon

#3. 使用acme.sh申请证书

Ali_KeyAli_Secret 替换为你在本节第一步申请的 AccessKey IDAccess Key Secret,并将 example.com 替换为你的域名,执行,你会看到 checking 的字样,这时 CA 正在颁发证书,稍等两分钟,之后弹出 success 之类的提示词,那么说明,申请证书成功了!~

example.com 一级域名和它的二级域名 *.example.com,都可以使用同一证书。

docker  exec \
    -e Ali_Key="你的Key" \
    -e Ali_Secret="你的Secret"  \
    acme.sh --issue -d example.com -d "*.example.com" --dns dns_ali --server letsencrypt

#4. 使用acme.sh自动部署证书

注意,sh.acme.autoload.domain的值需要与你运行的 nginx 容器 label 值一致,并把文件路径域名替换成自己的。

docker  exec \
    -e DEPLOY_DOCKER_CONTAINER_LABEL=sh.acme.autoload.domain=razzh.cn  \
    -e DEPLOY_DOCKER_CONTAINER_KEY_FILE=/etc/nginx/certs/razzh.cn/key.pem   \
    -e DEPLOY_DOCKER_CONTAINER_CERT_FILE="/etc/nginx/certs/razzh.cn/cert.pem"  \
    -e DEPLOY_DOCKER_CONTAINER_CA_FILE="/etc/nginx/certs/razzh.cn/ca.pem"   \
    -e DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE="/etc/nginx/certs/razzh.cn/full.pem"  \
    -e DEPLOY_DOCKER_CONTAINER_RELOAD_CMD="service nginx force-reload"   \
    acme.sh --deploy -d razzh.cn  --deploy-hook docker

#测试

打开你的网站就可以看到

image

证书只有3个月有效期,我们在第四步已经做了自动续期的操作,在证书快到期的时候 acme.sh 会自动续期。

image

#Nginx 配置

SSL 证书已经部署完成,我们还需要配置 Nginx 来监听80和443接口,高亮的行必须跟 dockernginx 中创建数据卷(映射)时的路径一致,网站也要替换成自己的。

#/etc/conf/conf.d/razzh.cn.conf 
server {
    listen       80;
    server_name  razzh.cn;
 
    #80跳转到443
    rewrite ^(.*)$ https://${server_name}$1 permanent;
 
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}
 
server {
    listen 443 ssl http2;
    server_name  razzh.cn;
 
    ssl_certificate          /etc/nginx/certs/razzh.cn/full.pem;
    ssl_certificate_key      /etc/nginx/certs/razzh.cn/key.pem;
 
    ssl_session_timeout  5m;
 
    #开启HSTS
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
 
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;
    #适时移除TLSv1.2
    ssl_protocols TLSv1.3 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
 
    location / {
        root   /usr/share/nginx/html/blog/out;
        index  index.html index.htm;
    }
 
}

保存好配置后,我们执行命令重启一下 docker 中的 nginx 即可

docker container restart mynginx_1

#Github Actions 部署

要使用工作流,我们需要在项目跟目录下创建一个 .github/workflows 的目录并添加 deploy.yml 的文件,文件名可以随便起。

name: Deploy
 
on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main
 
jobs:
  build:
    # 运行在ubuntu上
    runs-on: ubuntu-latest
 
    # 任务流步骤
    steps:
      - name: 拉取代码
        uses: actions/checkout@v4
 
      - name: 安装NodeJS
        uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm install -g pnpm@10
      - run: pnpm install
      - run: pnpm build
 
      - name: 部署博客
        uses: appleboy/scp-action@master
        with:
          host: ${{ secrets.REMOTE_HOST }}
          username: ${{ secrets.REMOTE_USER }}
          password: ${{ secrets.REMOTE_PASS }}
          port: 22
          # 本地打包后的目录
          source: './out/'
          # 服务器存放dist的目录
          target: ${{ secrets.REMOTE_TARGET }}

为了安全性考虑,服务器的信息不能对外暴露,所以我们需要设置 secrets 变量,secrets 变量可在 Github 中的 Settings -> Secrets and variables -> actions 中配置。

代码被 push 到 github 上时就会触发工作流执行这个脚本。

image

#参考

全员docker化!使用docker中的acme.sh为docker中的Nginx添加SSL证书
Github Actions 文档

浙ICP备2024129591号-1
春秋(Live) - 张敬轩
--:-- / --:--
  1. 1春秋(Live)张敬轩
  2. 2不吐不快(live)张敬轩
  3. 3男孩最痛(live)张敬轩
  4. 4粤语残片(live)陈奕迅
  5. 5几分之几(live)卢广仲
  6. 6地球很危险古巨基
  7. 7樱花树下(live)张敬轩

春秋 (Live) - 张敬轩 (Hins Cheung)

词:林夕

曲:Edmond Tsang

那夜谁将酒喝掉

因此我讲得多了

然后你摇着我手拒绝我

动人像友情深了

我没权终止见面

只因你友善依然

仍用接近甜蜜那种字眼通电

没人应该 怨地怨天

得到这结局

难道怪罪神没有更伪善的祝福

我没有为你伤春悲秋不配有憾事

你没有共我踏过万里

不够剧情延续故事

头发未染霜 着凉亦错在我幼稚

应快活像个天使

有没有运气再扮弱者 玩失意

有没有道理为你落发

必须得到世人同意

心灰得极可耻 心伤得无新意

那一线眼泪 欠大志

爱若能堪称伟大 再难挨照样开怀

如令你发现为你而活到失败

令人不安 我品性坏

我没有为你伤春悲秋不配有憾事

你没有共我踏过万里

不够剧情延续故事

头发未染霜 着凉亦错在我幼稚

应快活像个天使

有没有运气再扮弱者玩失意

有没有道理为你落发

必须得到世人同意

心灰得极可耻 心伤得无新意

那一线眼泪 欠大志 太没意思

若自觉这叫痛苦未免过份容易

我没有被你改写一生怎配有心事

我没有被你害过恨过

写成情史 变废纸

春秋只转载要事

如果爱你欠意义

这眼泪 无从安置

我没有运气放大自私的失意

更没有道理在这日

你得到真爱制造恨意

想心酸 还可以 想心底 留根刺

至少要见面上万次