MyBB 1.8.41 常用运维命令与排障详解
MyBB 1.8.41 日常运维命令与排障实操:mysqldump 备份与灾难恢复演练、crontab 定时备份、管理员密码重置(双层加盐 md5 算法实测+前台/后台登录验证)、datacache 缓存与计数统计重建、插件冲突排障(坏插件定位、插件表丢失全站 500 事故链、SQL 紧急停用与残留清理)、错误日志定位,全部命令在 Ubuntu 22.04 实测。
MyBB 1.8.41 常用运维命令与排障详解
目标:覆盖 MyBB 1.8.41 上线后的日常运维命令与高频事故排障——数据库备份与灾难恢复演练、定时备份、管理员密码重置(按 MyBB 密码算法实测并登录验证)、数据缓存/计数/统计重建、插件激活与冲突排障(含"插件表丢失导致全站 500"完整事故链实录)、错误日志定位。全部命令与回显均在 Ubuntu 22.04(Apache 2.4.52 + PHP 8.1.2 + MariaDB 10.6.23)实测环境逐条跑通。
一、环境信息
- 操作系统:Ubuntu 22.04 LTS(x86_64)
- Web 服务器:Apache 2.4.52(Ubuntu 官方源),站点配置
/etc/apache2/sites-available/mybb.conf,DocumentRoot /var/www/mybb - PHP:8.1.2-1ubuntu2.28(apache2 handler 模块方式运行)
- 数据库:MariaDB 10.6.23(
mysql Ver 15.1 Distrib 10.6.23-MariaDB),数据库名mybbdb,业务账号mybb,表前缀mybb_ - MyBB:1.8.41(安装于
/var/www/mybb,后台目录admin/,前台http://localhost/index.php,首页标题实测MyBB Demo Forum) - 备份目录:
/var/backups/(本文全部备份产物落在此处) - 演示管理账号:
admin/q1w2e3r4(前台与 Admin CP 同账号,用户组为管理员组 uid=1)
💡 技术拓展:MyBB 的密码不是以明文或简单 md5 存储的。同类论坛软件的口令存储方案对比——
方案 原理 代表软件 说明 双层加盐 md5 md5(md5(salt) + md5(密码)),每用户独立随机 saltMyBB(本文所用) 1.8 系列沿用;salt 存 mybb_users.saltbcrypt 自适应代价哈希,盐内嵌于哈希串 phpBB 3.3、Flarum 无需单独 salt 列 Argon2id 内存困难型哈希 Discourse(外部认证侧) 抗 GPU 暴破更强 phpBB 旧式 md5 md5(密码)单层phpBB 3.0(已淘汰) 已被 bcrypt 替代 MyBB 1.8.41 实际采用双层加盐 md5,本文第五章的重置操作完全围绕该算法展开,第五章 5.1 用 SQL 实测核对了这一等式。
二、工具概览
MyBB 本体不带 CLI 命令行工具(区别于 NodeBB 的 nodebb CLI 或 Flarum 的 flarum 命令),日常运维入口分四类:
| 运维入口 | 载体 | 典型用途 | 本文章节 |
|---|---|---|---|
| MySQL 命令行 | mysql / mysqldump / mysqlcheck | 备份恢复、密码重置、插件紧急停用、缓存直查 | 四、五、六、八、十 |
| Admin CP 维护工具 | 后台 Tools & Maintenance 菜单 | Cache Manager 缓存重建、Recount & Rebuild 计数统计重建、任务计划 | 六、七 |
| MyBB 内置日志表 | mybb_adminlog 等 6 张日志表 | 后台操作审计、任务执行历史 | 九 |
| 系统日志 | /var/log/apache2/ + PHP 错误配置 | Fatal/Parse error 定位、请求审计 | 九 |
其中 MySQL 命令行承担了绝大多数"后台打不开时"的救急操作,是本文重点。
三、前置条件
- 已按 《Ubuntu 22.04 安装 MyBB 指南》 完成安装并能打开论坛前台与 Admin CP;
- 拥有
mybbdb库的业务账号mybb(安装向导创建,具备本库全部权限,可直接执行 mysqldump 与数据修复 SQL); - 已登录 Admin CP(
http://localhost/admin/,账号admin),用于后台工具章节的实测; - 可通过 SSH 登录服务器并具备 sudo/root 权限(日志、crontab、文件操作需要);
- 涉及数据库的每一章动手前,建议先按第四章完成一次全量备份。
四、MySQL 数据库备份与恢复
4.1 全量备份(mysqldump)
MyBB 的全部业务数据都在 mybbdb 一个库的 75 张表里(含 6 张日志表),单库 mysqldump 逻辑备份即可覆盖全量。先确认当前数据基线:
# 统计库内表数
mysql -u mybb -pq1w2e3r4 -N -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='mybbdb';"
实测回显:
75
# 关键数据量基线(users/threads/posts/caches 四项)
mysql -u mybb -pq1w2e3r4 mybbdb -e "SELECT (SELECT COUNT(*) FROM mybb_users) users,(SELECT COUNT(*) FROM mybb_threads) threads,(SELECT COUNT(*) FROM mybb_posts) posts,(SELECT COUNT(*) FROM mybb_datacache) caches;"
实测回显:
users threads posts caches
1 1 2 31
执行全量备份并核对备份文件结构:
# 全量备份(--databases 带建库语句,恢复时免手工建库语义更完整)
mysqldump -u mybb -pq1w2e3r4 --databases mybbdb > /var/backups/mybbdb_full.sql
# 备份文件大小
ls -lh /var/backups/mybbdb_full.sql
实测回显:
-rw-r--r-- 1 root root 875K Oct 30 14:19 /var/backups/mybbdb_full.sql
# 备份文件内 CREATE TABLE 语句总数(应等于表数 75)
grep -c "CREATE TABLE" /var/backups/mybbdb_full.sql
# 抽查前 5 条建表语句位置
grep -n "CREATE TABLE" /var/backups/mybbdb_full.sql | head -5
实测回显:
75
34:CREATE TABLE `mybb_adminlog` (
63:CREATE TABLE `mybb_adminoptions` (
96:CREATE TABLE `mybb_adminsessions` (
126:CREATE TABLE `mybb_adminviews` (
160:CREATE TABLE `mybb_announcements` (
备份文件 875K、75 条 CREATE TABLE 与库内表数一致,说明全量覆盖无遗漏。
💡 技术拓展:数据库备份方案不止 mysqldump 一种——
方案 类型 特点 适用 mysqldump / mariadb-dump 逻辑备份 生成可读 SQL,跨版本兼容好,单机中小库首选 本文采用(75 表 875K 量级完全够用) XtraBackup 物理热备 不锁表、TB 级库适用 大流量高并发论坛 LVM/文件系统快照 物理快照 秒级完成,依赖卷管理 可接受短暂暂停的维护窗口 ACP Database Backups MyBB 内置 后台一键导出 gzip SQL(底层同为 SQL 导出) 无 SSH 权限时的替代入口 本文按单机中小站规模采用 mysqldump 逻辑备份;ACP 后台的 Database Backups 入口(Tools & Maintenance → Database Backups)导出的也是同构 SQL,可作为无命令行权限时的替代。
4.2 压缩与定时备份
原始 dump 压缩比约 6.4:1:
# gzip 压缩(-c 保留原文件)
gzip -c /var/backups/mybbdb_full.sql > /var/backups/mybbdb_full.sql.gz
ls -lh /var/backups/mybbdb_full.sql.gz
实测回显:
-rw-r--r-- 1 root root 136K Oct 30 14:19 /var/backups/mybbdb_full.sql.gz
配合 crontab 做每日定时备份(Ubuntu Server 自带 cron;本实测环境需先 apt-get install -y cron):
# 追加每日 03:30 定时备份任务(保留日期后缀,按天滚动)
(crontab -l 2>/dev/null; echo "30 3 * * * mysqldump -u mybb -pq1w2e3r4 --databases mybbdb | gzip > /var/backups/mybbdb_\$(date +\%Y\%m\%d).sql.gz") | crontab -
# 查看已生效的定时任务
crontab -l
实测回显:
30 3 * * * mysqldump -u mybb -pq1w2e3r4 --databases mybbdb | gzip > /var/backups/mybbdb_$(date +\%Y\%m\%d).sql.gz
验证定时任务里的备份管道可独立执行(与 cron 调用的命令一致):
# 手动按同一管道执行一次
mysqldump -u mybb -pq1w2e3r4 --databases mybbdb | gzip > /var/backups/mybbdb_daily.sql.gz
ls -lh /var/backups/mybbdb_daily.sql.gz
实测回显:
-rw-r--r-- 1 root root 136K Oct 30 14:26 /var/backups/mybbdb_daily.sql.gz
⚠️ 注意:crontab 里
%是特殊字符(表示换行),必须写成\%转义,否则 date 命令在 cron 环境下会被截断导致备份文件名异常;实测条目中的\$(date +\%Y\%m\%d)已含转义。验证无误后用crontab -r清除了本次测试条目(生产按需保留)。
4.3 灾难恢复演练(DROP → 重建 → 恢复 → 验证)
本节完整演练"误删库后从备份恢复"的全过程,命令与回显均为实测照抄。动手前确认 4.1 的备份文件存在。
第一步,记录恢复前基线(75 表、四项计数见 4.1),然后模拟灾难:
# 模拟误删整库
mysql -uroot -e "DROP DATABASE mybbdb;"
# 确认库已不存在(计数应为 0)
mysql -uroot -N -e "SHOW DATABASES;" | grep -c mybbdb
实测回显:
0
第二步,确认业务账号是否幸存——MariaDB 的用户账号与权限独立于业务库存在,DROP DATABASE 不会删除 mybb 账号:
mysql -uroot -e "SELECT user,host FROM mysql.user WHERE user='mybb';"
实测回显:
User Host
mybb localhost
第三步,重建库并导入备份(无需重建账号授权):
# 重建库(字符集与排序规则须与原库一致,MyBB 官方推荐 utf8mb4_unicode_ci)
mysql -uroot -e "CREATE DATABASE mybbdb DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
# 用业务账号直接导入全量备份
mysql -u mybb -pq1w2e3r4 mybbdb < /var/backups/mybbdb_full.sql
echo $?
实测回显:
0
第四步,恢复后全面验证:
# 表数核对
mysql -u mybb -pq1w2e3r4 -N -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='mybbdb';"
# 关键数据量核对(应与 4.1 基线完全一致)
mysql -u mybb -pq1w2e3r4 mybbdb -e "SELECT (SELECT COUNT(*) FROM mybb_users) users,(SELECT COUNT(*) FROM mybb_threads) threads,(SELECT COUNT(*) FROM mybb_posts) posts,(SELECT COUNT(*) FROM mybb_datacache) caches;"
# 前台与标题验证
curl -s -o /dev/null -w "forum:%{http_code}\n" http://localhost/index.php
curl -s http://localhost/index.php | grep -oE "<title>[^<]+" | head -1
实测回显:
75
users threads posts caches
1 1 2 31
forum:200
<title>MyBB Demo Forum
75 表、四项计数、前台 200 与标题全部与事故前一致,恢复闭环完成。
4.4 表检查与优化(mysqlcheck)
例行维护用 mysqlcheck 做全库分析(--analyze 更新索引统计)与优化(--optimize 回收空间),InnoDB 表通常返回 OK 或 already up to date:
# 全库分析(输出节选,实测共 75 行)
mysqlcheck -u mybb -pq1w2e3r4 --analyze mybbdb 2>/dev/null | head -8
实测回显:
mybbdb.mybb_adminlog OK
mybbdb.mybb_adminoptions OK
mybbdb.mybb_adminsessions OK
mybbdb.mybb_adminviews OK
mybbdb.mybb_announcements Table is already up to date
mybbdb.mybb_attachments Table is already up to date
mybbdb.mybb_attachtypes OK
mybbdb.mybb_awaitingactivation Table is already up to date
# 全库优化(输出节选:InnoDB 表多数直接报 already up to date)
mysqlcheck -u mybb -pq1w2e3r4 --optimize mybbdb 2>/dev/null | grep -v "OK$" | head -3
实测回显:
mybbdb.mybb_adminsessions Table is already up to date
mybbdb.mybb_awaitingactivation Table is already up to date
mybbdb.mybb_badwords Table is already up to date
75 表全部分析通过、无损坏告警。ACP 后台的对应入口是 Tools & Maintenance → Optimize Database,效果等同。
五、管理员密码重置(排障实录核心)
忘记 admin 密码(或接手旧站)是论坛运维最高频事故。MyBB 不能在数据库里"直接写一个新 md5 密码"——它采用双层加盐算法,直接 SET password=MD5('新密码') 必然登录失败。本节按事故现场流程实测:先核对算法 → 模拟事故 → 两种重置方法 → 登录验证。
5.1 密码算法核对(实测确认)
先看当前库里的密码字段结构:
mysql -u mybb -pq1w2e3r4 mybbdb -e "SELECT uid,username,salt,password FROM mybb_users WHERE uid=1;"
实测回显:
uid username salt password
1 admin QBoTBMzd c695b88e2c2be19ec498966ad6290276
mybb_users 表两个字段承担口令存储:salt(8 位随机盐,每用户独立)与 password(32 位 md5)。用 SQL 一步核对"MyBB 密码 = md5(md5(salt) + md5(密码))"这一等式(以演示密码 q1w2e3r4 为例):
mysql -u mybb -pq1w2e3r4 mybbdb -e "SELECT MD5(CONCAT(MD5(salt), MD5('q1w2e3r4'))) AS computed, password AS stored, MD5(CONCAT(MD5(salt), MD5('q1w2e3r4')))=password AS match_ FROM mybb_users WHERE uid=1;"
实测回显:
computed stored match_
c695b88e2c2be19ec498966ad6290276 c695b88e2c2be19ec498966ad6290276 1
computed 与 stored 完全一致、match_=1,算法实测确认。重置密码的 UPDATE 必须按这个结构生成哈希, salt 与哈希必须成对更新。
5.2 方法一:保盐改哈希(快速)
模拟事故——admin 密码被改成 Test123456(salt 保持不变,只按算法重算哈希):
mysql -u mybb -pq1w2e3r4 mybbdb -e "UPDATE mybb_users SET password=MD5(CONCAT(MD5(salt),MD5('Test123456'))) WHERE uid=1; SELECT salt,password FROM mybb_users WHERE uid=1;"
实测回显:
salt password
QBoTBMzd 087ac75df76687ce65a8bea7ed285128
验证:旧密码 q1w2e3r4 登录应失败。用 curl 模拟完整登录(先从登录页取 CSRF 令牌 my_post_key,再 POST 到 member.php):
cd /tmp && rm -f f1.jar
# 第一步:带 Cookie 访问登录页,抽取 my_post_key
KEY=$(curl -s -c f1.jar "http://localhost/member.php?action=login" | grep -oE "my_post_key\" type=\"hidden\" value=\"[a-z0-9]{32}\"" | grep -oE "[a-z0-9]{32}" | head -1)
# 第二步:用旧密码提交登录
curl -s -b f1.jar -c f1.jar -d "action=do_login&url=&quick_login=0&quick_username=admin&quick_password=q1w2e3r4&my_post_key=$KEY&submit=Login" "http://localhost/member.php" -o fail.html -w "old_login:%{http_code}\n"
实测回显:
old_login:200
失败响应页中的真实报错文案(fail.html 原文照抄):
You have entered an invalid username/password combination. If you have forgotten your password please retrieve a new one.
再用新密码 Test123456 登录并访问首页确认登录态(登录成功后首页导航会出现退出链接):
rm -f f2.jar
KEY=$(curl -s -c f2.jar "http://localhost/member.php?action=login" | grep -oE "my_post_key\" type=\"hidden\" value=\"[a-z0-9]{32}\"" | grep -oE "[a-z0-9]{32}" | head -1)
curl -s -b f2.jar -c f2.jar -d "action=do_login&url=&quick_login=0&quick_username=admin&quick_password=Test123456&my_post_key=$KEY&submit=Login" "http://localhost/member.php" -o ok.html -w "new_login:%{http_code}\n"
# 登录态验证:首页应出现 logout 链接
curl -s -b f2.jar http://localhost/index.php | grep -oE "member\.php\?action=logout" | head -1
实测回显:
new_login:200
member.php?action=logout
旧密码失败、新密码成功,方法一闭环验证通过。
5.3 方法二:新盐一步重置(推荐,与 MyBB 自身改密行为一致)
MyBB 用户在后台修改密码时会同时再生 salt。数据库重置也推荐一步完成"生成新盐 + 按新盐算哈希",一条 UPDATE 内 salt 先赋值、password 引用更新后的 salt(MySQL 同一 UPDATE 内右侧列取新值):
mysql -u mybb -pq1w2e3r4 mybbdb -e "UPDATE mybb_users SET salt=SUBSTRING(MD5(RAND()),1,8), password=MD5(CONCAT(MD5(salt),MD5('q1w2e3r4'))) WHERE uid=1; SELECT salt,password FROM mybb_users WHERE uid=1;"
实测回显:
salt password
b33448de 88ae209d91e0e63ac97547f1bfc14f6f
salt 已从 QBoTBMzd 再生为 b33448de,哈希随之变化。重置后用 q1w2e3r4 登录验证:
rm -f f3.jar
KEY=$(curl -s -c f3.jar "http://localhost/member.php?action=login" | grep -oE "my_post_key\" type=\"hidden\" value=\"[a-z0-9]{32}\"" | grep -oE "[a-z0-9]{32}" | head -1)
curl -s -b f3.jar -c f3.jar -d "action=do_login&url=&quick_login=0&quick_username=admin&quick_password=q1w2e3r4&my_post_key=$KEY&submit=Login" "http://localhost/member.php" -o ok2.html -w "reset_login:%{http_code}\n"
curl -s -b f3.jar http://localhost/index.php | grep -oE "member\.php\?action=logout" | head -1
实测回显:
reset_login:200
member.php?action=logout
5.4 Admin CP 后台登录验证
密码重置最终要看后台能否进入。Admin CP 登录无需 CSRF 令牌,直接 POST:
rm -f acp2.jar
curl -s -c acp2.jar -X POST "http://localhost/admin/index.php" --data "do=login&username=admin&password=q1w2e3r4" -o /dev/null -w "acp_login:%{http_code}\n"
# 登录后访问控制台页面验证
curl -s -b acp2.jar "http://localhost/admin/index.php?module=dashboard" | grep -oE "<title>[^<]+" | head -1
实测回显:
acp_login:200
<title>Dashboard
前台与后台双向验证通过,密码重置完整闭环。
⚠️ 注意:多次输错密码会触发登录尝试锁定(设置项
loginattempts控制次数,超限后进入awaitingactivation/锁定流程)。用数据库重置密码前,若站点开启了登录锁定,同步清零可避免"密码对了却仍提示错误":UPDATE mybb_users SET loginattempts=0, loginlocked=0 WHERE uid=1;(字段是否存在以DESC mybb_users实查为准)。
六、数据缓存重建
MyBB 把版块树、权限矩阵、用户组、表情、插件清单等热点数据序列化缓存在 mybb_datacache 表(默认缓存后端为 db,各后端对比见 《MyBB 1.8.41 配置参数详解》)。缓存行损坏或手工改库后不同步时,需要重建。本节实测两种重建路径:SQL 直删后前台按需自动重建、ACP Cache Manager 手工重建。
6.1 缓存清单查看
# 列出全部缓存项与序列化体积(实测 31 项)
mysql -u mybb -pq1w2e3r4 mybbdb -e "SELECT title, LENGTH(cache) FROM mybb_datacache ORDER BY title;"
实测回显(31 行全量照抄):
attachtypes 7037
awaitingactivation 46
badwords 6
bannedemails 6
bannedips 6
birthdays 6
default_theme 3530
forumpermissions 14
forums 2346
forumsdisplay 6
groupleaders 6
internal_settings 68
moderators 34
mostonline 49
mycode 6
plugins 25
posticons 1931
profilefields 1677
reportedcontent 69
reportreasons 1280
smilies 4173
spiders 1712
statistics 102
stats 266
tasks 38
threadprefixes 6
update_check 34
usergroups 19467
usertitles 620
version 60
version_history 843
其中 forums(版块树)、forumpermissions(权限矩阵)、usergroups(用户组)是与前台展示最相关的三张大缓存。
6.2 实测一:SQL 删除后前台按需自动重建
MyBB 前台读取缓存行不存在时会自动从源表重建并回写 mybb_datacache。实测验证这一机制:
# 删除 forums 缓存行(模拟缓存损坏)
mysql -u mybb -pq1w2e3r4 mybbdb -e "SELECT COUNT(*) AS before_del FROM mybb_datacache WHERE title='forums';"
mysql -u mybb -pq1w2e3r4 mybbdb -e "DELETE FROM mybb_datacache WHERE title='forums';"
mysql -u mybb -pq1w2e3r4 mybbdb -N -e "SELECT COUNT(*) FROM mybb_datacache WHERE title='forums';"
实测回显:
before_del
1
0
# 访问一次前台,触发按需重建
curl -s -o /dev/null -w "forum:%{http_code}\n" http://localhost/index.php
# 复查缓存行
mysql -u mybb -pq1w2e3r4 mybbdb -e "SELECT title,LENGTH(cache) AS rebuilt_size FROM mybb_datacache WHERE title='forums';"
实测回显:
forum:200
title rebuilt_size
forums 2346
删除后计数 0,前台一次请求即自动重建出 2346 字节(与 6.1 清单中原始体积一致),前台无任何报错。
6.3 实测二:ACP Cache Manager 手工重建
后台路径:Tools & Maintenance → Cache Manager(admin/index.php?module=tools-cache)。页面按行列出各缓存项与体积,每行有 Rebuild Cache 链接,页头另有 Reload All。后台所有操作链接都带会话级 CSRF 令牌 my_post_key(同一登录会话内恒定),从任一后台页面源码抽取即可:curl -s -b acp2.jar "http://localhost/admin/index.php?module=tools-cache" | grep -oE "my_post_key=[a-z0-9]+" | head -1(实测本会话取值 2f366dee58e7d05d421b91c12a3f5593,下文各后台请求同用此值)。实测先用 SQL 删除 forums 行,再用后台按钮重建:
mysql -u mybb -pq1w2e3r4 mybbdb -e "DELETE FROM mybb_datacache WHERE title='forums';"
# (后台页面点击 forums 行的 Rebuild Cache 按钮,等价于以下带 my_post_key 的 GET 请求)
curl -s -b acp2.jar "http://localhost/admin/index.php?module=tools-cache&action=rebuild&title=forums&my_post_key=2f366dee58e7d05d421b91c12a3f5593" -o /dev/null -w "rebuild:%{http_code}\n"
mysql -u mybb -pq1w2e3r4 mybbdb -e "SELECT title,LENGTH(cache) AS size_after_acp_rebuild FROM mybb_datacache WHERE title='forums';"
实测回显:
rebuild:302
title size_after_acp_rebuild
forums 2346
后台重建返回 302 跳转回列表页,缓存行恢复为同样的 2346 字节。ACP 重建与 SQL 直删自动重建等效,区别在于 ACP 可对 settings 这类"非 datacache 存储"的缓存项工作(见 6.4)。
6.4 特殊缓存:settings 存于文件而非 datacache
设置项缓存在 mybb_datacache 里没有对应行(6.1 清单中无 settings),它持久化在 /var/www/mybb/inc/settings.php 文件中。直接改 mybb_settings 表后,该文件不会自动同步。实测用 ACP 重建 settings 缓存并核对文件:
# (ACP Cache Manager 页点击 settings 行 Rebuild Cache,等价于)
curl -s -b acp2.jar "http://localhost/admin/index.php?module=tools-cache&action=rebuild&title=settings&my_post_key=2f366dee58e7d05d421b91c12a3f5593" -o /dev/null -w "rebuild_settings:%{http_code}\n"
# 核对文件头尾与残留
head -3 /var/www/mybb/inc/settings.php
tail -3 /var/www/mybb/inc/settings.php
grep -c "hello_display" /var/www/mybb/inc/settings.php
实测回显:
rebuild_settings:302
<?php
/*********************************\
DO NOT EDIT THIS FILE, PLEASE USE
$settings['woldisplayspiders'] = "1";
$settings['wolorder'] = "username";
0
文件头固定为"DO NOT EDIT"声明(提示此文件由系统维护)、尾行为最后一个设置项,grep 计数 0 表示无已删除插件的残留设置。第八章 8.4 的插件残留清理正是用这一步收尾。
七、计数与统计重建(Recount & Rebuild)
论坛的帖子计数、版块计数、统计数字都是冗余存储的(为列表页性能妥协),删帖、导库、SQL 直改都可能造成与真实数据不同步。ACP 的 Tools & Maintenance → Recount & Rebuild 页面提供 8 项重建动作,实测清单如下:
| 动作名 | 作用 | 每页处理量默认值 |
|---|---|---|
| Rebuild Forum Counters | 重算各版块主题数/帖子数/最后发表 | 50 |
| Rebuild Thread Counters | 重算各主题回帖数/浏览数/最后回复 | 500 |
| Rebuild Poll Counters | 重算投票计数 | 500 |
| Recount User Post Counts | 重算用户发帖数(排除关闭计数的版块) | 500 |
| Recount User Thread Counts | 重算用户主题数 | 500 |
| Rebuild Attachment Thumbnails | 重建附件缩略图 | — |
| Recount Statistics | 重算全站统计(首页/统计页数字) | — |
| Recount Reputation | 重算用户声望值 | — |
分页默认值实测读取自页面表单(name="forumcounters" value="50" 等),大数据量论坛可调大每页量减少点击次数。
7.1 实测:论坛计数不同步修复
人为制造计数错误,再用后台修复,验证全流程:
# 记录修复前各版块计数基线
mysql -u mybb -pq1w2e3r4 mybbdb -e "SELECT fid,name,threads,posts FROM mybb_forums;"
实测回显:
fid name threads posts
1 My Category 0 0
2 My Forum 0 0
3 General Discussion 1 2
# 模拟事故:把版块 posts 篡改为 999
mysql -u mybb -pq1w2e3r4 mybbdb -e "UPDATE mybb_forums SET posts=999 WHERE fid=1; SELECT fid,name,threads,posts FROM mybb_forums WHERE fid=1;"
实测回显:
fid name threads posts
1 My Category 0 999
后台 Recount & Rebuild → Rebuild Forum Counters 点 Go(表单提交,等价请求如下;my_post_key 为后台会话 CSRF 令牌):
curl -s -b acp2.jar -X POST "http://localhost/admin/index.php?module=tools-recount_rebuild" --data "do_rebuildforumcounters=Go&forumcounters=50&my_post_key=2f366dee58e7d05d421b91c12a3f5593" -o /dev/null -w "rebuild:%{http_code}\n"
# 修复后核对
mysql -u mybb -pq1w2e3r4 mybbdb -e "SELECT fid,name,threads,posts FROM mybb_forums WHERE fid=1;"
实测回显:
rebuild:302
fid name threads posts
1 My Category 0 0
posts 从 999 修复回 0(与基线一致),动作返回 302 跳回列表页。
7.2 实测:全站统计重建
先看统计缓存当前值,再触发 Recount Statistics:
# 重建前:stats 缓存(numposts 为 0,与真实帖子数 2 不符——直改库造成的滞后)
mysql -u mybb -pq1w2e3r4 mybbdb -e "SELECT cache FROM mybb_datacache WHERE title='stats'\G"
实测回显:
*************************** 1. row ***************************
title: stats
cache: a:9:{s:10:"numthreads";s:1:"1";s:20:"numunapprovedthreads";s:1:"0";s:8:"numposts";i:0;s:18:"numunapprovedposts";s:1:"0";s:8:"numusers";s:1:"1";s:15:"numdeletedposts";s:1:"0";s:17:"numdeletedthreads";s:1:"0";s:7:"lastuid";s:1:"1";s:12:"lastusername";s:5:"admin";}
curl -s -b acp2.jar -X POST "http://localhost/admin/index.php?module=tools-recount_rebuild" --data "do_recountstats=Go&my_post_key=2f366dee58e7d05d421b91c12a3f5593" -o /dev/null -w "recount_stats:%{http_code}\n"
mysql -u mybb -pq1w2e3r4 mybbdb -e "SELECT LEFT(cache,120) AS stats_after FROM mybb_datacache WHERE title='stats';"
实测回显:
recount_stats:302
stats_after
a:9:{s:10:"numthreads";s:1:"1";s:20:"numunapprovedthreads";s:1:"0";s:8:"numposts";s:1:"2";s:18:"numunapprovedposts";s:1:
numposts 从 i:0 修正为 s:1:"2"(2 与真实帖子数一致),统计重建生效。恢复备份后建议顺手跑一遍 7.1/7.2 两项。
八、插件管理与冲突排查
MyBB 插件是 inc/plugins/ 目录下的 PHP 文件,激活状态记录在 mybb_datacache 的 plugins 缓存行。插件类故障有三类典型现场:坏插件文件(语法错误)、激活插件的数据表丢失(Fatal 白屏)、插件残留(停用不彻底)。本章用官方示例插件 hello 做全流程实测。
8.1 查看插件目录与激活状态
ls /var/www/mybb/inc/plugins/
# 激活状态(plugins 缓存行,active 数组为空表示无激活插件)
mysql -u mybb -pq1w2e3r4 mybbdb -N -e "SELECT cache FROM mybb_datacache WHERE title='plugins';"
实测回显:
hello.php
index.html
a:1:{s:6:"active";a:0:{}}
后台对应页:Configuration → Plugins(admin/index.php?module=config-plugins),会扫描 inc/plugins/ 全目录列出可激活插件。
8.2 插件激活实测(hello 示例插件)
后台 Plugins 页点击 Hello World! 的 Activate(等价带 my_post_key 的 GET 请求),激活后三处变化实测如下:
curl -s -b acp2.jar "http://localhost/admin/index.php?module=config-plugins&action=activate&plugin=hello&my_post_key=2f366dee58e7d05d421b91c12a3f5593" -o /dev/null -w "activate:%{http_code}\n"
# 变化一:激活态
mysql -u mybb -pq1w2e3r4 mybbdb -N -e "SELECT cache FROM mybb_datacache WHERE title='plugins';"
# 变化二:插件安装的数据表
mysql -u mybb -pq1w2e3r4 mybbdb -e "SHOW TABLES LIKE '%hello%';"
# 变化三:后台操作审计
mysql -u mybb -pq1w2e3r4 mybbdb -e "SELECT uid,action,LEFT(ipaddress,15) AS ip,dateline FROM mybb_adminlog ORDER BY dateline DESC LIMIT 3;"
实测回显:
activate:302
a:1:{s:6:"active";a:1:{s:5:"hello";s:5:"hello";}}
Tables_in_mybbdb (%hello%)
mybb_hello_messages
uid action ip dateline
1 activate 1793370131
1 rebuild 1793370109
1 activate 1793365514
激活即向 plugins 缓存写入 active 数组、创建插件自带的 mybb_hello_messages 表,并在 mybb_adminlog 留下审计记录(激活/重建缓存各一条)。
8.3 坏插件文件:定位与影响面
模拟手误产生一个语法错误的插件文件(少一个右花括号):
cat > /var/www/mybb/inc/plugins/broken_test.php << 'EOF'
<?php
// Broken plugin test
function broken_test_info()
{
return array("name" => "Broken Test",
"description" => "plugin with syntax error",
"website" => "https://example.com",
"author" => "test",
"version" => "1.0",
"compatibility" => "18*"
);
}
function broken_test_activate()
{
EOF
# 语法检查
php -l /var/www/mybb/inc/plugins/broken_test.php
实测回显:
PHP Parse error: Unclosed '{' on line 14 in /var/www/mybb/inc/plugins/broken_test.php on line 15
Errors parsing /var/www/mybb/inc/plugins/broken_test.php
坏文件在场时实测各入口的表现:
# 前台:未激活插件不会被加载,不受影响
curl -s -o /dev/null -w "forum:%{http_code}\n" http://localhost/index.php
# ACP 插件列表页:扫描器静默跳过坏文件,页面正常
curl -s -b acp2.jar "http://localhost/admin/index.php?module=config-plugins" -o plug_page.html -w "acp_plugins:%{http_code}\n"
grep -c "Broken Test" plug_page.html
# 但 Apache 错误日志已留下记录
tail -1 /var/log/apache2/mybb_error.log
实测回显:
forum:200
acp_plugins:200
0
[Fri Oct 30 14:22:11.340142 2026] [php:error] [pid 14124] [client 127.0.0.1:45598] PHP Parse error: Unclosed '{' on line 14 in /var/www/mybb/inc/plugins/broken_test.php on line 15
结论(三条都实测):坏插件文件不会打挂前台(未激活不加载)、不会打挂后台插件页(列表页静默跳过、列表里也不显示),只在 Apache 错误日志留 Parse error。排障抓手是 php -l 与错误日志;处理方式是修复或删除该文件:
rm /var/www/mybb/inc/plugins/broken_test.php
curl -s -o /dev/null -w "forum_after_fix:%{http_code}\n" http://localhost/index.php
curl -s -b acp2.jar "http://localhost/admin/index.php?module=config-plugins" | grep -c "Hello World"
实测回显:
forum_after_fix:200
1
删除坏文件后插件页恢复正常列出 Hello World!(计数 1)。
8.4 事故链实录:激活插件数据表丢失 → 全站 500 → SQL 紧急停用
这是本章核心排障实录,还原"用旧备份恢复了数据库、备份里没有插件的表"这一经典事故。hello 插件处于激活态(8.2),其数据表被误删:
# 事故注入:激活态下删除插件数据表
mysql -u mybb -pq1w2e3r4 mybbdb -e "DROP TABLE mybb_hello_messages; SHOW TABLES LIKE '%hello%';"
实测回显:
Tables_in_mybbdb (%hello%)
(0 行结果 = 表已删除。)前台立即受影响:
curl -s -o /dev/null -w "forum:%{http_code} size:%{size_download}\n" http://localhost/index.php
实测回显:
forum:500 size:0
全站 500、响应 0 字节(白屏)。定位:看 Apache 错误日志(完整一条照抄):
[Fri Oct 30 14:23:25.051847 2026] [php:error] [pid 14053] [client 127.0.0.1:60936] PHP Fatal error: Uncaught mysqli_sql_exception: Table 'mybbdb.mybb_hello_messages' doesn't exist in /var/www/mybb/inc/db_mysqli.php:340\nStack trace:\n#0 /var/www/mybb/inc/db_mysqli.php(340): mysqli_query()\n#1 /var/www/mybb/inc/db_mysqli.php(801): DB_MySQLi->query()\n#2 /var/www/mybb/inc/plugins/hello.php(473): DB_MySQLi->simple_select()\n#3 /var/www/mybb/inc/class_plugins.php(142): hello_index()\n#4 /var/www/mybb/index.php(26): pluginSystem->run_hooks()\n#5 {main}\n thrown in /var/www/mybb/inc/db_mysqli.php on line 340
堆栈清晰指认事故链:index.php → pluginSystem->run_hooks() → 激活插件 hello.php(473) 查询了不存在的表。此时 ACP 前台页面同样 500(后台框架也走同一钩子),数据库直改是唯一出路——把 plugins 缓存行的激活数组清空:
# SQL 紧急停用全部插件
mysql -u mybb -pq1w2e3r4 mybbdb -e "UPDATE mybb_datacache SET cache='a:1:{s:6:\"active\";a:0:{}}' WHERE title='plugins';"
mysql -u mybb -pq1w2e3r4 mybbdb -N -e "SELECT cache FROM mybb_datacache WHERE title='plugins';"
# 恢复验证
curl -s -o /dev/null -w "forum_recovered:%{http_code}\n" http://localhost/index.php
实测回显:
a:1:{s:6:"active";a:0:{}}
forum_recovered:200
前台立即恢复 200。紧急停用是绕过 ACP 的救命操作,但属于"暴力"手段——它跳过了插件正常的 _deactivate() 清理逻辑,会留下残留。实测 hello 插件的残留与清理:
# 残留一:插件写入 mybb_settings 的设置项仍在
mysql -u mybb -pq1w2e3r4 mybbdb -e "SELECT sid,name FROM mybb_settings WHERE name LIKE 'hello%';"
# 清理设置项与设置组
mysql -u mybb -pq1w2e3r4 mybbdb -e "DELETE FROM mybb_settings WHERE name LIKE 'hello%'; SELECT ROW_COUNT() AS deleted;"
mysql -u mybb -pq1w2e3r4 mybbdb -e "DELETE FROM mybb_settinggroups WHERE name='hello'; SELECT ROW_COUNT() AS grp_deleted;"
# 复查清零
mysql -u mybb -pq1w2e3r4 mybbdb -N -e "SELECT COUNT(*) FROM mybb_settinggroups WHERE name LIKE '%hello%'; SELECT COUNT(*) FROM mybb_settings WHERE name LIKE 'hello%';"
实测回显:
sid name
301 hello_display1
302 hello_display2
deleted
2
grp_deleted
1
0
0
# 残留二:inc/settings.php 文件侧同步(按 6.4 用 ACP 重建 settings 缓存)
curl -s -b acp2.jar "http://localhost/admin/index.php?module=tools-cache&action=rebuild&title=settings&my_post_key=2f366dee58e7d05d421b91c12a3f5593" -o /dev/null -w "rebuild_settings:%{http_code}\n"
grep -c "hello_display" /var/www/mybb/inc/settings.php
# 最终状态复核
mysql -u mybb -pq1w2e3r4 mybbdb -N -e "SELECT cache FROM mybb_datacache WHERE title='plugins';"
curl -s -o /dev/null -w "forum_final:%{http_code}\n" http://localhost/index.php
实测回显:
rebuild_settings:302
0
a:1:{s:6:"active";a:0:{}}
forum_final:200
设置项 2 条、设置组 1 条全部清理,settings 文件无残留,论坛运行正常。若插件表仍在只是数据丢失,也可以走另一条路:从插件源码重新执行建表(或后台 Deactivate 再 Activate 让插件自建),不必紧急停用。
九、错误日志定位
9.1 Apache 日志(排障第一现场)
MyBB 站点的 Apache 日志由站点配置指定(ErrorLog ${APACHE_LOG_DIR}/mybb_error.log),实际落在:
ls -lh /var/log/apache2/ | grep -E "mybb|error\.log|access\.log"
实测回显:
-rw-r----- 1 root adm 0 Oct 30 12:11 access.log
-rw-r----- 1 root adm 776 Oct 30 12:12 error.log
-rw-r--r-- 1 root root 20K Oct 30 14:23 mybb_access.log
-rw-r--r-- 1 root root 7.3K Oct 30 14:23 mybb_error.log
-rw-r----- 1 root adm 0 Oct 30 12:11 other_vhosts_access.log
MyBB 站点流量集中在 mybb_access.log / mybb_error.log(站点专属),默认 access.log 为空。定位技巧:
# 看最近的 PHP 错误(Fatal/Parse/Warning 全在此)
tail -20 /var/log/apache2/mybb_error.log
# 按关键字过滤(表不存在类)
grep "doesn't exist" /var/log/apache2/mybb_error.log | tail -3
# 按时间定位:先从 access log 找到出错请求的精确时间点
tail -3 /var/log/apache2/mybb_access.log
实测回显(access log 末 3 行照抄):
127.0.0.1 - - [30/Oct/2026:14:23:49 +0000] "POST /admin/index.php HTTP/1.1" 200 9019 "-" "curl/7.81.0"
127.0.0.1 - - [30/Oct/2026:14:23:49 +0000] "GET /admin/index.php?module=tools-cache HTTP/1.1" 200 18713 "-" "curl/7.81.0"
127.0.0.1 - - [30/Oct/2026:14:23:49 +0000] "GET /admin/index.php?module=tools-cache&action=rebuild&title=settings&my_post_key=2f366dee58e7d05d421b91c12a3f5593 HTTP/1.1" 302 283 "-" "curl/7.81.0"
Fatal/Parse error 的完整样本已在 8.3 与 8.4 实录,日志行包含时间戳、错误级别、出错文件与行号、完整 PHP 堆栈,是 8.4 那类白屏事故的唯一可见线索。
9.2 PHP 错误配置
错误能进 Apache 日志依赖两项 php.ini 配置,实测值:
grep -E "^error_log|^log_errors|^display_errors" /etc/php/8.1/apache2/php.ini
实测回显:
display_errors = Off
log_errors = On
display_errors=Off + log_errors=On 是生产推荐组合:错误只进日志不暴露给访客(8.4 白屏时响应 0 字节正是 display_errors=Off 的表现)。若改成 display_errors=On,Fatal 详情会直接印在页面上——仅限本地调试。
9.3 MyBB 内置日志表(业务审计)
MyBB 把业务动作记录在 6 张专属日志表,行数实测总览:
mysql -u mybb -pq1w2e3r4 mybbdb -e "SELECT (SELECT COUNT(*) FROM mybb_adminlog) adminlog,(SELECT COUNT(*) FROM mybb_moderatorlog) modlog,(SELECT COUNT(*) FROM mybb_tasklog) tasklog,(SELECT COUNT(*) FROM mybb_mailerrors) mailerr,(SELECT COUNT(*) FROM mybb_spamlog) spamlog,(SELECT COUNT(*) FROM mybb_promotionlogs) promolog;"
实测回显:
adminlog modlog tasklog mailerr spamlog promolog
10 0 0 0 0 0
各表口径:adminlog(后台管理员操作,本文 8.2/8.4 的激活/重建都留了记录)、moderatorlog(版主操作)、tasklog(计划任务执行历史)、mailerrors(邮件发送失败)、spamlog、promotionlogs。后台对应入口:Tools & Maintenance → Logs 下的 Administrator Log / Moderator Log 等子页。抽查 adminlog 最近记录:
mysql -u mybb -pq1w2e3r4 mybbdb -e "SELECT uid,action,LEFT(data,40) AS data,FROM_UNIXTIME(dateline) AS at FROM mybb_adminlog ORDER BY dateline DESC LIMIT 6;"
实测回显:
uid action data at
1 rebuild a:1:{i:0;s:8:"settings";} 2026-10-30 14:23:49
1 activate a:2:{i:0;s:5:"hello";i:1;b:1;} 2026-10-30 14:22:11
1 rebuild a:1:{i:0;s:6:"forums";} 2026-10-30 14:21:49
1 activate a:2:{i:0;s:5:"hello";i:1;b:1;} 2026-10-30 13:05:14
1 deactivate a:2:{i:0;s:5:"hello";i:1;b:0;} 2026-10-30 13:05:14
1 reload a:1:{i:0;s:7:"plugins";} 2026-10-30 13:02:50
action 列与 8.2/6.3 的实测操作一一对应(activate b:1=激活、b:0=停用、rebuild=缓存重建)。排查"谁动了配置"时这张表是权威依据;日志修剪由计划任务 Log Pruning 按 ACP 设置保留期自动清理。
十、注意事项
- 先备份后动手:第五~八章所有 UPDATE/DELETE/DROP 前都应有 4.1 的全量备份兜底;恢复演练(4.3)本身也要先出新备份再 DROP。
- UPDATE 必带 WHERE:MyBB 表都有明确主键(
uid/sid/tid/title),批量更新前先SELECT同条件核对影响行数。 - salt 与 password 成对更新:只改
password不动salt是合法的(5.2),但手工拼哈希时盐值取错一个字符整条哈希即失效;推荐 5.3 的一条 UPDATE 让两者同步生成。 - 紧急停用插件是救命不是常规:8.4 的 SQL 停用会跳过
_deactivate()清理,事后务必补残留清理(设置项 + 设置组 + settings 文件重建);能进后台时永远优先用 ACP 正常 Deactivate。 - 恢复旧备份后检查插件表:备份版本若早于某插件安装时间,恢复后该插件表缺失会复现 8.4 的全站 500;恢复后先访问一次前台再交付。
- 备份文件含全量用户数据与口令哈希:
/var/backups/下的 dump 应收紧目录权限(仅 root/备份账号可读),避免与站点目录混放。 - 缓存直改后前台即生效:
mybb_datacache是实时读取的(默认 db 后端无独立文件缓存),SQL 改缓存行后无需重启任何服务;但settings缓存例外,在文件inc/settings.php(6.4)。
十一、常见问题(FAQ)
Q1:按 5.3 重置密码后,登录仍提示用户名密码不正确?
排查三处:① UPDATE 是否真的生效——SELECT salt,password FROM mybb_users WHERE username='admin'; 核对哈希已变;② salt 与哈希是否同源——用 5.1 的核对 SQL 重算 match_ 应为 1;③ 是否触发了登录锁定——检查 mybb_users.loginattempts(或 ACP 登录锁相关设置项),清零后重试。本文实测环境三项全部通过后前台/后台均一次登录成功(5.3/5.4 回显)。
Q2:从备份恢复数据库后,前台打开直接白屏(500)?
对照 8.4 事故链:大概率是备份版本早于某个已激活插件的安装时间、插件的表不在备份里。定位看 tail -20 /var/log/apache2/mybb_error.log 中形如 Table 'mybbdb.mybb_hello_messages' doesn't exist 的行(表名随插件而变),Fatal 堆栈里 inc/plugins/ 目录下的插件文件即肇事插件;用 8.4 的 SQL 紧急停用恢复前台,再决定补表或清理插件。
Q3:恢复后论坛能用,但版块/主题计数和统计数字明显不对?
计数是冗余存储,恢复过程不影响真实数据但可能滞后于备份时点。进 ACP Tools & Maintenance → Recount & Rebuild 依次执行 Rebuild Forum Counters 与 Recount Statistics(7.1/7.2 实测:posts 从手工篡改的 999 修复回 0、统计 numposts 从 0 修正为 2),无需改库。
Q4:后台打不开、怀疑插件冲突,但连插件页都 500?
走数据库路线:SELECT cache FROM mybb_datacache WHERE title='plugins'; 查看 active 数组里激活了哪些插件;按 8.4 清空 active 数组恢复;错误日志 mybb_error.log 里 Fatal 堆栈中 inc/plugins/ 下的文件名与行号可精确指认肇事插件。注意 8.3 的实测结论——坏插件文件(语法错误)只会进日志、不会打挂页面,能打挂页面的是"激活态插件运行时错误"。
Q5:只想备份/恢复单张表怎么办?
mysqldump 支持表级导出与导入:mysqldump -u mybb -pq1w2e3r4 mybbdb mybb_posts > posts.sql 导出,恢复用 mysql -u mybb -pq1w2e3r4 mybbdb < posts.sql(导出文件含 DROP TABLE+CREATE TABLE,导入即整表替换)。注意 4.3 的全量备份文件带 --databases 选项(含 CREATE DATABASE 语句),单表导出不带。
Q6:定时备份任务到点没生成文件?
按序检查:crontab -l 确认条目存在且 % 已转义为 \%(4.2 注意事项);手动执行条目里的命令观察输出(4.2 的 daily 演练即此目的,实测生成 136K 文件);确认 cron 守护进程在跑(systemctl is-active cron 应为 active);检查 /var/log/apache2 之外的系统日志 /var/log/syslog 中 CRON 行有无报错。
十二、参考链接
- MyBB 官方管理员文档(维护工具/日志/备份依据):https://docs.mybb.com/1.8/administration/
- MyBB 官方 FAQ(数据库错误类):https://docs.mybb.com/1.8/faq/database-errors/
- MariaDB mysqldump 官方文档(备份参数依据):https://mariadb.com/kb/en/mysqldump/
- MariaDB mysqlcheck 官方文档(表维护依据):https://mariadb.com/kb/en/mysqlcheck/
- Ubuntu cron 定时任务官方手册(crontab 语法依据):https://manpages.ubuntu.com/manpages/jammy/man5/crontab.5.html
- 本站姊妹篇:《MyBB 1.8.41 介绍与选型指南》、《Ubuntu 22.04 安装 MyBB 指南》、《MyBB 1.8.41 配置参数详解》