Hubzilla 11.4.2 配置参数详解
Hubzilla 11.4.2 三层配置模型(.htconfig 文件层→DB config 表→代码兜底默认值)实测验证、system 家族全参数逐项详解、json 前缀存储格式与 6 类配置故障排障实录
Hubzilla 11.4.2 配置参数详解
目标:把 Hubzilla 11.4.2 的「
.htconfig.php文件层 → 数据库 config 表 → 代码兜底默认值」三层配置模型讲透,逐项解释 system 家族核心参数的含义、真实默认值与常量映射,并沉淀「文件改了不生效」「/admin 挂 60 秒」「目录服务器随机外指」等 6 类实测配置故障。已在 Hubzilla 11.4.2(DB build 1265,PHP 8.3.36 + Apache/2.4.69,MariaDB 11.8.9)实测通过;部署形态见 《Hubzilla Docker Compose 部署指南》,选型背景见 《Hubzilla 介绍与选型指南》。
一、环境信息
| 项目 | 实测值 |
|---|---|
| Hubzilla | 11.4.2(boot.php STD_VERSION 实测 '11.4.2') |
| 数据库版本 | DB build 1265(config 表 db_version = 1265) |
| 运行时 | PHP 8.3.36 + Apache/2.4.69 |
| 数据库 | MariaDB 11.8.9,业务库 hubzilla |
| 文件层配置 | /var/www/html/.htconfig.php(安装向导生成,4721 字节) |
| 数据库配置表 | config(列 cat/k/v,v 为明文或 json: 前缀串) |
| 账号级配置表 | pconfig(列 uid/cat/k/v,v 为 mediumtext) |
| CLI 配置工具 | /var/www/html/util/config、util/pconfig |
| 站点 URL | http://10.89.72.10 |
| 演示账号 | admin / q1w2e3r4 |
本文命令均在部署完成的编排内执行(docker compose exec -w /var/www/html web php util/config <family> <key>,形态见部署篇);数据库侧证据用 docker compose exec db mariadb -uhubzilla -pq1w2e3r4 hubzilla -e "<SQL>"。
二、前置条件
- 已按 《Hubzilla Docker Compose 部署指南》 完成部署并通过安装向导(
.htconfig.php已生成、config 表已有数据); - 能在站点根目录执行
php util/config(CLI 工具会加载 boot.php 完整启动链,必须cd到站点根目录,编排内用-w /var/www/html指定); - 能访问数据库(同上
mariadb客户端); - 理解一个前提:安装完成后,管理面板与
util/config写入的都是数据库 config 表,数据库值覆盖.htconfig.php文件值——这是排障的第一心智模型。
三、参数查看与修改方式
3.1 三层配置模型(先读这一节)
Hubzilla 启动时配置按以下链路合并,后层覆盖前层:
| 层 | 载体 | 加载点(源码实测) |
|---|---|---|
| 1 文件层 | .htconfig.php(直接给 App::$config['system'][key] 赋值) | boot.php L662 @include('.htconfig.php'); |
| 2 数据库层 | config 表按家族整表读入,覆盖同名文件值 | Zotlabs/Lib/Config.php::Load() L38 SELECT * FROM config WHERE cat = '<family>' |
| 3 代码兜底 | 未设置时的硬编码默认值 | 如 include/network.php L117-126(curl 超时 60/30)、boot.php L678(server_role='pro')、L680(timezone 兜底 UTC) |
另有两条特殊规则(boot.php L660-670 实测源码):
.htpreconfig.php:仅在「未安装状态」(.htconfig.php不存在或为空,App::$install为 true)才被 include,用于预置安装期配置;安装完成后不再加载;$default_timezone变量:.htconfig.php里若定义了$default_timezone,会在 boot.php L672-673 覆盖timezone。
.htconfig.php 文件头注释(实测原文,即官方对覆盖关系的权威表述):
Notice: Many of the following settings will be available in the admin panel after a successful site install. Once they are set in the admin panel, they are stored in the DB - and the DB setting will over-ride any corresponding setting in this file
实测验证「DB 覆盖文件」:.htconfig.php 文件层写死 sitename = "Hubzilla",用 util/config 写入 DB 后,读取值立即变为 DB 值:
$ docker compose exec -T web php util/config system sitename "Quzuo Test Hub"
config[system][sitename] = Quzuo Test Hub
$ docker compose exec -T web php util/config system sitename
config[system][sitename] = Quzuo Test Hub
$ docker compose exec -T web php util/config system sitename "Hubzilla" # 恢复
config[system][sitename] = Hubzilla
写入后 config 表多出一行(此后文件层的 "Hubzilla" 永远被这行覆盖,直到删除该行):
cat k v
system sitename Hubzilla
⚠️ 注意:想「改回文件值」不能把 DB 行改成和文件一样,而要删除 DB 行(
delete from config where cat='system' and k='sitename'),否则以后改文件一律无效。util/config没有删除子命令,删除只能走 SQL。
3.2 util/config 命令行工具
官方用法文档 util/config.md(实测全文):
config
displays all config entries
config family
displays all config entries for family (system, database, etc)
config family key
displays single config entry for specified family and key
config family key value
set config entry for specified family and key to value and display result
Notes:
Setting config entries which are manually set in .htconfig.php may result in
conflict between database settings and the manual startup settings.
实测样例(两参数读类别、三参数读单键、四参数写入并回显):
$ docker compose exec -T web php util/config system curl_timeout
config[system][curl_timeout] = 5
$ docker compose exec -T web php util/config system register_policy
config[system][register_policy] = 2
输出格式统一为 config[<family>][<key>] = <值>。无参数全量 dump 会把 prvkey/pubkey 整段 RSA 私钥/公钥打进终端,生产环境慎用。
3.3 管理面板
Admin → Site 表单(源码 Zotlabs/Module/Admin/Site.php)保存即 Config::Set('system', key, value) 写 config 表——与 util/config 同层,面板改过的键再去改 .htconfig.php 不生效属正常覆盖关系。面板上「Network timeout」字段实测即写 curl_timeout(Admin/Site.php L219 Config::Set('system','curl_timeout', $timeout),L519 表单默认值 60)。
3.4 直接读写数据库 config 表
config 表结构(实测 DESCRIBE config):
Field Type Null Key Default Extra
id int(10) unsigned NO PRI NULL auto_increment
cat char(191) NO MUL
k char(191) NO
v text NO NULL
与 Friendica 的 PHP serialize 存储不同,Hubzilla 的 v 列是明文,仅两种编码扩展(Zotlabs/Lib/Config.php L71-99 Set() 实测源码):
- 数组值写入时加
json:前缀:$dbvalue = ((is_array($value)) ? 'json:' . json_encode($value) : $value); - 布尔值转整数:
is_bool → intval; - 读取时(
Get()L134-141):json:前缀走json_unserialize;兼容旧版 PHP serialize 串(匹配正则|^a:[0-9]+:{.*}$|s)走受限unserialize(禁对象)。
全新安装 + 日常运行后实测全表 16 行(SELECT k,v FROM config ORDER BY k,prvkey/pubkey 两行超长 RSA 密钥此处省略,见 5.5):
k v
allowed_themes redbasic
as_objects_moved 1
curl_connecttimeout 3
curl_ssl_ciphers ALL:!eNULL
curl_timeout 5
db_version 1265
diaspora_objects_moved 1
directory_server https://zotsite.net
lastcron 2026-11-02 05:37:25
lastcroncheck 2026-11-02 05:37:25
lastpoll 2026-11-02 05:37:25
perms json:["view_stream","send_stream","view_profile","view_contacts","view_storage","write_storage","view_pages","view_wiki","write_pages","write_wiki","post_wall","post_comments","post_mail","post_like","chat","republish","delegate"]
sitename Hubzilla
urlverify 687474703a2f2f31302e38392e37322e3130
其中 curl_connecttimeout=3、curl_timeout=5、sitename 三行是本文实验写入的(演示 3.1/5.4 的修复与覆盖机制),其余为安装向导与运行期自动写入。
3.5 pconfig:账号级/渠道级参数
config 表管「站点」,pconfig 表管「账号/渠道」。表结构(实测 DESCRIBE pconfig):
Field Type Null Key Default Extra
id int(11) NO PRI NULL auto_increment
uid int(11) NO MUL 0
k char(191) NO
v mediumtext NO NULL
updated datetime NO MUL 0001-01-01 00:00:00
实测运行一段时间后全表 40 行,按 cat 分布:
cat COUNT(*)
perm_limits 34
system 6
uid=2(admin 渠道)的 cat='system' 6 行实测:
uid cat k v
2 system default_permcat default
2 system permissions_role personal
2 system photo_path %Y-%m
2 system attach_path %Y-%m
2 system import_system_apps 2026-11-02
2 system force_import_system_apps 11.4.2
解读:permissions_role = personal 是渠道权限模板(personal/business/community 三档,决定 perm_limits 里各权限的默认上限,如 view_pages 上限 1、chat 上限 128);photo_path/attach_path 是照片与附件的存储目录模板(%Y-%m 按年月归档)。
CLI 工具 util/pconfig 语法为 util/pconfig <uid> <family> <key> [value]。实测坑:参数多于 4 个时只取前 4 个(util/pconfig 2 admin system test_key hello 实际把 family 写成 admin、key 写成 system、value 写成 test_key);把值设为空串不会删除行,删除只能 SQL delete from pconfig where uid=2 and cat='admin'。
四、参数总览
php util/config system 输出的是三层合并后的生效值(实测节选,密钥类省略):
config[system][smarty3_folder] = /var/www/html/store/[data]/smarty3
config[system][db_skip_locked_supported] = 0
config[system][timezone] = Asia/Shanghai
config[system][baseurl] = http://10.89.72.10
config[system][sitename] = Hubzilla
config[system][location_hash] = d4ad632911ec67035ec5057ef9a1e3bdda02a8d7772d7b0f6f1ea3dc689de92e
config[system][transport_security_header] = 1
config[system][content_security_policy] = 1
config[system][ssl_cookie_protection] = 1
config[system][register_policy] = 2
config[system][register_text] =
config[system][admin_email] = root@example.com
config[system][verify_email] = 1
config[system][access_policy] = 0
config[system][sellpage] =
config[system][max_import_size] = 200000
config[system][php_path] = /usr/local/bin/php
config[system][directory_mode] = 0
config[system][theme] = redbasic
config[system][server_role] = pro
config[system][allowed_themes] = redbasic
config[system][curl_ssl_ciphers] = ALL:!eNULL
来源分类(对照 3.1 三层模型):
| 来源 | 参数 |
|---|---|
.htconfig.php 文件层(向导生成) | db_* 变量、timezone、baseurl、sitename、location_hash、三个安全头、register_policy/register_text/admin_email、verify_email、access_policy、sellpage、max_import_size、php_path、directory_mode、theme、db_skip_locked_supported |
| 代码硬编码(boot.php 等) | server_role(恒 pro,L678)、smarty3_folder、curl_ssl_ciphers |
| 运行期写入 DB | db_version、urlverify、perms、prvkey/pubkey、allowed_themes、as_objects_moved、diaspora_objects_moved、directory_server、lastcron/lastcroncheck/lastpoll、curl_timeout/curl_connecttimeout(管理员写) |
数据库连接参数是唯一不走 App::$config['system'] 合并链的组:.htconfig.php 顶层变量 $db_host/$db_port/$db_user/$db_pass/$db_data/$db_type(实测 L6-11),只认文件、改后无需清 DB。
五、核心参数分类详解
5.1 站点身份
| 参数 | 实测值 | 说明 |
|---|---|---|
baseurl | http://10.89.72.10 | 站点根 URL,严禁结尾斜杠(.htconfig.php L37 原文注释 "DO NOT ADD A TRAILING SLASH!");改 baseurl 后 urlverify、目录注册、联邦身份全部要重验 |
sitename | Hubzilla | 站点显示名 |
timezone | Asia/Shanghai | 仅影响匿名访客看到的时间戳(L32-33 注释);账号各自有渠道时区 |
location_hash | d4ad632911ec67035ec5057ef9a1e3bdda02a8d7772d7b0f6f1ea3dc689de92e | 安装时 random_string() 生成的站点指纹(64 位 hex),用于目录统计去重,不要手改 |
urlverify | 687474703a2f2f31302e38392e37322e3130 | baseurl 的 hex 编码(实测解码 python3 -c "print(bytes.fromhex('687474703a2f2f31302e38392e37322e3130').decode())" → http://10.89.72.10),安装期站点所有权校验凭证,换 baseurl 会重新生成 |
5.2 注册与访问控制
常量定义实测(boot.php L218-230):
define('REGISTER_CLOSED', 0);
define('REGISTER_APPROVE', 1);
define('REGISTER_OPEN', 2);
define('ACCESS_PRIVATE', 0);
define('ACCESS_PAID', 1);
define('ACCESS_FREE', 2);
define('ACCESS_TIERED', 3);
| 参数 | 实测值 | 说明 |
|---|---|---|
register_policy | 2(文件层写常量 REGISTER_OPEN,DB 存数值) | 0 关闭注册 / 1 需管理员批准 / 2 开放注册 |
register_text | 空 | 注册页顶部公告文本 |
verify_email | 1 | 注册必须点邮件确认链接。部署篇 11.1 实测:为 1 且无可用 MTA 时,注册事务在 create_account_from_register() 因确认邮件发送失败整体回滚(zar.log 报 ZAR1238E Account creation error);设 0 可跳过邮件验证直接建号,测试环境可用、生产不推荐 |
access_policy | 0 | 站点访问策略;ACCESS_PRIVATE(0)表示即使 register_policy=2 也不会在目录里被列成开放 hub(.htconfig.php L69-77 注释原文) |
admin_email | root@example.com | 系统邮件发件人兼管理员通知地址;REGISTER_APPROVE 时必须是已注册人员的邮箱(L55-56 注释) |
sellpage | 空 | 公共站点销售页绝对 URL(http/https 开头) |
theme / allowed_themes | redbasic / redbasic | 默认主题与允许主题列表;装新主题后要加入 allowed_themes 才可选用 |
5.3 联邦与目录服务器
常量定义实测(boot.php L93-96):
define('DIRECTORY_MODE_NORMAL', 0x0000); // 目录客户端,自动寻找目录服务器
define('DIRECTORY_MODE_PRIMARY', 0x0001); // 主目录服务器(每个 realm 只有一个)
define('DIRECTORY_MODE_SECONDARY', 0x0002); // 镜像/缓存目录服务器
define('DIRECTORY_MODE_STANDALONE', 0x0100); // 离线/私有目录,自身即目录服务器(=256)
| 参数 | 实测值 | 说明 |
|---|---|---|
directory_mode | 0(NORMAL) | NORMAL 模式下 Hubzilla 会随机挑选公共目录服务器:Zotlabs/Lib/Libzotdir.php 实测源码在 NORMAL 模式 mt_rand 从 fallback 列表(boot.php L107-119 DIRECTORY_FALLBACK_MASTER + get_directory_fallback_servers(),含 hub.netzgemeinde.eu、zotsite.net)选一台写入 directory_server |
directory_server | https://zotsite.net | 本次重装实测随机落点即 zotsite.net(印证上一行为)。内网/隔离环境该值导致站点向外部目录注册与拉取,生产建议 directory_mode 设 256(STANDALONE)并把 directory_server 指向自身 baseurl(部署篇 11.6 实测修复) |
5.4 网络抓取超时
实测源码 include/network.php L113-127:
// include/network.php L117-118(总超时)
$curl_time = intval(@Config::Get('system','curl_timeout'));
@curl_setopt($ch, CURLOPT_TIMEOUT, (($curl_time !== 0) ? $curl_time : 60));
// include/network.php L125-126(连接超时)
$curl_contime = intval(@Config::Get('system','curl_connecttimeout'));
@curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, (($curl_contime !== 0) ? $curl_contime : 30));
| 参数 | 默认(兜底) | 实测值 | 说明 |
|---|---|---|---|
curl_timeout | 60 | 5 | 单次抓取总超时(秒);设 0 反而回到 60(!== 0 判断),"0=不限"在面板文案里有误导 |
curl_connecttimeout | 30 | 3 | TCP 连接超时(秒);设 0 同样回 30 |
curl_ssl_ciphers | 代码内置 | ALL:!eNULL | 抓取对端的 TLS 加密套件白名单 |
这两个参数是部署篇 11.3「/admin 摘要页挂 60 秒」故障的修复开关:摘要页 get_repository_version() 硬编码抓 framagit.org(官方源不可达时 connecttimeout 30s×2 次请求=60s),实测设 curl_connecttimeout 3 + curl_timeout 5 后页面 6.02s 返回 200。
5.5 站点密钥与安全头
| 参数 | 实测值 | 说明 |
|---|---|---|
prvkey / pubkey | PEM 格式密钥串(config 表两行,各约 1.7KB,3.4 全表 dump 中省略) | 安装向导生成的站点级 RSA 密钥对(Zot 协议签名根密钥),存 DB 明文带 \n 转义。备份站点必须备份 config 表,丢私钥等于丢站点身份,联邦对端全部失联 |
transport_security_header | 1 | 响应附 HSTS 头;反代已发同名头时设 0(.htconfig.php L43-46 注释) |
content_security_policy | 1 | 响应附 CSP 头;要嵌外部统计/资源时设 0 |
ssl_cookie_protection | 1 | HTTPS 下 Cookie 加 Secure 属性;纯 HTTP 站点无效果 |
5.6 数据库与运行期状态
| 参数 | 实测值 | 说明 |
|---|---|---|
db_version | 1265 | 数据库结构版本号,util/update_db 比对它决定是否跑升级 SQL(部署篇实测回显 DB up to date: 1265) |
db_skip_locked_supported | 0 | .htconfig.php L13-16 注释:postgres>9.5 / mysql>8.0 / mariadb>10.6 支持 SKIP LOCKED(守护进程取任务不锁行)。向导保守写 0;MariaDB 11 环境建议改 1 降低多 daemon 争用 |
lastcron / lastcroncheck / lastpoll | 2026-11-02 05:37:25(三值同步) | poller 心跳时间戳(UTC)。跑一次 php Zotlabs/Daemon/Master.php Cron 后三值刷新——部署篇 4.8 用它验证 cron 真正生效,管理员面板「Cron check」据此告警 |
perms | json: 前缀数组(完整值见 3.4 全表 dump) | 渠道默认权限清单(17 项),即 3.4 数组编码的实例 |
as_objects_moved / diaspora_objects_moved | 1 | 旧版 Diaspora/ActivityStreams 对象迁移完成标记,运行期自动写入 |
5.7 PHP 运行时层(php.ini)
Hubzilla 三层模型之外还有一层容器/系统 PHP 配置,直接影响行为:本环境镜像内 99-hubzilla.ini 实测 5 行(upload_max_filesize=64M、post_max_size=64M、memory_limit=512M、max_execution_time=120、date.timezone=Asia/Shanghai)。max_import_size=200000(Hubzilla 层,字节)与 post_max_size(PHP 层)要成对调:导入大档案时 Hubzilla 放行而 PHP 截断,表现为「导入无提示失败」。
六、生产配置模板
.htconfig.php 文件层最小可用集(基于实测生成文件裁剪,公网 HTTPS 站点视角):
<?php
$db_host = 'db';
$db_port = '0';
$db_user = 'hubzilla';
$db_pass = '<强密码>';
$db_data = 'hubzilla';
$db_type = '0';
App::$config['system']['db_skip_locked_supported'] = 1; // MariaDB 11 建议开
App::$config['system']['timezone'] = 'Asia/Shanghai';
App::$config['system']['baseurl'] = 'https://hub.example.com'; // 无结尾斜杠
App::$config['system']['sitename'] = "Example Hub";
App::$config['system']['register_policy'] = REGISTER_APPROVE; // 生产控注册
App::$config['system']['admin_email'] = 'admin@example.com';
App::$config['system']['verify_email'] = 1;
App::$config['system']['access_policy'] = ACCESS_PRIVATE;
App::$config['system']['max_import_size'] = 200000;
App::$config['system']['php_path'] = '/usr/local/bin/php';
App::$config['system']['directory_mode'] = DIRECTORY_MODE_STANDALONE; // 内网/隐私站
App::$config['system']['theme'] = 'redbasic';
安装完成后用 util/config 把运行期参数固化到 DB 层(实测生效格式):
php util/config system curl_connecttimeout 3
php util/config system curl_timeout 10
php util/config system directory_server https://hub.example.com
php util/config system transport_security_header 1
管理面板没有暴露、但排障常用的键(curl_connecttimeout、db_skip_locked_supported、as_objects_moved 等)都可直接 util/config 读写——面板只是 config 表的图形前端。
七、常见问题
Q1 改了 .htconfig.php 不生效
第一层原因即 3.1 覆盖模型:该键已存在于 config 表(面板或 CLI 写过一次就永久落 DB)。实测 SELECT cat,k,v FROM config ORDER BY k 比对;要回到文件值必须删除 DB 行而不是改文件。第二层原因:baseurl 改动后 urlverify/location_hash 不会自动跟随,站点身份校验失败表现五花八门,改 baseurl 要按部署篇流程重验。
Q2 /admin 页面转圈一分钟才出来
get_repository_version() 硬编码请求 https://framagit.org/hubzilla/core/raw/<branch>/boot.php(Zotlabs/Module/Admin.php L136-137 摘要页调用 master/dev 两次),官方源不可达时按兜底 connecttimeout 30s×2=60s 挂起。修复见 5.4:util/config system curl_connecttimeout 3 + curl_timeout 5,实测 60.02s → 6.02s。
Q3 内网站点出现对外部目录的连接/注册请求
directory_mode=0(NORMAL)时 directory_server 由 Libzotdir.php 随机取自公共目录 fallback 列表(实测落点 https://zotsite.net)。隔离网络里设 directory_mode 256(STANDALONE)并覆写 directory_server 为自身(六章命令)。
Q4 手工 SQL 写数组配置后配置失效
Config::Get() 只认 json: 前缀(L135 str_starts_with($value, 'json:'))与旧版 serialize 串(源码匹配正则 |^a:[0-9]+:{.*}$|s)。手工 INSERT 数组必须写成 json:["a","b"] 整串(对照实测 perms 行),裸 JSON 数组文本会被当字符串返回。
Q5 util/config system curl_timeout 0 想「不超时」反而变 60
5.4 源码:($curl_time !== 0) ? $curl_time : 60——0 被兜底逻辑吃掉回默认值。要长超时就直接写大数(如 300)。
Q6 util/pconfig 参数错位
3.5 实测坑:多于 4 个参数只取前 4 个(uid/family/key/value),空值不删行。批量清理账号级配置直接 SQL delete from pconfig where uid=<n> and cat='<family>'。
八、参考链接
- Hubzilla 官网:https://hubzilla.org/
- 官方管理手册 CLI 章节:https://github.com/hubzilla/hubzilla-project/blob/master/doc/en/adminmanual/CLI_tools.md
- 高级配置文档:https://github.com/hubzilla/hubzilla-project/blob/master/doc/en/advanced_configurations.md
- 站内互链:部署实录见 《Hubzilla Docker Compose 部署指南》;选型背景见 《Hubzilla 介绍与选型指南》;CLI 工具逐项实测见 《Hubzilla 11.4.2 常用 CLI 命令与工具详解》。