将 Discuz! X3.5 迁移至 Discourse 主要是通过 Discourse 官方内置的迁移脚本 discuz_x.rb,将原论坛的版块、用户、帖子与附件数据写入 Discourse 数据库。
准备工作
- Discuz! 数据导出:导出 MySQL/MariaDB 数据库(
.sql 文件)以及附件目录(通常位于 Discuz 根目录下的 data/attachment/)。
- 字符集确认:Discuz! X3.5 建议使用 UTF-8 / UTF8MB4 编码导出。如果是 GBK 编码,导入前必须通过
iconv 或导出设置转为 UTF-8。
- Discourse 实例:一台安装好 Docker 的 Linux 服务器,并完成 Discourse 的基本部署。
迁移步骤
步骤 1:导入 Discuz 数据库至临时 MySQL
在与 Discourse 相同的服务器(或其内网机器)上启动一个临时的 MySQL 容器,供导入脚本读取数据:
# 启动临时 MySQL 容器
docker run --name temp-mysql -e MYSQL_ROOT_PASSWORD=your_password -p 3306:3306 -d mysql:5.7
# 创建数据库并导入 Discuz 的 SQL 备份
docker exec -i temp-mysql mysql -uroot -pyour_password -e "CREATE DATABASE discuz CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
docker exec -i temp-mysql mysql -uroot -pyour_password discuz < /path/to/your/discuz_backup.sql
验证成功标准:运行 docker exec -it temp-mysql mysql -uroot -pyour_password -e "SELECT count(*) FROM discuz.pre_forum_post;" 能返回正常的帖子数量。
步骤 2:挂载附件与修改 Discourse 容器配置
将 Discuz! 附件目录挂载到 Discourse 容器内,以便脚本提取图片和附件。
编辑 /var/discourse/containers/app.yml,在 volumes: 下添加挂载:
volumes:
- volume:
host: /var/discourse/shared/standalone
guest: /shared
- volume:
host: /path/to/discuz/data/attachment
guest: /shared/discuz_attachments
重新编译或启动容器:
cd /var/discourse
./launcher rebuild app
验证成功标准:执行 ./launcher enter app 后运行 ls /shared/discuz_attachments,能列出论坛附件文件。
步骤 3:配置迁移脚本环境
进入 Discourse 容器并安装脚本运行所依赖的 MySQL Gem:
./launcher enter app
# 在容器内临时安装依赖
apt-get update && apt-get install -y libmysqlclient-dev default-libmysqlclient-dev
gem install mysql2
Discourse 官方提供的 Discuz 导入脚本路径为 script/import_scripts/discuz_x.rb。你可以直接通过环境变量传入连接信息,或复制并修改该脚本:
# 切换到 discourse 运行用户
su - discourse
cd /var/www/discourse
# 配置临时 MySQL 连接环境变量
export DISCUZ_HOST="172.17.0.1" # Docker 宿主机内网 IP 或 MySQL 容器 IP
export DISCUZ_PORT="3306"
export DISCUZ_DB="discuz"
export DISCUZ_USER="root"
export DISCUZ_PW="your_password"
export DISCUZ_TABLE_PREFIX="pre_"
export DISCUZ_ATTACHMENT_PATH="/shared/discuz_attachments"
验证成功标准:执行 ruby -e "require 'mysql2'; client = Mysql2::Client.new(host: ENV['DISCUZ_HOST'], username: ENV['DISCUZ_USER'], password: ENV['DISCUZ_PW'], database: ENV['DISCUZ_DB']); puts client.query('SELECT 1').first" 能打印出 {"1"=>1}。
步骤 4:执行数据迁移脚本
在容器内执行导入命令:
bundle exec ruby script/import_scripts/discuz_x.rb
脚本会按顺序同步:
- 用户体系:迁移用户名、邮箱与注册时间。
- 分类与版块:映射 Discuz! 的分区与版块至 Discourse Categories。
- 主题与回帖:自动转换 BBCode、保留楼层关系。
- 附件与图片:重新上传并生成 Discourse Markdown 图片链接。
验证成功标准:脚本输出包含 import_users、import_categories、import_posts 且进度条跑到 100%,无致命抛错。
步骤 5:重建索引与善后
数据导入完成后,需要让 Discourse 重建搜索与统计数据:
# 在 /var/www/discourse 目录下执行
bundle exec rake posts:rebake
exit # 退出 discourse 用户
exit # 退出容器
- 停止并删除临时创建的 MySQL 容器:
docker rm -f temp-mysql。
- 进入 Discourse 管理后台,在 设置 -> 邮件 中检查是否需要重置导入用户的密码通知。
常见问题与注意事项
- 用户密码处理:Discuz! 使用
MD5(MD5(password) + salt) 算法,Discourse 默认不支持此散列算法。迁移后用户一般需要通过“找回密码/邮件重置”设置新密码,或在导入前安装官方的 discourse-migrate-password 插件支持无缝过渡。
- 无邮箱用户:Discuz 部分旧用户或第三方登录用户可能没有有效邮箱,Discourse 强制要求邮箱唯一。导入脚本会自动填充类似于
[email protected] 的虚拟邮箱,用户后续绑定真实邮箱即可。