项目信息
官网地址:https://halo.run/
GitHub地址:https://github.com/halo-dev/halo
Demo地址:https://demo.halo.run
Demo后台:https://demo.halo.run/console
用户名:demo
密码:P@ssw0rd123..
安装Halo
sudo -i
mkdir -p /root/data/docker_data/halo
cd /root/data/docker_data/halonano docker-compose.ymlservices:
halo:
image: registry.fit2cloud.com/halo/halo:2.23.2
restart: on-failure:3
depends_on:
halodb:
condition: service_healthy
networks:
halo_network:
volumes:
- ./halo2:/root/.halo2
ports:
- "5090:8090"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5090/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:postgresql://halodb/halo
- --spring.r2dbc.username=halo
# PostgreSQL 的密码,请保证与下方 POSTGRES_PASSWORD 的变量值一致。
- --spring.r2dbc.password=Ca!
- --spring.sql.init.platform=postgresql
# 外部访问地址,请根据实际需要修改
- --halo.external-url=https://blog.sortiey.com
halodb:
image: postgres:15.4
restart: on-failure:3
networks:
halo_network:
volumes:
- ./db:/var/lib/postgresql/data
healthcheck:
test: [ "CMD", "pg_isready" ]
interval: 10s
timeout: 5s
retries: 5
environment:
- POSTGRES_PASSWORD=Ca!
- POSTGRES_USER=halo
- POSTGRES_DB=halo
- PGUSER=halo
networks:
halo_network:版本号可以看这边:https://github.com/halo-dev/halo/releases 保证自己是新版本~
以下配置已经没有了,但是里面提到的安全措施可以借鉴
docker-compose.yml里面数据库3306并没有写成3306:3306,官网是写的后者,咕咕改成了前者,为的就是不在公网暴露halo数据库的端口,这样也能一定程度保障博客的安全。
查看端口是否被占用(以 5090 为例),输入:
lsof -i:5090 #查看 5090 端口是否被占用,如果被占用,重新自定义一个端口如果啥也没出现,表示端口未被占用,我们可以继续下面的操作了~
如果出现:
-bash: lsof: command not found运行:
apt install lsof #安装 lsof如果端口没有被占用(被占用了就修改一下端口,比如改成 6090,注意 docker 命令行里和防火墙都要改)
最后:
cd /root/data/docker_data/halo # 来到 dockercompose 文件所在的文件夹下
docker compose up -d 理论上我们就可以输入 http://ip:5090 访问安装了。
不知道服务器 IP,可以直接在命令行输入:curl ip.sb,会显示当前服务器的 IP。
NPM设置




client_body_buffer_size 512k;
proxy_read_timeout 86400s;
client_max_body_size 0;更新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
cd ..
rm -rf /root/data/docker_data/halo # 完全删除映射到本地的数据
docker images
docker rmi imageid备份Halo
cd /root/data/docker_data/
nano migrate_halo.sh#!/bin/bash
export PATH=$PATH:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# --- 配置信息 ---
PROJECT_NAME="halo"
BASE_DIR="/root/data/docker_data"
REMOTE_IP="31.0.5.22"
REMOTE_PORT="4454"
REMOTE_USER="root"
REMOTE_PASS="C12!"
REMOTE_DIR="/home/data/群晖同步/halo_blog_backup/"
BACKUP_FILE="halo_migration_$(date +%Y%m%d_%H%M).tar.gz"
cd $BASE_DIR
echo "1. [本地] 正在停止 Docker 服务: $PROJECT_NAME..."
cd $PROJECT_NAME && docker compose stop && cd ..
echo "2. [本地] 正在打包压缩文件夹..."
tar -czvf $BACKUP_FILE $PROJECT_NAME/
echo "3. [远程] 正在清理新 VPS 上2天之前的旧备份(保留最近两天)并创建目录..."
#sshpass -p "$REMOTE_PASS" ssh -p $REMOTE_PORT -o StrictHostKeyChecking=no $REMOTE_USER@$REMOTE_IP "mkdir -p $REMOTE_DIR && rm -f $REMOTE_DIR/*.tar.gz"
sshpass -p "$REMOTE_PASS" ssh -p $REMOTE_PORT -o StrictHostKeyChecking=no $REMOTE_USER@$REMOTE_IP "mkdir -p $REMOTE_DIR && find $REMOTE_DIR -name '*.tar.gz' -mtime +1 -delete"
echo "4. [传输] 正在采用断点续传模式发送压缩包..."
# 使用 rsync 的 --append-verify 实现断点续传,-e 指定 sshpass
sshpass -p "$REMOTE_PASS" rsync -avP --append-verify -e "ssh -p $REMOTE_PORT -o StrictHostKeyChecking=no" $BACKUP_FILE $REMOTE_USER@$REMOTE_IP:$REMOTE_DIR/
echo "5. [本地] 正在删除本地临时压缩包..."
rm -f $BACKUP_FILE
echo "6. [本地] 正在恢复原 VPS 服务..."
cd $PROJECT_NAME && docker compose up -d && cd ..
echo "------------------------------------------------"
echo "迁移任务完成!"
echo "压缩包已传输至新 VPS: $REMOTE_DIR/$BACKUP_FILE"需要使用 sshpass 来自动化处理密码输入,并使用 rsync 来实现断点续传
在原 VPS 上,需要安装 sshpass 和 rsync(如果尚未安装):
apt-get update && apt-get install -y sshpass rsync在目标VPS上,安装 rsync
apt-get update && apt-get install -y rsync如何使用:
赋予权限:chmod +x migrate_halo.sh
执行脚本:./migrate_halo.sh
添加定时任务:
1. 确保脚本具有执行权限
chmod +x /root/data/docker_data/migrate_halo.sh2. 打开 Crontab 编辑器
crontab -e如果是第一次运行,它可能会让你选择编辑器,通常建议选 1 (nano)
3. 添加定时任务
在文件的最后一行,添加以下内容:
0 3 * * * /bin/bash /root/data/docker_data/migrate_halo.sh >> /root/data/docker_data/migrate.log 2>&1这行命令的含义:
0 3 * * *: 表示每天凌晨3点执行一次。
/bin/bash: 指定使用 bash 运行脚本,确保环境兼容。
/root/data/docker_data/migrate_karakeep.sh: 脚本的绝对路径(Crontab 中必须使用绝对路径)。
>> /root/data/docker_data/migrate.log 2>&1: 这是日志记录。它会将脚本运行的所有输出(包括报错)保存到 migrate.log 文件中。这样如果哪次迁移失败了,你可以通过查看日志找到原因。
5. 验证定时任务是否生效
crontab -l只要能看到刚才添加的那行代码,任务就已经在后台排队了。
6. 日志检查
cat /root/data/docker_data/migrate.log确认有没有出现 command not found 之类的错误。
检查Halo备份
恢复Halo备份
cd /root/data/docker_data/
nano update_halo.sh#!/bin/bash
# --- 配置信息 ---
BASE_DIR="/root/data/docker_data"
PROJECT_DIR="$BASE_DIR/halo"
cd $BASE_DIR
# 1. 自动寻找最新的备份压缩包
LATEST_BACKUP=$(ls -t halo_migration_*.tar.gz 2>/dev/null | head -n 1)
if [ -z "$LATEST_BACKUP" ]; then
echo "错误: 未找到 halo_migration_*.tar.gz 压缩包!"
exit 1
fi
echo "检测到最新备份文件: $LATEST_BACKUP"
# 2. 进入项目目录并停止当前服务
echo "1. 正在停止当前运行的 halo 服务..."
if [ -d "$PROJECT_DIR" ]; then
cd $PROJECT_DIR && docker compose down
else
echo "错误: 未找到项目目录 $PROJECT_DIR"
exit 1
fi
# 3. 备份旧数据(以防万一)
echo "2. 正在备份当前旧数据至 halo_old_backup..."
cd $BASE_DIR
rm -rf halo_old_backup
mv $PROJECT_DIR halo_old_backup
# 4. 解压新数据
echo "3. 正在解压新备份数据..."
tar -xzvf $LATEST_BACKUP
# 5. 启动服务
echo "4. 正在启动更新后的服务..."
cd $PROJECT_DIR
docker compose up -d
# 6. 清理
echo "5. 更新完成,正在清理..."
# 如果你希望保留压缩包,可以注释掉下面这行
# rm -f $BASE_DIR/$LATEST_BACKUP
echo "------------------------------------------------"
echo "halo 数据更新成功!"
echo "如果发现数据异常,旧数据存放在: $BASE_DIR/halo_old_backup"1. 赋予权限:chmod +x update_halo.sh
2. 执行更新:./update_halo.sh
脚本逻辑说明:
安全第一:脚本使用 docker compose down 而不是 stop,确保容器和网络被彻底清理后再替换文件,避免文件占用导致解压失败。
双重保险(karakeep_old_backup):在解压新包之前,它会将你当前正在运行的文件夹重命名为 karakeep_old_backup。如果更新后发现新数据不对,你可以随时通过 mv 命令换回来。
自动识别:因为它使用了 ls -t | head -n 1,即使你目录下有好几个带不同时间戳的备份包,它也只会使用最新生成的那一个。