Limbas 7.1.15 常用运维命令与排障实操
Limbas 7.1.15 运维实操实测:cli.php/cron.php 计划任务与 8 个命令类、REST /admin/jobs 管理接口、psql/pg_dump 数据库侧运维、三通道备份与恢复演练、整包升级替换与补丁重放演练,含 10 条真实报错回显的排障实录
Limbas 7.1.15 常用运维命令与排障实操
目标:把 Limbas 7.1.15 的日常运维面——服务健康检查、计划任务命令行(
cli.php/cron.php与 8 个命令类)、REST 管理接口/admin/jobs、数据库侧 SQL 运维、三通道备份与恢复演练、整包升级替换与补丁重放——全部用真实命令与实测回显讲清,并沉淀升级与运行中真实踩到的坑。所有命令与输出均来自真实服务器 limbas-server(Ubuntu 22.04.5 + Apache 2.4.52 + PHP 8.3.36 + PostgreSQL 14.24,Limbas 7.1.15,安装路径/opt/limbas/openlimbas-7.1.15,数据库limbasdb)实测。安装过程见《Ubuntu 22.04 安装 Limbas 7.1.15 指南》,参数含义见《Limbas 7.1.15 配置参数详解》,软件背景见《Limbas 介绍与选型指南》。
一、环境信息
| 项目 | 值 |
|---|---|
| 操作系统 | Ubuntu 22.04.5 LTS(主机名 limbas-server,IP 10.89.59.2) |
| Web 服务器 | Apache/2.4.52 (Ubuntu),mpm_prefork + libapache2-mod-php8.3,监听 80 |
| PHP | PHP 8.3.36 (cli)(ondrej/php PPA,与 apache2 模块同版本) |
| 数据库 | PostgreSQL 14.24(Ubuntu 22.04 默认源),库 limbasdb,应用角色 limbas |
| Limbas | openlimbas 7.1.15(limbas_src/lib/version.inf 实测 7.1.15.2519;lmb_dbpatch 最新补丁 id=726) |
| 安装路径 | /opt/limbas/openlimbas-7.1.15(Web 根为其 public/ 子目录) |
| 应用备份目录 | /opt/limbas/openlimbas-7.1.15/dependent/BACKUP/ |
| 运维日志 | /var/log/apache2/limbas_access.log、limbas_error.log;cron 输出 /var/log/limbas-cron.log |
| 演示账号 | 应用管理员 admin / q1w2e3r4;数据库角色 limbas / q1w2e3r4;系统 root |
| 系统规模实测 | public schema 152 张表、lmb_umgvar 143 项全局配置、lmb_crontab 4 个作业、lmb_dbpatch 724 条补丁记录 |
二、运维工具链总览与前置条件
Limbas 没有独立的运维控制台命令(不存在类似 bin/console 的管理 CLI),日常运维由四条命令线支撑:系统服务命令(systemctl/apache2ctl)、应用任务命令行(limbas_src/cli.php、limbas_src/cron.php 与 8 个命令类)、REST 管理接口(/admin/jobs 资源路由)、数据库侧 SQL(psql/pg_dump 直改 lmb_* 系统表)。Web 管理界面(配置中心、备份页、作业页)与命令行操作的是同一份数据,可任选入口。
| 运维对象 | 命令/入口 | 频率 |
|---|---|---|
| 服务进程(Apache/PostgreSQL/cron) | systemctl / apache2ctl | 巡检 |
| 应用健康与版本 | curl 登录页 + version.inf + lmb_dbpatch | 每日 |
| 计划任务(索引/OCR/备份/提醒等) | php limbas_src/cli.php <job-id|命令类> | 按需/crontab |
| 全量作业批跑 | php limbas_src/cron.php | 每分钟(可选) |
| 作业增删改(REST) | PUT/GET/DELETE /admin/jobs[/{id}[/run]] | 按需 |
| 全局配置 | Web action=setup_umgvar 或 SQL 直改 lmb_umgvar | 按需 |
| 备份 | Web 备份页 / cli.php Backup -c / pg_dump | 每日 |
| 升级 | 官方 tar 整包替换 + 登录触发 Updater 补丁 | 按版本 |
| 日志 | limbas_access.log / limbas_error.log | 巡检 |
前置条件:Limbas 已按《Ubuntu 22.04 安装 Limbas 7.1.15 指南》完成安装并可登录;本文命令默认在 root 下执行,涉及应用写操作的(作业、备份产物)注意产物属主(见 9.9)。
💡 技术拓展:Limbas 计划任务的驱动方式不止一种。常见三种对比——
驱动方式 原理 适用场景 系统 crontab 逐作业调 cli.php <id>每个 lmb_crontab作业对应一条 crontab 行需要按作业分粒度记日志、单独停启 系统 crontab 每分钟调 cron.php应用自己遍历全部 active 作业判断到点执行 作业多、不想改一次配置动一次系统 crontab REST GET /admin/jobs/{id}/runHTTP 触发单作业 与外部编排系统(如 CI、告警平台)集成 本文实际采用第一种(逐作业 crontab),理由:作业日志可分文件落盘、单作业失败不影响其他作业的调度记录;
cron.php批跑方式在 4.4 节同样给出实测。
三、服务管理与健康检查
服务面只有 Apache、PostgreSQL 两个常驻进程(外加驱动计划任务的 cron)。本节命令是每日巡检与变更后验证的最小集合。
3.1 服务状态速查
systemctl is-active apache2
systemctl is-active postgresql
systemctl is-enabled apache2
systemctl is-enabled postgresql
实测回显:
active
active
enabled
enabled
看进程详情:
systemctl status apache2 --no-pager | head -5
● apache2.service - The Apache HTTP Server
Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor preset: enabled)
Active: active (running) since Mon 2026-11-02 22:27:06 UTC; 3h 35min ago
Docs: https://httpd.apache.org/docs/2.4/
Main PID: 19156 (apache2)
改完 vhost 或 php.ini 后先语法检查再重载:
apachectl configtest
systemctl reload apache2
实测回显(AH00558 为未设全局 ServerName 的告警,不影响运行,可在 apache2.conf 加 ServerName limbas-server 消除):
AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 10.89.59.2. Set the 'ServerName' directive globally to suppress this message
Syntax OK
3.2 版本与补丁层级速查
apache2ctl -v | head -2
php -v | head -1
su - postgres -c "psql --version"
cat /opt/limbas/openlimbas-7.1.15/limbas_src/lib/version.inf; echo
实测回显:
Server version: Apache/2.4.52 (Ubuntu)
Server built: 2026-10-08T19:59:46
PHP 8.3.36 (cli) (built: Oct 21 2026 14:31:50) (NTS)
psql (PostgreSQL) 14.24 (Ubuntu 14.24-0ubuntu0.22.04.1)
7.1.15.2519
Limbas 的「代码版本」看 version.inf,「数据库结构版本」看 lmb_dbpatch 表最大行,两者一致才算升级闭环(机制见第八章):
su - postgres -c "psql -d limbasdb -c \"select id, major, version, revision, status from lmb_dbpatch order by id desc limit 3;\""
su - postgres -c "psql -d limbasdb -tAc 'select count(*) from lmb_dbpatch;'"
id | major | version | revision | status
-----+-------+---------+----------+--------
726 | 7 | 1 | 15 | t
725 | 7 | 1 | 14 | t
724 | 7 | 1 | 13 | t
(3 rows)
724
3.3 HTTP 与数据库连通性
curl -s -o /dev/null -w "GET / -> %{http_code}, %{size_download} bytes\n" http://localhost/
curl -s http://localhost/ | grep -o '<title>[^<]*</title>'
pg_isready -h localhost -p 5432
实测回显(未登录时登录页标题带 lmb_umgvar id=110 配置的自定义前缀 Limbas-Demo - ,可顺带验证全局配置生效):
GET / -> 200, 1959 bytes
<title>Limbas-Demo - Login</title>
localhost:5432 - accepting connections
3.4 日志巡检
tail -n 4 /var/log/apache2/limbas_access.log
tail -n 6 /var/log/apache2/limbas_error.log
实测回显(access 节选;error 为未认证 GET 请求触发的 PHP Warning,属 7.x 遗留代码噪音、非致命,判读原则见 9.9):
127.0.0.1 - - [03/Nov/2026:01:58:20 +0000] "GET / HTTP/1.1" 200 2240 "-" "curl/7.81.0"
127.0.0.1 - - [03/Nov/2026:02:02:15 +0000] "GET / HTTP/1.1" 200 2240 "-" "curl/7.81.0"
[Tue Nov 03 02:02:15.650539 2026] [php:warn] [pid 19424] [client 127.0.0.1:50950] PHP Warning: Undefined array key "PHP_AUTH_PW" in /opt/limbas/openlimbas-7.1.15/limbas_src/lib/auth/AuthDefault.php on line 90
[Tue Nov 03 02:02:15.650555 2026] [php:warn] [pid 19424] [client 127.0.0.1:50950] PHP Warning: session_name(): Session name cannot be changed when a session is active in /opt/limbas/openlimbas-7.1.15/limbas_src/lib/auth/Session.php on line 26
[Tue Nov 03 02:02:15.697271 2026] [php:warn] [pid 19163] [client 127.0.0.1:50958] PHP Warning: Undefined array key "authId" in /opt/limbas/openlimbas-7.1.15/limbas_src/lib/auth/Auth.php on line 121
四、计划任务命令行:cli.php 与 cron.php
Limbas 的作业体系数据在 lmb_crontab 表(4 个作业:2 个 INDIZE、1 个 TEMPLATE、1 个 OCR),执行入口有两个:单作业/命令类用 cli.php,批跑全部到点作业用 cron.php。本节逐条实测。
4.1 cli.php 用法与无参回显
cli.php 的入口逻辑(实测源码 limbas_src/cli.php 节选):第一个参数是数字则按 lmb_crontab.id 跑作业,是字符串则按命令类名跑 \Limbas\admin\tools\cron\commands\<Name>,命令类还支持 -c/--config <json> 覆盖作业配置:
$command = $argv[1];
if(empty($command)) {
echo 'Command or job id not specified' . PHP_EOL;
exit(1);
}
if(is_numeric($command)) {
$command = intval($command);
}
$status = $limbas->runCommand($command, $argv);
exit($status);
不带参数执行的实测回显(exit 1,可直接当用法说明):
cd /opt/limbas/openlimbas-7.1.15/limbas_src
php cli.php; echo "exit=$?"
PHP Warning: Undefined array key 1 in /opt/limbas/openlimbas-7.1.15/limbas_src/cli.php on line 19
Command or job id not specified
exit=1
4.2 按作业 ID 执行
先看待跑作业清单(该 SQL 也是 REST/Web 的数据源):
su - postgres -c "psql -d limbasdb -c \"select id, type, active, description, config, cron_minutes, cron_hours from lmb_crontab order by id;\""
实测回显(job4 的 config 已是空数组——它原本配置指向 demo 库不存在的字段,清理过程见 9.5):
id | type | active | description | config | cron_minutes | cron_hours
----+----------+--------+------------------+----------------------------------------------+--------------+------------
1 | INDIZE | t | Indexing (1) | {"includeSubdirs":true,"files":["2"]} | 0 | 1
2 | TEMPLATE | t | TEMPLATE (1) | {"template":"\/EXTENSIONS\/ocr\/update.job"} | 0 | 1
3 | OCR | t | OCR (1) | {"files":["1"]} | 0 | 1
4 | INDIZE | t | indize-feldtypen | [] | 0 | 3
(4 rows)
跑作业 1(文件结构索引):
php cli.php 1 > /tmp/cli1.out 2>&1; echo "exit=$?"; wc -c /tmp/cli1.out
head -c 600 /tmp/cli1.out; echo; echo '...TAIL...'; tail -c 300 /tmp/cli1.out
实测回显(进度以 HTML 片段输出,Dokumente 即被索引的文件目录;尾部是 7.1.15 的一个真实 SQL 缺陷——索引历史写入语句多一个尾逗号,索引本身已完成,判读见 9.6):
exit=0
1080 /tmp/cli1.out
PHP Warning: Trying to access array offset on null in /opt/limbas/openlimbas-7.1.15/limbas_src/Limbas.php on line 235
PHP Warning: Undefined global variable $umgvar in /opt/limbas/openlimbas-7.1.15/limbas_src/lib/include_mbstring.lib on line 34
PHP Warning: Trying to access array offset on null in /opt/limbas/openlimbas-7.1.15/limbas_src/lib/include_mbstring.lib on line 34
<script>$('#indcontainer').show();</script>
<div class='lmb-progress-container'>
<div id='file_2_desc'>Dokumente</div>
<div class='lmb-progress'>
<span id='file_2_valtext' class='lmb-progress-valtext'></span>
<span id='file_2_val' class='lmb-progress-val'></span>
</div>
</div>Error: ERROR: syntax error at or near ")"
LINE 1: ...NUM,JOB) VALUES(1,'Filestructure Index',TRUE,0.0032,'',0,0,)
^ for query INSERT INTO LMB_INDIZE_HISTORY (ID,ACTION,RESULT,USED_TIME,MESSAGE,INUM,JNUM,JOB) VALUES(1,'Filestructure Index',TRUE,0.0032,'',0,0,)
跑作业 4(清理配置后)与不存在的作业 99:
php cli.php 4 2>&1; echo "exit=$?"
php cli.php 99 2>&1 | head -4; echo "exit=$?"
实测回显(job4 已无报错;job99 只留一条 Warning 就静默返回 exit=0——CLI 对不存在的作业 ID 不报错,脚本化时要自己核对 lmb_crontab):
PHP Warning: Trying to access array offset on null in /opt/limbas/openlimbas-7.1.15/limbas_src/Limbas.php on line 235
PHP Warning: Undefined global variable $umgvar in /opt/limbas/openlimbas-7.1.15/limbas_src/lib/include_mbstring.lib on line 34
PHP Warning: Trying to access array offset on null in /opt/limbas/openlimbas-7.1.15/limbas_src/lib/include_mbstring.lib on line 34
exit=0
PHP Warning: Trying to access array offset on null in /opt/limbas/openlimbas-7.1.15/limbas_src/Limbas.php on line 235
exit=0
4.3 命令类直调与 Backup 全量备份
limbas_src/admin/tools/cron/commands/ 下共 8 个命令类(实测目录清单):
Backup.php Datasync.php Indize.php Ocr.php Reminder.php Rsync.php StructureSync.php Template.php
不带 -c 时命令类读取对应作业的配置;带 -c 可用 JSON 直接传参。以 Backup 类做一次完整数据备份实测:
php cli.php Backup -c '{"backupType":"complete_data_backup","backupMedium":"file","backupTarget":"/opt/limbas/openlimbas-7.1.15/dependent/BACKUP/","backupAlive":7}' > /tmp/backup.out 2>&1
echo "exit=$?"; wc -c /tmp/backup.out
ls -la /opt/limbas/openlimbas-7.1.15/dependent/BACKUP/
实测回显(exit=0,输出仅 119 字节即一行 legacy Warning,成功与否以产物文件为准;新产物 26_11_03_02_35.DATA.gz 522064 字节,命名规则 YY_MM_DD_HH_MM.DATA.gz):
exit=0
119 /tmp/backup.out
total 2732
drwxrwxrwx 2 www-data www-data 4096 Nov 3 02:02 .
drwxrwxrwx 8 www-data www-data 4096 Aug 12 12:19 ..
-rw-rw-rw- 1 www-data www-data 38 Aug 12 12:19 .gitignore
-rw-r--r-- 1 root root 171525 Nov 2 22:39 26_11_02_39_40.DATA.gz
-rw-r--r-- 1 root root 171561 Nov 2 22:41 26_11_02_41_20.DATA.gz
-rw-r--r-- 1 www-data www-data 171592 Nov 2 22:41 26_11_02_41_26.DATA.gz
-rw-r--r-- 1 root root 522064 Nov 3 02:02 26_11_03_02_35.DATA.gz
-rw-r--r-- 1 root root 521930 Nov 2 23:24 26_11_03_24_29.DATA.gz
-rw-r--r-- 1 root root 522043 Nov 2 23:24 26_11_03_24_37.DATA.gz
-rw-rw-rw- 1 www-data www-data 174536 Aug 12 12:19 clean.tar.gz
-rw-r--r-- 1 www-data www-data 518754 Aug 12 12:20 demo.tar.gz
Backup 类接受 4 个配置键(实测源码 Backup.php):backupType(complete_data_backup/incremental_data_backup/log_backup)、backupMedium(file→1、tape→2)、backupTarget(目标目录)、backupAlive(保留天数,0/缺省则不过期)。注意键名是 backupMedium 不是 backupMedia,写错不报错但备份不落目标位(见 9.3)。每次成功备份还会向 lmb_history_backup 表写一行台账:
su - postgres -c "psql -d limbasdb -c 'select id, erstdatum, label, action, result, medium, size from lmb_history_backup order by id;'"
id | erstdatum | label | action | result | medium | size
----+----------------------------+-------+-----------+--------+----------------+------
1 | 2026-11-02 23:24:30.080954 | | SAVE DATA | t | DATA2611032429 | 510
2 | 2026-11-02 23:24:37.278181 | | SAVE DATA | t | DATA2611032437 | 510
3 | 2026-11-03 02:02:36.402559 | | SAVE DATA | t | DATA2611030235 | 510
(3 rows)
第 3 行正是上面 CLI 备份的台账(medium 列即产物文件名去扩展名,size 单位 KB)。
其余命令类以 Reminder 为例(无到期提醒数据时只留 Warning、exit=0):
php cli.php Reminder 2>&1 | head -6; echo "exit=$?"
PHP Warning: Trying to access array offset on null in /opt/limbas/openlimbas-7.1.15/limbas_src/Limbas.php on line 235
exit=0
4.4 cron.php 批跑全部到点作业
cron.php 与 cli.php 共用引导,只是直接调 Limbas::runCron()(实测源码全文 17 行,核心即末两行):
$request = Request::createFromGlobals();
$limbas = Limbas::get($request);
$limbas->runCron();
runCron() 内部 LimbasCron::loadJobs() 取 CronJob::active() 全部 active 作业按分钟匹配执行。实测直接跑:
timeout 120 php cron.php > /tmp/cronall.out 2>&1; echo "exit=$?"; wc -l /tmp/cronall.out
grep -c 'PHP Warning' /tmp/cronall.out
head -4 /tmp/cronall.out
实测回显(exit=0;20 行输出全部是 Warning——filestructure.lib/jobs_ext.lib/include.lib 等 legacy 代码在 CLI 上下文缺全局变量的噪音,不影响作业执行,判读原则见 9.9):
exit=0
20 /tmp/cronall.out
20
PHP Warning: Trying to access array offset on null in /opt/limbas/openlimbas-7.1.15/limbas_src/Limbas.php on line 235
PHP Warning: Trying to access array offset on null in /opt/limbas/openlimbas-7.1.15/limbas_src/extra/explorer/filestructure.lib on line 26
PHP Warning: Undefined variable $action in /opt/limbas/openlimbas-7.1.15/limbas_src/extra/explorer/filestructure.lib on line 32
PHP Warning: Undefined variable $gmimetypes in /opt/limbas/openlimbas-7.1.15/limbas_src/admin/tools/jobs_ext.lib on line 20
4.5 系统 crontab 部署
本机初始未装 cron(which crontab 无输出,dpkg -l cron 显示 un 未安装状态)。安装并注册作业:
DEBIAN_FRONTEND=noninteractive apt-get install -y cron
实测回显(输出节选(实测首尾);policy-rc.d denied 表示包安装脚本被策略阻止自启,必须手工 enable+start,见 9.8):
Setting up cron (3.0pl1-137ubuntu3) ...
Adding group `crontab' (GID 109) ...
Done.
invoke-rc.d: policy-rc.d denied execution of start.
Created symlink /etc/systemd/system/multi-user.target.wants/cron.service → /lib/systemd/system/cron.service.
/usr/sbin/policy-rc.d returned 101, not running 'start cron.service'
systemctl enable cron
systemctl is-active cron
Synchronizing state of cron.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install enable cron
inactive
/etc/cron.d/limbas 按 lmb_crontab 的调度(job1 每日 01:00、job4 每日 03:00)落盘,属主 root、权限 644:
# Limbas 7.1.15 计划任务: 驱动 lmb_crontab 作业(job1 01:00, job4 03:00)
SHELL=/bin/bash
0 1 * * * www-data php /opt/limbas/openlimbas-7.1.15/limbas_src/cli.php 1 >> /var/log/limbas-cron.log 2>&1
0 3 * * * www-data php /opt/limbas/openlimbas-7.1.15/limbas_src/cli.php 4 >> /var/log/limbas-cron.log 2>&1
启动并验证守护进程:
systemctl restart cron
systemctl is-active cron
journalctl -u cron --no-pager -n 3 | tail -3
实测回显:
active
Nov 03 02:04:57 limbas-server systemd[1]: Started Regular background program processing daemon.
Nov 03 02:04:57 limbas-server cron[25483]: (CRON) INFO (pidfile fd = 3)
Nov 03 02:04:57 limbas-server cron[25483]: (CRON) INFO (Running @reboot jobs)
⚠️ 注意:
lmb_crontab表里的 cron 表达式只是「应用内配置」,Limbas 自身不常驻调度进程;要么按本节把它翻译成系统 crontab(逐作业),要么每分钟一条* * * * * www-data php .../cron.php(批跑)。两者选一,不要同时启用同一作业,否则双跑。
五、REST 管理接口:/admin/jobs
作业管理除 Web 界面外有一组 REST 路由(实测源码 limbas_src/routes/admin.php 全文):
Route::group(['prefix' => 'admin', 'name' => 'admin.'], function () {
Route::resource('jobs', JobController::class, 'jobs', options: ['exclude' => ['show']]);
Route::get('jobs/{id}/run', [JobController::class, 'run'])->name('jobs.run');
});
即支持 GET/POST/PUT/DELETE /admin/jobs[/{id}] 与 GET /admin/jobs/{id}/run。鉴权复用应用会话:先用 admin / q1w2e3r4 登录拿 PHPSESSID Cookie,后续请求带 Cookie 即可。
5.1 登录取会话
curl -s -c /tmp/lmb_cookie.txt -o /tmp/login.html -w "POST /index.php -> %{http_code}, %{size_download} bytes\n" \
-d 'username=admin&password=q1w2e3r4' http://localhost/index.php
grep -o '<title>[^<]*</title>' /tmp/login.html | head -1
实测回显(111KB 主界面 + 标题带版本号即登录成功):
POST /index.php -> 200, 111440 bytes
<title>Limbas Enterprise Unifying Framework V 7.1.15</title>
5.2 触发作业运行
curl -s -b /tmp/lmb_cookie.txt -o /tmp/run1.html -w "GET /admin/jobs/1/run -> %{http_code}, %{size_download} bytes\n" http://localhost/admin/jobs/1/run
cat /tmp/run1.html
实测回显(461 字节 HTML 进度片段,0 done 表示本轮文件索引处理计数;同一请求在 error log 留下与 4.2 节相同的 INDIZE_HISTORY 尾逗号报错,两通道同缺陷):
GET /admin/jobs/1/run -> 200, 461 bytes
<script>$('#indcontainer').show();</script>
<div class='lmb-progress-container'>
<div id='file_2_desc'>Dokumente</div>
<div class='lmb-progress'>
<span id='file_2_valtext' class='lmb-progress-valtext'></span>
<span id='file_2_val' class='lmb-progress-val'></span>
</div>
</div><script>$('#file_2_val').css('width', '100%');$('#file_2_valtext').html('0 done');</script>
5.3 修改作业(PUT 必须全量键)
JobController::update() 逐键取表单参数赋给强类型属性(实测源码节选):
$job->cronMinutes = $request->get('cron_minutes');
$job->cronHours = $request->get('cron_hours');
$job->cronMonthdays = $request->get('cron_monthdays');
$job->cronMonths = $request->get('cron_months');
$job->cronWeekdays = $request->get('cron_weekdays');
$job->active = boolval($request->get('active'));
$job->description = $request->get('description', '');
$job->config->backupType = $request->get('backup_type', '');
$job->config->backupMedium = $request->get('backup_medium', '');
$job->config->backupTarget = $request->get('backup_target', '');
$job->config->backupAlive = $request->get('backup_alive', 0);
$job->userId = (int)$request->get('jobuser');
因此 PUT 必须 x-www-form-urlencoded 且带齐全套键(cron_minutes/cron_hours/cron_monthdays/cron_months/cron_weekdays/active/description/include_subdirs/template/backup_type/backup_medium/backup_target/backup_alive/jobuser),且 backup_alive 必须是数字。以作业 1 做一次与现值一致的幂等回写实测:
curl -s -b /tmp/lmb_cookie.txt -o /tmp/put1.json -w "PUT /admin/jobs/1 -> %{http_code}\n" -X PUT \
-d 'cron_minutes=0&cron_hours=1&cron_monthdays=*&cron_months=*&cron_weekdays=*&active=1&description=Indexing (1)&include_subdirs=1&template=&files[]=2&backup_type=&backup_medium=&backup_target=&backup_alive=0&jobuser=1' \
http://localhost/admin/jobs/1
head -c 500 /tmp/put1.json; echo
实测回显(success:true + 回传新行 HTML,0 1 * * * 即调度串):
PUT /admin/jobs/1 -> 200
{"success":true,"html":"\u003Ctr id=\u0022job-1\u0022\u003E\n \u003Ctd\u003E\u003Ci class=\u0022fas fa-pencil cursor-pointer link-primary\u0022 data-url=\u0022http:\/\/localhost\/admin\/jobs\/1\/edit\u0022 data-bs-toggle=\u0022modal\u0022 data-bs-target=\u0022#modal-jobs\u0022 data-id=\u00221\u0022\u003E\u003C\/i\u003E\u003C\/td\u003E\n \u003Ctd\u003E1\u003C\/td\u003E\n \u003Ctd\u003EINDIZE\u003C\/td\u003E\n \u003Ctd\u003E\u003C\/td\u003E\n \u003Ctd\u003E0 1 * * *\u003C\/td\u003E\
两个失败形态的实测回显(判读见 9.7):
curl -s -b /tmp/lmb_cookie.txt -X PUT -H 'Content-Type: application/json' -d '{"description":"x"}' http://localhost/admin/jobs/4 -o /tmp/put4b.html
grep -m2 -oE 'TypeError[^<]{0,140}' /tmp/put4b.html
TypeError
error log 中的完整异常(缺键 → cronMinutes 收到 null;backup_alive= 空串 → 字符串赋给 int 属性):
limbas.ERROR: Cannot assign string to property Limbas\admin\tools\cron\CronConfig::$backupAlive of type int
limbas.ERROR: Cannot assign null to property Limbas\admin\tools\cron\CronJob::$cronMinutes of type string
按正确姿势补齐 backup_alive=0 后重放作业 4 的 PUT,实测成功:
PUT /admin/jobs/4 -> 200
{"success":true,"html":"\u003Ctr id=\u0022job-4\u0022\u003E\n \u003Ctd\u003E\u003Ci class=\u0022fas fa-pencil cursor-pointer link-primary\u0022 data-url=\u0022http:\/\/localhost\/admin\/jobs\/4\/edit\u0022 data-bs-toggle=\u0022modal\u0022 data-bs-target=\u0
5.4 作业列表接口的已知缺陷
GET /admin/jobs(列表)实测返回 HTTP 200 但页面是 Server Error:
curl -s -b /tmp/lmb_cookie.txt -o /tmp/jobs_list.html -w "GET /admin/jobs -> %{http_code}, %{size_download} bytes\n" http://localhost/admin/jobs
grep -m1 -oE 'The controller must return.{0,160}' /tmp/jobs_list.html
GET /admin/jobs -> 200, 2546 bytes
The controller must return a "Symfony\Component\HttpFoundation\Response" object but it returned a string ("
error log 完整堆栈(JobController::index() 用 ob_get_clean() 返回 string 而非 Response 对象,7.1.15 框架缺陷;列表请走 Web 界面 action=setup_cron 或直接查 lmb_crontab 表):
limbas.ERROR: The controller must return a "Symfony\\Component\\HttpFoundation\\Response" object but it returned a string ("\n<script src="assets/vendor/select2/select2.full.min.js"></script>\n<link href="assets/vendor/select2/select2.min.css" rel="stylesheet">\n\n<div class="container-fluid p-3">\n \n <div class="card mb-3">\n <div class="card-body">\n <p>Nutz...").
#0 /opt/limbas/openlimbas-7.1.15/vendor/symfony/http-kernel/HttpKernel.php(183): ()
#1 /opt/limbas/openlimbas-7.1.15/vendor/symfony/http-kernel/HttpKernel.php(76): Symfony\Component\HttpKernel\HttpKernel->handleRaw()
#2 /opt/limbas/openlimbas-7.1.15/limbas_src/Limbas.php(99): Symfony\Component\HttpKernel\HttpKernel->handle()
#3 /opt/limbas/openlimbas-7.1.15/limbas_src/index.php(21): Limbas\Limbas->handle()
#4 /opt/limbas/openlimbas-7.1.15/public/index.php(12): require_once('...')
#5 {main}
六、数据库侧 SQL 运维
Limbas 的配置、作业、用户、会话、补丁台账全在 PostgreSQL limbasdb 的 lmb_* 系统表里,SQL 通道是命令行/Web 之外的第三入口,也是排障时的「真相源」。
6.1 连接身份切换实录
root 直接 psql 会被 PostgreSQL 的 peer 认证拦下(两种典型报错,实测逐行照抄):
psql -U postgres -d limbasdb -c 'select 1;'
psql -d limbasdb -c 'select 1;'
psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: FATAL: Peer authentication failed for user "postgres"
psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: FATAL: role "root" does not exist
正确姿势一:切到 postgres 系统用户(走 pg_hba.conf 的 peer 行):
su - postgres -c "psql -d limbasdb -tAc 'select current_user, current_database();'"
postgres|limbasdb
正确姿势二:用应用角色走 TCP(pg_hba.conf 对 127.0.0.1/32 配的是 scram-sha-256,口令即 include_db.lib 里的 q1w2e3r4):
PGPASSWORD=q1w2e3r4 psql -h 127.0.0.1 -U limbas -d limbasdb -tAc 'select current_user, current_database();'
limbas|limbasdb
权限边界实测:limbas 角色非超管,不能建库(备份恢复演练建目标库必须借道 postgres,见 7.5):
PGPASSWORD=q1w2e3r4 createdb -h 127.0.0.1 -U limbas testdb
createdb: error: database creation failed: ERROR: permission denied to create database
6.2 核心系统表速查
| 表 | 作用 | 实测规模 |
|---|---|---|
| lmb_umgvar | 全局配置(143 项,值在 norm 列) | 143 行 |
| lmb_crontab | 计划作业定义 | 4 行(全 active) |
| lmb_userdb | 应用用户(bcrypt 口令) | 3 行 |
| lmb_session | 登录会话 | 6 行(清理见 6.3) |
| lmb_dbpatch | 数据库补丁台账(版本判据) | 724 行,top=726/7.1.15/t |
| lmb_history_backup | 备份台账 | 3 行 |
| lmb_auth_token | API 令牌 | 0 行 |
会话表结构实测(\d lmb_session,清理过期会话按 erstdatum/logout 两列):
Table "public.lmb_session"
Column | Type | Collation | Nullable | Default
--------------------+-----------------------------+-----------+----------+-------------------
id | character varying(128) | | not null |
user_id | integer | | |
group_id | integer | | |
logout | boolean | | | false
erstdatum | timestamp without time zone | | | CURRENT_TIMESTAMP
ip | character varying(20) | | |
filestruct_changed | boolean | | | false
table_changed | boolean | | | false
snap_changed | boolean | | | false
Indexes:
"lmb_session_pkey" PRIMARY KEY, btree (id)
样例数据实测(cli- 前缀行是 CLI 会话,ip 记 noip):
id | user_id | group_id | logout | erstdatum | ip | filestruct_changed | table_changed | snap_changed
------------------------------+---------+----------+--------+----------------------------+-----------+--------------------+---------------+--------------
bcaj4boe377vpp6r4r26jh67tn | 1 | 0 | f | 2026-11-02 22:45:41.994209 | 127.0.0.1 | f | f | f
u2824uupcojuple7bkai5s4ekc | 1 | 0 | f | 2026-11-02 22:58:19.829499 | 127.0.0.1 | f | f | f
cli-e5cab71de172505d37590d83 | 1 | 0 | f | 2026-11-02 22:59:00.59789 | noip | f | f | f
(3 rows)
6.3 常用运维 SQL
查关键全局配置(路径类变量 id=3/21/27/59 出厂值仍是 vendor 目录 /srv/www/htdocs/projects/openlimbas/,与实装路径不符时应按《Limbas 7.1.15 配置参数详解》修正):
su - postgres -c "psql -d limbasdb -c \"select id, beschreibung, norm from lmb_umgvar where id in (3,21,27,59,110,111,134) order by id;\""
实测回显(宽列有删节):
id | beschreibung | norm
-----+----------------------------------------------------------------------------------------+--------------------------------------------------------------------
3 | absolute path of installation | /srv/www/htdocs/projects/openlimbas/dependent/
21 | default path of Backup | localhost:////srv/www/htdocs/projects/openlimbas/dependent/BACKUP/
27 | Base URL of installation |
59 | path to crontab | /var/spool/cron/tabs/webuser
110 | custom title %s | Limbas-Demo - %s
111 | check for updates (0/1) | 0
134 | show update page to user or try automatically in background (background / foreground) | foreground
(7 rows)
查用户(注意列名是 user_id/username/name/vorname,没有 id/lastname 列,按惯性写 SELECT id 会报错):
su - postgres -c "psql -d limbasdb -c 'select user_id, username, name, vorname from lmb_userdb order by user_id;'"
user_id | username | name | vorname
---------+----------+---------------+---------
1 | admin | Administratos | Adminus
5 | landros | Soffos | Landros
8 | Katinka | Parabel | Katinka
(3 rows)
清理过期/已登出会话(实测当前 6 个会话均为活跃新会话,DELETE 0 属正常结果;长期运行后该语句可回收 lmb_session):
su - postgres -c "psql -d limbasdb -tAc 'select count(*) from lmb_session;'"
su - postgres -c "psql -d limbasdb -c \"delete from lmb_session where logout = true or erstdatum < current_timestamp - interval '1 day';\""
su - postgres -c "psql -d limbasdb -tAc 'select count(*) from lmb_session;'"
6
DELETE 0
6
核对表规模(升级/恢复后验证用,实测 152):
su - postgres -c "psql -d limbasdb -tAc \"select count(*) from pg_tables where schemaname='public';\""
152
6.4 SQL 直改配置的生效方式
Web 配置中心(index.php?action=setup_umgvar,实测登录态 GET 返回 200、111447 字节)读写的不外乎 lmb_umgvar.norm,SQL 直改同样生效,区别只在生效时机:多数界面类变量下次请求即读新值,而 update_mode(id=134)这类流程变量改完立刻改变登录行为——第八章的补丁重放演练就是用 UPDATE lmb_umgvar SET norm='background' WHERE id=134 打开后台自动升级开关的,实测回显:
id | norm
-----+------------
134 | background
(1 row)
UPDATE 1
七、备份与恢复实操
💡 技术拓展:本文涉及三种备份形态,能力边界不同——
形态 命令/入口 覆盖 恢复方式 应用内备份(DATA.gz) Web 备份页 / cli.php Backup库数据 + 文件结构元数据(应用语义) 应用恢复页 pg_dump 逻辑备份 pg_dump -f xx.sql全库 SQL(152 表含结构) psql -f到任意同名版本库文件级备份 tar 打包 dependent/附件/本地文件/配置 解包回原位 生产建议三者都做:DATA.gz 供应用内恢复与审计(有
lmb_history_backup台账),pg_dump 是跨版本迁移与灾难恢复的兜底,dependent/目录 tar 补上附件文件面。
7.1 Web 管理备份入口
登录态下两个备份页 action 实测均可达(页面为 SPA 壳,功能在页内):
curl -s -b /tmp/lmb_cookie.txt -o /dev/null -w "GET index.php?action=setup_backup_man -> %{http_code}, %{size_download} bytes\n" http://localhost/index.php?action=setup_backup_man
curl -s -b /tmp/lmb_cookie.txt -o /dev/null -w "GET index.php?action=setup_backup_hist -> %{http_code}, %{size_download} bytes\n" http://localhost/index.php?action=setup_backup_hist
GET index.php?action=setup_backup_man -> 200, 111451 bytes
GET index.php?action=setup_backup_hist -> 200, 111452 bytes
Web 通道产物属主为 www-data(对照 4.3 节 CLI 产物属主 root,可凭属主区分通道来源):
-rw-r--r-- 1 www-data www-data 171592 Nov 2 22:41 26_11_02_41_26.DATA.gz
7.2 命令行全量备份
即 4.3 节 cli.php Backup -c 实测,产物 26_11_03_02_35.DATA.gz(522064 字节)与台账第 3 行 DATA2611030235 相互印证。要点:backupTarget 必须给绝对路径且执行用户对目标目录可写;backupAlive=7 表示保留 7 天。
7.3 pg_dump 逻辑备份
用应用角色走 TCP 全库导出:
mkdir -p /opt/limbas/backup
PGPASSWORD=q1w2e3r4 pg_dump -h 127.0.0.1 -U limbas -d limbasdb -f /opt/limbas/backup/limbasdb-$(date +%F).sql
echo "exit=$?"
ls -l /opt/limbas/backup/
grep -c '^CREATE TABLE' /opt/limbas/backup/limbasdb-$(date +%F).sql
head -5 /opt/limbas/backup/limbasdb-$(date +%F).sql
实测回显(2137290 字节、152 张表与 6.3 节表数一致;limbas 角色对自己库有完整读权限即可导出,无需 postgres 超管):
2026-11-03 02:05:10
exit=0
total 2088
-rw-r--r-- 1 root root 2137290 Nov 3 02:05 limbasdb-2026-11-03.sql
152
--
-- PostgreSQL database dump
--
\restrict YwK6beusETFkGLwdFKqSMWJ22c7OcqWwuHiXXnfpI9dOv2lBur2ekXgjAX46WTU
7.4 恢复演练
恢复到独立库 limbas_restore 验证备份可用性,不动生产。第一步清理目标库,实测该库不存在时的回显(首次演练属正常,直接建库即可):
su - postgres -c "dropdb limbas_restore"
su - postgres -c "createdb -O limbas limbas_restore"
echo "createdb exit=$?"
dropdb: error: database removal failed: ERROR: database "limbas_restore" does not exist
createdb exit=0
导入并验证(psql -f 全量执行,实测 exit=0、日志 0 个 error):
PGPASSWORD=q1w2e3r4 psql -h 127.0.0.1 -U limbas -d limbas_restore -f /opt/limbas/backup/limbasdb-$(date +%F).sql > /tmp/restore.log 2>&1
echo "psql -f exit=$?"
grep -ciE 'error' /tmp/restore.log
psql -f exit=0
0
对象数逐项与生产比对(实测恢复库 152 表 / 143 配置 / 3 用户 / 4 作业,与生产库完全一致):
su - postgres -c "psql -d limbas_restore -tAc \"select count(*) from pg_tables where schemaname='public';\""
su - postgres -c "psql -d limbas_restore -tAc 'select count(*) from lmb_umgvar;'"
su - postgres -c "psql -d limbas_restore -tAc 'select count(*) from lmb_userdb;'"
su - postgres -c "psql -d limbas_restore -tAc 'select count(*) from lmb_crontab;'"
152
143
3
4
生产恢复即:createdb -O limbas limbasdb + 导入 dump + 解回 dependent/ 文件目录 + systemctl reload apache2。跨版本恢复务必先确认 lmb_dbpatch 与代码版本关系(见第八章),库结构落后时登录会自动触发补丁补齐。
7.5 备份保留与官方种子包
dependent/BACKUP/ 里除轮转的 *.DATA.gz 外,还有官方安装器随带的两个种子包 clean.tar.gz(174536 字节,空库模板)与 demo.tar.gz(518754 字节,示例业务数据),属主 www-data、时间戳即装机日(Aug 12 12:19/12:20),不要当业务备份误删,但可另作「重置演示数据」的恢复源。
八、升级实操(整包替换与补丁重放演练)
Limbas 升级没有专用命令,机制是「代码整包替换 + 数据补丁自动重放」:登录会话触发 Updater::checkVersion(),比较代码版本(limbas_src/lib/version.inf)与库版本(lmb_dbpatch 最大行),库落后即按 admin/tools/update/updates/ 下的补丁类(实测存在 Update5m0.php ~ Update7m1.php 共 8 个 minor 类)逐级补到最新。本节用 7.1.15 官方包做一次完整的替换+补丁重放演练,跨小版本升级流程与回显形态相同。
8.1 升级判据源码
Updater::checkVersion() 核心逻辑实测(limbas_src/admin/tools/update/Updater.php 节选):
$versions = self::getVersions();
$updateNeeded = version_compare($versions['source'], $versions['db'], '>');
if (!$noAutoUpdate && $updateNeeded && array_key_exists('update_mode', $umgvar) && $umgvar['update_mode'] === 'background') {
return self::runUpdate();
}
if ($updateNeeded && $redirect) {
if ($LINK['setup_update']) {
header('Location: main_admin.php?action=setup_update');
} else {
header('Location: main.php?action=maintenance');
}
exit(0);
}
即:update_mode=background 时登录自动补补丁;foreground(默认,见 6.3 实测值)时重定向到升级页/维护页。getVersions() 的库版本 SQL 就是 SELECT REVISION,VERSION,MAJOR FROM LMB_DBPATCH ORDER BY MAJOR DESC, VERSION DESC, REVISION DESC。
8.2 升级前三件套备份
按第七章:pg_dump 全库(limbasdb-2026-11-03.sql,2137290 字节)+ 应用内 Backup 类 DATA.gz(26_11_03_02_35.DATA.gz)+ 代码目录快照:
cp -a /opt/limbas/openlimbas-7.1.15 /opt/limbas/openlimbas-7.1.15.bak-$(date +%F-%H%M)
实测快照目录就位(后续回滚直接 mv 回来):
/opt/limbas/openlimbas-7.1.15.bak-2026-11-03-0206
8.3 官方包下载与校验
cd /opt/limbas
curl -sSL -w "HTTP %{http_code}, %{size_download} bytes, %{time_total}s\n" \
-o openlimbas-7.1.15-new.tar.gz \
https://github.com/limbas/limbas/releases/download/v7.1.15/openlimbas-7.1.15.tar.gz
sha256sum openlimbas-7.1.15-new.tar.gz openlimbas-7.1.15.tar.gz
实测回显(GitHub 官方源直连可用、2.4 秒完成,未发生代理降级;两个包 sha256 一致,与首次安装留档相同):
HTTP 200, 11667224 bytes, 2.372642s
052f503973129ddb673209344d650132da2d357eac08a374fdf6ee5fb0e7ead5 openlimbas-7.1.15-new.tar.gz
052f503973129ddb673209344d650132da2d357eac08a374fdf6ee5fb0e7ead5 openlimbas-7.1.15.tar.gz
8.4 解包与整包替换(含一次真实事故)
mkdir -p upgrade-staging && tar xzf openlimbas-7.1.15-new.tar.gz -C upgrade-staging
ls upgrade-staging/
实测回显——注意:官方 tar 包没有顶层目录,解出来包根直接就是应用根(limbas_src、public、dependent、vendor 平铺),不存在 upgrade-staging/openlimbas-7.1.15/ 这层:
LICENSE
Limbarine.png
README.md
composer.json
dependent
limbas_src
package.json
public
vendor
此时若沿用「先 mv 走旧目录、再 mv 新目录就位」的惯性写法,第二步会失败而站点已经没了——本次演练真实踩中,实测回显:
mv: cannot stat 'upgrade-staging/openlimbas-7.1.15': No such file or directory
cp: cannot create directory '/opt/limbas/openlimbas-7.1.15/dependent/': No such file or directory
swap exit=1
POST login -> 403, 274 bytes
<title>403 Forbidden</title>
修复(staging 本身就是新根,直接改名就位;再把旧 dependent/ 全量迁进新树保住数据库连接配置与备份产物):
mv /opt/limbas/upgrade-staging /opt/limbas/openlimbas-7.1.15
cp -a /opt/limbas/openlimbas-7.1.15.bak-2026-11-03-0206/dependent/. /opt/limbas/openlimbas-7.1.15/dependent/
chown -R www-data:www-data /opt/limbas/openlimbas-7.1.15/dependent
systemctl reload apache2
替换后验证(数据库连接文件 md5 与替换前一致 ddb4089c1a695a11d5fc241708044cc7,登录恢复 200、版本号正确、备份产物目录完整):
fix exit=0
ddb4089c1a695a11d5fc241708044cc7 /opt/limbas/openlimbas-7.1.15/dependent/inc/include_db.lib
POST login -> 200, 111440 bytes
<title>Limbas Enterprise Unifying Framework V 7.1.15</title>
-rw-r--r-- 1 www-data www-data 522064 Nov 3 02:02 26_11_03_02_35.DATA.gz
-rw-r--r-- 1 www-data www-data 521930 Nov 2 23:24 26_11_03_24_29.DATA.gz
-rw-r--r-- 1 www-data www-data 522043 Nov 2 23:24 26_11_03_24_37.DATA.gz
⚠️ 升级替换铁律:新包解出的
dependent/是出厂默认(数据库连接为空、无 LMB_ENC_KEY),必须把旧dependent/内容迁移进新树(或替换前先把旧dependent/inc/include_db.lib单独备份再覆盖回去),否则站点立刻连不上库。include_db.lib中的LMB_ENC_KEY一旦更换,历史加密字段将无法解密。
8.5 补丁重放演练(模拟「代码新、库旧」)
真跨版本升级时新代码自带更高 version.inf,登录即触发补丁。演练做法:保持代码 7.1.15,人为把库版本退回 7.1.14(删台账顶行),并打开后台自动升级开关:
su - postgres -c "psql -d limbasdb -c \"update lmb_umgvar set norm='background' where id=134 returning id, norm;\""
su - postgres -c "psql -d limbasdb -c 'delete from lmb_dbpatch where id=726 returning id, major, version, revision, status;'"
su - postgres -c "psql -d limbasdb -c 'select id, major, version, revision from lmb_dbpatch order by id desc limit 2;'"
实测回显(库版本降到 7.1.14):
id | norm
-----+------------
134 | background
(1 row)
UPDATE 1
id | major | version | revision | status
-----+-------+---------+----------+--------
726 | 7 | 1 | 15 | t
(1 row)
DELETE 1
id | major | version | revision
-----+-------+---------+----------
725 | 7 | 1 | 14
724 | 7 | 1 | 13
(2 rows)
登录触发 Updater:
curl -s -c /tmp/lmb_cookie3.txt -o /tmp/login3.html -w "POST login -> %{http_code}, %{size_download} bytes\n" -d 'username=admin&password=q1w2e3r4' http://localhost/index.php
实测回显(200 但只有 659 字节、标题版本号被清空——这是补丁执行中的中间页,正是 foreground 模式下用户会看到的升级/维护形态):
POST login -> 200, 659 bytes
<title>Limbas Enterprise Unifying Framework V </title>
验证补丁自动重放结果(726 行以 status=t 回到台账、总数恢复 724):
su - postgres -c "psql -d limbasdb -c 'select id, major, version, revision, status, left(msg,60) as msg from lmb_dbpatch order by id desc limit 3;'"
su - postgres -c "psql -d limbasdb -tAc 'select count(*) from lmb_dbpatch;'"
id | major | version | revision | status | msg
-----+-------+---------+----------+--------+-----
726 | 7 | 1 | 15 | t |
725 | 7 | 1 | 14 | t |
724 | 7 | 1 | 13 | t |
(3 rows)
724
恢复 foreground 并复验登录(回到 111440 字节完整界面、版本号齐全,升级闭环):
id | norm
-----+------------
134 | foreground
(1 row)
UPDATE 1
POST login -> 200, 111440 bytes
<title>Limbas Enterprise Unifying Framework V 7.1.15</title>
补丁执行期间 error log 有一条 Undefined array key "update_check" Warning(Updater.php:43 读联网检查开关的键名与 umgvar 实际键不完全一致,7.x 遗留噪音,不阻断补丁,判读见 9.9)。
8.6 升级标准流程清单与回滚
- 三件套备份:pg_dump +
cli.php Backup+cp -a代码目录(8.2); - 下载新包并
sha256sum校验(8.3); - 解包后先看结构:官方 tar 无顶层目录,staging 即新根(8.4 事故实录);
- 旧目录
mv改名 → 新树就位 → 旧dependent/全量迁入新树 →chown -R www-data:www-data dependent→systemctl reload apache2; - 管理员登录触发补丁(
background自动补 /foreground走升级页),核对lmb_dbpatch顶行与新版本一致、version.inf一致(8.5); - 验证:登录页 200、
GET /admin/jobs/1/run200、error log 无新增 FATAL; - 回滚:新树
mv走、.bak-*目录mv回来、reload;库侧若补丁已执行且不可逆,用 7.4 节 dump 恢复。
九、常见问题排障实录
以下问题全部在本环境真实发生并定位,错误回显逐行照抄。
9.1 psql 直连报 Peer authentication failed / role "root" does not exist
现象见 6.1 实测。定位:pg_hba.conf 对 local socket 的 postgres 行是 peer(要求 OS 同名用户),root 无对应角色。解决:su - postgres -c "psql ..." 或应用角色走 TCP PGPASSWORD=q1w2e3r4 psql -h 127.0.0.1 -U limbas。不建议为图方便把 local 改成 trust。
9.2 查配置表报 relation "umgvar" does not exist
现象:select * from umgvar; 报错。定位:Limbas 系统表全部带 lmb_ 前缀(库内 152 表实测均 lmb_* 或 demo 业务表名)。解决:查 lmb_umgvar。
9.3 备份作业配了参数却不出产物
现象:Backup 作业 config 写 "backupMedia" 时备份不落目标目录、也不报错。定位:Backup.php 识别的键是 backupMedium(medium 不是 media),错键被静默忽略。解决:键名改为 backupMedium;验证方法以 4.3 节实测为准——-c 传 backupMedium 后 exit=0、BACKUP 目录新增 DATA.gz 产物且 lmb_history_backup 多一行台账,三证齐全才算配对。
9.4 GET /admin/jobs 返回 Server Error 页
现象与完整异常堆栈见 5.4:JobController::index() 返回 string 触发 ControllerDoesNotReturnResponseException,7.1.15 已知缺陷。解决:列表核对走 lmb_crontab SQL(4.2 实测)或 Web 作业页;单作业 PUT/GET run/DELETE 接口不受影响(5.2/5.3 实测 200)。
9.5 cli.php 报 column "ind_7" does not exist
现象(早期实测原文):php cli.php 4 打印 Error: ERROR: column "ind_7" does not exist ... SELECT COUNT(*) AS ANZAHL FROM versandart WHERE IND_7 = FALSE AND DEL = FALSE。定位:作业 4 的 config 指定索引 tab 13(versandart)的字段 7/8,而 demo 库该表没有 ind_7/ind_8 列——作业配置与表结构脱钩。解决:清空该作业字段配置(config 置 [])或改配真实字段;修复后实测 php cli.php 4 仅剩 Warning、exit=0、无 SQL 错误(4.2 节回显)。
9.6 INDIZE 作业尾部 INSERT INTO LMB_INDIZE_HISTORY 语法错误
现象:作业 1 跑完进度 HTML 后打印 ERROR: syntax error at or near ")" ... VALUES(1,'Filestructure Index',TRUE,0.0032,'',0,0,)(CLI 与 REST run 两通道同现,见 4.2/5.2)。定位:7.1.15 索引历史写入 SQL 拼接多一个尾逗号,属上游代码缺陷;索引动作本身已完成(USED_TIME 已产生)。解决:功能不受影响可忽略;需要干净台账时给 LMB_INDIZE_HISTORY 建触发器代写或升级后关注上游修复,勿手改 vendor 外的 legacy 源码。
9.7 PUT /admin/jobs/{id} 报 TypeError
两种实测形态(5.3 节):只传部分键 → Cannot assign null to property CronJob::$cronMinutes of type string;backup_alive= 传空串 → Cannot assign string to property CronConfig::$backupAlive of type int。解决:x-www-form-urlencoded 带全 14 个键、backup_alive 给数字(0 起步),实测 {"success":true,...}。
9.8 apt 装 cron 后服务没起来
现象:安装回显 invoke-rc.d: policy-rc.d denied execution of start.、随后 systemctl is-active cron 为 inactive(4.5 实测)。定位:系统存在 policy-rc.d 策略时包脚本不自动启动服务。解决:systemctl enable cron + systemctl restart cron,用 journalctl -u cron 确认 (CRON) INFO (pidfile fd = 3)。
9.9 满屏 PHP Warning 怎么判读
CLI/Web 日志大量 Undefined array key/Trying to access array offset on null/Undefined variable Warning(4.2/4.4/8.5 多处实测),是 7.x legacy 代码在 PHP 8.3 严格上下文下的噪音,判读原则:看 exit code 与产物/台账行(如 exit=0 + 新 DATA.gz + lmb_history_backup 新行 = 成功),只有 Error:/FATAL/limbas.ERROR 前缀行才是真故障。
9.10 升级替换后站点 403
现象与修复全程见 8.4:DocumentRoot 指向的目录被 mv 走后新树没就位(tar 无顶层目录导致 mv 失败)。解决:按 8.4 修复三连(staging 改名就位 + dependent 迁移 + reload);预防:升级脚本先 ls 解包结构再动旧目录,且永远保留 .bak-* 目录直到验证通过。
十、注意事项
- 产物属主:root 跑
cli.php Backup产出的 DATA.gz 属 root,Web 通道产物属 www-data;混用时注意后续 Web 恢复页可能读不了 root 属主文件,统一用chown www-data:www-data或固定以 www-data 身份跑(su -s /bin/bash www-data -c "php ...")。 - include_db.lib 权限:内含数据库口令与
LMB_ENC_KEY,保持 640 以内权限、绝不进 Web 可达路径(它在dependent/inc/,.htaccess已只放行public/)。 - REST 会话:
/admin/jobs复用登录会话 Cookie,Cookie 过期后接口返回登录页 HTML(非 401),脚本里应校验响应体而非只看状态码。 - 升级开关:生产建议保持
update_mode=foreground(默认),升级窗口内人工确认补丁;background适合自动化流水线但要配合升级前备份。 - 下载渠道:本文 GitHub 官方 Release 直连实测可用(8.3,2.4s),未使用代理降级;若你所在网络官方源不可达,按「官方源 → 国内源 → 代理」降级链处理并在变更单注明。
- 备份三件套常态化:crontab 里除业务作业外,加一条每日
pg_dump+find /opt/limbas/backup -mtime +14 -delete的轮转,与backupAlive应用内轮转互补。
十一、相关文档
十二、参考链接
- Limbas 官方网站:https://www.limbas.com/
- GitHub 仓库(Release 下载源):https://github.com/limbas/limbas
- GPL-2.0 许可证:https://opensource.org/licenses/GPL-2.0
- PostgreSQL pg_dump 手册:https://www.postgresql.org/docs/14/app-pgdump.html