本文主要记录我的博客从 Wordpress 到 Hexo 的过程。

国内访问(阿里云)

我选择了阿里云服务器作为我博客的国内访问主机。当然在国内服务器搭建网站需要备案

具体方案在阿里云上搭建一个 Git 服务器,之后利用 Nginx 进行静态 HTML 文件的反向代理,以实现博客内容的展示。

Git服务器搭建

本文选择 Hexo 作为博客框架,Hexo 是一个基于 Node.js 的静态博客生成器,它能够将 Markdown 格式的文本转换成静态的 HTML 页面,而我在服务器上搭建 Git 仓库,主要是为了创建一个版本控制系统,用于管理我的 Hexo 博客代码和内容。

  1. 创建 git 用户
1
adduser git
  1. 给 git 用户添加文件权限
1
vim /etc/sudoers

找到User privilege specification部分,添加如下内容:

1
git    ALL=(ALL:ALL) ALL
  1. 切换到 git 用户
1
su git
  1. 安装 git
1
2
sudo apt-get update
sudo apt-get install git-core
  1. 创建仓库
1
2
3
4
5
6
7
cd 
sudo mkdir repos
sudo chown -R $USER:$USER /home/git/repos
sudo chmod -R 755 /home/git/repos

cd repos
git init --bare hexoBlog.git

配置 Nginx

  1. 安装 Nginx
1
sudo apt-get install nginx -y
  1. 创建 repos\hexoBlog目录,用于Nginx托管,修改目录所有权和权限
1
2
3
4
cd /home/git/repos
sudo mkdir hexBlog
sudo chown -R $USER:$USER /home/git/repos/hexBlog
sudo chmod -R 755 /home/git/repos/hexBlog
  1. 修改 nginx 配置

/etc/nginx/sites-available/ 下添加需要代理的网站的配置文件。例如

1
vim /etc/nginx/sites-available/infinite-zh.com

具体配置如下

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
server {
listen 443 ssl;
server_name infinite-zh.com www.infinite-zh.com;

ssl_certificate /etc/ssl/certs/infinite-zh.com.pem;
#证书私钥文件
ssl_certificate_key /etc/ssl/private/infinite-zh.com.key;

ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;

ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1.2 TLSv1.3;

ssl_prefer_server_ciphers on;

root /home/git/repos/hexoBlog;
index index.html index.htm index.nginx-debian.html;

location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
}

# Ensure root access works as expected
location = / {
try_files /index.html =404;
}
}

server {
listen 80;
server_name infinite-zh.com www.infinite-zh.com;
return 301 https://$host$request_uri;
}

启用该配置文件

1
sudo ln -s /etc/nginx/sites-available/infinite-zh.com /etc/nginx/sites-enabled/
  1. 重启Nginx服务,使得改动生效
1
sudo service nginx restart

创建 Git 钩子

  1. 在之前创建的hexoBlog.git裸仓库下有一个hooks文件夹,在其中创建一个名为post-receive的钩子文件:

    命令如下:

    1
    vim /home/repos/hexBlog.git/hooks/post-receive

    在其中写入如下内容:

    1
    2
    3
    #!/bin/bash

    git --work-tree=/var/www/hexo --git-dir=/var/repo/hexo_static.git checkout -f

    保存后退出

  2. 让该文件变为可执行文件

    命令如下:

    1
    chmod +x /home/repos/hexBlog.git/hooks/post-receive

配置 Https 访问

可以从阿里云的 数字证书管理服务(原SSL证书) 中获取免费证书,可以免费买20个,每一个可以用3个月,三个月得去换一下。

阿里云购买的服务器可以通过官网的云服务器部署进行自动部署,具体操作指南可以参考 部署SSL证书至阿里云轻量应用服务器或云服务器ECS

cas_deploy

当然如果服务器不是阿里云是别的厂商的,则可以手动进行上传,具体文档参考 安装证书到服务器_数字证书管理服务

OSS 配置

为了更好的访问博客的图片等资源,采用阿里云oss来进行存储。因为我需要将原来的一些图片批量上传,故设置了一个脚本。

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package main

import (
"fmt"
"log"
"os"
"path/filepath"
"strings"

"github.com/aliyun/aliyun-oss-go-sdk/oss"
)

// 阿里云OSS配置
const (
endpoint = // 例如 "https://oss-cn-hangzhou.aliyuncs.com"
accessKeyID =
accessKeySecret =
bucketName =
)

// 上传单个文件到阿里云OSS
func uploadFile(client *oss.Client, bucketName, localFilePath, remoteFilePath string) error {
bucket, err := client.Bucket(bucketName)
if err != nil {
return fmt.Errorf("获取bucket失败: %v", err)
}

err = bucket.PutObjectFromFile(remoteFilePath, localFilePath)
if err != nil {
return fmt.Errorf("上传文件失败: %v", err)
}

fmt.Printf("上传成功: %s -> %s\n", localFilePath, remoteFilePath)
return nil
}

// 递归遍历文件夹并上传图片
func uploadDirectory(client *oss.Client, bucketName, localDir, remoteDir string) error {
err := filepath.Walk(localDir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
// 忽略以.开头的文件夹和readme.md文件
if info.IsDir() && strings.HasPrefix(info.Name(), ".") {
return filepath.SkipDir
}

if !info.IsDir() && (strings.ToLower(info.Name()) == "readme.md") {
return nil
}

if !info.IsDir() {
remotePath := filepath.Join(remoteDir, strings.TrimPrefix(path, localDir))
remotePath = strings.ReplaceAll(remotePath, "\\", "/")
return uploadFile(client, bucketName, path, remotePath)
}
return nil
})
return err
}

func main() {
client, err := oss.New(endpoint, accessKeyID, accessKeySecret)
if err != nil {
log.Fatalf("创建OSS客户端失败: %v", err)
}
fmt.Print("创建OSS客户端成功\n")
localDir := "" // 本地图片文件夹的根路径
remoteDir := "" // OSS上对应的远程目录

err = uploadDirectory(client, bucketName, localDir, remoteDir)
if err != nil {
log.Fatalf("上传文件夹失败: %v", err)
}
}

CDN 配置

CDN 主要是跟着阿里云官方指示配置域名等信息,可以选择之前备案的域名的子域名。

然后可以在 数字证书管理服务(原SSL证书) 配置 CDN 的Https 访问。

然后就可以通过子域名的方式访问 OSS 的资源,当首次访问资源的时候会发现,会发现 Response header 的X-CacheMISS TCP_MISS dirn:-2:-2,表示没有命中缓存,需要直接从原始服务器获取数据

cdn_test

国外访问(GitHub Page)

创建所需仓库

  1. 创建 hexo-source 仓库用来存放 Hexo 项目
  2. 创建 your.github.io 仓库用来存放静态博客页面
  3. 创建 blog-images 仓库用来存储博客图片等资源

将源代码文件和前段页面分开,还可以设置源代码仓库为private。

生成部署密钥

1
ssh-keygen -f blog-deploy-key

当前目录下会有 blog-deploy-keyblog-deploy-key.pub 两个文件。

配置部署密钥

复制 blog-deploy-key 文件内容,在 blog 仓库 Settings -> Secrets and variables -> Actions -> New repository secret 页面上添加。

  1. Name 输入框填写 DEPLOY_KEY
  2. Value 输入框填写 blog-deploy-key 文件内容。

复制 blog-deploy-key.pub 文件内容,在 your.github.io 仓库 Settings -> Deploy keys -> Add deploy key 页面上添加。

  1. Title 输入框填写 HEXO_DEPLOY_PUB
  2. Key 输入框填写 blog-deploy-key.pub 文件内容。
  3. 勾选 Allow write access 选项。

此外还有 Github 的 ACCESS_TOKEN,位于头像 -> Settings -> Developer Settings -> Personal access tokens -> Tokens。

编写 Github Actions

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
name: DEPLOY

on:
push:
branches:
- main

env:
GIT_USER: xxxx # 填写 github user
GIT_EMAIL: xxxxx # 填写 github email
DEPLOY_REPO: xxxxxx/xxxxxxxx.github.io # 填写存放静态博客页面的仓库
DEPLOY_BRANCH: gh-pages # 填写部署分支

jobs:
build:
name: Build on node ${{ matrix.node_version }} and ${{ matrix.os }}
runs-on: ubuntu-latest
strategy:
matrix:
os: [ubuntu-latest]
node_version: [20.x]

steps:
- name: Checkout
uses: actions/checkout@v4
with:
token: ${{ secrets.ACCESS_TOKEN }}
submodules: true

- name: Checkout deploy repo
uses: actions/checkout@v4
with:
repository: ${{ env.DEPLOY_REPO }}
ref: ${{ env.DEPLOY_BRANCH }}
path: .deploy_git

- name: Use Node.js ${{ matrix.node_version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node_version }}

- name: Configuration environment
env:
HEXO_DEPLOY_PRI: ${{secrets.DEPLOY_KEY}}
run: |
sudo timedatectl set-timezone "Asia/Shanghai"
mkdir -p ~/.ssh/
echo "$HEXO_DEPLOY_PRI" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan github.com >> ~/.ssh/known_hosts
git config --global user.name $GIT_USER
git config --global user.email $GIT_EMAIL
- name: Install dependencies
run: |
npm ci
- name: Deploy Hexo
run: |
npm run deploy

该 workflow 会在提交代码的时候,自动进行运行,效果如下。

deploy

如果是第一次运行可能会出现,gh-pages 分支不存在的问题,可以手动添加一下分支来修复问题。

设置图片资源的 CDN

jsDelivr - A free, fast, and reliable CDN for JS and open source

使用 jsDelivr 作为 Github 仓库的 CDN,加速图片资源等的访问。

参考 qxdn 的方案,设置 Github Actions ,设置上传 tag 时自动发布release版本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
name: release

permissions:
contents: write

on:
push:
tags:
- "v*.*.*"

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Release
uses: softprops/action-gh-release@v1
with:
draft: true

Reference

Hexo部署至服务器(Ubuntu 20.04) | 花猪のBlog (cnhuazhu.top)

在 GitHub Pages 上部署 Hexo | Hexo

利用 Github Actions 自动部署 Hexo 博客 | Sanonz