Halo 博客跨服务器迁移与恢复操作文档
1. 文档用途
本文记录一次实际完成的 Halo 博客服务器迁移过程。
适用于类似架构:
Ubuntu
├── 宝塔面板
│ ├── Nginx
│ ├── MySQL
│ └── 网站/SSL/反向代理配置
│
└── Docker
└── Halo 2.26
网站访问链路:
用户
↓
域名
↓
Nginx 80/443
↓
反向代理
↓
127.0.0.1:8090
↓
Halo 2.26
↓
MySQL
↓
halo 数据库
本次迁移的核心思路是:
使用宝塔整机迁移恢复网站、Nginx 和 MySQL 数据库,然后在新服务器重新安装 Docker 和 Halo,让新的 Halo 直接连接迁移过来的原
halo数据库。
2. 迁移前准备
迁移之前,建议至少准备两份备份。
2.1 宝塔备份
需要备份:
网站
MySQL 数据库
Nginx 网站配置
SSL 相关配置
宝塔管理的数据
如果新旧服务器都使用宝塔,可以优先使用:
宝塔 → 整机迁移
进行迁移。
2.2 Halo 后台备份
进入:
Halo Console
→ 备份
→ 创建备份
下载并妥善保存 Halo 备份文件。
这份备份主要作为第二道保险。
如果宝塔迁移过来的数据库能够直接恢复原站,就不需要使用 Halo 备份覆盖现有数据。
Halo 官方支持通过 Console 对站点进行完整备份和恢复。
3. 新服务器准备
建议新服务器安装与旧服务器相同或接近版本的 Ubuntu。
首先安装:
宝塔面板
然后通过宝塔整机迁移,将原服务器的数据迁移到新服务器。
4. 宝塔整机迁移
通过宝塔完成整机迁移后,检查:
网站
数据库
Nginx
SSL
是否已经恢复。
特别检查:
宝塔 → 数据库
本次迁移后发现原来的 Halo 数据库已经存在:
数据库名:halo
用户名:halo
这说明宝塔已经把 Halo 使用的 MySQL 数据库迁移到了新服务器。
5. 检查 Halo 数据库
进入 phpMyAdmin。
打开:
halo
本次数据库中存在:
extensions
migrations
不要因为只有两张表就认为数据库没有恢复。
Halo 2.x 的大量资源数据存储在 extensions 中。
可以通过 SSH 检查数据库。
/www/server/mysql/bin/mysql -h 127.0.0.1 -u halo -p halo
输入宝塔中显示的 halo 数据库密码。
进入 MySQL 后:
SHOW TABLES;
本次显示:
extensions
migrations
继续检查当前数据库用户:
SELECT CURRENT_USER();
本次结果:
halo@localhost
检查权限:
SHOW GRANTS;
确认 halo 用户拥有:
halo.*
数据库权限。
退出:
exit;
6. 检查 MySQL 监听状态
执行:
ss -lntp | grep 3306
本次服务器显示:
*:3306
说明 MySQL 正在监听 3306。
注意:
不要因为 Halo 需要访问 MySQL,就在腾讯云/其他云厂商安全组中向公网开放 3306。
Halo 和 MySQL 都运行在同一台服务器时,没有必要将数据库暴露到 Internet。
7. 检查 Docker
宝塔整机迁移并不会保证 Docker 环境和 Docker 容器一起迁移。
执行:
docker ps -a
如果出现:
Command 'docker' not found
说明新服务器还没有 Docker。
8. 安装 Docker
安装 Docker:
curl -fsSL https://get.docker.com | sh
安装完成后检查:
docker --version
以及:
docker compose version
本次环境为:
Docker 29.7.2
Docker Compose v5.5.0
版本号未来可能不同,只要 Docker 和 Compose 正常工作即可。
9. 创建 Halo 工作目录
本次将 Halo 放在:
/opt/halo2
创建:
sudo mkdir -p /opt/halo2
sudo chown -R $USER:$USER /opt/halo2
cd /opt/halo2
这里使用 /opt 只是为了把 Docker 应用与宝塔 /www 目录分开管理。
Halo 并不强制要求安装在 /opt。
最终目录:
/opt/halo2/
├── docker-compose.yaml
└── data/
其中:
data/
映射到 Halo 容器中的:
/root/.halo2
这里以后会保存 Halo 的主题、插件、附件、日志、备份等工作目录数据,因此需要纳入服务器备份。
10. 创建 Halo Docker Compose
进入:
cd /opt/halo2
创建:
nano docker-compose.yaml
配置:
services:
halo:
image: registry.fit2cloud.com/halo/halo:2.26
container_name: halo
restart: unless-stopped
network_mode: host
volumes:
- ./data:/root/.halo2
command:
- --server.port=8090
- --spring.r2dbc.url=r2dbc:pool:mysql://127.0.0.1:3306/halo
- --spring.r2dbc.username=halo
- --spring.r2dbc.password=你的Halo数据库密码
- --spring.sql.init.platform=mysql
- --halo.external-url=https://你的域名
注意:
你的Halo数据库密码
必须填写宝塔数据库中 halo 用户的实际密码。
域名也必须替换为自己的实际域名。
11. 为什么使用 host 网络
本次数据库用户是:
halo@localhost
而 MySQL 运行在宿主机。
如果使用普通 Docker bridge 网络:
Halo Container
↓
Docker Network
↓
Host MySQL
MySQL 看到的连接来源不一定是 localhost。
因此本次使用:
network_mode: host
这样 Halo 可以直接连接:
127.0.0.1:3306
也不需要为了 Docker 将 MySQL 3306 暴露给公网。
Halo 官方 Docker Compose 文档同样提供了使用 network_mode: host 连接已有外部数据库的部署示例。
12. 检查 Compose 配置
保存文件后:
docker compose config
如果没有报错,说明 YAML 和 Compose 配置基本正确。
注意:
docker compose config
可能会直接显示数据库密码。
因此不要把输出截图公开到互联网。
13. 启动 Halo 前再次备份数据库
第一次启动新的 Halo 之前:
宝塔
→ 数据库
→ halo
→ 备份
创建一次数据库备份。
原因是 Halo 启动时可能进行数据库 migration。
如果发生版本或数据库异常,可以恢复到启动之前的状态。
14. 启动 Halo
执行:
cd /opt/halo2
sudo docker compose up -d
如果当前 Linux 用户已经加入 docker 用户组,可以省略 sudo。
15. Docker permission denied 的处理
如果出现:
permission denied while trying to connect to the docker API
说明当前用户没有访问:
/var/run/docker.sock
的权限。
临时直接使用:
sudo docker compose up -d
即可。
如果希望以后不用 sudo:
sudo usermod -aG docker $USER
然后:
退出 SSH
→ 重新登录
测试:
docker ps
16. 检查 Halo 容器
执行:
sudo docker ps
正常情况下应该看到:
halo
STATUS: Up ...
然后查看日志:
sudo docker logs halo --tail 100
正常日志中会出现类似:
Started Application
CategoryReconciler
UserReconciler
TagReconciler
ConfigMap
PolicyReconciler
如果旧数据库中已经存在用户、分类、标签等资源,Halo 会开始读取和同步这些数据。
17. 测试 8090
测试:
curl -I http://127.0.0.1:8090
本次根路径返回:
404 Not Found
这并不代表 Halo 没有启动。
继续测试后台:
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8090/console
本次返回:
302
说明 Halo Console 路由已经正常工作。
因此判断 Halo 是否正常不能只看:
/
一个路径。
还需要结合:
docker ps
docker logs
/console
综合判断。
18. Nginx 反向代理
Halo 运行:
127.0.0.1:8090
宝塔中的网站通过 Nginx 反向代理到 Halo。
基本逻辑:
https://域名
↓
Nginx
↓
127.0.0.1:8090
↓
Halo
典型 Nginx 反向代理核心配置类似:
location / {
proxy_pass http://127.0.0.1:8090;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
如果宝塔整机迁移已经恢复原网站配置,一般不需要重新创建。
19. 域名解析
确认域名:
A记录 → 新服务器公网IP
并确认服务器和云厂商安全组允许:
80/TCP
443/TCP
正常访问。
MySQL:
3306
不需要对公网开放。
Halo:
8090
如果只通过 Nginx 反向代理访问,同样没有必要向公网开放。
20. 测试 Halo 后台
浏览器访问:
https://你的域名/console
本次成功进入原来的 Halo 登录页面。
原来的管理员账号也已经从旧数据库恢复。
登录成功后,可以看到原来的:
文章
用户
浏览量
网站设置
其他数据库内容
这说明:
宝塔整机迁移
↓
MySQL halo 数据库
↓
Halo 2.26
恢复成功。
21. 检查完整性
迁移完成后逐项检查:
首页能够打开
Halo Console 可以登录
原管理员账号存在
文章数量正确
文章内容正常
分类正常
标签正常
页面正常
附件和图片正常
主题正常
插件正常
网站设置正常
Logo / Banner 正常
HTTPS 正常
手机端正常
Nginx 反向代理正常
Halo 容器能够自动启动
MySQL 数据正常
全部确认后,才算迁移完成。
22. Halo 后台备份什么时候使用
如果:
宝塔整机迁移
→ halo 数据库完整
→ 新 Halo 可以读取旧数据
就不要再使用 Halo 后台备份覆盖当前数据。
Halo 后台备份作为灾难恢复手段保留即可。
只有在:
数据库没有迁移
数据库损坏
数据严重缺失
需要建立一个全新的 Halo
等情况下,再考虑:
Halo Console
→ 备份
→ 恢复
Halo 官方说明,备份恢复不限制部署方式和数据库类型,因此它非常适合作为跨服务器恢复的第二道保险。
23. 本次迁移过程中遇到的问题
问题一:宝塔整机迁移后没有 Docker
表现:
docker: command not found
原因:
宝塔整机迁移不等于操作系统磁盘克隆。
解决:
重新安装 Docker。
问题二:原 Halo 数据库其实已经迁移
最开始计划:
重新创建 MySQL
→ 安装 Halo
→ 上传 Halo 备份
后来发现:
宝塔数据库
→ halo
已经存在,而且包含:
extensions
migrations
因此改变方案:
新 Halo
↓
直接连接迁移过来的原 halo 数据库
最终成功恢复。
问题三:数据库用户只有 localhost 权限
检查:
SELECT CURRENT_USER();
得到:
halo@localhost
因此没有额外创建:
halo@%
而是让 Halo Docker 使用:
network_mode: host
直接连接:
127.0.0.1:3306
既简单,也避免为了 Docker 放宽数据库访问范围。
问题四:Docker permission denied
表现:
permission denied while trying to connect to the docker API
解决:
sudo docker compose up -d
长期解决:
sudo usermod -aG docker $USER
然后重新登录 SSH。
问题五:访问 8090 根目录返回 404
测试:
curl http://127.0.0.1:8090/
返回:
404
但:
curl http://127.0.0.1:8090/console
返回:
302
同时:
docker ps
显示容器:
Up
日志显示:
Started Application
最终通过域名:
https://域名/console
成功进入 Halo 后台。
所以:
单独看到
/返回 404 时,不要立即判断 Halo 启动失败。
24. 最终服务器结构
迁移完成后的结构:
Ubuntu
│
├── 宝塔
│ │
│ ├── Nginx
│ │ ↓
│ │ HTTPS / 域名
│ │ ↓
│ │ 127.0.0.1:8090
│ │
│ └── MySQL
│ ↓
│ halo
│
└── Docker
│
└── Halo 2.26
│
├── /opt/halo2/data
│
└── 127.0.0.1:3306
↓
宝塔 MySQL
25. 日常备份建议
以后不要只依赖一种备份。
建议采用三层备份。
第一层:Halo 自带备份
定期:
Halo Console
→ 备份
至少保留最近几份。
第二层:MySQL 数据库备份
宝塔:
数据库
→ halo
→ 备份
建议开启定时数据库备份。
第三层:Halo 工作目录
重点备份:
/opt/halo2/
尤其:
/opt/halo2/docker-compose.yaml
/opt/halo2/data/
Halo 官方说明,工作目录中可能包含:
themes
plugins
attachments
logs
backups
application.yaml
所以数据库备份不能完全替代 Halo 工作目录备份。
26. 下次迁移的最简流程
以后再次迁移服务器,可以直接按照下面执行:
① Halo 后台创建完整备份
↓
② 宝塔备份网站和 halo 数据库
↓
③ 新服务器安装 Ubuntu + 宝塔
↓
④ 宝塔整机迁移
↓
⑤ 确认 halo 数据库存在
↓
⑥ 安装 Docker
↓
⑦ 创建 /opt/halo2
↓
⑧ 创建 docker-compose.yaml
↓
⑨ Halo 连接宝塔原 halo 数据库
↓
⑩ docker compose up -d
↓
⑪ 检查 docker ps / docker logs
↓
⑫ 检查 /console
↓
⑬ 检查 Nginx 反向代理
↓
⑭ 域名解析到新服务器
↓
⑮ 登录 Halo 后台
↓
⑯ 检查文章、附件、主题、插件
↓
⑰ 确认网站完整恢复
27. 重要安全注意事项
不要在公开截图中暴露数据库密码。
不要向公网开放 MySQL 3306,除非确实有远程数据库需求并配置严格的访问控制。
docker-compose.yaml包含数据库密码,应限制服务器文件访问权限。Halo、MySQL、宝塔和 Ubuntu 都应定期更新安全补丁。
修改服务器之前先备份数据库。
Halo 升级之前先备份。
不要把唯一备份保存在网站所在的同一台服务器。
建议至少有一份备份保存在本地电脑或其他云存储中。
旧服务器不要在新服务器验证完成前立即销毁。
SSL、DNS、安全组属于迁移验收的一部分,不要只检查 Halo 后台。
28. 常用维护命令
查看 Halo:
sudo docker ps
查看日志:
sudo docker logs halo --tail 100
实时查看日志:
sudo docker logs -f halo
重启 Halo:
sudo docker restart halo
进入 Halo Compose 目录:
cd /opt/halo2
停止:
sudo docker compose down
启动:
sudo docker compose up -d
检查 Compose:
sudo docker compose config
查看 8090:
ss -lntp | grep 8090
查看 MySQL:
ss -lntp | grep 3306
测试 Halo Console:
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8090/console
查看磁盘:
df -h
查看 Docker 磁盘占用:
sudo docker system df
29. 核心恢复原则
这次迁移最值得保留的经验是:
宝塔负责迁移宝塔能够管理的数据,Docker 应用则需要单独确认。
对于 Halo 网站,真正需要关注的是:
数据库
+
Halo 工作目录
+
Docker Compose 配置
+
Nginx
+
SSL
+
DNS
只要这些核心数据都存在,即使原服务器完全不存在,也可以在一台新的 Ubuntu 服务器上重新搭建 Halo 并恢复网站。
因此以后不要把“服务器”本身当成唯一资产。
真正需要长期保存的是:
数据
配置
备份
恢复文档
有了这些,即使更换腾讯云、阿里云、AWS 或其他云服务器,也能重新恢复网站。