返回
Featured image of post 搭建基于Hugo的个人博客,并设置自动构建工具链

搭建基于Hugo的个人博客,并设置自动构建工具链

引言

之前,我一直在Github Pages上学习和搭建个人网站,它免费而且简单,但在国内访问速度非常慢。

最近偶然有台国内服务器,借此我决定自己搭建一个博客网站,换掉原来的Github Pages,在经历多方搜索和尝试后,我选择了静态网页生成器Hugo

实现效果

  • 基于Markdown进行写作,通过Git上传到远程仓库,服务器收到更新消息自动更新网站内容。
  • 通过https://example.com访问网站。

先决条件

在开始前,准备好以下云资源:

  • 云服务器,系统环境为Ubuntu,且有公网IP,如11.4.5.14,接下来称为<Your-Server-IP>
    • 下文中提到的对外端口80 443 10086端口需要在服务器控制台设置允许外部访问
  • 域名,并可以访问其 DNS 管理控制台,如example.com

要在国内服务器上部署站点,需要进行备案,否则无法通过域名访问;

如果服务器和DNS服务商都在海外,则可以不用备案。

部署流程

前言

在开始之前,先了解一下涉及到的几个工具:

  • Hugo:一个快速的静态网页生成器,用于将Markdown文件转换为静态网页。
  • Git:一个分布式版本控制系统,用于管理网站的源代码。
  • Nginx:一个高性能的HTTP和反向代理服务器,用于部署网站。
  • Webhook:一个用于监听HTTP请求的工具,用于接收GithubWebhook请求,触发网站更新。
  • Go:一个开源的编程语言,用于编写Webhook服务。
  • acme.sh:一个用于申请免费SSL证书的工具。

本文环境:

  • 服务器:Ubuntu 22.04 LTS (阿里云)
  • 本地环境:Windows 11 Pro 24H2
  • Hugo版本:v0.136.1 extended
  • Nginx版本:1.24.0
  • acme.sh版本:3.1.0
  • Go版本:1.22.2

登录服务器

使用SSH登录到服务器,可以直接使用PowerShell(Windows),也可以使用PuTTY等工具。

配置SSH密钥

在服务器生成SSH密钥对:

如果是第一次生成,一路回车默认即可

# 生成SSH密钥对,-C参数为注释,可填写自己的邮箱
ssh-keygen -t rsa -b 4096 -C "<your_email@mail.com>"

再将服务器公钥(默认~/.ssh/id_rsa.pub)的内容添加到Github的SSH Keys中。

准备Github仓库

在Github上创建一个新的仓库,如my-hugo-site,并将其克隆到服务器。

# 克隆仓库,需要修改为实际仓库地址
git clone git@github.com:<your_username>/my-hugo-site.git

配置Hugo

Hugo提供了多种安装方式,具体可参考官方文档

此处以v0.136.1为例,通过wget获取Hugo的二进制版本,并解压主程序到/usr/local/bin目录下。

# 下载hugo发布包
wget https://github.com/gohugoio/hugo/releases/download/v0.136.1/hugo_extended_0.136.1_linux-amd64.tar.gz
# 解压hugo发布包
tar -zxvf hugo_extended_0.136.1_linux-amd64.tar.gz
# 移动hugo主程序到/usr/local/bin目录
mv hugo /usr/local/bin
# 清理不需要的文件
rm hugo_extended_0.136.1_linux-amd64.tar.gz LICENSE README.md
# 验证安装
hugo version

进入刚才克隆的仓库目录,初始化Hugo站点,然后创建一个新的文章。

cd my-hugo-site
hugo new site .
hugo new posts/my-first-post.md

查看content/posts/my-first-post.md文件,该文件是一个Markdown文件,开头的+++之间是Front Matter,用于配置文章的元数据。

编辑Front Matter,将draft字段改为false,表示文章已经发布,并在后面编写文章内容,效果如下:

+++
date = '2024-10-18T09:29:58Z'
draft = false
title = 'My First Post'
+++

# Hello World!

This is my first post.

直接在本目录执行hugo命令,将Markdown文件转换为静态网页。

之后my-hugo-site/public目录下会生成一些文件,其中包括index.html文件,这是博客的网站首页。

部署Nginx

安装Nginx,并配置my-hugo-site/public目录为站点根目录。

# 安装Nginx
sudo apt update
sudo apt-get install nginx

编写一个Nginx配置文件/etc/nginx/sites-available/my-hugo-site,示例如下:

# 添加一个server块,用于访问博客网站
server {
    listen 80;
    listen 8080;
    server_name example.com <Your-Server-IP>; # 需要修改为实际域名和服务器IP

    location / {
        root /path/to/my-hugo-site/public; # 需要修改为实际网站根目录
        index index.html;
    }
}

启用站点配置文件,并重启Nginx服务。

sudo ln -s /etc/nginx/sites-available/my-hugo-site /etc/nginx/sites-enabled/
sudo systemctl restart nginx

现在访问http://<Your-Server-IP>,应该可以看到博客首页。

配置Webhook

在服务器上配置Webhook,监听Github目标仓库的push事件,触发git pull命令并进行自动构建,这样免去每次在更新仓库后手动在服务器执行构建的步骤。

先编写build.sh脚本,示例如下:

#!/bin/bash

# 日志文件路径,需要修改为实际路径
LOGFILE="/srv/ghpg/log.build.log"

echo "====== Build Started: $(date) ======" >> "$LOGFILE"

# 切换到博客目录,需要修改为实际路径
cd /path/to/my-hugo-site || {
  echo "!!!!! Error: Could not change directory !!!!!" >> "$LOGFILE"
  exit 1
}

echo "Pulling latest changes..." >> "$LOGFILE"
git pull origin main

if [ $? -ne 0 ]; then
  echo "!!!!! Error: Failed to pull latest changes !!!!!" >> "$LOGFILE"
  exit 1
fi

echo "Running Hugo to build site..." >> "$LOGFILE"
/usr/local/bin/hugo --minify

if [ $? -ne 0 ]; then
  echo "!!!!! Error: Hugo build failed !!!!!" >> "$LOGFILE"
  exit 1
fi

echo "✓✓✓✓✓ Build completed: $(date) ✓✓✓✓✓" >> "$LOGFILE"

此处使用go编写一个简单的Webhook服务,监听/webhook路径,接收POST请求。

# 安装go
sudo apt update
sudo apt-get install golang-go

编写webhook.go文件,示例如下:

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"
    "os/exec"
)

type Payload struct {
    Ref string `json:"ref"`
}

func handleWebhook(w http.ResponseWriter, r *http.Request) {
    // 监听的分支,需要修改为实际分支,默认为main
    var branch string = "refs/heads/main"

    // 构建脚本路径,需要修改为实际路径
    var build_sh = "/path/to/my-hugo-site/build.sh"

    var payload Payload
    json.NewDecoder(r.Body).Decode(&payload)

    if payload.Ref == branch {
        fmt.Fprintln(w, "Webhook received, processing...")

        go func() {
            log.Println("Starting build process...")
            cmd := exec.Command("/bin/bash", build_sh)
            err := cmd.Run()

            if err != nil {
                log.Printf("Build failed: %s\n", err.Error())
            } else {
                log.Println("Build completed successfully")
            }
        }()
    } else {
        fmt.Fprintln(w, "Not "+branch+" branch push, ignoring.")
    }
}

func main() {
    http.HandleFunc("/webhook", handleWebhook)

    // 监听10085端口,需要修改为实际端口
    log.Println("Starting server on :10085")
    http.ListenAndServe(":10085", nil)
}

编译webhook.go文件,生成可执行文件。

go build webhook.go -o webhook.x

将生成的webhook.x文件注册为系统服务,使其在服务器启动时自动运行。

编写/etc/systemd/system/webhook-my-hugo-site.service文件,示例如下:

[Unit]
Description=Webhook Service
After=network.target

[Service]
ExecStart=/path/to/my-hugo-site/webhook.x # 需要修改为实际Webhook.x可执行文件路径
Restart=always
User=root
Environment=GOPATH=/usr/local/go
Environment=PATH=/usr/local/go/bin:/usr/bin:/bin

[Install]
WantedBy=multi-user.target

在启动前,需要修改刚才的Nginx配置文件/etc/nginx/sites-available/my-hugo-site,添加一个server块,用于接收Webhook请求。

server {
    listen 80;
    listen 8080;
    server_name example.com <Your-Server-IP>; # 需要修改为实际域名和服务器IP

    location / {
        root /path/to/my-hugo-site/public; # 需要修改为实际网站根目录
        index index.html;
    }
}

# 添加一个server块,用于接收Webhook请求
server {
    listen 10086; # 添加Webhook监听端口,按需修改
    server_name example.com <Your-Server-IP>; # 需要修改为实际域名和服务器IP
    location / {
        proxy_pass http://localhost:10085; # 需要修改为实际Webhook监听端口
    }
}

启用服务并启动:

# 重载Daemon
sudo systemctl daemon-reload
# 启动服务
sudo systemctl enable webhook-my-hugo-site
sudo systemctl start webhook-my-hugo-site
# 查看服务状态
sudo systemctl status webhook-my-hugo-site

然后,在Github的my-hugo-site仓库的Settings中,找到Webhooks,添加一个新的Webhook,填写服务器的Webhook地址,如http://<Your-Server-IP>:10086/webhook,并选择application/json格式。

现在,每次在Github上更新仓库后,服务器都会自动构建网站。

配置DNS和TLS

为了实现通过域名访问网站,需要在域名的DNS管理控制台中添加一条A记录,将域名解析到服务器的公网IP。

如果你的服务器基于阿里云,可以参考阿里云DNS解析

为了实现HTTPS访问,可以使用acme.sh工具申请ZeroSSL免费SSL证书。

# 安装acme.sh
curl https://get.acme.sh | sh
source ~/.bashrc
# 注册ZeroSSL申请邮箱
acme.sh --register-account -m <your_email@example.com>
# 申请并安装证书
sudo acme.sh --issue --standalone -d example.com -d www.example.com \
    --key-file /etc/nginx/ssl/example.com.key \
    --fullchain-file /etc/nginx/ssl/example.com.crt

编辑/etc/nginx/sites-available/my-hugo-site文件,添加ssl_certificatessl_certificate_key字段。

server {
    listen 80;
    listen 8080;
    server_name example.com <Your-Server-IP>; # 需要修改为实际域名和服务器IP

    location / {
        root /path/to/my-hugo-site/public; # 需要修改为实际网站根目录
        index index.html;
    }

    listen 443 ssl; # 添加SSL监听端口
    ssl_certificate /etc/nginx/ssl/example.com.crt; # 需要修改为实际证书路径
    ssl_certificate_key /etc/nginx/ssl/example.com.key; # 需要修改为实际私钥路径
}

server {
    listen 10086; # 添加Webhook监听端口,按需修改
    server_name example.com <Your-Server-IP>; # 需要修改为实际域名和服务器IP
    location / {
        proxy_pass http://localhost:10085; # 需要修改为实际Webhook监听端口
    }
}

重启Nginx服务sudo systemctl restart nginx

现在,通过https://example.com访问网站,应该可以看到已经使用HTTPS加密。

若访问顺利,代表证书有效,可以继续配置Nginx,添加HTTPHTTPS的重定向。

编辑/etc/nginx/sites-available/my-hugo-site文件,添加一个server块,用于重定向。

server {
    # 此处移除原先的80、8080端口监听

    server_name example.com <Your-Server-IP>; # 需要修改为实际域名和服务器IP

    location / {
        root /path/to/my-hugo-site/public; # 需要修改为实际网站根目录
        index index.html;
    }

    listen 443 ssl; # 添加SSL监听端口
    ssl_certificate /etc/nginx/ssl/example.com.crt; # 需要修改为实际证书路径
    ssl_certificate_key /etc/nginx/ssl/example.com.key; # 需要修改为实际私钥路径
}

# 添加一个server块,用于重定向
server {
    listen 80;
    server_name example.com <Your-Server-IP>; # 需要修改为实际域名和服务器IP
    return 301 https://$host$request_uri;
}

server {
    listen 10086; # 添加Webhook监听端口,按需修改
    server_name example.com <Your-Server-IP>; # 需要修改为实际域名和服务器IP
    location / {
        proxy_pass http://localhost:10085; # 需要修改为实际Webhook监听端口
    }
}

重启Nginx服务sudo systemctl restart nginx

现在,通过http://example.com访问网站,也会自动重定向到https://example.com

后续写作

在Windows上安装Hugo的方法如下,打开PowerShell,执行以下命令:

# 安装Scoop
iwr -useb get.scoop.sh | iex
# 安装Hugo
scoop install hugo-extended
# 验证安装
hugo version

在一切配置完成后,我们可以在自己的环境上也克隆my-hugo-site仓库,安装Hugo,用同样的方式新建文章然后通过Markdown写作,之后用Git提交到Github。

在编写中,可以通过hugo server命令在本地环境预览网站效果。

结语

至此,我们已经完成了基于Hugo的个人博客的搭建,实现了:

基于Markdown在本地写作,通过Git上传到远程仓库;远程仓库更新时触发Webhook自动更新网站内容,通过Nginx作为Web服务器,通过域名访问网站;通过acme.sh申请ZeroSSl免费SSL证书,实现HTTPS访问。

参考