Hubzilla 11.4.2 配置参数详解

Hubzilla 11.4.2 三层配置模型(.htconfig 文件层→DB config 表→代码兜底默认值)实测验证、system 家族全参数逐项详解、json 前缀存储格式与 6 类配置故障排障实录

HubzillaHubzillaZot联邦平台PHP 应用2026/11/02

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 介绍与选型指南》。

一、环境信息

项目实测值
Hubzilla11.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
站点 URLhttp://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>"。

二、前置条件

  1. 已按 《Hubzilla Docker Compose 部署指南》 完成部署并通过安装向导(.htconfig.php 已生成、config 表已有数据);
  2. 能在站点根目录执行 php util/config(CLI 工具会加载 boot.php 完整启动链,必须 cd 到站点根目录,编排内用 -w /var/www/html 指定);
  3. 能访问数据库(同上 mariadb 客户端);
  4. 理解一个前提:安装完成后,管理面板与 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
运行期写入 DBdb_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 站点身份

参数实测值说明
baseurlhttp://10.89.72.10站点根 URL,严禁结尾斜杠(.htconfig.php L37 原文注释 "DO NOT ADD A TRAILING SLASH!");改 baseurl 后 urlverify、目录注册、联邦身份全部要重验
sitenameHubzilla站点显示名
timezoneAsia/Shanghai仅影响匿名访客看到的时间戳(L32-33 注释);账号各自有渠道时区
location_hashd4ad632911ec67035ec5057ef9a1e3bdda02a8d7772d7b0f6f1ea3dc689de92e安装时 random_string() 生成的站点指纹(64 位 hex),用于目录统计去重,不要手改
urlverify687474703a2f2f31302e38392e37322e3130baseurl 的 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_policy2(文件层写常量 REGISTER_OPEN,DB 存数值)0 关闭注册 / 1 需管理员批准 / 2 开放注册
register_text空注册页顶部公告文本
verify_email1注册必须点邮件确认链接。部署篇 11.1 实测:为 1 且无可用 MTA 时,注册事务在 create_account_from_register() 因确认邮件发送失败整体回滚(zar.log 报 ZAR1238E Account creation error);设 0 可跳过邮件验证直接建号,测试环境可用、生产不推荐
access_policy0站点访问策略;ACCESS_PRIVATE(0)表示即使 register_policy=2 也不会在目录里被列成开放 hub(.htconfig.php L69-77 注释原文)
admin_emailroot@example.com系统邮件发件人兼管理员通知地址;REGISTER_APPROVE 时必须是已注册人员的邮箱(L55-56 注释)
sellpage空公共站点销售页绝对 URL(http/https 开头)
theme / allowed_themesredbasic / 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_mode0(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_serverhttps://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_timeout605单次抓取总超时(秒);设 0 反而回到 60(!== 0 判断),"0=不限"在面板文案里有误导
curl_connecttimeout303TCP 连接超时(秒);设 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 / pubkeyPEM 格式密钥串(config 表两行,各约 1.7KB,3.4 全表 dump 中省略)安装向导生成的站点级 RSA 密钥对(Zot 协议签名根密钥),存 DB 明文带 \n 转义。备份站点必须备份 config 表,丢私钥等于丢站点身份,联邦对端全部失联
transport_security_header1响应附 HSTS 头;反代已发同名头时设 0(.htconfig.php L43-46 注释)
content_security_policy1响应附 CSP 头;要嵌外部统计/资源时设 0
ssl_cookie_protection1HTTPS 下 Cookie 加 Secure 属性;纯 HTTP 站点无效果

5.6 数据库与运行期状态

参数实测值说明
db_version1265数据库结构版本号,util/update_db 比对它决定是否跑升级 SQL(部署篇实测回显 DB up to date: 1265)
db_skip_locked_supported0.htconfig.php L13-16 注释:postgres>9.5 / mysql>8.0 / mariadb>10.6 支持 SKIP LOCKED(守护进程取任务不锁行)。向导保守写 0;MariaDB 11 环境建议改 1 降低多 daemon 争用
lastcron / lastcroncheck / lastpoll2026-11-02 05:37:25(三值同步)poller 心跳时间戳(UTC)。跑一次 php Zotlabs/Daemon/Master.php Cron 后三值刷新——部署篇 4.8 用它验证 cron 真正生效,管理员面板「Cron check」据此告警
permsjson: 前缀数组(完整值见 3.4 全表 dump)渠道默认权限清单(17 项),即 3.4 数组编码的实例
as_objects_moved / diaspora_objects_moved1旧版 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 11.4.2 配置参数详解 - Quzuo