Modern Forum Choices, and Migrating from Discuz to NodeBB
After Discuz stopped updating, alternative forum choices were needed. I experimented with several and will briefly share my impressions and migration methods.
The following are listed in order of their GitHub ranking.
Discourse
This is the top-ranked forum, but it’s based on RoR (Ruby on Rails). The performance of RoR is not just a little poor; its memory usage is also high, so I gave up on it directly.
For example, our previous login system was built with RoR. When web crawlers were scraping our Discuz forum, since each post had a login link with different from parameters, some less intelligent crawlers would crawl them all. That page only rendered a login box, but it directly brought down the RoR login system. Meanwhile, the Discuz forum being crawled showed no fluctuation at all. Be prepared if you’re used to Discuz’s speed and cost-effectiveness; see if you can tolerate it.
Flarum
The interface of this one is very nice. Based on PHP + MySQL, performance shouldn’t be a big issue in theory. However, the forum’s SQL queries are not optimized. Visiting the initial posts on an empty forum can trigger 100 SQL queries, with page load times starting at 100ms. With a low-end cloud database, 200ms is normal. This speed, combined with other loading content, results in a wait time of nearly one second.
NodeBB
This is built with NoSQL + Node.js, offering strong performance and very low CPU usage. It also uses WebSocket long connections, resulting in very fast response times. Memory usage starts at 1GB but grows slowly. It has comprehensive plugins and APIs, which is why I chose this one.
Apache / Answer
This is also quite good, similar to Zhihu or StackOverflow. However, after searching around, I couldn’t find a way to remove features like “asking questions” and “accepting answers.” If these could be removed, it would become a forum centered around articles (long-form main posts), suitable for forums that don’t need extensive interactive features, like strategy guides.
Flaskbb / Flaskbb
A Python-based forum with excellent performance, but it hasn’t been updated for a long time.
rafalp / Misago
Looks like an anime-style forum at first glance, also Python-based. The author started development not many years ago but is quite diligent. I noticed they use Python’s SocialAuth library, which allows easy integration of login methods like QQ, WeChat, Google, etc., including integration with your own website.
Additionally, there are two domestic (Chinese) forums that look good: one is Casbin, a high-fidelity imitation of v2ex; the others are bbs-go and symphony, which resemble CSDN-style blogs. However, I haven’t tested any of them.
Migrating from Discuz to NodeBB
If you have your own website, for NodeBB passport migration, you can use these two official plugins: nodebb-plugin-session-sharing or nodebb-plugin-sso-oauth2-multiple.
As for importing from Discuz, you’ll have to write the code yourself. You can ask an AI to write a framework in Python for you, and then modify the rest.
If you only need to import posts, loop through Discuz’s posts table; each row is a post. first=1 indicates a topic (original post).
For topic posts, call NodeBB’s api/v3/topics/ endpoint. For replies, call the api/v3/topics/{tid} endpoint. For users, you can use the user creation endpoint. Since I used session-sharing, I used the api/session-sharing/user endpoint for creation, and api/session-sharing/lookup?id={passport_id} for querying.
The API processing speed is about 5 requests per second, so be prepared for a slow migration.
Example call:
async def create_topic(title, body, timestamp, category, tags, uid):
# Create topic POST
data = {
"cid": category, # Category ID
"title": title,
"content": body,
"timestamp": int(timestamp), # Timestamp in milliseconds
"tags": tags,
"_uid": uid # Poster's UID
}
# API admin key
headers = {"Authorization": f"Bearer 1239383-3323-2323-2323-asd123123123"}
# Call
async with aiohttp.ClientSession() as session:
async with session.post(
'https://xxx.com/api/v3/topics/',
headers=headers,
json=data
) as response:
if response.status != 200:
# If the error is something like "Please add content, cannot be less than 1 character", the content wasn't escaped.
response_text = await response.text()
raise Exception(f"Error creating topic {title}: {response_text}")
result = await response.json()
topic_object = result['response']
return topic_object['tid']Note: The API posting logic is the same as user posting, so it’s subject to all the forum’s character limits. Similarly, the timestamp parameter becomes ineffective for the same reason; posts will still be published with the current time. The solution is to modify the timestamp logic on line 16 of src/api/helpers.js. Simply comment out the line data.timestamp = Date.now();. Remember to revert this change after migration, otherwise users could also modify timestamps.
After making this change, the reply API endpoint api/v3/topics/{tid} will also support passing a timestamp to specify the time.
248520b