Hatsu 0.3.5 配置参数详解

Hatsu 0.3.5 配置体系实测:进程环境变量与 .env(dotenvy)双层加载顺序、HATSU_ENV_FILE 兜底路径的文档与源码不一致、10 个 HATSU_* 参数逐项默认值与实测效果,含缺省 sqlite::memory: 连接池陷阱、主账号 Feed 校验、ACCESS_TOKEN 开关与 NodeInfo 元数据注入的逐行回显,查询与实测日期 2026-11-02。

HatsuHatsuActivityPubFediverseRust语言2026/11/02

Hatsu 0.3.5 配置参数详解

目标:把 Hatsu 0.3.5 的全部配置面——10 个 HATSU_* 环境变量、dotenv 双层加载顺序、数据库 URL 格式——逐项给出默认值、实测效果与配错的真实后果。全部回显为 2026-11-02 在三套实测实例(SQLite 栈、PostgreSQL 栈、故障复现栈)上的记录,源码口径以官方仓库 v0.3.5 标签的 src/commands/run.rs 为准。部署过程见 《Hatsu 0.3.5 Docker Compose 部署指南》,命令工具面见 《Hatsu 0.3.5 常用 CLI 命令与工具详解》。

一、环境信息

  • 组件与版本:Hatsu 0.3.5(启动日志自报 Hatsu v0.3.5 "Strobe Nights")。
  • 配置体系:官方文档 Environments 一节明确「Hatsu supports dotenv」——配置只有环境变量与 .env 文件两层,没有独立的 TOML/YAML 配置文件;.env 由 Rust 的 dotenvy 库在进程内加载。
  • 实测口径:三套实例分别演示不同配置层——SQLite 栈全部走编排注入的环境变量;PostgreSQL 栈演示 postgres:// URL;故障复现栈演示缺省值陷阱与 .env 文件层。
  • 必填口径(官方文档规则原文):变量名无 (optional) 后缀即必填,除非源码内置缺省值或 .env.example 给出示例值。

二、配置加载顺序与优先级

2.1 源码加载序列

src/commands/run.rs(v0.3.5)的启动序列决定了各配置层的生效性:

pub async fn run() -> Result<(), AppError> {
    hatsu_tracing::init()?;

    tracing::info!("{}", AppEnv::info());

    tracing::info!("loading environment variables");
    if dotenvy::dotenv().is_err() {
        let env_file =
            env::var("HATSU_ENV_FILE").unwrap_or_else(|_| String::from("/etc/hatsu/.dev"));
        if dotenvy::from_path(Path::new(&env_file)).is_err() {
            tracing::debug!("no .env file found");
        }
    }

    let env = AppEnv::init()?;

对应的实测日志序列(故障复现栈,时间戳为 2026-11-02):

  2026-11-02T06:18:44.398962Z  INFO hatsu::commands::run: Hatsu v0.3.5 "Strobe Nights"
  2026-11-02T06:18:44.398982Z  INFO hatsu::commands::run: loading environment variables
  2026-11-02T06:18:44.399001Z  INFO hatsu::commands::run: connecting database: sqlite::memory:
  2026-11-02T06:18:44.399366Z  INFO hatsu::commands::run: running database migration

2.2 优先级结论

由上述序列可确定生效顺序(高→低):

  1. 进程环境变量(编排 environment:、systemd Environment= 等注入)——dotenvy 的 dotenv() 语义是只补齐缺失项、不覆盖已存在变量,因此同名变量进程环境赢;
  2. 当前工作目录向上查找到的 .env 文件(官方制品工作目录为 /app,即 /app/.env);
  3. HATSU_ENV_FILE 指定路径的文件(仅当第 2 步找不到 .env 时才尝试);
  4. 源码内置缺省值(见第六章总表)。

⚠️ 两个源码级细节:

  • HATSU_ENV_FILE 的兜底路径:官方文档写缺省为 /etc/hatsu/.env,但 v0.3.5 源码 run.rs 的 unwrap_or_else 分支实际写的是 /etc/hatsu/.dev——文档与源码不一致,以源码为准(实测口径:给制品挂 /etc/hatsu/.env 并不会被兜底读到,除非显式设置 HATSU_ENV_FILE)。
  • hatsu_tracing::init() 发生在 dotenvy::dotenv() 之前,日志级别只读进程环境变量——写在 .env 文件里的 HATSU_LOG 不生效,必须走环境注入。

2.3 双层配置的实测证据

SQLite 栈只用了编排环境注入(9 个变量,无 .env 文件):

HATSU_ACCESS_TOKEN=123e4567-e89b-12d3-a456-426614174000
HATSU_DATABASE_URL=sqlite://hatsu.sqlite3
HATSU_DOMAIN=hatsu.local
HATSU_LISTEN_HOST=0.0.0.0
HATSU_LISTEN_PORT=3939
HATSU_LOG=info
HATSU_NODE_DESCRIPTION=S8 test instance
HATSU_NODE_NAME=My Hatsu
HATSU_PRIMARY_ACCOUNT=github.blog

故障复现栈则演示 .env 层:编排环境里只有 5 个变量、不含 HATSU_NODE_NAME/HATSU_NODE_DESCRIPTION:

HATSU_DOMAIN=hatsu.local
HATSU_LISTEN_HOST=0.0.0.0
HATSU_LISTEN_PORT=3939
HATSU_LOG=info
HATSU_PRIMARY_ACCOUNT=github.blog

而挂载进 /app/.env 的文件内容为:

HATSU_NODE_NAME=Hatsu Dotenv 实例
HATSU_NODE_DESCRIPTION=由 .env 文件注入的 NodeInfo 元数据

其 NodeInfo 实测回显(8146 端口)——两个仅存在于 .env 文件的值被进程读到:

{"version":"2.1","software":{"name":"hatsu","version":"0.3.5","repository":"https://github.com/importantimport/hatsu","homepage":"https://hatsu.cli.rs"},"protocols":["activitypub"],"services":{"inbound":[],"outbound":[]},"openRegistrations":false,"usage":{"users":{"total":1},"localPosts":0},"metadata":{"nodeName":"Hatsu Dotenv 实例","nodeDescription":"由 .env 文件注入的 NodeInfo 元数据"}}

三、核心参数逐项实测

3.1 HATSU_DOMAIN(必填,缺省 None)

实例对外域名(不带 https://),是所有联邦对象 URL 的骨架。实测 hatsu.local 的效果链:

  • actor 地址:https://hatsu.local/users/github.blog;
  • WebFinger subject:acct:github.blog@hatsu.local;
  • host-meta 的 lrdd 模板:https://hatsu.local/.well-known/webfinger?resource={uri}。

同时它决定主账号校验时生成的用户 URL(generate_user_url(domain, primary_account))。生产必须与反代对外域名一致,否则对端实例解析到的对象地址与可达地址不符。

3.2 HATSU_PRIMARY_ACCOUNT(必填,缺省 None)

实例的签名主体账号(signed_fetch_actor),取值为带有效 Feed 的站点域名。源码语义(run.rs):启动时按 HATSU_DOMAIN + HATSU_PRIMARY_ACCOUNT 组出的用户 ID 查库,查不到则现场创建——创建过程要真实拉取该域名 Feed 发现 Feed URL。

实测三种行为:

  1. github.blog(有 RSS):启动日志 checking primary account: github.blog 通过,账号自动入库(psql 回显 The GitHub Blog | github.blog | t);
  2. example.com(无 Feed):启动即致命错误、重启循环:
Error: AppError { error: "Unable to find Feed Url named example.com", error_id: 01a19a40-6c59-7a72-8824-fa925477e5a1, status: 404, context: SpanTrace [] }
  1. 主账号不可删除:Admin API 对 github.blog 返回 405(Remove account API not yet implemented,且不止主账号——0.3.5 所有删号都是 405,见命令篇)。

3.3 HATSU_LISTEN_HOST / HATSU_LISTEN_PORT(缺省 127.0.0.1 / 3939)

监听地址与端口。官方制品的环境基线里已注入 HATSU_LISTEN_PORT=3939(制品配置的 Env 项实测可见),编排部署必须显式 HATSU_LISTEN_HOST: 0.0.0.0 才能被宿主端口映射打通(127.0.0.1 缺省只监听回环)。实测三套栈分别映射宿主 8144/8145/8146 → 服务内 3939。

另见部署篇第十章 10.1 节:官方制品的探针把该变量写进了不展开的 exec 形式里,是制品缺陷而非本参数问题。

3.4 HATSU_DATABASE_URL(缺省 sqlite::memory:——生产必须显式设置)

只接受 sqlite: 或 postgres: URL(SeaORM/sqlx 口径)。官方文档自述缺省值动机:「sqlite::memory: is used by default to ensure that hatsu does not report errors as a result」——仅为让 Hatsu 不因缺配置而直接报错。

实测两种取值:

SQLite 文件路线(官方推荐 sqlite://hatsu.sqlite3,相对制品工作目录 /app,需与挂载目标对齐):

  2026-11-02T03:14:12.201110Z  INFO hatsu::commands::run: connecting database: sqlite://hatsu.sqlite3

PostgreSQL 路线(口令走编排内部网络,数据库不映射宿主端口;示例口令 q1w2e3r4):

HATSU_DATABASE_URL: postgres://hatsu:q1w2e3r4@db:5432/hatsu

缺省值的真实后果(故障复现栈全程实录):不设该变量 → connecting database: sqlite::memory: → 启动时迁移与主账号写入发生在连接池的第一个连接上,而 :memory: 是每连接独立的私有库——后续请求被派到其他连接时表根本不存在:

{"error":"Query Error: error returned from database: (code: 1) no such table: user","error_id":"01a19ae5-2ca0-7252-8de1-f20a0d270f74"} [HTTP 500]

表现为间歇性 500(刚启动时部分请求 200,之后越来越 500),日志里迁移明明全部 has been applied。结论:sqlite::memory: 与连接池模型不兼容,不具备生产可用性,任何部署都必须显式设置本参数。

3.5 HATSU_LOG(缺省 info)

格式同 RUST_LOG(tracing EnvFilter 语法)。官方示例:

info,tokio::net=debug,sqlx::query=warn

实测 HATSU_LOG=info 时,sqlx 的逐条 SQL 会以 INFO 级别刷屏(部署篇第五、八章日志里大量 summary: "SELECT \"user\"... 行即此),生产建议按示例把 sqlx::query 压到 warn。注意 2.2 节结论:本参数写进 .env 文件不生效(tracing 初始化早于 dotenv 加载),必须走进程环境注入。

四、可选参数

4.1 HATSU_ACCESS_TOKEN(可选——Admin API 总开关)

官方文档:「If this value is not set, the Hatsu Admin API will not be available.」建议 uuid v4,示例生成命令:

echo "\nHATSU_ACCESS_TOKEN = \"$(cat /proc/sys/kernel/random/uuid)\"" >> .env

实测三态(token 值 123e4567-e89b-12d3-a456-426614174000):

  • 未设置该变量(故障复现栈):任何 Admin API 调用直接 401 空响应:
HTTP 401
  • 设置了但 token 传错(SQLite 栈):同样 401 空响应:
HTTP 401
  • 正确 token:建号 201、封禁 200 等(见部署篇第七章)。

即本参数是 Admin API 的存在性开关,无 token 实例等于关闭全部管理能力。

4.2 HATSU_NODE_NAME / HATSU_NODE_DESCRIPTION(可选)

只影响 NodeInfo 的 metadata.nodeName / nodeDescription 两字段(源码 NodeInfoMetadata::new 直接克隆 data.env 对应字段,skip_serializing_if = Option::is_none)。实测对照:

  • SQLite 栈(环境注入):"metadata":{"nodeName":"My Hatsu","nodeDescription":"S8 test instance"};
  • 故障复现栈(.env 注入):"metadata":{"nodeName":"Hatsu Dotenv 实例","nodeDescription":"由 .env 文件注入的 NodeInfo 元数据"};
  • PostgreSQL 栈(两者都没设):"metadata":{}——字段整体消失,合法降级。

除展示外无功能影响,FEP-f1d5 口径的实例元数据。

4.3 HATSU_ENV_FILE(可选)

.env 兜底路径开关,仅在「工作目录链上找不到 .env」时生效(见 2.1 序列)。文档缺省写 /etc/hatsu/.env、源码实际兜底 /etc/hatsu/.dev(2.2 节不一致点);要固定路径建议显式设置本变量,别赌兜底。

五、数据库 URL 格式与迁移机制

两种 URL 实测均可用(3.4 节),建库建表由启动时 SeaORM Migrator 自动完成,无独立迁移命令(CLI 里没有 migrate 子命令,实测 error: unrecognized subcommand 'migrate',见命令篇)。

迁移版本表实测(PostgreSQL 栈 psql,SQLite 栈同构):

                  version                   
--------------------------------------------
 m20240131_000001_user
 m20240131_000002_user_feed_item
 m20240131_000003_post
 m20240131_000004_activity
 m20240131_000005_received_follow
 m20240501_000001_received_like
 m20240501_000002_received_announce
 m20240515_000001_user_feed_hatsu_extension
 m20240515_000002_user_feed
 m20240926_000001_blocked_url
 m20241028_000001_user_language
(11 rows)

对应 9 张业务表(user/post/activity/user_feed_item/received_follow/received_like/received_announce/blocked_url/seaql_migrations)。升级版本时重启即自动补迁移,回滚需谨慎(无 down 流程暴露给运维)。

六、参数总表

参数必填缺省实测要点
HATSU_LOG否infoRUST_LOG 语法;.env 里设置不生效(时序)
HATSU_ENV_FILE否文档 /etc/hatsu/.env,源码 /etc/hatsu/.dev仅 .env 缺失时兜底;文档/源码不一致
HATSU_DATABASE_URL否(但必须设)sqlite::memory:缺省值与连接池冲突→间歇 500;用 sqlite://hatsu.sqlite3 或 postgres://
HATSU_DOMAIN是None对象 URL/WebFinger 骨架;须与反代域名一致
HATSU_LISTEN_HOST否127.0.0.1编排/反代部署必改 0.0.0.0
HATSU_LISTEN_PORT否3939制品基线已注入 3939;探针缺陷波及本变量
HATSU_PRIMARY_ACCOUNT是None必须有有效 Feed,否则启动崩溃循环;不可删除
HATSU_ACCESS_TOKEN可选None未设则 Admin API 整体 401
HATSU_NODE_NAME可选NoneNodeInfo metadata.nodeName;环境/.env 两层均可注入
HATSU_NODE_DESCRIPTION可选NoneNodeInfo metadata.nodeDescription;同上

七、常见错配速查

  1. 忘设 HATSU_DATABASE_URL:服务能起、日志显示迁移成功,但接口间歇 500 no such table: user——不是数据库坏了,是缺省内存库(3.4 节)。
  2. HATSU_PRIMARY_ACCOUNT 填了无 Feed 的域名:启动即崩、重启循环,日志尾行 Unable to find Feed Url named <域名>(3.2 节)。
  3. 没设 HATSU_ACCESS_TOKEN:Admin API 全部 401,无法建号/封禁(4.1 节)。
  4. HATSU_LISTEN_HOST 留缺省:宿主端口映射不通(3.3 节)。
  5. HATSU_LOG 写进 .env:静默无效,日志级别不会变(2.2 节时序)。
  6. SQLite 相对路径与挂载目标不对齐:sqlite://hatsu.sqlite3 相对 /app,挂载必须落在 /app/hatsu.sqlite3(部署篇第四章要点 4)。

完整故障定位过程(含探针缺陷案例)见 《Hatsu 0.3.5 Docker Compose 部署指南》 第十章;配置改完后的重启与验证命令见 《Hatsu 0.3.5 常用 CLI 命令与工具详解》。

Hatsu 0.3.5 配置参数详解 - Quzuo