TrailBase 配置详解:启动参数、环境变量、config.textproto 与认证密钥(v0.35.6 实测)
基于 TrailBase v0.35.6 实测讲解三层配置体系:trail 全局参数与 run 子命令参数全清单、ADDRESS/DEPOT 等环境变量、config.textproto(TTL 与 record_apis)生效验证、WAL 模式、Ed25519 密钥、只读模式与 CORS 安全实践。
TrailBase 配置详解:启动参数、环境变量、config.textproto 与认证密钥(v0.35.6 实测)
目标:把 TrailBase 的配置体系一次讲透——CLI 参数、环境变量、
config.textproto三层各自管什么、如何验证生效,以及 SQLite WAL、JWT 密钥、CORS、只读模式等关键项的生产建议。全部命令与回显为 2026-10-28 在 Ubuntu 22.04.5 LTS + TrailBase v0.35.6 实测。安装与 systemd 托管见本专栏 《TrailBase 安装部署实战》篇。
一、配置体系总览
1.1 三层配置与优先级
TrailBase 的配置入口有三层,运维视角的优先级为:CLI 命令行参数 > 环境变量 > depot 内的 config.textproto 配置文件(后者主要负责认证策略、邮件、记录 API 等业务面配置,修改后需重启)。查看官方参数清单的最权威方式是 --help:
$ trail --help
Command line arguments for TrailBase's CLI
Usage: trail [OPTIONS] [COMMAND]
Commands:
run Starts the HTTP server
schema Export JSON Schema definitions
openapi Export OpenAPI definitions
migration Creates new empty migration file
admin Manage admin users (list, demote, promote)
user Manage users. Unlike the admin UI this will also let you change admin users
email Programmatically send emails
components Manage WASM components
backups Manage backups
mcp Starts a local MCP server connected to a running TrailBase server @[ADDRESS]
help Print this message or the help of the given subcommand(s)
Options:
--depot <DEPOT>
Directory for runtime files including the databases. Will be created by TrailBase if dir doesn't exist
[env: DEPOT=]
--public-url <PUBLIC_URL>
Public url used to access TrailBase. This is necessary for sending valid auth emails and OAuth2 redirects, i.e. after users authenticating externally
[env: PUBLIC_URL=]
--version
Print `trail` version
--shell-completion <SHELL_COMPLETION>
Generate shell auto-completion files.
[possible values: bash, elvish, fish, powershell, zsh]
-h, --help
Print help (see a summary with '-h')
两个全局参数都是环境变量友好的:--depot(数据目录,环境变量 DEPOT)与 --public-url(外部访问地址,环境变量 PUBLIC_URL)。注意它们必须写在 run 等子命令之前——写错位置会直接报 unexpected argument(真实排障案例见 《TrailBase 安装部署实战》篇 4.2)。
1.2 run 子命令参数全清单(实测照抄)
$ trail run --help
Starts the HTTP server
Usage: trail run [OPTIONS]
Options:
-a, --address <ADDRESS>
Socket address the HTTP server binds to, e.g. "0.0.0.0:80" for TCP or "unix:/tmp/tb.sock" for UDS (Default: localhost:4000) [env: ADDRESS=] [default: localhost:4000]
--admin-address <ADMIN_ADDRESS>
Optional socket address to start a separately served admin server for both UI and APIs [env: ADMIN_ADDRESS=]
--public-dir <PUBLIC_DIR>
Optional path to static assets that will be served at the HTTP root [env: PUBLIC_DIR=]
--spa
Enable SPA fallback: serve index.html for routes (paths without file extensions). File requests (e.g., /favicon.ico) will still return 404 if not found. Use with --public-dir [env: SPA=]
--geoip-db-path <GEOIP_DB_PATH>
Optional path to MaxmindDB geoip database. Can be used to map logged IPs to a geo location [env: GEOIP_DB_PATH=]
--read-only
Start with DBs and config in read-only mode, i.e. all writes will fail. Only supported with SQLite. Writes to the HTTP access logs DB are excluded
--dev
Use permissive CORS and cookies to allow for cross-origin requests when developing the UI using externally hosted UI, e.g. using a dev server
--demo
In demo mode, PII will be redacted from the logs
--stderr-logging
--cors-allowed-origins <CORS_ALLOWED_ORIGINS>
Limit the set of allowed origins the HTTP server will answer to [default: *]
--runtime-threads <RUNTIME_THREADS>
Number of threads the WASM runtime uses (Default: #cpus) [env: RUNTIME_THREADS=]
--runtime-extra-components <RUNTIME_EXTRA_COMPONENTS>
Optional list of additional WASM components to load besides `<depot>/wasm/*.wasm` [env: RUNTIME_EXTRA_COMPONENTS=]
--runtime-root-fs <RUNTIME_ROOT_FS>
Optional path to sandboxed root Filesystem accessible by WASM guests [env: RUNTIME_ROOT_FS=]
--experimental-pg <EXPERIMENTAL_PG>
Postgres URL, like: postgresql://<user>:<pass>@localhost:<port>/<db> [env: EXPERIMENTAL_PG=]
-h, --help
Print help
除 TCP 外还支持 Unix Domain Socket(--address unix:/tmp/tb.sock),适合本机反代场景;--experimental-pg 可把存储后端换成 Postgres(v0.28+ 实验特性,本文默认 SQLite)。
二、网络与监听配置实测
2.1 默认绑定:localhost:4000
不带任何参数启动,实测日志:
[INFO trailbase::server] Listening on http://[::1]:4000 🚀
默认只监听本机回环(IPv6 ::1,等效 localhost)的 4000 端口。这意味着默认配置外网不可达,这是安全默认值,生产对外需要显式改绑定。
2.2 --address 参数与 ADDRESS 环境变量(实测)
命令行方式:
$ trail run --address 0.0.0.0:8090
[INFO trailbase::server] Listening on http://0.0.0.0:8090 🚀
环境变量方式(效果等价,实测 healthz 返回 200):
$ ADDRESS=0.0.0.0:4100 DEPOT=/tmp/c1/depot-env trail run
[INFO trailbase::data_dir] Initialized or repaired depot: "/tmp/c1/depot-env"
[INFO trailbase::server] Listening on http://0.0.0.0:4100 🚀
$ curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:4100/_/admin/api/healthz
200
2.3 管理面分离:--admin-address(实测)
把 Admin UI/管理 API 拆到独立端口,业务面与管理面可分网段防护:
$ ADDRESS=127.0.0.1:4101 ADMIN_ADDRESS=127.0.0.1:4102 trail run
[INFO trailbase::server] Listening on http://127.0.0.1:4101 🚀 (Admin UI: http://127.0.0.1:4102/_/admin/)
实测验证:业务端口 4101 上 /_/admin/api/healthz 返回 404(管理路由已迁走),4102 上 Admin UI 返回 200。生产建议:ADMIN_ADDRESS 绑定内网地址或 localhost,仅经跳板访问。
2.4 CORS:默认放行任意来源(实测 + 安全建议)
默认 --cors-allowed-origins *,实测带任意 Origin 头请求,服务端直接回显放行:
$ curl -s -i http://127.0.0.1:8090/_/admin/api/healthz -H 'Origin: https://evil.example' | grep -i access-control
access-control-allow-origin: https://evil.example
生产建议显式收敛:--cors-allowed-origins https://app.example.com(多个来源用逗号分隔)。前端与 API 同域部署(反代同源)时可保持默认并在网关层控制。
三、数据目录 depot 与环境变量
3.1 --depot / DEPOT:数据落点
--depot(或环境变量 DEPOT)决定全部运行时文件的位置,目录不存在时自动创建(实测见 2.2 日志 Initialized or repaired depot)。标准目录结构:
| 子项 | 用途 |
|---|---|
data/ | SQLite 数据库:main.db、session.db、logs.db(含 -wal/-shm) |
secrets/keys/ | Ed25519 JWT 私钥/公钥(private_key.pem / public_key.pem) |
secrets/secrets.textproto | 应用级加密密钥库 |
config.textproto | 服务端业务配置(见第四节) |
migrations/ | schema 迁移文件(建表/改表按序落盘) |
backups/ | 内置备份输出目录(按时间戳分子目录) |
uploads/、wasm/ | 上传文件、WASM 组件 |
备份 = 备份整个 depot 目录(停机冷备可直接打包;在线备份见 《TrailBase 命令与运维实战》篇的 backups trigger 与 SQLite .backup)。
3.2 PUBLIC_URL 与公开静态资源
--public-url:外部可达地址,影响认证邮件里的重置链接和 OAuth2 回跳(help 原文:"necessary for sending valid auth emails and OAuth2 redirects")。生产必配,且要与反代对外域名一致。--public-dir+--spa:把编译好的前端静态文件挂到 HTTP 根路径;--spa启用 SPA 回退(无扩展名路径回 index.html)。
四、config.textproto 配置文件
4.1 默认内容逐行解读(实测)
首次启动自动生成(路径 <depot>/config.textproto):
# Auto-generated `config.Config` textproto.
email {}
server {
application_name: "TrailBase"
logs_retention_sec: 604800
}
auth {
auth_token_ttl_sec: 3600
refresh_token_ttl_sec: 2592000
}
jobs {}
email {}:SMTP 未配置(为空时回落本机 sendmail);server.logs_retention_sec: 604800:访问日志保留 7 天;auth.auth_token_ttl_sec: 3600:JWT 访问令牌 1 小时;auth.refresh_token_ttl_sec: 2592000:刷新令牌 30 天;jobs {}:后台定时任务(内置 Backup 任务默认关闭)。
4.2 实测:改 auth_token_ttl_sec 并验证 JWT 生效
把 TTL 从 3600 改为 120 秒,重启后登录并解码 JWT(exp - iat):
$ sed -i 's/auth_token_ttl_sec: 3600/auth_token_ttl_sec: 120/' <depot>/config.textproto
$ systemctl restart trailbase
登录取 auth_token,Base64 解码 payload 实测结果:
iat: 1793154680 exp: 1793154800 ttl: 120
TTL 修改即时反映在签发的 JWT 上,验证了配置文件的有效性。该值越小越安全(泄漏窗口短),配合刷新令牌机制一般保持默认 3600 即可。
4.3 实测:record_apis 注册记录 API(含 STRICT 报错实录)
TrailBase 不会自动把表暴露成 REST 记录 API——必须在 config.textproto 的 record_apis 中显式注册(或用 Admin UI 配置)。示例(表 notes,匿名只读、登录用户可增删改):
record_apis {
name: "notes"
table_name: "notes"
acl_world: 2
acl_authenticated: 15
enable_subscriptions: true
}
权限位含义:CREATE=1、READ=2、UPDATE=4、DELETE=8(acl_world: 2 即匿名仅读;acl_authenticated: 15 即登录用户全部权限)。
排障实录一:表必须 STRICT。 笔者先用普通 CREATE TABLE notes (...) 建表,重启服务直接失败,日志原文:
trail[3743]: Error: Config(Invalid("TABLE \"notes\" referenced by API 'notes': Must be STRICT for strong end-to-end type-safety."))
trailbase.service: Main process exited, code=exited, status=1/FAILURE
TrailBase 强制要求被记录 API 引用的表是 STRICT 表(SQLite 3.37+ 的严格类型模式)。改建:
CREATE TABLE notes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
body TEXT DEFAULT '',
owner TEXT,
created_at INTEGER DEFAULT (unixepoch())
) STRICT;
修正后重启服务 active,记录 API 全链路可用(CRUD 实测见 《TrailBase 命令与运维实战》篇第三节)。
五、SQLite 与密钥体系
5.1 WAL 模式确认(实测)
三库默认启用 WAL(这也是官方声明可用 --read-only 的前提):
$ sqlite3 'file:/var/lib/trailbase/traildepot/data/main.db?mode=ro' 'PRAGMA journal_mode;'
wal
目录中可见配套的 main.db-wal / main.db-shm 文件。WAL 带来读写并发能力,且 checkpoint 前数据落在 -wal 文件——备份必须用在线备份手段(见 《TrailBase 命令与运维实战》篇),直接拷 main.db 单文件可能丢最新写入。
5.2 Ed25519 密钥对与公钥分发(实测)
JWT 用 EdDSA(Ed25519)非对称签名,密钥在 <depot>/secrets/keys/:
private_key.pem # 168 字节,务必随 depot 备份、严控权限
public_key.pem # 113 字节
其他后端服务可拿公钥离线验签,无需回调 TrailBase。公钥也可经管理 API 在线获取(实测):
$ curl -s http://127.0.0.1:8090/api/_admin/public_key -H "Authorization: Bearer $AT" -H "CSRF-Token: $CS"
-----BEGIN PUBLIC KEY-----
MCowBQYDK2VwAyEAe8NUeNOX9qgGfNDIkqGNNOff3QhcJOqGkEb49Jyrxfk=
-----END PUBLIC KEY-----
注意:换 depot = 换密钥 = 全部旧 JWT 失效;迁移环境请整体搬 secrets/。
5.3 管理 API 的双头认证(实测错误提示)
Admin API(/api/_admin/...)要求 Authorization: Bearer <JWT> 和 CSRF-Token: <csrf_token> 两个请求头同时有效(登录响应三令牌中的 csrf_token,其值同时编在 JWT claims 里,服务端做比对)。实测缺失/错误时的真实回显:
GET 不带 CSRF-Token -> "admin APIs require csrf header"
CSRF-Token 填错 -> "invalid CSRF token"(HTTP 400)
curl 调用模板见 《TrailBase 命令与运维实战》篇。
六、运行模式开关实测
6.1 --read-only 只读模式(实测)
$ trail run --address 127.0.0.1:4104 --read-only
[INFO trailbase::server] Listening on http://127.0.0.1:4104 🚀
只读模式下一切写库操作失败。实测用正确凭据登录(登录要写 session 库)返回 500,服务日志无崩溃,进程保持运行。典型用途:把存量库挂给只读副本对外提供查询,或运维窗口冻结写入。
6.2 其他开关速览
| 参数 | 用途 | 建议 |
|---|---|---|
--dev | 宽松 CORS/Cookie,配合外部开发服务器调试 UI | 仅开发用 |
--demo | 日志脱敏(PII redact) | 对外演示可用 |
--stderr-logging | 日志输出到 stderr | 交给 journald 收集时可用 |
--geoip-db-path | 挂 MaxMindDB 把日志 IP 映射地理位置 | 需自行下载库文件 |
--runtime-threads | WASM 运行时线程数(默认 CPU 数) | 一般不动 |
--experimental-pg | 实验性 Postgres 后端 | 生产暂不建议 |
七、配置变更生效路径与排障速查
- CLI 参数/环境变量:随进程重启生效;
config.textproto:改完systemctl restart trailbase。 - 常见报错对照:
| 报错(实测原文) | 根因 | 处置 |
|---|---|---|
unexpected argument '--public-url' found | 全局参数写到 run 后 | 移到子命令前 |
Must be STRICT for strong end-to-end type-safety. | 被 API 引用的表非 STRICT | 重建为 STRICT 表 |
admin APIs require csrf header / invalid CSRF token | Admin API 缺/错 CSRF 头 | 登录取 csrf_token 一并携带 |
| 改了配置不生效 | 只改了环境变量但 systemd unit 里 ExecStart 带同名参数 | CLI 优先级更高,二选一 |
- 相关互链:安装与 systemd → 《TrailBase 安装部署实战》;记录 API 的 curl CRUD、备份与升级 → 《TrailBase 命令与运维实战》;选型背景 → 《TrailBase 认知与选型》。