于是 —— Go 真香!迁移到了 Hugo。和 Hexo 一样作为一个静态网站生成器,集成 Github Pages 几乎是标配了,但是 GH 近期在大陆似乎不太如意,眼看着就差彻底断联了。所以还是更想放在自己的香港 VPS 上。作为踩坑记录,这篇文章出现了。

上传文件到 VPS

因为 hugo 生成本身非常容易,就一行命令的事,所以我们先来解决主要矛盾,那就是怎么把生成的文件放到 VPS 上。

rsync

当然,你大可以配一下 Hook,GH 生成完毕后打包传到 Release 或其他什么鬼地方,通知服务器,然后服务器再去拉取回来解压。显然,这不是一个「优雅」的方案。

我希望这一步尽可能地简单,简单到无序通知 VPS 进行额外操作,GH 可以单方面部署完成,这样就少了许多维护成本与不稳定因素。既然是文件传输,自然想到 FTP SFTP/SCP。这两个其实都行啦,不过这里都不用 😂,而且另一个更加适合此场景的东西——rsync。这是一个文件同步服务,可以进行差异比较只传输必要部分,和其他一堆现代化的特性,有兴趣自己查查看吧

标准的服务器系统应该预置了 rsync(不要告诉我你使用 windows),这东西用起来和 scp 很像——都是借用 ssh 进行传输,也使用系统账户进行认证。一条命令轻松实现需求

  • -a 表示递归同步,并且同步元数据
  • -v 打印一些信息
  • --delete 删除目标文件夹存在但本地不存在的玩意,不加这个参数就是增量同步。你一定不希望删掉某个不可描述的东西后实际上文件还在那吧 😄
rsync -av --delete source/ username@host:destination

(才怪)难道你的服务器不要身份验证了?

你可以直接把 VPS root 的用户名密码,或者密钥拿过来使,又不是不能用。但是我 觉得 肯定这不是个好主意。新建个系统用户?然后 balabala...

关于 rsync 的中文使用总结可以看看阮一峰的博客

其实除了走 ssh 协议,rsync 还有自己的协议,采用的也是独立的用户系统。这种模式需要服务器开一个守护进程,并且做一丢丢配置。

rsync 服务端守护进程

我的系统的 Ubuntu 20 LTS,Cent OS 死忠粉自己转换命令

系统预装了 rsync,先把示例配置文件拷贝一份到标准目录:

sudo cp /usr/share/doc/rsync/examples/rsyncd.conf /etc   

然后编辑一下,全局参数没怎么改,只是把 log 取消注释了好记录日志。重点是下面的模块配置,这里只列出我改动的部分:

[cheblog] # 模块名,后面传输文件的时候用到
        comment = chenhe blog web root # 注释
        path = /www/wwwroot/xxxxx # 模块的根路径
        read only = no # 取消只读
        uid = 1002 # 进程使用的uid根据情况填写,0是root,我用的是www
        gid = 1002 # 进程使用的gid根据情况填写,0是root,我用的是www
        auth users = myblog # 允许的用户名(与系统用户无关)
        secrets file = /etc/rsyncd.secrets # 用户数据库(我们一会创建)

然后在上面 secrets file 指定地方创建一个文件,里面写上用户名和密码,一行一个,用英文冒号隔开,注意用户名得和 auth users 一样,否则将无法连接此模块。比如这样:

myblog:123123

⚠️ 必须设置用户数据文件权限为只有所属用户可读写,所属用户必须和启用 rsync 的用户一致 。默认是 root 启动的,也是 root 创建的,所以我们修改一下权限就行了:

sudo chmod 600 /etc/rsyncd.secrets

最后手动启动一下:

sudo rsync --daemon

ps -aux | grep rsync # 确认启动成功

客户端设置

其实客户端已经可以直接使用了:

rsync -av --delete source/ [username]@[host]::[moduleName]

但是这样需要我们手动输入密码,不适合自动化执行。可以创建一个文件,里面写上密码,不要写用户名。同样,这个文件的权限也必须是只有执行 rsync 的用户可以读写。

然后执行:

rsync -av --delete source/ [username]@[host]::[moduleName] --password-file=[密码文件]

大功告成!

Github Actions 编写

这个就非常简单了,捋一下思路:

  1. 克隆博客源码
  2. 安装 hugo
  3. 生成网站
  4. 同步 vps

前两步已经有了非常完善的轮子,生成只要执行一下hugo就行,稍微动手写一下最后一步:

- name: Deploy to VPS
  env:
    RSYNC_PWD: ${{ secrets.RSYNC_PASSWORD }}
  run: |
    echo $RSYNC_PWD > rsync.pwd
    sudo chmod 600 rsync.pwd
    rsync -av --delete public/ username@[ip]::module --password-file=rsync.pwd

唯一注意的就是,为了安全(很多朋友喜欢把博客源码仓库一并公开),上传用的密钥万万不可硬编码到 actions 文件里,也不应该通过命令行直接传递,因为后者可能会暴露在 log 中。

最佳实践是填写到仓库设置中专用的 secrtes 区域,然后通过环境变量从上下文中注入,最后使用环境变量传递。

下面附上完整的 actions 配置文件:

name: Deploy

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

  workflow_dispatch:

## A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
      - uses: actions/checkout@v2
      
      - name: Setup Hugo
        uses: peaceiris/actions-hugo@v2

      - name: Build
        run: hugo --minify

      - name: Deploy to VPS
        env:
          RSYNC_PWD: ${{ secrets.RSYNC_PASSWORD }}
        run: |
          echo $RSYNC_PWD > rsync.pwd
          sudo chmod 600 rsync.pwd
          rsync -av --delete public/ [username]@[ip]::[module] --password-file=rsync.pwd

现在我们更新文章后只要一句 git push,后面的就不用操心啦。

Last modification:August 16, 2021