Migrate a Phorum forum to Discourse

If you have an old Phorum forum and thinking to migrate to Discourse, then this tutorial is for you. The process is straightforward and we will be using the official Phorum Importer script. Let’s get started.

On a high level, we will do the following.

  • Preparing the local development environment.
  • Exporting the database from the production environment.
  • Importing the production database to a local Discourse instance.
  • Running the Phorum importer script.

What can be migrated

  • Categories
    • Every forums and folders => Root category
  • Topics & Posts
  • Users (with the following attributes)
    • banned status
    • username
    • real name => name
    • email
    • admin status
    • date added
    • last active

Preparing Local Development Environment

Follow one of these guides to install Discourse itself and consult this guide if you have any problems.

Install MySQL DB server;

Ubuntu 18.04:

$ sudo apt update
$ sudo apt install mysql-server -y

After finishing installing MySQL, check its status:

$ systemctl status mysql.service

If it is not running, run the following:

$ sudo systemctl start mysql

MacOS:

$ brew install mysql@5.7
$ echo 'export PATH="/usr/local/opt/mysql@5.7/bin:$PATH"' >> ~/.bash_profile
$ source ~/.bash_profile

Check the services status:

$ brew services list

You should see something like this:

...
mysql@5.7         started
...

Otherwise, run the following and check again:

$ brew services start mysql@5.7

For Windows, you can follow the official installation guide.

This environment will be our Discourse server.

Exporting The Database from Production Environment:

Export the production database (from Phorum production server):

$ mysqldump -u USER_NAME -p DATABASE_NAME > phorum_dump.sql

Copy the database dump to the Discourse server.

:bulb: Use scp or rsync to copy the database. And of course, you can gzip it first.

Importing The Production Database to Discourse server

On Discourse server, Create a database:

$ mysql -u root

:bulb: If your database user has a password you should use: mysql -u root -p then type your password.

mysql> CREATE DATABASE phorum;

Make sure that the database is created:

mysql> SHOW DATABASES;

You should see something like this:

+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| phorum             |
| sys                |
+--------------------+
5 rows in set (0.04 sec)

This is an empty database. Our next step is to import the production database into it.

$ mysql -u root phorum < phorum_dump.sql

While we are here, let’s get the table prefix. We will need it later:

$ mysql -u root
mysql> USE phorum;
mysql> SHOW TABLES;

You will see something like this:

+---------------------------+
| Tables_in_phorum          |
+---------------------------+
| pw_banlists           |
| pw_files              |
| pw_forum_group_xref   |
| pw_forums             |
| pw_groups             |
| pw_messages           |
| pw_messages_edittrack |
| pw_pm_buddies         |
| pw_pm_folders         |
| pw_pm_messages        |
| pw_pm_xref            |
| pw_search             |
| pw_settings           |
| pw_subscribers        |
| pw_user_custom_fields |
| pw_user_group_xref    |
| pw_user_newflags      |
| pw_user_permissions   |
| pw_users              |
+---------------------------+
19 rows in set (0.00 sec)

From the output above you can see that the prefix is pw_.

Running Phorum Importer Script

First, install the importer dependencies:

$ cd ~/discourse
$ echo "gem 'mysql2', require: false" >> Gemfile
$ bundle install

Now let’s configure the script to fits our requirements. In our example this will do:

PHORUM_DB = "phorum"
TABLE_PREFIX = "pw_"
BATCH_SIZE = 1000

# ...

host: "localhost",
username: "root",
password: "", # Change this if you have a password for MySQL database
database: PHORUM_DB

If you want to create a url redirecting, then you should uncomment the following:

# categories.each do |category|
#   Permalink.create(url: "list.php?#{category['id']}", category_id: category_id_from_imported_category_id(category['id'].to_i))
# end

#...

# results.each do |post|
#   if post['parent_id'] == 0
#     topic = topic_lookup_from_imported_post_id(post['id'].to_i)
#     Permalink.create(url: "read.php?#{post['category_id']},#{post['id']}", topic_id: topic[:topic_id].to_i)
#   end
# end

It will be like this:

categories.each do |category|
  Permalink.create(url: "list.php?#{category['id']}", category_id: category_id_from_imported_category_id(category['id'].to_i))
end

#...

results.each do |post|
  if post['parent_id'] == 0
    topic = topic_lookup_from_imported_post_id(post['id'].to_i)
    Permalink.create(url: "read.php?#{post['category_id']},#{post['id']}", topic_id: topic[:topic_id].to_i)
  end
end

Run the importer with a clean Discourse instance:

bundle exec rake db:drop db:create db:migrate
bundle exec ruby script/import_scripts/phorum.rb

The importer will connect to the MySQL server and migrates our Phorum database to Discourse database.

Start Discourse server after the importer finish importing:

$ bundle exec rails server

Start Sidekiq to process the migrated data:

$ bundle exec sidekiq

:bulb: You can monitor sidekiq progress at http://localhost:3000/sidekiq/queues.

Setup your Discourse production server by following this tutorial.

Perform a backup for Discourse database and upload it to your Discourse production server by following this tutorial.

It’s done :tada:

7개의 좋아요

Phorum 포럼을 Discourse로 마이그레이션하는 작업을 시작하려고 합니다. 게시글에 첨부된 파일(주로 사진)을 유지하는 것이 목표입니다. 현재 마이그레이션 스크립트에서는 이 기능이 지원되지 않는 것 같습니다. 이 문제에 대해 이미 고민해 보신 분이 계신가요?

1개의 좋아요

phorum의 첨부 파일/파일/업로드를 마이그레이션하는 내용을 포함하여 마이그레이션 스크립트에 몇 가지 조정을 했습니다. 풀 리퀘스트는 여기에 있습니다:

1개의 좋아요

스크립트 감사합니다!

다만 매뉴얼이 다소 거칠고 명확하지 않다는 느낌을 받았습니다. 실제로 무엇을 제안하고 있는지 이해하려면 예를 들어 Xenforo 마이그레이션 가이드를 참고해야 했습니다. 누락된 단계를 몇 가지 추가해 보겠습니다:

  • Discourse를 설치하고 실행 상태로 유지
  • 원래 Phorum에서 mysqldump 생성 - 모든 것이 명확하고 정상적입니다.
  • 데이터베이스 덤프를 Discourse 폴더로 복사: docker cp/path/to/backup/phorum_db.sql.gz app:/shared/phorum_db.sql.gz (컨테이너 이름이 표준인 app이라고 가정)

그리고 여기 누락된 부분이 있습니다:

  • 실제로 Discourse Docker 컨테이너에 접속하여 MySQL을 설치합니다:
docker exec -it app bash
apt-get update && apt-get upgrade
# pv는 진행 상황을 표시하기 위한 편의성 목적이며, lsb-release은 무엇인가에 의해 필요합니다
 apt-get install -y lsb-release pv mariadb-server mariadb-client libmariadb-dev
 service mariadb start

MySQL 설치 과정은 약간 더 까다로울 수 있지만, MariaDB도 충분히 잘 작동합니다.

이후 데이터베이스를 생성합니다: mysql → CREATE database phorum.

그 다음 백업으로 데이터를 채웁니다: pv phorum_db.sql.gz | gunzip | mysql phorum (덤프가 순수 SQL이면 gunzip은 필요 없습니다)

Ruby에 MySQL 지원을 추가합니다:

cd /var/www/discourse/
echo "gem 'mysql2'" >>Gemfile
bundle config unset deployment
bundle install --no-deployment

마이그레이션 스크립트의 데이터를 수정합니다(데이터베이스 자격 증명, 접두사, 영구 링크):

nano /var/www/discourse/script/import_scripts/phorum.rb

그리고 원래 게시물의 가이드로 돌아가면, 그 부분은 모두 정상입니다:

깨끗한 Discourse 인스턴스로 가져오기를 실행합니다:

git config --global --add safe.directory /var/www/discourse
bundle exec ruby script/import_scripts/phorum.rb

만약 Discourse 데이터베이스가 실제로 깨끗하지 않다면, 사전에 bundle exec rake db:drop db:create db:migrate로 정리하는 것이 좋습니다.

“PG::ConnectionBad: connection to server on socket “/var/run/postgresql/.s.PGSQL.5432” failed: FATAL: Peer authentication failed for user “discourse” (PG::ConnectionBad)” 오류로 실패하는 경우:

  1. 'Peer authentication failed for user "discourse"' 오류가 발생하는 경우:
  2. /etc/postgresql/13/main/pg_hba.conf 파일을 편집합니다
  3. 모든 'peer’를 'trust’로 변경하고 파일을 저장합니다
  4. postgres 서버를 다시 로드합니다: /etc/init.d/postgresql reload (또는 psql -U postgres -c "SELECT pg_reload_conf();"를 사용할 수도 있지만, 제 경우 가끔 실패했습니다)

처음에는 사용자 마이그레이션이 실행되며, 이는 상대적으로 느릴 수 있습니다(스크립트 출력 기준 분당 약 1,200명. 저는 10만 명의 사용자가 있었습니다…).

이후 카테고리를 생성하고 메시지와 주제 마이그레이션을 시작합니다(동일한 속도, 분당 약 1,200개). 하지만 이 시점에는 이미 웹사이트에 액세스하여 그 모습을 확인할 수 있습니다.

Phorum처럼 오래된 엔진에 대해 기대했던 것보다 훨씬 더 순조롭게 진행되는 것 같습니다. 사적 메시지(PM) 마이그레이션은 없는 것 같지만, 저에게는 적어도 장애 요인이 되지는 않을 것입니다.

스크립트와 노고에 다시 한번 감사합니다!

이렇게 복잡한 주제에 대해 모든 단계를 다루는 가이드를 작성하는 것은 쉽지 않습니다. 특정 사용자에게 어떤 부분만 알려야 하는지 파악하는 것조차 복잡합니다. 누락된 부분들을 포함하는 다른 가이드를 찾아내신 것은 잘하셨습니다.

mysql 템플릿을 포함하여 mysql을 설치하거나, 이미 설치된 mysql 서버에 어떤 방식으로든 접근하는 방법(보통 제가 사용하는 방식)을 사용할 수도 있었을 것입니다.

원하시면 PM을 가져오는 다른 스크립트들을 참고 예시로 살펴보실 수 있습니다.