Featured image of post Hugo 博客 Github Page /私有化 部署指南

Hugo 博客 Github Page /私有化 部署指南

Hugo CI/CD 自动化部署、国际化配置。

Hugo 是一个用 Go 编写的开源静态网站生成器,一般只需几秒钟就能生成一个网站,被称为“世界上最快的网站构建框架”。用户可以使用 markdown 语法编写博客内容,结合 Github Page 可以无需服务器部署自己的博客,同时也支持采用 Nginx 、Apache 等 HTTP 服务器的私有化部署方式。本文结合本博客的部署过程,详细叙述以上两种部署方式,以及 CI/CD 自动化部署、国际化配置等过程。

英文站点 - Github Page 访问地址:

zoyao.github.io

中文站点 - Nginx 私有化部署访问地址:

zoyao.top

Hugo 安装

hugo 本地安装,建议首次使用时在本地安装好 hugo 客户端,方便调试。后续使用过程中,可脱离 hugo 客户端使用,在本地编辑好 markdown 文件上传至 github,即可触发自动化部署,详见 Github Pages 自动化部署与私有化自动化部署章节

  • hugo 安装

    安装过程 - 以 windows winget 为例,安装 Extended 版本

    1
    2
    3
    4
    5
    
    //安装
    winget install Hugo.Hugo.Extended
    
    //卸载
    winget uninstall --name "Hugo (Extended)"
    

    其它系统及安装方式,可查看 官方文档

  • 新建站点

    执行以下命令,即可在当前文件夹下新建站点 mysite

    1
    
    hugo new site mysite
    
  • 预览

    执行成功,可以在本地 1313 端口下,预览网站

    1
    
    hugo server
    
  • 打包

    打包完成,在 public 目录下生成静态网站

    1
    
    hugo
    
  • 环境配置

    hugo 在 config 文件夹下对环境配置文件进行管理(默认不存在该目录,需要用户自己新建),目录结构如下所示

    1
    2
    3
    4
    5
    6
    7
    
    mysite
    ├── config.toml
    └── config
        ├── development
        │   └── config.toml
        └── production
            └── config.toml
    

    如上,新建了 development 与 production 环境配置,可以通过 --environment development 指定配置文件,若无指定,则

    hugo server 预览命令,默认使用 development 环境

    hugo 打包命令,默认使用 production 环境

    指定配置文件的启动命令:

    1
    2
    3
    4
    5
    
    //预览
    hugo server --environment development
    
    //打包
    hugo --environment development
    

主题配置

得益于 hugo 丰富的主题库,我们可以简单快捷地获取到许多个性化 hugo 主题,可以预览 官网主题库 挑选自己喜欢的主题

以下,将采用 hugo-theme-stack 主题为例进行说明

  • git 初始化

    1
    2
    3
    4
    5
    
    //进入所在目录
    cd mysite
    
    //git初始化
    git init
    
  • 添加子模块,方便后续主题更新

    1
    2
    
    //在 mysite/themes 目录下,拉取 hugo-theme-stack 并创建名为 stack 的主题
    git submodule add https://github.com/CaiJimmy/hugo-theme-stack.git themes/stack
    
  • 配置主题

    打开刚刚下载的主题文件,将 themes/stack/exampleSite 目录下的配置文件复制到根目录,覆盖原先的配置文件,编辑配置文件,将 theme 字段配置为上述步骤创建的主题名称,即 stack

    hugo-theme-stack 部分配置说明

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    
    //访问url,页面跳转时用到
    baseurl: https://example.com/
    
    //主题名称,在此处应为 stack
    theme: hugo-theme-stack
    
    //网站名称
    title: Example Site
    
    //网站说明
    copyright: Example Person
    

    配置完成重启即可看到主题改动

    hugo-theme-stack 其他配置可至 官网查询

Github Pages 自动化部署 CI/CD

GitHub Pages 是 GitHub 提供的一个网页寄存服务,可以用于存放静态网页,包括博客、项目文档等,hugo 可以快速构建静态网站,天然支持使用 GitHub Pages 部署

  • GitHub Pages 配置

    使用 Github Pages 需要创建一个以 Github 用户名开头,.github.io 结尾的 repository,并且必须为公开仓库。具体流程为:

    1. New repository

    2. Repository name: xxxx(用户名).github.io

    3. Public

    4. Create repository

    创建完成,打开仓库的 Settings 配置,修改 Default branch 可以修改默认展示的分支。

    当前配置为main分支

    上传静态页面 index.html 文件至仓库指定分支

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Hello World</title>
    </head>
    <body>
        <h1>Hello World</h1>
    </body>
    </html>
    

    打开 https://用户名.github.io/ 即可看到刚刚上传的静态页面。

  • 关联 Hugo 仓库自动化部署

    在这里,我们采用两个不同的 Github 仓库

    • blog 仓库 – 用来存放原始的博客文件,主要格式为 Mrakdown

    • GitHub Pages 仓库 – 即上一个步骤创建的仓库,用来存放打包后的静态网站

    具体流程如下:

    1. 打通两个仓库的权限

      • 打开 Github 全局配置(非仓库配置)Settings / Settings / Personal access tokens / Fine-grained tokens / Generate new token

        alt text

      • Token name 可随意填写

      • Expiration 过期时间建议选择 No expiration,避免过期后无法使用

      • Repository access 安全考虑建议选择 Only select repositories,只选择刚刚创建的 GitHub Pages 仓库仓库

        alt text

      • Permissions 权限配置将 Contents 修改为 Read and write

        alt text

      • 保存并复制好自动生成的 token

      • 在 blog 仓库增加 token 配置,路径为:blog 仓库 / Settings / Security / Secrets and variables / Actions / Repository secrets / New repository secret,Name 命名为 PERSONAL_TOKEN,并将上述步骤复制的 token 粘贴到 Secret 中保存

        alt text

    2. hugo 自动打包、发布

      在 blog 仓库的 .github/workflows 目录下,创建deploy.yml,配置内容如下

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      
      name: deploy
      
      on:
          # git push时执行 action
          push:
          workflow_dispatch:
          schedule:
              # Runs everyday at 8:00 AM
              - cron: "0 0 * * *"
      
      jobs:
          build:
              runs-on: ubuntu-latest
              steps:
                  - name: Checkout
                  uses: actions/checkout@v2
                  with:
                      submodules: true
                      fetch-depth: 0
      
                  - name: Setup Hugo
                  uses: peaceiris/actions-hugo@v2
                  with:
                      hugo-version: "latest"
      
                  # hugo 打包
                  - name: Build Web
                  run: hugo
      
                  # 打包完成推送至指定仓库
                  - name: Deploy Web
                  uses: peaceiris/actions-gh-pages@v3
                  with:
                      PERSONAL_TOKEN: ${{ secrets.PERSONAL_TOKEN }}
                      EXTERNAL_REPOSITORY: zoyao/zoyao.github.io
                      PUBLISH_BRANCH: master
                      PUBLISH_DIR: ./public
                      commit_message: ${{ github.event.head_commit.message }}
      

      配置完成之后,当执行 git push 之后,即触发自动化部署,可在 blog 仓库的 action 中,看到相关流程

      alt text

私有化自动化部署 CI/CD

采用 GitHub Pages 可以很方便的完成自动化部署,但是 GitHub 域名在部分网络环境下访问较慢,如果有这部分需求的童鞋,可以采用私有化部署,部署到自己的服务器上。

  • 私有化部署

    这里采用 Nginx 进行私有化部署

    1. 将打包后的博客静态文件复制到私有服务器,/app/blog/目录下

    2. 配置 Nginx,在 Nginx 的 ./nginx/conf.d目录下,新建配置文件,这里命名为blog-8888.conf

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      
      server {
          # 监听8888端口
          listen 8888;
          # 这里先采用IP访问,后续 HTTPS 配置再修改为域名
          server_name 服务器公网IP;
          # server_name www.zoyao.top;
      
          # 指定静态资源位置
          location / {
              root   /app/blog;
              index  index.html index.htm;
          }
      }
      
    3. 更新 Nginx 配置之后,访问 http://服务器公网IP:8888/ 即可看到博客首页

  • 自动化部署

    使用自动化部署,需要先配置 ssh key 登录,建议先新建用户,做好权限隔离

    1. 使用 adduser 命令创建新用户,这里命名为 git,可自定义

      1
      
      sudo adduser git
      
    2. 目录授权,需要将 /app/blog 授权给上一步骤新建的用户,切换到git用户执行

      1
      
      sudo chmod -R 777 /app/blog
      
    3. 切换到 git 用户,创建 ssh key,并保存在 Github secret 中

      • 切换到 git 用户

        1
        
        su git
        
      • 在 /home/git 目录下创建新目录 .ssh 并授权

        1
        
        mkdir -p ~/.ssh && chmod 700 ~/.ssh
        
      • 执行 ssh-keygen 生成密钥对,建议使用 ed25519 比 rsa 更安全

        1
        
        ssh-keygen -t ed25519 -C "github-actions-deploy-key" -f ~/.ssh/github_actions
        
      • 复制公钥至 authorized_keys

        1
        
        sh -c 'cat ~/.ssh/github_actions.pub >> ~/.ssh/authorized_keys
        
      • 授权 authorized_keys

        1
        
        chmod 600 ~/.ssh/authorized_keys
        
      • 查看并复制私钥内容备用

        1
        
        cat ~/.ssh/github_actions
        
      • 本地使用 ssh 登录验证是否成功

      • 在 blog 仓库增加密钥配置,路径为:blog 仓库 / Settings / Security / Secrets and variables / Actions / Repository secrets / New repository secret,Name 命名为 SERVER_SSH_KEY,并将上述步骤复制的私钥粘贴到 Secret 中保存

        alt text

    4. Github 配置自动化部署

      在 blog 仓库的 .github/workflows 目录下,创建deploy.yml,配置内容如下,服务器IP修改为自己的私有化服务器

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      
      name: deploy
      
          on:
              push:
              workflow_dispatch:
              schedule:
                  # Runs everyday at 8:00 AM
                  - cron: "0 0 * * *"
      
          jobs:
              build:
                  runs-on: ubuntu-latest
                  steps:
                      - name: Checkout
                      uses: actions/checkout@v2
                      with:
                          submodules: true
                          fetch-depth: 0
      
                      - name: Setup Hugo
                      uses: peaceiris/actions-hugo@v2
                      with:
                          hugo-version: "latest"
      
                      - name: Build Web
                      run: hugo
      
                      - name: Deploy Web Self
                      uses: easingthemes/ssh-deploy@main
                      with:
                          SSH_PRIVATE_KEY: ${{ secrets.SERVER_SSH_KEY }}
                          REMOTE_HOST: 服务器IP
                          REMOTE_USER: git
                          SOURCE: ./public/
                          TARGET: /app/blog/hugo/
                          ARGS: -avz --delete --chown=git:git    
      

HTTPS 配置

这里我们使用阿里云的免费 ssl 证书进行 HTTPS 配置,但是由于免费证书有效期较短,需要安装 acme 进行自动续期,自动更新

  1. 申请阿里云的 api

    • 创建 acme 访问用户

      登录阿里云后台后,进入 权限与安全 / 权限与安全, 选择 身份管理 / 用户,创建新用户,勾选 使用永久 AccessKey 访问,确认后保存对应的 key 以及 secret 备用

      alt text

    • 配置权限

      点击添加权限,授予新用户以下权限:

      AliyunRAMFullAccess

  2. 配置 acme 自动更新

    • 安装 acme

      1
      
      curl https://get.acme.sh | sh -s email=xxxx@xxxx.com
      
    • 使用步骤1保存的 key 以及 secret ,配置好阿里云的系统参数

      1
      2
      
      export Ali_Key="key"
      export Ali_Secret="Secret"
      
    • 拉取证书

      1
      
      acme.sh --issue --dns dns_ali -d zoyao.top -d '*.zoyao.top' --dnssleep 300 --debug
      
    • 保存证书, 因本人使用 docker 部署的 nginx,拉取证书后,需要重启 nginx,所以增加了--reloadcmd "docker restart nginx"可根据实际需要删除或修改为自己的命令

      1
      
      acme.sh --install-cert -d zoyao.top --key-file       /app/nginx/ssl/zoyao.top/key.pem  --fullchain-file /app/nginx/ssl/zoyao.top/cert.pem --reloadcmd     "docker restart nginx"
      
    • 执行成功后,可在 /app/nginx/ssl/zoyao.top/ 目录下查看到证书

  3. nginx ssl 配置

    在 Nginx 的 ./nginx/conf.d目录下,新建配置文件,这里命名为common.conf

    在前边的私有化部署中,我们使用了8888端口作为博客的访问端口,在这里只需要将 ssl 443 端口转发至 8888 端口,并配置上 ssl 证书地址即可,配置文件如下:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    
    server {
        listen 443 ssl http2;
        listen [::]:443 ssl http2;
    
        # 配置博客域名
        server_name www.zoyao.top zoyao.top;
    
        # 上一个步骤保存的 ssl 证书地址,这里因为是 docker 部署,配置了映射后的地址
        ssl_certificate "/app/ssl/zoyao.top/cert.pem";
        ssl_certificate_key "/app/ssl/zoyao.top/key.pem";
        ssl_session_cache shared:SSL:1m;
        ssl_session_timeout  10m;
        ssl_ciphers HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers on;
    
        location / {
            # 请求转发至实际博客部署的端口
            proxy_pass  http://127.0.0.1:8888; # 转发规则
            proxy_set_header Host $proxy_host; # 修改转发请求头,让8080端口的应用可以受到真实的请求
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    
    }
    

    至此,HTTPS 部署完成,打开 https://www.zoyao.top 即可访问

i18n国际化

Hugo 本身提供的完整的国际化方案,可以在 hugo.yaml 中,定义不同的语言方案

在这里,我定义了中英文两种语言

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
languages:
    en:
        languageName: English
        title: zoyao’s Travel Diary
        weight: 1
        params:
            sidebar:
                subtitle: Let's bust our asses and meet again at the pinnacle of success.
    zh-cn:
        languageName: 中文
        title: zoyao的旅行日记
        weight: 2
        params:
            sidebar:
                subtitle: 顶峰相见

相对应的,在文章中,也需要不同的 markdown 来区分不同的语言

例如,本篇文章,采用index.zh-cn.md为中文

在相同目录下,可创建index.en.md为英文

可以通过DefaultContentLanguage配置网站默认语言

1
2
DefaultContentLanguage: zh-cn
languageCode: zh-cn

本网站针对不同的部署方式,采用了不同的默认语言,在 zoyao.top 中默认中文,在 zoyao.github.io 中默认英文,只需要在根目录下的 config 文件夹中定义好相应的配置

1
2
3
4
5
6
7
mysite
├── config.toml
└── config
    ├── development
    │   └── config.toml
    └── production
        └── config.toml

不同的配置文件采用不同的DefaultContentLanguage

同样的,在自动化部署时,可以指定不同的配置文件,即可完成对应语言环境的部署

1
2
- name: Build Web
    run: hugo --environment production