Gerbera 常用命令与运维实战(核心篇)
Gerbera 3.3.0 运维核心篇实测:gerbera CLI 参数全景与运行方式、check-config 好坏配置拦截、数据库备份-校验-破坏-恢复完整闭环(--databases 翻车与 --drop-tables 行为偏差取证)、日志五段读法与四类报错对照、Web UI API 化重扫/虚拟文件夹增删/在线转码五环排障、db_version=29 迁移机制与升级 SOP,回显逐行照抄。
Gerbera 常用命令与运维实战(核心篇)
本文是 Gerbera 专栏的核心运维篇,在真实服务器环境(Gerbera 3.3.0 + MariaDB 11.8,2026-10-29 实测)下完成五组运维实战:
gerbera命令行参数与运行方式、数据库备份与恢复的完整闭环(含一次--databases参数翻车实录与--drop-tables行为偏差取证)、日志排障方法论、Web UI 日常运维(容器树浏览 / 全量重扫 / 虚拟文件夹增删 / 在线转码开通与排障)、版本升级机制与标准流程。全部命令与回显均为服务器实测逐行照抄。
前置阅读:组件定位与选型结论见 《Gerbera 介绍与选型指南》;服务从 0 到 1 的部署过程见 《Gerbera Docker Compose 部署实战》(以下简称部署篇);config.xml 逐节参数含义见 《Gerbera 配置参数详解》(以下简称配置篇)。
一、运维环境与服务身份盘点
运维任何服务,第一步都是搞清楚「我面对的是哪一个二进制、它被编译成了什么样」。本章先固化本篇实测环境口径,再盘点 Gerbera 的服务身份信息。
1.1 实测环境口径
延续部署篇完成的环境,关键信息汇总如下(本篇所有命令均在此环境执行):
| 项目 | 值 |
|---|---|
| Gerbera 版本 | 3.3.0 |
| 服务绑定地址 | 10.89.56.10:4949(局域网经 8136 端口对外发布,规划见部署篇) |
| 主配置文件 | /var/run/gerbera/config.xml |
运行数据目录(<home>) | /var/run/gerbera/ |
| 媒体库目录 | /mnt/content(只读挂载的存储卷) |
| 数据库 | MariaDB 11.8.9 @ 10.89.56.20:3306,库名 gerbera,账号 gerbera/q1w2e3r4 |
| Web UI 账号 | admin/q1w2e3r4 |
安装数据目录(PACKAGE_DATADIR) | /usr/local/share/gerbera |
| 媒体文件 | tone.flac、tone440.mp3 等 7 个音频 + clip.mp4 视频 + photo.jpg 图片 |
1.2 gerbera --version 与 --compile-info:看清你的二进制
gerbera --version
实测回显:
Gerbera UPnP Server 3.3.0
Copyright 2016-2026 Gerbera Contributors.
Licence GPLv2: GNU GPL version 2.
This is free software: you are free to change and redistribute it.
再看编译信息,这条命令的输出直接决定「这台服务器上的 Gerbera 能做什么」:
gerbera --compile-info
实测回显(节选关键段,完整输出 60 余行):
Compile info:
-------------
WITH_NPUPNP OFF
STATIC_LIBUPNP ON
WITH_MAGIC ON
WITH_MYSQL ON
WITH_PGSQL ON
WITH_CURL ON
WITH_INOTIFY ON
WITH_JS ON
WITH_TAGLIB ON
WITH_AVCODEC ON
WITH_FFMPEGTHUMBNAILER ON
WITH_EXIF ON
WITH_EXIV2 ON
WITH_MATROSKA ON
WITH_WAVPACK ON
WITH_SYSTEMD NO
WITH_ICU ON
WITH_ZIP ON
WITH_LASTFM ON
WITH_ONLINE_SERVICES OFF
WITH_DEBUG ON
WITH_DEBUG_OPTIONS ON
WITH_TESTS OFF
Build info:
-----------
FMT 110200
SPDLOG 11700
CXXOPTS 3.3.1
SQLITE 3.53.4
PUGIXML 1150
JSONCPP 1.9.6
PACKAGE_DATADIR /usr/local/share/gerbera
PUPNP 220100
HAVE_ICU 78.1
HAVE_JS 20700
HAVE_MYSQL Server 10.8.8-MariaDB, Client 3.4.6
HAVE_PGSQL Pqxx 7.10.3, PqLib 180006
HAVE_CURL 8.22.0
HAVE_TAGLIB 2.3.2
HAVE_FFMPEG Lavu60.26.102, Lavf62.12.102, Lavc62.28.102, Lavfi11.14.102
HAVE_FFMPEGTHUMBNAILER 2.3.1
Git info:
---------
Git Branch: HEAD
Git Commit: 28361d9e22812c9d7042a85b355a17c8f8495217
逐段解说:
- WITH_ 开头的开关是功能编译开关:
WITH_MYSQL ON说明本二进制支持 MySQL/MariaDB 后端;WITH_INOTIFY ON说明 inotify 实时扫描可用(部署篇验证过);WITH_JS ON说明虚拟布局自定义脚本可用(配置篇 boxlayout 的前提)。 WITH_SYSTEMD NO值得注意:本二进制编译时未带 systemd 支持包,安装目录里不会自带 systemd unit 文件,常驻运行要自己写单元(见 2.4 节)或使用发行版打包版。WITH_ONLINE_SERVICES OFF:Last.FM 之外在线服务未编译,--init-lastfm之外的在线功能无需考虑。PACKAGE_DATADIR /usr/local/share/gerbera:安装数据目录,后面第六章的数据库迁移脚本就放在这里,排障时要能对上号。- Git Commit:出现版本疑难杂症时,凭 commit 号去官方仓库比对,比报版本号更精确。
💡 技术拓展:
--compile-info是排查「同一个版本、不同行为」的首选命令。Gerbera 官方分发版与发行版仓库(Debian/Fedora 等)的编译开关并不相同,例如官方镜像默认无 systemd 单元、发行版包则相反。报障或迁移前先存一份 compile-info,等于给二进制做了「指纹登记」。
二、gerbera CLI 参数与运行方式
Gerbera 是单进程守护进程,命令行参数覆盖配置、运行、日志、数据库四大类。本章把 --help 全景过一遍,并实测最常用的几组。
2.1 gerbera --help 参数全景
gerbera --help
实测回显(逐行照抄):
Gerbera UPnP Media Server - https://gerbera.io
Usage:
gerbera [OPTION...]
-h, --help Print this help and exit
-D, --debug Enable debugging
-v, --version Print version info and exit
--compile-info Print compile info and exit
--create-config [=Section(=All)]
Print a default config.xml file and exit
--create-example-config [=Section(=All)]
Print a example config.xml file and exit
--create-advanced-config [=Section(=All)]
Print a advanced example config.xml file and
exit
--modules [=Module(=None)]
Create "from-file" module statements in
config.xml
--check-config Check config.xml file and exit
--print-options Print simple config options and exit
--offline Do not answer UPnP content requests
--drop-tables Drop all database tables and exit
--init-lastfm Get Last.FM session key
-d, --daemon Daemonize after startup
-u, --user UID Drop privs to user UID
-P, --pidfile FILE Write a pidfile to the specified location,
e.g. /run/gerbera.pid
-c, --config FILE Path to config file
-f, --cfgdir DIR Override name of config folder
(.config/gerbera) in home folder
-l, --logfile FILE Set log location
--rotatelog FILE Set rotating log location
--syslog [=LOG(=USER)] Log to syslog
--add-file FILE Scan a file into the DB on startup, can be
specified multiple times
--set-option OPT=VAL Set simple config option OPT to value VAL,
can be specified multiple times use
--print-options for value OPTs
-s, --database DB=(sqlite|mysql|postgres)
Select Database for storage
-p, --port PORT Port to bind with, must be >=49152
-i, --ip IP IP to bind with
-e, --interface IF Interface to bind with
-m, --home DIR Search this directory for a .config/gerbera
folder containing a config file
--scripts DIR Search this directory for custom javascript
files
--magic FILE Set magic FILE
--import-mode MODE Activate import MODE ('mt' or 'grb')
--debug-mode FACILITY Set debugging mode to FACILITY
按运维场景归组解读:
- 配置体检类(改配置后、重启服务前必跑):
--check-config、--print-options、--create-config系列、--set-option。前三者在配置篇已逐个实测,本章重点展开--check-config。 - 运行形态类:前台直跑、
-d守护进程化、-Ppidfile、-u降权、--offline离线模式。 - 日志类:
-l/--logfile(单文件)、--rotatelog(轮转文件)、--syslog(系统日志)三通道,可按需组合。 - 数据库类:
-s临时切换存储后端、--drop-tables清空数据表、--add-file启动时补扫单个文件。 - 绑定类:
-p端口(注意>=49152的约束,部署篇就是用--port 4949覆盖了配置文件的 49152 缺省值)、-i绑 IP、-e绑网卡。 - 调试类:
-D全量调试、--debug-mode FACILITY按设施开调试,排障核武器(见第四章)。
2.2 --check-config:上线与变更的第一道闸
好配置直接过:
gerbera --check-config -c /var/run/gerbera/config.xml
实测回显(关键段):
2026-10-29 00:01:12 info: Gerbera UPnP Server 3.3.0 - https://gerbera.io/
2026-10-29 00:01:12 info: Loading configuration from: /run/gerbera/config.xml
2026-10-29 00:01:12 info: Parsing configuration...
2026-10-29 00:01:12 info: Configuration load succeeded.
2026-10-29 00:01:12 info: Validating configuration...
2026-10-29 00:01:12 warning: Found extra config file entry '/config/server/storage/postgres/database'
2026-10-29 00:01:12 warning: Found extra config file entry '/config/server/storage/postgres/host'
2026-10-29 00:01:12 warning: Found extra config file entry '/config/server/storage/postgres/username'
2026-10-29 00:01:12 warning: Found extra config file entry '/config/server/storage/sqlite3/backup'
2026-10-29 00:01:12 warning: Found extra config file entry '/config/transcoding/mimetype-profile-mappings/transcode'
2026-10-29 00:01:12 warning: Found extra config file entry '/config/transcoding/profiles/profile/agent'
(……中间另有 sqlite3/database-file、各 profile 的 buffer/encoder 等 warning,共 26 条……)
2026-10-29 00:01:12 info: Configuration check succeeded.
解说两个要点:
- 退出码 0 +
Configuration check succeeded.才算通过。--check-config只做「解析 + 校验」,不连数据库、不绑端口,可以随时在变更窗口前跑。 - 26 条
Found extra config file entrywarning 不是错误:它们指向被禁用后端(postgres、sqlite3)里的参数,以及转码 profiles 里「被映射表引用但映射语法上不认识」的子元素。Gerbera 的校验器对「配置文件里有、但当前启用配置不需要」的条目一律提示 extra,留着无害,追求零告警可注释掉禁用后端小节。
再故意喂一份坏配置(把 <port> 改成 abc 的 bad.xml)看失败长什么样:
gerbera --check-config -c /var/run/gerbera/bad.xml
实测回显:
2026-10-29 00:01:12 info: Loading configuration from: /run/gerbera/bad.xml
2026-10-29 00:01:12 info: Parsing configuration...
2026-10-29 00:01:12 warning: Error in configuration, could not find command "ffmpeg" in $PATH for '/config/attribute::command'
2026-10-29 00:01:12 warning: Error in configuration, could not find command "vlc" in $PATH for '/config/attribute::command'
2026-10-29 00:01:12 error: Runtime error parsing config file '/var/run/gerbera/bad.xml': [/gerbera_build/src/config/setup/config_setup_int.cc:104] T ConfigIntegerSetup<T, OptionClass>::checkIntValue(std::string&, const std::string&) const [with T = unsigned int; OptionClass = UIntOption; std::string = std::__cxx11::basic_string<char>] Error: Error in config file: /config//server/port unreadable int value 'abc'
echo $?
1
解说:
- 错误三级分明:两条 warning(转码 agent 依赖的 ffmpeg / vlc 命令在
$PATH里找不到,external profile 会受影响)+ 一条致命 error(/config//server/port unreadable int value 'abc',直接点名 XML 路径与非法值)。 - 退出码 1 是脚本化变更的关键信号:CI 或变更脚本里
gerbera --check-config ... || abort即可把坏配置挡在重启之前。 - 顺带验证了 error 行暴露的源码路径(
config_setup_int.cc:104),这是 3.3.0 端口参数的校验实现位置,比对上游代码时可用。
2.3 前台运行、--logfile 与 --offline
排障时最有价值的运行形态是「前台 + 落日志 + 离线」,即不对外宣告 UPnP、把启动全过程写进指定文件:
gerbera -c /var/run/gerbera/config.xml --port 4952 --offline --logfile /var/run/gerbera/d1-offline.log &
sleep 6 && kill %1
日志文件 d1-offline.log 开头(逐行照抄):
2026-10-29 00:01:25 info: Running in offline mode
2026-10-29 00:01:25 info: Gerbera UPnP Server 3.3.0 - https://gerbera.io/
2026-10-29 00:01:25 info: Copyright 2016-2026 Gerbera Contributors.
2026-10-29 00:01:25 info: Gerbera is free software, covered by the GNU General Public License version 2
2026-10-29 00:01:25 info: Loading configuration from: /run/gerbera/config.xml
2026-10-29 00:01:25 info: Parsing configuration...
2026-10-29 00:01:25 info: Configuration load succeeded.
2026-10-29 00:01:25 info: Validating configuration...
2026-10-29 00:01:25 info: Configuration check succeeded.
2026-10-29 00:01:25 info: Loading 0 configuration items from database
2026-10-29 00:01:25 info: Initialising UPnP with interface: <unset>, port: 4952
2026-10-29 00:01:25 info: IPv4: Server bound to: 10.89.56.10:4952
2026-10-29 00:01:25 info: The Web UI can be reached by following this link: http://192.168.146.128:8136
结尾(收到 kill 后的优雅退出):
2026-10-29 00:01:30 info: Gerbera shutting down. Please wait...
2026-10-29 00:01:31 info: Gerbera exiting. Have a nice day.
解说:
Running in offline mode:--offline让服务跳过 UPnP 内容应答,但仍完成配置加载、数据库连接与端口绑定——专门用于「验证配置 + 观察 DB 行为」而不干扰线上客户端。-p 4952换了端口:UPnP 端口被常驻实例占着,诊断实例必须错开(--help明确端口须>=49152,4952 合规)。--logfile落盘 + 前台运行是复现启动期问题的标准姿势;结尾两行说明 Gerbera 收到 SIGTERM 会优雅退出(先shutting down再exiting),这为第五章的重启操作兜了底。- 注意日志里
Loading configuration from: /run/gerbera/config.xml——服务把/var/run显示为/run(两者是同一目录的符号链接),与配置里的/var/run/gerbera/config.xml并无冲突。
2.4 常驻运行方式:daemon 参数与 systemd 单元
生产常驻有两条路:
路径一:-d 守护进程化(简单场景)
gerbera -c /var/run/gerbera/config.xml -p 4949 -u gerbera -P /run/gerbera.pid -d
-d让进程 fork 到后台;-P落 pidfile,供运维脚本kill $(cat /run/gerbera.pid)停服;-u gerbera在启动后把有效用户切到 gerbera(--help里写作 "Drop privs to user UID"),避免媒体服务以 root 长跑;- 缺点:进程崩了没人拉起,日志要自己接
--logfile或--syslog。
路径二:systemd 单元(生产推荐)
# /etc/systemd/system/gerbera.service
[Unit]
Description=Gerbera Media Server
After=network-online.target mariadb.service
Wants=network-online.target
[Service]
User=gerbera
ExecStartPre=/usr/local/bin/gerbera --check-config -c /var/run/gerbera/config.xml
ExecStart=/usr/local/bin/gerbera -c /var/run/gerbera/config.xml -p 4949 --logfile /var/log/gerbera/gerbera.log
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
解说:
- 本二进制
WITH_SYSTEMD NO,单元文件需自备;ExecStartPre把 2.2 节的--check-config固化成「起服前自动体检」,坏配置直接阻断启动,比崩了再查日志省一个排障循环; Restart=on-failure吸收偶发崩溃——部署篇复现过的「数据库地址写错 → 崩溃-重启循环」正是这类参数的用武之地:服务会反复拉起,但journalctl/logfile 里每次都留下同一条数据库错误,定位反而更快;- 本实测环境的常驻实例即按「守护进程 + 自定义启动参数(
--port覆盖)」方式运行,与部署篇IMAGE_PORT变量的行为一致。
💡 技术拓展:
-c/--config与-m/--home的分工——-c指定主配置文件路径,-m指定「家目录」用于搜索.config/gerbera隐藏配置目录。只用-c显式传配置时-m通常不需要;但当配置里<home>缺省时,Gerbera 会回退到-m指定目录下找.config/gerbera,缓存(缩略图等)也落在<home>/cache-dir。实测环境里<home>显式写死为/var/run/gerbera/,缩略图缓存就在/var/run/gerbera/cache-dir/content/clip.mp4-thumb.jpg。
三、数据库备份与恢复实战
Gerbera 的全部「资产」——媒体条目、虚拟布局结果、客户端记录、配置覆盖项——都在数据库里;媒体文件本身只需重新扫描即可找回,因此备份恢复演练的对象就是数据库。本章完成「备份 → 可恢复性校验 → 破坏 → 恢复 → 业务验证」全闭环,中间如实保留一次参数选择失误实录。
3.1 全量备份:mariadb-dump
在数据库服务器上对 gerbera 库做一致性快照:
mariadb-dump -ugerbera -pq1w2e3r4 gerbera --single-transaction \
> /var/backups/gerbera/gerbera-d1-20261028.sql
ls -la /var/backups/gerbera/
实测回显:
-rw-r--r-- 1 root root 59579 Oct 28 23:43 gerbera-20261028-ops.sql
-rw-r--r-- 1 root root 59708 Oct 28 23:29 gerbera-2026-10-28.sql
-rw-r--r-- 1 root root 56793 Oct 28 22:50 gerbera-full-20261028.sql
-rw-r--r-- 1 root root 59792 Oct 29 00:01 gerbera-d1-20261028.sql
备份文件头部:
/*M!999999\- enable the sandbox mode */
-- MariaDB dump 10.20-11.8.9-MariaDB, for debian-linux-gnu (x86_64)
--
-- Host: localhost Database: gerbera
-- ------------------------------------------------------
-- Server version 11.8.9-MariaDB-ubu2404
解说:
--single-transaction在 InnoDB 表上获得一致性快照且不锁表;Gerbera 建表用 MyISAM(见 3.4 节mt_internal_setting的engine=MyISAM),该参数对 MyISAM 不生效——若在业务高峰备份 MyISAM 表仍可能读到中间态,本实测环境媒体库变更频率低,实际影响可忽略,但规范上应知道这个边界;- 第一行
/*M!999999\- enable the sandbox mode */是 MariaDB 11 系 dump 的防注入标记,3.2 节会看到它的影响; - 目录里另有三份此前演练留存的历史备份(大小 56~59 KB),说明这个库的体量很小——全量备份永远是最划算的首选策略。
3.2 备份可恢复性校验:临时库比对(含 --databases 翻车实录)
备份没校验过恢复,等于没备份。标准做法是把备份灌进一个临时库,与生产库比对行数和表数。第一次尝试就翻车了,过程完整保留——当时多加了 --databases 参数:
mariadb-dump -ugerbera -pq1w2e3r4 --databases gerbera --single-transaction \
> /var/backups/gerbera/gerbera-d1-20261028.sql
mariadb -uroot -pq1w2e3r4 -e "CREATE DATABASE gerbera_verify;"
mariadb -uroot -pq1w2e3r4 gerbera_verify < /var/backups/gerbera/gerbera-d1-20261028.sql
mariadb -uroot -pq1w2e3r4 -e "SELECT COUNT(*) AS verify_objects FROM gerbera_verify.mt_cds_object;"
实测回显:
ERROR 1146 (42S02) at line 1: Table 'gerbera_verify.mt_cds_object' doesn't exist
--verbose 重放导入,真相在输出里:
--------------
CREATE DATABASE /*!32312 IF NOT EXISTS*/ `gerbera` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_uca1400_ai_ci */
--------------
--------------
DROP TABLE IF EXISTS `grb_cds_resource`
--------------
解说(翻车复盘):
- 带
--databases的 dump 会内嵌CREATE DATABASE gerbera+USE gerbera语句;导入时即使命令行指定了目标库gerbera_verify,USE gerbera一到,后续所有建表、灌数全部切回了gerbera库——临时库始终是空的,而生产库被「原样重灌」了一遍; - 这次失误的意外收获是完整走了一遍「用备份重灌生产库」且数据无损(123 个媒体对象原样恢复),但规范操作必须避免这种隐式写生产:
- 正确姿势:单库备份不加
--databases,dump 里就没有CREATE DATABASE/USE,导入目标完全由命令行控制:
mariadb-dump -ugerbera -pq1w2e3r4 gerbera --single-transaction \
> /var/backups/gerbera/gerbera-d1-clean.sql
grep -c 'CREATE DATABASE\|^USE' /var/backups/gerbera/gerbera-d1-clean.sql
0
重新走校验流程:
mariadb -uroot -pq1w2e3r4 -e "DROP DATABASE IF EXISTS gerbera_verify; CREATE DATABASE gerbera_verify;"
mariadb -uroot -pq1w2e3r4 gerbera_verify < /var/backups/gerbera/gerbera-d1-clean.sql
mariadb -uroot -pq1w2e3r4 -e "SELECT \"gerbera(生产库)\" AS src, COUNT(*) AS cds_objects FROM gerbera.mt_cds_object UNION ALL SELECT \"gerbera_verify(校验库)\", COUNT(*) FROM gerbera_verify.mt_cds_object; SELECT COUNT(*) AS verify_tables FROM information_schema.TABLES WHERE TABLE_SCHEMA=\"gerbera_verify\";"
实测回显:
src cds_objects
gerbera(生产库) 123
gerbera_verify(校验库) 123
verify_tables
8
校验通过后清理临时库:
mariadb -uroot -pq1w2e3r4 -e "DROP DATABASE gerbera_verify; SELECT 'verify db dropped' AS done;"
done
verify db dropped
解说:生产/校验 123=123、8 张表齐全,备份可用性闭环完成。日后例行演练只需重复 3.2 的正确姿势三分钟。
3.3 --drop-tables 实测与官方清库路径
Gerbera 自带清库参数,安装目录里也有配套脚本(/usr/local/share/gerbera/ 下可见 mysql-drop.sql、mysql.sql、mysql-upgrade.xml 三件套)。实测 --drop-tables:
gerbera --drop-tables -c /var/run/gerbera/config.xml
实测回显(尾部):
2026-10-29 00:04:55 info: Configuration check succeeded.
2026-10-29 00:04:55 info: Dropping tables with /usr/local/share/gerbera/mysql-drop.sql
2026-10-29 00:04:55 error: Run: logic error map::at
再查库——8 张表一张没少:
Tables_in_gerbera
grb_cds_resource
grb_client
grb_config_value
grb_playstatus
mt_autoscan
mt_cds_object
mt_internal_setting
mt_metadata
配套脚本内容(实测照抄):
DROP TABLE `grb_playstatus`;
DROP TABLE `grb_cds_resource`;
DROP TABLE `mt_metadata`;
DROP TABLE `mt_autoscan`;
DROP TABLE `mt_cds_object`;
DROP TABLE `mt_internal_setting`;
DROP TABLE `grb_config_value`;
DROP TABLE `grb_client`;
解说:
--drop-tables成功加载配置、找到mysql-drop.sql,但在真正执行阶段报Run: logic error map::at退出,表未删除——这是 3.3.0 在 MySQL 后端 + 常驻实例并存场景下的行为偏差,实测两要素(并发实例、logic error)之间的因果关系未再深究,但结论明确:这版--drop-tables不可依赖;- 官方文档(docs.gerbera.io troubleshooting 页)的口径是:数据库自动迁移失败或需要换新布局特性时,「用
mysql-drop.sql删掉 MySQL/MariaDB 库里全部表,或运行gerbera --drop-tables -c <config>」清空重建——即官方把两者视为等价路径,本实测证明了等价性会破,兜底动作应优先选手工执行mysql-drop.sql(脚本内容就是上面 8 条 DROP,手工跑完全可控); - 顺带记录:
grb_*四张表是 2.x 起新增的(资源、客户端、配置覆盖、播放状态),mt_*四张是 MediaTomb 血统的老表(对象、扫描、元数据、内部设置),8 张全清才是完整重置。
3.4 破坏性恢复演练闭环
在备份校验通过后,做一次最彻底的演练:把库删掉,再从零恢复。
第一步,记录原库的建库参数(字符集/排序规则是恢复时最容易丢的细节):
mariadb -uroot -pq1w2e3r4 -e "SHOW CREATE DATABASE gerbera\G"
实测回显:
*************************** 1. row ***************************
Database: gerbera
Create Database: CREATE DATABASE `gerbera` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_uca1400_ai_ci */
第二步,删库,并观察服务故障现象。CDS 接口立刻变质:
python3 cds_browse.py http://127.0.0.1:8136 0
urllib.error.HTTPError: HTTP Error 500: Internal Server Error
服务日志同步留下报错(截取关键行):
2026-10-29 00:05:15 warning: Exception: Mysql: mysql_real_query() failed: mysql_error (1146): "Table 'gerbera.mt_cds_object' doesn't exist"; query: SELECT `f`.`id`, `f`.`ref_id`, ... FROM `mt_cds_object` `f` LEFT JOIN `mt_cds_object` `rf` ON `f`.`ref_id` = `rf`.`id` LEFT JOIN `mt_autoscan` `as` ON `as`.`obj_id` = `f`.`id` WHERE `f`.`id` = 0: Error: mysql_error (1146): "Table 'gerbera.mt_cds_object' doesn't exist"
第三步,按第一步记录的原参数重建库并灌备份:
mariadb -uroot -pq1w2e3r4 -e "CREATE DATABASE gerbera DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_uca1400_ai_ci;"
mariadb -uroot -pq1w2e3r4 gerbera < /var/backups/gerbera/gerbera-d1-clean.sql
echo RESTORE_OK
RESTORE_OK
第四步,数据层验证:
mariadb -uroot -pq1w2e3r4 -e "SELECT COUNT(*) AS cds_objects FROM gerbera.mt_cds_object; SELECT COUNT(*) AS tables_cnt FROM information_schema.TABLES WHERE TABLE_SCHEMA=\"gerbera\"; SELECT * FROM gerbera.mt_internal_setting;"
实测回显:
cds_objects
123
tables_cnt
8
key value
db_version 29
string_limit 255
resource_attribute size,duration,bitrate,sampleFrequency,nrAudioChannels,resolution,colorDepth,protocolInfo,resFile,type,fanArtObject,fanArtResource,bitsPerSample,dc:language,sec:acodec,sec:vcodec,format,orientation,pixelFormat,lyrics,offset
engine MyISAM
charset utf8
collation utf8_general_ci
第五步,业务层验证——CDS 根容器恢复如初:
object.container PC Directory
object.container Audio
object.container Photos
object.container Video
object.container.dynamicFolder Music Recently Played
object.container.dynamicFolder Recently Modified
object.container.dynamicFolder Recently Added
解说:
- 服务不重启即自愈:删库期间 Web UI 与 CDS 全部 500,恢复库表后常驻服务凭连接池重连立即恢复正常,全程未动 Gerbera 进程——这是「数据库外置」架构的运维红利;
mt_internal_setting是恢复验证的金标准:db_version=29是数据库 schema 版本号(第六章升级机制的钥匙),engine=MyISAM、charset=utf8记录了建库时代参数;- 媒体 URL 由
<home>与数据库共同决定,库恢复后无需重扫,客户端缓存的对象 ID(如 flac 的 97)原样可用; - 整个闭环的固化为一句 SOP:改库前必有当日 dump,恢复时先
SHOW CREATE DATABASE存参数,再重建、再灌数、先查mt_internal_setting再看业务。
💡 技术拓展:SQLite3 后端用户没有
mariadb-dump,但配置里<sqlite3><backup enabled="yes" interval="600"/>是 Gerbera 内建的定时备份(每 600 秒把库文件另存),恢复动作退化为「停服 → 拷回备份的.db文件 → 起服」。三后端里 MySQL/MariaDB/PostgreSQL 走 SQL 层备份,SQLite 走文件层备份,演练方法不同但「先校验后依赖」的原则一致。
四、日志排障实战
Gerbera 日志是单通道文本,格式统一为「时间戳 + 级别 + 消息」,级别只有 info / warning / error 三档。本章把启动日志读法、常见报错对照讲透。
4.1 日志通道与启动日志逐段解读
第三章 2.3 节已实测 --logfile。一次完整启动的日志天然分五段,以常驻实例重启后的日志为例(--logfile 与前台输出内容一致):
2026-10-29 00:06:19 info: Gerbera UPnP Server 3.3.0 - https://gerbera.io/
2026-10-29 00:06:19 info: Loading configuration from: /run/gerbera/config.xml
2026-10-29 00:06:19 info: Parsing configuration...
2026-10-29 00:06:19 info: Configuration load succeeded.
2026-10-29 00:06:19 info: Validating configuration...
2026-10-29 00:06:19 info: Configuration check succeeded.
2026-10-29 00:06:19 info: Loading 0 configuration items from database
2026-10-29 00:06:19 info: Initialising UPnP with interface: <unset>, port: 4949
2026-10-29 00:06:19 info: IPv4: Server bound to: 10.89.56.10:4949
2026-10-29 00:06:19 info: The Web UI can be reached by following this link: http://192.168.146.128:8136
分段记忆法:
- 横幅段:版本 + 版权,确认重启后跑的确实是预期版本;
- 配置段:
Loading → Parsing → load succeeded → Validating → check succeeded,任何一步失败即退出,与--check-config的输出结构完全同构——这也是「起服前先 check-config」能拦截 90% 启动故障的原因; - 数据库段:
Loading N configuration items from database,数字来自grb_config_value表(UI 里改过的参数会落库,0 表示没在 UI 改过参数); - UPnP 段:绑定地址与端口,
10.89.56.10:4949对上网络规划; - 入口段:打印 Web UI 访问链接,看到这行 = 服务就绪。
4.2 典型故障日志对照表
以下为本篇实测中真实出现过的报错,按「日志原文 → 病因 → 处置」整理:
① 配置值非法(2.2 节实测)
error: Runtime error parsing config file '/var/run/gerbera/bad.xml': ... Error in config file: /config//server/port unreadable int value 'abc'
病因:配置值类型错误。处置:按 error 行点名的 XML 路径改值;--check-config 可在重启前拦截同类问题。
② 依赖命令缺失(每次启动可见)
warning: Error in configuration, could not find command "ffmpeg" in $PATH for '/config/attribute::command'
warning: Error in configuration, could not find command "vlc" in $PATH for '/config/attribute::command'
病因:转码 external profile 的 agent 依赖 ffmpeg/vlc 可执行文件,服务器 $PATH 里没有。处置:装包或忽略(不用 external 转码即无影响),但要知道它是 warning 不是 error、不阻断启动。
③ 数据库表消失(3.4 节删库实测)
error: Exception: Mysql: mysql_real_query() failed: mysql_error (1146): "Table 'gerbera.mt_cds_object' doesn't exist"; query: ...
病因:库/表被删或权限丢失,接口层表现为 HTTP 500。处置:按 3.4 闭环恢复;若反复出现且伴随重启循环,参考部署篇「崩溃-重启循环」复盘,先修 <storage><mysql> 四要素(host/port/username/password)。
④ 转码失败(5.5 节实测,日志原文)
error: Error occurred when opening output file '/tmp/grb-tr-e73bd705-0205-4157-9713-1b5c3a450754.mp3' (error 'Invalid argument')
error: Exception: [/gerbera_build/src/transcoding/transcode_io_handler.cc:112] virtual void TranscodeInternalIOHandler::open(UpnpOpenFileMode) Error: open output for /content/tone.flac failed
病因:internal 转码器为每次请求在 /tmp 建临时输出文件,打开失败。处置思路见 5.5 的完整排障。
4.3 调试开关:-D 与 --debug-mode
--help 里 -D/--debug 与 --debug-mode FACILITY 是排障深水区工具:-D 全量打开调试日志(需要编译期 WITH_DEBUG ON,1.2 节确认本二进制满足);--debug-mode 可按设施(线程、SSDP、数据库等)单独开,避免全量日志刷屏。日常排障顺序建议:先读 error 行 → 复现一次前台运行 → 仍无头绪再上 -D,调试日志量大,用完即关。
💡 技术拓展:三通道日志(
--logfile、--rotatelog、--syslog)可以并存。生产上推荐--rotatelog(按大小自动轮转,防单文件膨胀)或--syslog(交给 rsyslog 统一采集与轮转策略);--logfile更适合排障期临时挂载。配置文件里另有<server>下的日志级别细粒度参数,见配置篇对应章节。
五、Web UI 日常运维实战
Web UI 不仅是管理界面,更是一套完整的 REST 运维 API(/interface 端点,登录三步握手见部署篇)。本章用脚本化方式实测四组高频运维动作:容器树浏览、全量重扫、虚拟文件夹增删、在线转码开通与排障。
5.1 容器树与条目浏览
登录后查询虚拟容器树根节点(req_type=containers&action=get_containers&parent_id=0):
python3 ops_probe2.py
实测回显(关键段):
LOGIN: {'success': True, 'task': None}
--- containers parent_id=0 ---
root children: [(1, 'PC Directory'), (4, 'Audio'), (33, 'Photos'), (91, 'Video'), (-10002, 'Music Recently Played'), (-10001, 'Recently Modified'), (-10000, 'Recently Added')]
条目浏览(req_type=items&action=browse&parent_id=1):
{"items": {"autoscan_mode": "none", "autoscan_type": "none", "item": [], "parent_id": 1, "protect_container": false, "protect_items": false, "result_size": 0, "start": 0, "total_matches": 0, "virtual": false}, "success": true, "task": null}
解说:
- 根下 7 个容器分两类:正 ID 的物理/布局容器(PC Directory=1、Audio=4、Photos=33、Video=91,ID 即 CDS object_id,部署篇用 SOAP Browse 验证过的就是同一套 ID)与 负 ID 的动态容器(-10000/-10001/-10002,来自配置篇讲过的
<containers>动态容器节,LastAdded/LastModified/LastPlayed 三件套); protect_container/protect_items字段对应 UI 里对容器的保护锁,脚本化删除前先看这两个标志可避免误删持久容器(PC Directory 的persistent: true就是持久标记);total_matches/start/count构成分页参数,大批量条目巡检按页拉取即可。
5.2 全量重扫与任务队列
向 UI 提交全量重扫(等价于界面上 Database → 右键 PC Directory → Rescan):
--- config_save action=rescan target=--all ---
{"success": true, "task": {"cancellable": true, "id": 5, "text": "Scan: /content"}, "update_ids": {"pending": false}}
两秒后查任务队列(req_type=tasks&action=list):
{"success": true, "task": null, "tasks": []}
解说:
- 重扫是异步任务:提交立即返回 task id=5 与描述
Scan: /content,不阻塞 API;小媒体库秒级完成,tasks 列表随即清空——「提交成功 + 队列转空」就是完成信号; - 单目录重扫把
target换成对应 autoscan 目录 ID 即可;cancellable: true说明长任务可在 UI 里取消; - 配置篇讲过 autoscan
inotify模式下文件增删自动入库,全量重扫主要用于:虚拟布局脚本改了、映射规则改了、怀疑索引漂移这三类场景。
5.3 虚拟文件夹增删闭环
在根下新建一个自定义容器(等价于 UI 里 Database 树右键 → Add Container):
--- add_object 虚拟容器 ---
{"success": true, "task": null}
复查发现新容器拿到 ID 145(标题 Ops Notes),随即删除(req_type=remove&object_id=145&all=1):
Ops containers found: [(145, 'Ops Notes')]
remove 145 -> {'success': True, 'task': None}
root titles after cleanup: ['PC Directory', 'Audio', 'Photos', 'Video', 'Music Recently Played', 'Recently Modified', 'Recently Added']
解说:
- 创建→复查→删除→复查 是脚本化运维虚拟容器的最小闭环;新建容器 ID 从 100+ 段分配(媒体对象占 1~97 区间),删除后根容器树恢复 7 个原状;
- 这类「UI 里的手工动作」全部 API 化后,就能进定时任务或 CMDB 工具流;注意
remove带all=1才会连子对象一起删,只删空容器可省; - 删除虚拟容器不影响底层媒体文件与物理目录扫描结果——虚拟布局是数据库里的「视图」,这正是 Gerbera 虚拟文件夹体系的运维安全感来源。
5.4 在线转码开通与排障实录
配置篇讲过转码三大件:<transcoding enabled> 总开关、<mimetype-profile-mappings> 映射表、<profiles> profile 定义。本节实测把默认关闭的转码开起来,过程中收获一次完整排障。
第一步:开总开关并重启服务(转码参数不支持热加载,改完必须重启):
<transcoding enabled="yes">
重启后用 CDS 查看库中 flac 文件(object_id=97)的资源列表:
object.item.audioItem.musicTrack tone
--- res URLs ---
http://192.168.146.128:8136/media/object_id/97/res_id/0/group/default/ext/file.flac
只有 1 条 res(原始 flac),没有出现转码资源。
第二步:从数据反查。转码资源生成的条件是「条目 mimetype 命中映射表」,直接查库:
mariadb -uroot -pq1w2e3r4 -e "SELECT id, dc_title, mime_type FROM gerbera.mt_cds_object WHERE id=97;"
id dc_title mime_type
97 tone audio/flac
<!-- 映射表里只有这一条 flac 相关映射 -->
<transcode mimetype="audio/x-flac" using="int2mp3" />
病因水落石出:条目实际 mimetype 是 audio/flac(TagLib 识别结果),而默认映射表写的是 audio/x-flac——差一个前缀,永远命中不了。
第三步:补映射并重启:
<transcode mimetype="audio/x-flac" using="int2mp3" />
<transcode mimetype="audio/flac" using="int2mp3" />
再次 CDS 查询,转码资源出现了(2 条 res):
--- res URLs ---
http://192.168.146.128:8136/media/object_id/97/res_id/none/pr_name/int2mp3/tr/1/group/default/ext/file.mp3
http://192.168.146.128:8136/media/object_id/97/res_id/0/group/default/ext/file.flac
第四步:拉流验证转码输出:
curl -sI 'http://192.168.146.128:8136/media/object_id/97/res_id/none/pr_name/int2mp3/tr/1/group/default/ext/file.mp3'
实测回显:
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Content-Type: audio/mpeg
Access-Control-Allow-Origin: *
Server: Linux/7.0.0-38-generic, UPnP/1.0, Portable SDK for UPnP devices/22.1.0
X-User-Agent: redsonic
响应头全部正确(200 + audio/mpeg + chunked 流式),但正文字节数为 0,服务端日志随即给出 4.2-④ 的两行 error——internal 编码器为请求打开 /tmp/grb-tr-*.mp3 临时输出文件时报 Invalid argument。尝试移除 int2mp3 profile 的 afilter="anull" 参数后复现相同报错,确认是 3.3.0 internal 转码器在该构建(ffmpeg Lavf62.12.102 组合,见 1.2 节 compile-info)+ 本机环境下无法创建输出文件的环境性限制。
排障结论:
- 链路已打通到流媒体层:总开关 → mimetype 映射 → profile 匹配 → 转码 res 生成 → HTTP 流式响应头,五环全部验证通过;
- 断点在 internal 编码器写临时文件这一步,日志两行(
opening output file ... Invalid argument+transcode_io_handler.cc:112)精确定位;external profile(ogg2mp3/vlcmpeg)依赖 ffmpeg/vlc 命令,本机$PATH无此二者(4.2-② 的 warning 长期存在),也无法在此环境落地; - 运维启示:「转码配好了」要拆成五环逐环验证,DIDL 里有没有转码 res(CDS 层)与拉流有没有数据(传输层)是两回事,curl 一发 + 日志两行即可定位到环;
- 排障结束后已将 encoder 参数恢复默认(
afilter="anull"),总开关与audio/flac映射保留——映射正确性不依赖编码器可用性,作为后续环境补齐 ffmpeg 后的现成开关。
💡 技术拓展:转码 res URL 的结构值得记住——
res_id/none/pr_name/int2mp3/tr/1中pr_name直接暴露 profile 名、tr/1是转码流水线序号,而原始资源的 URL 只有res_id/0。客户端是否选择转码资源由其请求的 DLNAPROFILE 决定,服务端只是「把两条 res 都摆上货架」。另外X-User-Agent: redsonic是 Gerbera 沿用 MediaTomb 时代的兼容标记,老客户端靠它识别媒体服务器。
六、版本升级流程
Gerbera 的版本升级本质上是「换二进制 + 数据库 schema 迁移」,媒体文件与配置文件原样不动。本章先弄清迁移机制,再给出经过本篇实测动作验证的标准流程。
6.1 升级机制盘点:db_version 与迁移脚本
数据库 schema 版本号存在 mt_internal_setting 表(3.4 节恢复验证时顺带读到):
key value
db_version 29
安装数据目录 /usr/local/share/gerbera/ 下的三件套与迁移描述:
js
mysql-drop.sql
mysql-upgrade.xml
mysql.sql
postgres-drop.sql
postgres-upgrade.xml
postgres.sql
sqlite3-drop.sql
sqlite3-upgrade.xml
sqlite3.sql
web
mysql-upgrade.xml 是增量迁移链,实测确认共 28 个 <version> 块(number 2~29),每块若干条 SQL。当前版本 29 的迁移内容:
<version number="29" remark="import_mode in autoscan">
<script>ALTER TABLE `mt_autoscan` ADD `import_mode` enum('mt','grb','mediatomb','gerbera') NOT NULL default 'mt'</script>
<script>UPDATE `mt_autoscan` SET `import_mode`='mt'</script>
</version>
解说:
- 启动时自动迁移:Gerbera 启动读库得到
db_version,若低于二进制内建的目标版本,就按mysql-upgrade.xml逐版本执行缺失的<script>,每成功一步推进一次版本号——3.3.0 的目标版本正是 29,本环境无需迁移; <upgrade-file>配置参数可把迁移描述换成自定义路径(默认${datadir}/mysql-upgrade.xml),特殊环境才有必要动它;mysql.sql是全新初始化 schema(首次启动建表用),mysql-drop.sql是清库脚本(3.3 节实测过),三者与--drop-tables的关系已在第三章理清。
6.2 标准升级 SOP
综合官方文档建议与本篇实测动作,升级到新版本(例:3.3.0 → 3.x 更新版)流程如下:
第 1 步:升级前备份(3.1/3.2 节动作)
mariadb-dump -ugerbera -pq1w2e3r4 gerbera --single-transaction \
> /var/backups/gerbera/gerbera-pre-upgrade-$(date +%Y%m%d).sql
再按 3.2 校验一遍可恢复性,同时留存旧版 gerbera 二进制(或旧版本包),--compile-info 输出存档。
第 2 步:更新二进制/安装包
替换 Gerbera 程序与 PACKAGE_DATADIR 数据目录(新版本会带来新版 mysql-upgrade.xml、web/ 界面资源与 js/ 脚本);媒体文件、config.xml、数据库本体不动。
第 3 步:新版本配置体检(官方明确建议的动作)
gerbera --check-config -c /var/run/gerbera/config.xml
官方文档(配置生成章节)原话要点:升级 Gerbera 版本后应当重新运行配置检查,以发现新增或变更的配置项;更彻底的做法是跑 --create-example-config 与现有配置 diff,把新参数按需合入。退出码非 0 就地修复,不带病升级。
第 4 步:启动并确认自动迁移
起服后读日志:配置五段照旧通过后,观察数据库段——schema 落后时会执行迁移(版本号从旧值爬升到新目标值);随后验证:
mariadb -uroot -pq1w2e3r4 -e "SELECT value FROM gerbera.mt_internal_setting WHERE key='db_version';"
值应等于新版本的目标 schema 版本(不小于 29)。再抽查 CDS 根容器与 Web UI 登录(5.1 节两组探针直接复用)。
第 5 步:观察期
重点盯三类日志:迁移类 error、映射/兼容性 warning(新版本可能新增配置校验项,2.2 节的 extra entry warning 家族可能扩员)、客户端兼容问题(grb_client 表记录了各客户端特征,升级后首次回连是否正常看这张表)。
6.3 迁移失败的兜底路径
官方 troubleshooting 的口径:数据库通常由 Gerbera 自动迁移;迁移失败时清库重建——用 mysql-drop.sql 删掉全部表(或 gerbera --drop-tables,本篇 3.3 实测其在 3.3.0 存在行为偏差,优先手工执行脚本),重启 Gerbera 即按全新库初始化,再依赖 autoscan 重新导入媒体。
结合本篇实测给出更稳的兜底顺序:
- 先用升级前备份直接回灌(3.4 闭环演练过的动作),回到旧版本继续服务;
- 排查迁移失败的具体 SQL(
mysql-upgrade.xml对应版本块,错误日志会带出语句); - 确认必须重置时才走清库重建:清库 → 起服自动初始化 → 验证
db_version达标 → 重扫媒体库(5.2 节动作)→ 重建自定义虚拟容器(5.3 节动作有建删脚本,重放即可)。
清库重建的代价只有「重扫时间 + 自定义布局重放」,媒体文件零损失——这也是 6.2 第 1 步强调「备份先行」后敢于快速兜底的底气。
6.4 升级前检查清单
- 当日全量备份 + 临时库校验通过(3.1/3.2)
-
SHOW CREATE DATABASE参数存档(3.4) - 旧二进制留存 +
--compile-info存档(1.2) -
config.xml当前版本留存副本,新版本--check-config通过(2.2) -
mt_internal_setting.db_version当前值记录(6.1) - 回归脚本就绪:CDS 根容器探针 + UI 登录探针(5.1)
- 客户端通知:升级窗口内 SSDP 宣告中断,客户端列表重连后需复查(
grb_client)
💡 技术拓展:Gerbera 的
db_version与 config.xml 根元素的version="2"(配置篇讲过)是两条独立的版本线——前者管数据库 schema,由mysql-upgrade.xml驱动;后者管配置文件语法,由内置校验器驱动。升级排障时先分清报错属于哪条线:带 SQL 语句的错误找前者,带 XML 路径的错误找后者。
结语
本篇以五组实测串起 Gerbera 的日常运维主线:--check-config 把变更风险挡在重启前,备份-校验-破坏-恢复闭环让数据库操作有恃无恐,日志五段读法与四类典型报错构成排障路标,Web UI API 化的增删重扫与转码五环验证把界面动作纳入脚本体系,db_version 迁移机制则把版本升级从玄学变成清单。至此本专栏四篇完结:认知(《Gerbera 介绍与选型指南》)→ 部署(《Gerbera Docker Compose 部署实战》)→ 配置(《Gerbera 配置参数详解》)→ 运维(本篇),从选型到长期运维的完整链路已全部落地实测。