侧边栏壁纸
  • 累计撰写 24 篇文章
  • 累计创建 10 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

Halo博客搭建——强大易用的开源建站工具

Joe
Joe
2025-09-02 / 0 评论 / 0 点赞 / 51 阅读 / 0 字

前言

经过对比之后,最终还是选择了Halo,因为Halo更加符合我的操作习惯,用起来更加顺手。Halo更新至Halo 2后,根据官方的介绍,已经是一个建站工具,不单单是个简单的博客,本次已搭建博客教程为主,更多功能大家可以参考官方资料,自己去摸索。

本次搭建的是Halo 2,因为 Halo 2.0 的底层架构变动,无法兼容 1.x 的数据,导致无法平滑升级,所以需要进行数据迁移。为此,官方提供了从 Halo 1.5 / 1.6 版本迁移的插件。官方提供了迁移教程:点击打开。在进行迁移之前,有几点注意事项和要求,如果你目前无法满足,建议先暂缓迁移。

Halo简介

相关

Github项目地址:https://github.com/halo-dev/halo

官网地址:https://www.halo.run/

官方文档:https://docs.halo.run/

官方论坛:https://bbs.halo.run/

官方还提供在线体验:

Halo 2介绍

DEMO

img

img

特性

  • 代码开源——Halo 的项目代码开源在 GitHub 上且处于积极维护状态,截止目前已经发布了 109 个版本。你也可以在上面提交你的问题或者参与代码贡献。

  • 易于部署——推荐使用 Docker 的方式部署 Halo,便于升级,同时避免了各种环境依赖的问题。统一管理在工作目录中的应用数据也能方便地进行备份和迁移。

  • 插件机制——支持在插件运行时为系统添加新功能,同时保持 Halo 自身的简洁轻量。这种灵活的插件机制让用户根据自身需求自由扩展 Halo 的功能,帮助用户实现富有想象力的站点。

  • 模板机制——支持自定义配置、主题预览、多语言等功能。这种灵活的模板系统让用户可以针对自己的需求进行自定义配置,为网站带来更加个性化的外观和交互体验。

  • 附件管理——支持多种存储策略,并支持通过插件扩展外部存储位置,可以让用户更加灵活地地上传、查看和管理附件。

  • 搜索引擎——内置全文搜索引擎,支持关键字搜索文章和页面内容。同时支持通过插件扩展外部搜索引擎,做到让用户按需选择、自由扩展。

安装Docker和Docker Compose

  1. 本次搭建的环境是Debian12系统,使用Docker Compose部署,数据库采用mysql。

  2. 准备好域名并做好托管解析,cloudfraer的话,直接开启小云朵。

  3. 部署Halo的VPS内存最好在2G或以上,不够的话开点Swap(教程),不然加载的时候容易卡死。

  4. 如果配置不够,装好或者重启启动的时候,需要加载一点时间才能进入博客界面,要等一会,具体时间看VPS的配置。

升级系统软件包

apt update -y

apt upgrade -y

安装docker

wget -qO- get.docker.com | bash
docker -v  #查看 docker 版本
systemctl enable docker  # 设置开机自动启动

安装 Docker-compose

sudo curl -L "https://github.com/docker/compose/releases/download/版本号/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

替换命令中的版本号,打开Docker-compose查看最新版本,如最新版本为v2.35.1,则把版本号改为v2.35.1,示例:sudo curl -L "https://github.com/docker/compose/releases/download/2.35.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

sudo chmod +x /usr/local/bin/docker-compose
docker-compose --version  #查看 docker-compose 版本

部署Halo

创建文件夹

mkdir -p /root/data/docker_data/halo

cd /root/data/docker_data/halo

编辑Docker-compose配置文件

注意

  • 目前 Halo 2 并未更新 Docker 的 latest 标签镜像,主要因为 Halo 2 不兼容 1.x 版本,防止使用者误操作。我们推荐使用固定版本的标签,比如 2.20 或者 2.20.0。

  • registry.fit2cloud.com/halo/halo:2:表示最新的 2.x 版本,即每次发布新版本都会更新此镜像。

  • registry.fit2cloud.com/halo/halo:2.20:表示最新的 2.20.x 版本,即每次发布 patch 版本都会同时更新此镜像。

  • registry.fit2cloud.com/halo/halo:2.20.0:表示一个具体的版本。

  • 本次 registry.fit2cloud.com/halo/halo:2 为例。

nano docker-compose.yml

官方提供了docker-compose.yml的配置模板,我在官方模板模板的提前下修改了一些内容,更加合适我,但不一定合适你,建议使用官方的模板就好。

官方模板

version: "3"

services:
  halo:
    image: registry.fit2cloud.com/halo/halo:2
    restart: on-failure:3
    depends_on:
      halodb:
        condition: service_healthy
    networks:
      halo_network:
    volumes:
      - ./halo2:/root/.halo2
    ports:
      - "8090:8090"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8090/actuator/health/readiness"]
      interval: 30s
      timeout: 5s
      retries: 5
      start_period: 30s
    environment:
      # JVM 参数,默认为 -Xmx256m -Xms256m,可以根据实际情况做调整,置空表示不添加 JVM 参数
      - JVM_OPTS=-Xmx256m -Xms256m
    command:
      - --spring.r2dbc.url=r2dbc:pool:mysql://halodb:3306/halo
      - --spring.r2dbc.username=root
      # MySQL 的密码,请保证与下方 MYSQL_ROOT_PASSWORD 的变量值一致。
      - --spring.r2dbc.password=o#DwN&JSa56
      - --spring.sql.init.platform=mysql
      # 外部访问地址,请根据实际需要修改
      - --halo.external-url=http://localhost:8090/

  halodb:
    image: mysql:8.1.0
    restart: on-failure:3
    networks:
      halo_network:
    command: 
      - --default-authentication-plugin=caching_sha2_password
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_general_ci
      - --explicit_defaults_for_timestamp=true
    volumes:
      - ./mysql:/var/lib/mysql
      - ./mysqlBackup:/data/mysqlBackup
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "--silent"]
      interval: 3s
      retries: 5
      start_period: 30s
    environment:
      # 请修改此密码,并对应修改上方 Halo 服务的 SPRING_R2DBC_PASSWORD 变量值
      - MYSQL_ROOT_PASSWORD=o#DwN&JSa56
      - MYSQL_DATABASE=halo

networks:
  halo_network:

根据自己的实际情况调整,不懂修改就直接按照官方的模板来,要修改

  • halo.external-url=http://localhost:8090/localhost要改成你的域名

  • spring.r2dbc.passwordMYSQL_ROOT_PASSWORD的密码,一定要修改!!!不要和模板的一样,两个密码要一致。

我的模板

version: "3"

services:
  halo:
    image: registry.fit2cloud.com/halo/halo:2
    container_name: halo
    restart: unless-stopped
    depends_on:
      halodb:
        condition: service_healthy
    networks:
      halo_network:
    volumes:
      - ./:/root/.halo2
    ports:
      - "8090:8090"
    command:
      - --spring.r2dbc.url=r2dbc:pool:mysql://halodb:3306/halo
      - --spring.r2dbc.username=root
      # MySQL 的密码,请修改,不要和这里一样,请保证与下方 MYSQL_ROOT_PASSWORD 的变量值一致。
      - --spring.r2dbc.password=o#DwN&JSa56
      - --spring.sql.init.platform=mysql
      # 外部访问地址,请根据实际需要修改
      - --halo.external-url=https://域名/
      # 初始化的超级管理员用户名,不一定是admin,这只是示例
      - --halo.security.initializer.superadminusername=admin
      # 初始化的超级管理员密码,要修改,不要和这里一样
      - --halo.security.initializer.superadminpassword=o#DwN&JSa56

  halodb:
    image: mysql:8.0.31
    container_name: halodb
    restart: unless-stopped
    networks:
      halo_network:
    command: 
      - --default-authentication-plugin=mysql_native_password
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_general_ci
      - --explicit_defaults_for_timestamp=true
    volumes:
      - ./mysql:/var/lib/mysql
      - ./mysqlBackup:/data/mysqlBackup
    ports:
      - "3306"
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "--silent"]
      interval: 3s
      retries: 5
      start_period: 30s
    environment:
      # 请修改此密码,并对应修改上方 Halo 服务的 SPRING_R2DBC_PASSWORD 变量值
      - MYSQL_ROOT_PASSWORD=o#DwN&JSa56
      - MYSQL_DATABASE=halo

networks:
  halo_network:

修改的地方:

  1. restart:改成了unless-stopped,重启开机后会自动启动。原本on-failure:3意思是如果容器异常退出(比如崩溃、返回错误码不为 0),自动重启最多 3 次,如果连续 3 次都失败了,就停止尝试重启,需要你手动干预

  2. volumes:我改成了合适我自己的路径,可以不用修改

  3. halo.external-url=https://域名/:因为后续反代了,所以直接https://域名/

  4. 增加了一个管理员账户,也可以不要,在第一次登录的时候配置就好

一定要记住要修改spring.r2dbc.passwordMYSQL_ROOT_PASSWORD的密码,不要用默认的。否则被人删除/修改数据库,敲诈勒索就来不及了!

一定要记住要修改spring.r2dbc.passwordMYSQL_ROOT_PASSWORD的密码,不要用默认的。否则被人删除/修改数据库,敲诈勒索就来不及了!

Ctrl+x确认保存并退出。

打开服务器防火墙并访问网页(非必需)

打开防火墙的端口 8090

查看端口是否被占用(以8090 为例),输入:

lsof -i:8090  #查看 8090 端口是否被占用,如果被占用,重新自定义一个端口

如果啥也没出现,表示端口未被占用,我们可以继续下面的操作了~

如果出现:

-bash: lsof: command not found

运行:

apt install lsof  #安装 lsof

如果端口没有被占用(被占用了就修改一下端口,比如改成 8091,注意 docker 命令行里和防火墙都要改)

拉取Halo

cd /root/data/docker_data/halo
docker-compose up -d 

跑完命令后,理论上就可以输入 http://ip:8090 访问了。

反代

Ningx、Caddy、Nginx Proxy Manager都可以。官方有Ningx、Caddy、Traefik反代配置:反向代理

此处为了操作简单且通俗易懂,使用Caddy进行反代。

安装Caddy

Caddy官网安装教程:点击打开,找到自己对应系统的安装方式,如Debian, Ubuntu, Raspbian适用的:

sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/testing/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-testing-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/testing/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-testing.list
sudo apt update
sudo apt install caddy

等待安装完成,在浏览器输入你的ip,会显示:

b09176c38f975c63448b54e03c888133.jpeg

到此Caddy安装成功。

配置Caddy

域名 {
    reverse_proxy localhost:8090
}

域名修改成你的域名

打开Caddy的配置文件:

nano /etc/caddy/Caddyfile

把修改好的配置信息粘贴到最后去,然后Ctrl+x确认保存并退出。

重启Caddy:

systemctl reload caddy

此时,直接在浏览器输入你的域名即可。

更新Halo

cd /root/data/docker_data/halo

docker-compose down 

cp -r /root/data/docker_data/halo /root/data/docker_data/halo.archive  # 万事先备份,以防万一

docker-compose pull

docker-compose up -d    # 请不要使用 docker-compose stop 来停止容器,因为这么做需要额外的时间等待容器停止;docker-compose up -d 直接升级容器时会自动停止并立刻重建新的容器,完全没有必要浪费那些时间。

docker image prune  # prune 命令用来删除不再使用的 docker 对象。删除所有未被 tag 标记和未被容器使用的镜像

提示:

WARNING! This will remove all dangling images.
Are you sure you want to continue? [y/N]

输入 y

卸载 Halo

cd /root/data/docker_data/halo

docker-compose down 

rm -rf /root/data/docker_data/halo     # 完全删除映射到本地的数据

用Docker Compose部署、更新、卸载都很方便。

备份

做好备份绝对没毛病,繁琐一点就繁琐一点。Halo上也有备份,但是需要再次安装好Halo之后才可以恢复。这次用的是Docker Compose部署,可以打包整个文件夹备份,迁移或者恢复都很方便。本次做两种备份方式:1是直接打包到本地,2是打包后传到别的VPS。传到网盘类的比较复杂,这里不做教程。

本地备份

备份脚本

采用一个简单的本地备份脚本就可以完成,脚本如下:

#!/bin/bash

# 定义备份文件的存储路径
BACKUP_DIR="/root/backups"
LOG_FILE="/root/backups/backup.log"

# 生成备份文件的名称(带时间戳)
BACKUP_FILE="$BACKUP_DIR/data-backup-$(date '+%Y%m%d%H%M%S').tar.gz"

# 创建备份
echo "$(date '+%Y-%m-%d %H:%M:%S') - 开始备份..." >> "$LOG_FILE"
tar -czf "$BACKUP_FILE" /root data

# 记录备份完成
echo "$(date '+%Y-%m-%d %H:%M:%S') - 备份完成:$BACKUP_FILE" >> "$LOG_FILE"

# 删除 7 天前的备份文件
echo "$(date '+%Y-%m-%d %H:%M:%S') - 删除超过 7 天的备份文件..." >> "$LOG_FILE"
find "$BACKUP_DIR" -type f -name "*.tar.gz" -mtime +7 -exec rm -f {} \;

# 记录清理完成
echo "$(date '+%Y-%m-%d %H:%M:%S') - 清理完成,已删除超过 7 天的备份文件" >> "$LOG_FILE"

脚本解读:

把data文件夹打包,生成一个tar.gz格式文件且带时间戳的备份文件名,备份到/root/backups文件夹,备份的日志在/root/backups/下,名字是backup.log。每次执行脚本,在备份的同时,也会检查超过7天的文件,如果备份文件超过7天,会把该超时的备份删除,防止大量备份占用磁盘资源。

路径、名称、清理备份的时间自己调整成合适自己的。

nano /root/backup_script.sh

然后把脚本粘贴进去,调整完毕后,ctrl+x确认保存并退出。

赋予脚本权限

chmod +x /root/backup_script.sh

执行权限授予后,可以直接运行脚本来验证其是否正常工作

/bin/bash /root/backup_script.sh

自行去查看/root/backups文件夹查看是否备份成功,按照教程的话,正常会备份成功。

设置定时任务(cron)

此时每次备份我们还要手动去执行脚本,无法自动执行,为了让备份脚本自动定期执行,可以使用 cron 设置定时任务

编辑 cron 任务

crontab -e

第一次可能遇到以下提示,提示用哪个编辑器,按照个人习惯来,我选择1

img

拉到最后,添加以下行

0 3 * * * /bin/bash /root/backup_script.sh

这条规则表示每天凌晨 3 点执行 /root/backup_script.sh 脚本,ctrl+x确认保存并退出。

完整流程总结

  • cron 定时任务:定期执行备份脚本,自动备份并清理过期文件。

  • 日志记录:备份和清理操作会被记录在 /root/backups /backup.log,方便后续查看。

  • 备份脚本:将 /root下的data 文件夹备份到 /root/backups 目录,并且清理超过 7 天的旧备份文件。

远程备份

这次说的是备份到别的VPS上,接收备份的VPS需要设置成SSH密钥登录,不然每次备份传输前都要输入密码。如果接收的VPS没有设置SSH密钥登录,那么要先设置SSH密钥登录

设置 SSH 密钥登录(只需做一次)

设置密钥

在 本地(发起备份的 VPS) 上运行

ssh-keygen -t rsa -b 4096 -C "[email protected]"

一直按回车,生成密钥对(默认位置:/root/.ssh/id_rsaid_rsa.pub.pub

它会生成两个文件:

  • /root/.ssh/id_rsa(私钥,自己保存好)

  • /root/.ssh/id_rsa.pub(公钥,发给远程服务器)

把【公钥】复制到【远程服务器】

ssh-copy-id 命令可以一键搞定:

ssh-copy-id your-username@your-server-ip

usernameyour-server-ip换成另外一台VPS的登录账户名和IP,然后它会提示你输入一次密码(就这一次),之后就设置好了,以后脚本里用 scpssh 都不用再输密码了!

ssh-copy-id命令的解释
  • 执行 ssh-copy-id your-username@your-server-ip 后,传过去的公钥默认会存放在远程服务器的目标用户目录下的 ~/.ssh/id_rsa.pub 文件中。具体路径是/home/your-username/.ssh/id_rsa.pub,如果你是以 root 用户身份执行的,它会存放在 /root/.ssh/id_rsa.pub 文件里。

  • ssh-copy-id 命令中的 id 指的是 公钥文件,默认是 ~/.ssh/id_rsa.pub,但它可以指向任何你希望复制到远程服务器的公钥文件。

默认操作

如果你没有指定其他公钥文件,ssh-copy-id 会自动使用 默认的公钥,即 ~/.ssh/id_rsa.pub。你可以通过以下命令复制默认公钥到远程服务器:

ssh-copy-id your-username@your-server-ip
自定义公钥文件

如果你有多个公钥文件,或者公钥文件不叫 id_rsa.pub,可以指定具体的公钥文件。例如my_custom_key.pub

ssh-copy-id -i ~/.ssh/my_custom_key.pub your-username@your-server-ip

这样,你就可以根据需要选择合适的公钥文件来进行复制。

测试

在本机输入

ssh your-username@your-server-ip

usernameyour-server-ip换成另外一台VPS的登录账户名和IP,如果能直接登录进去而不要求输入密码,那就说明配置成功!

如果你的远程服务器不在默认 22 端口,还可以加上 -p 端口号,例如:ssh-copy-id -p 22022 your-username@your-server-ip

最后提醒

  • 千万别把私钥 (id_rsa) 给别人!!!

  • 如果是 root 用户,就直接在 /root/.ssh/ 目录下面生成和保存。

远程备份脚本

#!/bin/bash

# ====== 配置区域 ======
DATA_DIR="/root/data"
BACKUP_DIR="/root/docker-backups"
REMOTE_USER="your-username"        # 改成远程 VPS 用户名
REMOTE_IP="your-server-ip"          # 改成远程 VPS IP
REMOTE_DIR="/remote/backup/path/"   # 改成远程 VPS 存储路径
KEEP_DAYS=30
SSH_KEY="/root/.ssh/id_rsa"     # 私钥路径
LOG_FILE="$BACKUP_DIR/backup.log"   # 日志文件路径

# ====== 颜色配置(只用于终端,不用于日志) ======
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # 没有颜色

# ====== 函数定义(方便同时输出到终端和日志) ======

log() {
    # 参数:$1=输出到终端的文字(带颜色)  $2=输出到日志的文字(纯净)
    echo -e "$1"
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $2" >> "$LOG_FILE"
}

# ====== 脚本执行区域 ======

# 时间戳
DATE=$(date +"%Y%m%d-%H%M%S")
BACKUP_FILE="$BACKUP_DIR/data-backup-$DATE.tar.gz"

# 创建备份目录
mkdir -p "$BACKUP_DIR"

log "${BLUE}🛠 开始备份流程,时间:$DATE${NC}" "开始备份流程,时间:$DATE"

# 打包整个 /root/data
log "${YELLOW}📦 正在打包 $DATA_DIR 到 $BACKUP_FILE...${NC}" "正在打包 $DATA_DIR 到 $BACKUP_FILE..."
if tar -zcvf "$BACKUP_FILE" -C /root data; then
    log "${GREEN}✅ 本地打包成功${NC}" "本地打包成功"
else
    log "${RED}❌ 打包失败,终止脚本${NC}" "打包失败,终止脚本"
    exit 1
fi

# 上传到远程服务器
log "${YELLOW}☁️ 正在上传备份到远程服务器 $REMOTE_IP...${NC}" "正在上传备份到远程服务器 $REMOTE_IP..."
if scp -i "$SSH_KEY" "$BACKUP_FILE" "$REMOTE_USER@$REMOTE_IP:$REMOTE_DIR"; then
    log "${GREEN}✅ 上传成功${NC}" "上传成功"
else
    log "${RED}❌ 上传失败,终止脚本${NC}" "上传失败,终止脚本"
    exit 1
fi

# 清理旧备份
log "${YELLOW}🧹 正在清理超过 $KEEP_DAYS 天的旧备份...${NC}" "正在清理超过 $KEEP_DAYS 天的旧备份..."
if find "$BACKUP_DIR" -type f -mtime +$KEEP_DAYS -name "*.tar.gz" -exec rm -f {} \;; then
    log "${GREEN}✅ 清理完成${NC}" "清理完成"
else
    log "${RED}⚠️ 清理时出现问题(通常不影响)${NC}" "清理时出现问题"
fi

log "${BLUE}🎉 全部完成!备份文件位置:$BACKUP_FILE${NC}" "全部完成!备份文件位置:$BACKUP_FILE"

exit 0

注意

  • 把这几行换成你的实际信息

# 远程服务器信息
REMOTE_USER="your-username"          #改成远程服务器登录用户名
REMOTE_IP="your-server-ip"           #改成远程服务器IP
REMOTE_DIR="/remote/backup/path/"    #改成远程服务器存储路径

#保留被备份的时间
KEEP_DAYS=30                         #自己修改,默认30天,需要注意磁盘空间
  • 确认你的密钥路径是 /root/.ssh/id_rsa,如果不是,请改掉

创建脚本

nano /root/backup_script.sh

然后把脚本粘贴进去,调整完毕后,ctrl+x确认保存并退出。

赋予脚本权限

chmod +x /root/backup_script.sh

测试

/bin/bash /root/backup_script.sh

自行去查看两台VPS是否备份成功,按照教程的话,正常会备份成功。

设置定时任务(cron)

此时每次备份我们还要手动去执行脚本,无法自动执行,为了让备份脚本自动定期执行,可以使用 cron 设置定时任务

编辑 cron 任务

crontab -e

第一次可能遇到以下提示,提示用哪个编辑器,按照个人习惯来,我选择1

img

拉到最后,添加以下行

0 3 * * * /bin/bash /root/backup_script.sh >> /root/docker-backups/cronjob.log 2>&1

这条规则表示每天凌晨 3 点执行 /root/backup_script.sh 脚本,上面对比多了输出cron的日志,把定时执行的输出也保存到 cronjob.log,包括标准输出和错误输出。

然后ctrl+x确认保存并退出。

本地vps的文件架构

执行后的文件结构大概是这样的

/root/docker-backups/
├── backup.log         # 脚本自己维护的详细日志
├── cronjob.log        # crontab跑脚本时的输出记录(出错可以排查)
├── data-backup-20250430-020001.tar.gz  # 每天新生成的备份包
├── data-backup-20250501-020001.tar.gz
├── ...

完整流程总结

  • cron 定时任务:定期执行备份脚本,自动备份并清理过期文件。

  • 日志记录:备份和清理操作会被记录在 /root/backups /backup.log和cronjob.log,方便后续查看。

  • 备份脚本:将 /root下的data 文件夹备份到 /root/backups 目录,并且清理超过 30 天的旧备份文件。

主题和插件

可访问 官方应用市场awesome-halo 仓库 查看适用于 Halo 2.x 的主题和插件。

插件安装和更新方式可参考:https://docs.halo.run/user-guide/plugins

文章编辑器默认是没有Markdown,用到的话要添加插件。

总结

这次只是搭建博客,按照Halo官方的说法,现在的Halo 2不单单是博客这么简单,还有更多的功能,大家可以查看官网资料学习,Halo的文档是比较详细的,网上也有很多的教程。

Github项目地址:https://github.com/halo-dev/halo

官网地址:https://www.halo.run/

官方文档:https://docs.halo.run/

官方论坛:https://bbs.halo.run/

0

评论区