Halo迁移指南_云服务器到NAS
Halo 博客从云服务器迁移到 NAS 完整指南
本文档记录将部署在 Ubuntu 云服务器 Docker 中的 Halo 博客系统,完整迁移到 Debian NAS 的 Docker 环境中的全过程,包含遇到的实际问题和解决方法。
一、迁移前的环境情况
云服务器(源):
- 系统:Ubuntu
- 部署目录:
/opt/halo - 容器构成:
halo(镜像halohub/halo:2)—— Halo 博客程序本体halodb(镜像postgres:15.4)—— PostgreSQL 数据库
- 数据库信息:数据库名
halo,用户名halo,密码见 compose 文件中的POSTGRES_PASSWORD - 数据卷:
./halo2:/root/.halo2—— 文章、配置、上传图片等程序数据./db:/var/lib/postgresql/data—— 数据库文件
- SSH 登录方式:仅允许密钥登录,不支持密码登录(root 账号)
NAS(目标):
- 系统:Debian
- 已有服务:ZFile(占用 8080 端口)、Dockge、Jellyfin 等
- 局域网 IP:
192.168.1.6 - 节点小宝虚拟网络 IP:
100.66.1.2 - 操作账号:
shuke(普通用户,非 root)
⚠️ 由于 NAS 上 8080 端口已被 ZFile 占用,Halo 的端口需要改为其他端口(本次改为 8081)。
二、在云服务器上:备份数据
1. 找到部署目录,停止容器
cd /opt/halo
docker compose stop # 停止 halo 和 halodb 两个容器
# 用 stop 而不是 down,避免误删数据卷
2. 重新启动数据库容器,导出数据库备份
因为 pg_dump 需要数据库处于运行状态才能连接,所以先单独把数据库启动:
docker compose up -d halodb # 只启动数据库容器
docker ps # 确认 halodb 状态变为 Up ... (healthy)
导出数据库为 SQL 备份文件:
docker exec halodb pg_dump -U halo halo > /opt/halo/halo_db_backup.sql
# -U halo : 数据库用户名
# halo : 数据库名称(用户名和库名在这里恰好同名)
# > 后面的路径是导出文件保存位置
ls -lh /opt/halo/halo_db_backup.sql # 检查文件是否生成、大小是否正常(不应为 0 字节)
导出完成后,重新停止数据库容器:
docker compose stop halodb
3. 打包 Halo 程序数据目录
tar -czvf halo2-data.tar.gz ./halo2
# -c 创建压缩包 -z 用gzip压缩 -v 显示过程 -f 指定文件名
# 这里只打包 halo2 目录(文章、配置、图片),不需要打包 ./db,
# 因为数据库内容已经用 pg_dump 单独导出了
ls -lh halo2-data.tar.gz # 检查压缩包大小
此时 /opt/halo 目录下应有三个待迁移的文件:
docker-compose.ymlhalo_db_backup.sqlhalo2-data.tar.gz
三、传输文件:云服务器 → 本地电脑 → NAS
说明:云服务器有公网 IP,本地电脑可以直接访问;但云服务器访问不到 NAS 的局域网 IP(
192.168.1.6),两者不在同一网络。因此不能直接从云服务器 scp 到 NAS,需要中转一次:先下载到本地电脑,再从本地电脑上传到 NAS。
1. 云服务器 SSH 只允许密钥登录
尝试用密码直接 scp 会报错:
Permission denied (publickey).
这是因为云服务器的 sshd_config 配置了仅允许密钥认证(PermitRootLogin prohibit-password),需要使用密钥文件登录,而不是密码。
2. 在本地 Windows 电脑上,用密钥从云服务器下载文件
Windows 自带 OpenSSH 客户端,直接在 PowerShell 中操作:
scp -i "C:\Users\shuke\.ssh\server-key.pem" root@云服务器公网IP:/opt/halo/docker-compose.yml .
scp -i "C:\Users\shuke\.ssh\server-key.pem" root@云服务器公网IP:/opt/halo/halo_db_backup.sql .
scp -i "C:\Users\shuke\.ssh\server-key.pem" root@云服务器公网IP:/opt/halo/halo2-data.tar.gz .
# -i 指定私钥文件路径
# 最后的 "." 表示下载到当前所在目录
如果提示
UNPROTECTED PRIVATE KEY FILE警告,说明密钥文件权限过于开放,可执行以下命令收紧权限:icacls "C:\Users\shuke\.ssh\server-key.pem" /inheritance:r icacls "C:\Users\shuke\.ssh\server-key.pem" /grant:r "$($env:USERNAME):(R)"
下载完成后执行 dir 确认三个文件都已下载到本地,且大小与云服务器上一致。
3. 从本地电脑上传到 NAS
先在 NAS 上确认目标目录 /opt/halo 的所有者是 shuke(如果目录是用 root 创建的,需要先改所有权,否则上传会报 Permission denied):
# 在 NAS 上,用有权限的账号(如 root)执行:
chown -R shuke:shuke /opt/halo
然后回到本地 Windows 的 PowerShell,用 shuke 账号上传(NAS 支持密码登录,无需密钥):
scp docker-compose.yml halo_db_backup.sql halo2-data.tar.gz shuke@192.168.1.6:/opt/halo/
上传完成后,在 NAS 上执行 ls -lh /opt/halo/ 核对文件是否完整、大小是否一致。
四、在 NAS 上:恢复数据并修改配置
1. 解压 Halo 程序数据
cd /opt/halo
tar -xzvf halo2-data.tar.gz
ls # 确认多出一个 halo2 文件夹
2. 修改 docker-compose.yml 中的两处关键配置
nano docker-compose.yml
① 修改端口映射(避免和 NAS 上已有的 ZFile 8080 端口冲突):
ports:
- "8081:8090" # 左边宿主机端口改成 8081;右边 8090 是容器内部端口,不要改
② 修改外部访问地址(原来写死的是云服务器的公网 IP,必须改成 NAS 实际可访问的地址):
- --halo.external-url=http://100.66.1.2:8081/
# 换成 NAS 的实际访问地址(这里用的是节点小宝虚拟网络 IP),并同步改成新端口 8081
修改完成:Ctrl + O 保存 → 回车确认文件名 → Ctrl + X 退出。
3. 启动数据库容器,导入数据库备份
先只启动数据库:
docker compose up -d halodb
docker ps # 确认 halodb 状态为 Up ... (healthy)
导入之前从云服务器导出的数据库内容(注意要在 /opt/halo 目录下执行,不要在 halo2 子目录里,否则找不到备份文件):
cd /opt/halo
cat halo_db_backup.sql | docker exec -i halodb psql -U halo -d halo
4. 启动 Halo 本体容器
docker compose up -d halo
docker ps # 确认 halo 状态变为 Up ... (healthy)
五、验证迁移结果
浏览器访问:
http://100.66.1.2:8081
检查以下内容是否正常:
- [ ] 博客首页能正常打开
- [ ] 之前发布的文章、图片都还在
- [ ] 后台管理登录正常(用原有账号密码)
确认无误后,迁移完成。建议保留云服务器上的原始数据一段时间,作为回退方案,确认 NAS 上稳定运行一段时间后再考虑清理。
六、过程中遇到的问题与解决方法汇总
| 问题现象 | 原因 | 解决方法 |
|---|---|---|
| scp 直连从云服务器到 NAS 卡住不动 | 云服务器(公网)访问不到 NAS 的局域网 IP,两者不在同一网络 | 改为「云服务器 → 本地电脑 → NAS」两段式中转 |
Permission denied (publickey) |
云服务器 SSH 关闭了密码登录,只认密钥 | 使用 -i 参数指定 .pem 密钥文件登录 |
上传到 NAS 时 Permission denied |
目标目录 /opt/halo 属主是 root,普通用户 shuke 无写入权限 |
用 chown -R shuke:shuke /opt/halo 把目录所有权交给 shuke |
| 数据库导入时提示"没有那个文件或目录" | 命令执行时所在目录不对(在 halo2 子目录里执行了引用上级目录文件的命令) | cd .. 回到 /opt/halo 目录后再执行导入命令 |
| 担心 8080 端口冲突 | NAS 上 ZFile 已占用 8080 | 把 Halo 的宿主机端口改为 8081,容器内部端口 8090 不变 |
七、常用维护命令(迁移完成后备用)
docker compose logs -f halo # 实时查看 Halo 运行日志,排查问题用
docker compose restart halo # 重启 Halo 容器
docker compose down # 停止并移除容器(数据不会丢,在挂载目录中)
docker compose up -d # 重新启动全部服务
