Liwan 1.8 配置参数详解
Liwan 1.8 全量配置参数详解:TOML 与环境变量双轨、trusted_proxies 信任链、GeoIP 接入、DuckDB 与 limits 资源旋钮及实体级采集开关。
Liwan 1.8 配置参数详解
Liwan 的配置面非常克制:一个 TOML 文件或一组环境变量,加上看板里按实体逐项设置的采集开关,就构成了全部可调项。本文基于 v1.8.2(2026-10-29 发布)实测整理,配置样例文件由 liwan generate-config 在 Ubuntu 22.04 上实际生成,参数含义与默认值以官方配置参考(liwan.dev/reference/configuration/,查询日期 2026-10-30)为准并与实测行为交叉核对。安装过程见《Ubuntu 22.04 安装 Liwan 1.8 指南》,项目定位见《Liwan 1.8 介绍与选型指南》。
💡 技术拓展:TOML 与环境变量双轨制是这类 Rust 生态服务的常见惯例(底层多为 serde + config crate 组合)。TOML 适合落盘表达层级结构(如
[geoip]、[limits]段),环境变量适合无状态注入(systemdEnvironment=、容器编排 secrets),两者同名参数互为覆盖,一般环境变量优先级更高。Liwan 的环境变量名有固定规律:TOML 键路径大写、点号换下划线、加LIWAN_前缀,如duckdb.memory_limit→LIWAN_DUCKDB_MEMORY_LIMIT,记住规律就不用查表。
一、配置文件发现与生成
1.1 配置文件的查找位置
Liwan 启动时按以下优先级确定配置(来源:官方配置参考):
- 命令行
--config PATH指定的路径,或环境变量LIWAN_CONFIG; - 未指定时,在标准 XDG 配置目录(
~/.config/liwan/liwan.config.toml等)与当前工作目录查找liwan.config.toml。
完全没有任何配置文件时,Liwan 用内置默认值也能正常运行(默认监听 0.0.0.0:9042,数据落在 $HOME/.local/share/liwan/data)。
1.2 生成示例配置
liwan generate-config -o /root/liwan.config.toml
实测回显:
2026-10-30T02:13:05.383434Z WARN liwan::config: Base URL is not using HTTPS
Configuration file written to liwan.config.toml
生成的文件内容(实测全文,注释即官方说明):
base_url = "http://localhost:9042" # Public URL, optionally with a path, e.g. https://example.com/liwan
listen = 9042 # The port to listen on (http)
## Disable favicon fetching from the DuckDuckGo API.
# disable_favicons = false
## Folder to store the database in (Will be created if it doesn't exist)
## defaults to $HOME/.local/share/liwan/data on linux/macos
## defaults to ./liwan-data on other platforms
# data_dir="./liwan-data"
## Dashboard session lifetime (default: 14 days).
# session_duration = "14d"
## Additional dashboard footer links. Include the base path in local URLs if configured.
# footer_links = [{ label = "Privacy", url = "https://example.com/privacy" }, '<a href="/help">Help</a>']
## Custom HTML for the dashboard page head. Use only trusted HTML.
# head_html = '<meta name="custom" content="value">'
# head_html = ['<meta name="custom" content="value">', '<link rel="stylesheet" href="https://example.com/style.css">']
## Trusted client IP headers (used in order), defaults to X-Forwarded-For.
## Presets: cloudflare, fastly, fly, cloudfront, akamai.
## Provider presets can be combined with standard or custom headers.
# trusted_headers = ["X-Forwarded-For"]
## Trusted reverse proxies (IP or CIDR), defaults to the IPv4 and IPv6 loopback ranges.
## Use "*" to trust all direct peers only when network access to liwan is restricted.
# trusted_proxies = ["127.0.0.1/8", "::1/128"]
## Hour of day, in the server's local timezone, when visitor grouping salts rotate.
## Defaults to 4, meaning 4am local time.
# visitor_group_rotation_hour=4
[geoip] # GeoIp settings (Optional)
## MaxMind account ID and license key
## Required to automatically download the database and keep it up to date
# maxmind_account_id="MY_ACCOUNT_ID"
# maxmind_license_key="MY_LICENSE_KEY"
# maxmind_edition="GeoLite2-City"
## If you don't want to automatically download the database, you can specify a path to a local file
## Otherwise, the database will be downloaded automatically and stored in the data_dir
# maxmind_db_path="./GeoLite2-City.mmdb"
## Read location data supplied by a trusted proxy.
## Presets: akamai, cloudflare, cloudfront, netlify, vercel.
## Multiple presets and custom mappings are also supported, in priority order:
# headers=["cloudflare", { country="X-Country", city="X-City" }]
# headers="cloudflare"
[duckdb] # Database settings
## See https://liwan.dev/guides/duckdb for guidance
# threads=2
# memory_limit=2G
[limits] # Resource limits
## Maximum time a report may run before timing out.
# report_timeout_seconds=30
## Maximum number of reports running at once.
# report_max_concurrency=8
## Maximum number of days in a requested report range.
# report_max_range_days=3660
## Maximum number of values returned per dimension report.
# report_max_dimension_results=1000
## Minimum entry sessions for bounce rate in summary and dimension reports. Set to 0 to disable.
# report_min_bounce_rate_sessions=10
## Minimum measured pageviews for average time on site in summary and dimension reports. Set to 0 to disable.
# report_min_avg_time_on_site_samples=5
## Maximum number of time buckets returned by a graph report.
# report_max_datapoints=2000
## Maximum number of filters per report request.
# report_max_filters=20
## Maximum length of each filter value, in bytes.
# report_max_filter_value_bytes=2048
注意两个书写细节:listen = 9042 生成的是纯端口号形式;官方参考文档中 listen 的默认值写作 0.0.0.0:9042(监听地址:端口),两种写法等价,纯端口即监听全部网卡。
二、全局参数逐项详解
2.1 参数总表
| TOML 键 | 环境变量 | 默认值 | 作用 |
|---|---|---|---|
| base_url | LIWAN_BASE_URL | http://localhost:9042 | 对外公布的完整访问地址,可含路径前缀 |
| listen | LIWAN_LISTEN | 0.0.0.0:9042 | HTTP 监听地址与端口 |
| data_dir | LIWAN_DATA_DIR | $HOME/.local/share/liwan/data(Linux/macOS) | 数据库存放目录,不存在自动创建 |
| disable_favicons | LIWAN_DISABLE_FAVICONS | false | 关闭从 DuckDuckGo API 抓取站点图标 |
| session_duration | LIWAN_SESSION_DURATION | 14 days | 看板登录会话有效期 |
| footer_links | — | 空 | 看板页脚自定义链接 |
| head_html | — | 空 | 注入看板页面的自定义 HTML(仅可信内容) |
| trusted_headers | LIWAN_TRUSTED_HEADERS | X-Forwarded-For | 依次尝试的客户端 IP 请求头 |
| trusted_proxies | LIWAN_TRUSTED_PROXIES | 127.0.0.1/8, ::1/128 | 允许提供信任头的直连代理网段 |
| visitor_group_rotation_hour | LIWAN_VISITOR_GROUP_ROTATION_HOUR | 4 | 访客分组盐值每日轮转时刻(服务器本地时区) |
| geoip.maxmind_account_id | LIWAN_MAXMIND_ACCOUNT_ID | 空 | MaxMind 账号 ID |
| geoip.maxmind_license_key | LIWAN_MAXMIND_LICENSE_KEY | 空 | MaxMind 许可密钥 |
| geoip.maxmind_edition | LIWAN_MAXMIND_EDITION | GeoLite2-City | MaxMind 数据库版本 |
| geoip.maxmind_db_path | LIWAN_MAXMIND_DB_PATH | 空 | 本地 mmdb 文件路径(跳过自动下载) |
| geoip.headers | LIWAN_GEOIP_HEADERS | 空 | 从可信代理头读取位置信息 |
| duckdb.memory_limit | LIWAN_DUCKDB_MEMORY_LIMIT | 空(引擎默认) | DuckDB 内存上限 |
| duckdb.threads | LIWAN_DUCKDB_THREADS | CPU 核数 | DuckDB 工作线程数 |
| limits.report_timeout_seconds | LIWAN_LIMITS_REPORT_TIMEOUT_SECONDS | 30 | 单报表最长运行时间 |
| limits.report_max_concurrency | LIWAN_LIMITS_REPORT_MAX_CONCURRENCY | 8 | 同时运行的报表数上限(1-10) |
| limits.report_max_range_days | LIWAN_LIMITS_REPORT_MAX_RANGE_DAYS | 3660 | 报表允许的最大查询区间天数 |
| limits.report_max_dimension_results | LIWAN_LIMITS_REPORT_MAX_DIMENSION_RESULTS | 1000 | 单维度报表返回条目上限 |
| limits.report_min_bounce_rate_sessions | — | 10 | 跳出率进摘要/维度报表的最小会话数(0 关闭) |
| limits.report_min_avg_time_on_site_samples | — | 5 | 平均时长进报表的最小浏览量样本(0 关闭) |
| limits.report_max_datapoints | LIWAN_LIMITS_REPORT_MAX_DATAPOINTS | 2000 | 曲线图时间桶上限 |
| limits.report_max_filters | LIWAN_LIMITS_REPORT_MAX_FILTERS | 20 | 单请求过滤器数量上限 |
| limits.report_max_filter_value_bytes | LIWAN_LIMITS_REPORT_MAX_FILTER_VALUE_BYTES | 2048 | 单个过滤值最大字节数 |
其中 footer_links、head_html、report_min_bounce_rate_sessions、report_min_avg_time_on_site_samples 四项只出现在 generate-config 生成的文件中,官方参考页表格未列出,属于「文档外参数」,升级版本后建议重新生成一次样例文件比对增量。
2.2 base_url 与 listen
base_url 是 Liwan「以为的」对外地址,影响两类东西:发给你的邮件/页面里出现的链接,以及追踪脚本引用地址的拼接。生产环境套了反向代理 + TLS 后必须改成:
base_url = "https://analytics.example.com"
如果 Liwan 挂在子路径下(如 https://example.com/liwan),直接带路径写即可,生成的示例文件注释明确支持这一形态。listen 推荐与反向代理配合收紧为本地监听:
listen = "127.0.0.1:9042"
这样 9042 端口只接受本机连接,公网流量一律由 Nginx/Caddy 转发,Liwan 自身不暴露。
2.3 data_dir 与数据文件布局
默认目录下实测有两个库文件(各带 WAL 伴生文件):
| 文件 | 存什么 |
|---|---|
| liwan-app.sqlite | 用户、项目、实体、看板设置等元数据 |
| liwan-events.duckdb | 全部访问事件(列式存储) |
备份、迁移、磁盘规划都以这个目录为对象;更换路径后 Liwan 会自动创建目录并在首次启动时重建库结构。disable_favicons 关闭的是看板里站点图标的外网抓取(DuckDuckGo API),内网部署或想消除对外请求时设为 true。
2.4 session_duration
看板登录会话时长,默认 14 天。示例文件中的写法是 session_duration = "14d"(人文时间串);修改后重启生效。这个值只影响登录态,与访客会话无关——访客侧的会话时长由实体采集设置中的 session metrics 决定(见 4.2 节)。
2.5 footer_links 与 head_html
两者都是看板外观定制点:
footer_links = [{ label = "Privacy", url = "https://example.com/privacy" }, '<a href="/help">Help</a>']
head_html = '<link rel="stylesheet" href="https://example.com/custom.css">'
head_html 官方注释特别强调 "Use only trusted HTML"——它原样注入页面 head,不要把用户可控内容放进来,否则等于给看板开了一个注入口。
三、客户端 IP 解析:trusted_headers 与 trusted_proxies
这是 Liwan 配置里最值得花笔墨的一组参数,因为它直接决定:访客分组是否准确、GeoIP 是否命中、页面退出信号是否生效、登录与事件限流是否按真实 IP 计算。Liwan 的规则是两层信任链:请求必须来自 trusted_proxies 里的直连地址,其携带的 trusted_headers 里的头才会被采信;从最近的代理向客户端方向逐跳校验,遇到第一个不在信任列表里的地址就停。
3.1 请求头预设
| 预设 | 对应请求头 |
|---|---|
| akamai | True-Client-IP |
| cloudflare | CF-Connecting-IP |
| cloudfront | CloudFront-Viewer-Address |
| fastly | Fastly-Client-IP |
| fly | Fly-Client-IP |
预设可以与标准头、自定义头混排,如 trusted_headers = ["cloudflare", "X-Real-IP"]。头名大小写不敏感,下划线会归一化为连字符。对 X-Forwarded-For 与 Forwarded 这类链式头,Liwan 会从最近的代理向客户端方向逐跳检查,遇到第一个不受信的地址即止(来源:官方配置参考 Client IP Headers 节)。
3.2 三种典型部署的写法
场景一:Nginx 与 Liwan 同机(Nginx 从 127.0.0.1 连过来,实测场景):
trusted_headers = ["X-Forwarded-For"]
trusted_proxies = ["127.0.0.1/8", "::1/128"] # 默认值即满足,可省略
Nginx 侧补两行透传即可:
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
场景二:反向代理跑在容器网络里(Liwan 收到的连接来自 Docker 网桥地址 172.17.x.x):
trusted_headers = ["X-Forwarded-For"]
trusted_proxies = ["172.17.0.0/16"]
网桥网段用 docker network inspect <network> 查实际值,Docker 在存在多个网络或自定义地址池时会选用不同网段。
场景三:Cloudflare 等 CDN 在前:
trusted_headers = "cloudflare"
trusted_proxies = ["203.0.113.10", "2001:db8:1234::/48"] # 换成实际回源地址
3.3 两个危险开关
trusted_proxies = "*":信任所有直连节点。只有在「能连到 Liwan 的都是可信系统」时才允许,比如独立的内网编排网络且端口只绑回环;否则任何客户端都能伪造 IP 头,绕过按 IP 的限流;trusted_headers = []或trusted_proxies = []:彻底关闭转发 IP 解析。所有事件按无可用客户端 IP 处理——访客分组退化为不可用、退出信号被忽略(来源:官方配置参考)。
💡 技术拓展:为什么不默认信任所有 X-Forwarded-For。XFF 是逐跳追加的明文链,任何人都能在请求里手工塞一个假值。无条件的信任等于把「我是谁」的判断权交给客户端,统计会被污染,限流会被绕开。Liwan 用「网段白名单 + 逐跳回溯」把信任面压到最小,这与 Nginx 的
set_real_ip_from/real_ip_header、AWS ELB 的 proxy protocol 白名单是同一套思想,只是做进了应用层。
四、GeoIP 与实体级采集设置
4.1 geoip 段:MaxMind 与代理头两个来源
- MaxMind 自动下载:填
maxmind_account_id+maxmind_license_key后,Liwan 自动下载所选版本数据库到 data_dir 并保持更新(v1.8.2 修复的正是自动更新的一个 metadata 解析 bug);不填账号则不启用 MaxMind; - 本地数据库:用
maxmind_db_path指向手动下载的.mmdb文件,跳过自动下载; - 代理头来源:
geoip.headers支持预设akamai、cloudflare、cloudfront、netlify、vercel与自定义映射(如{ country = "X-Country", city = "X-City" }),可多值按优先级排列。各预设的字段来源(来源:官方配置参考):
| 预设 | 国家来源 | 城市来源 |
|---|---|---|
| akamai | X-Akamai-Edgescape 中的 country_code | X-Akamai-Edgescape 中的 city |
| cloudflare | CF-IPCountry | CF-IPCity |
| cloudfront | CloudFront-Viewer-Country | CloudFront-Viewer-City |
| netlify | X-NF-Geo 中的 /country/code | X-NF-Geo 中的 /city |
| vercel | X-Vercel-IP-Country | X-Vercel-IP-City |
两个来源同时存在时 MaxMind 结果优先(逐字段独立判断)。geoip.headers 同样只在直连节点位于 trusted_proxies 时生效。未配置任何地理来源时,国家/城市维度报表显示为 Unknown(实测:未配 MaxMind 的实例上 country 维度全部归入 Unknown)。
4.2 实体级采集开关(看板设置,非 TOML)
以下配置不在配置文件里,而是在看板 Settings → Entities 中按实体逐项设置(来源:liwan.dev/collected-data/):
| 设置项 | 可选值 | 影响 |
|---|---|---|
| 访客分组 | accurate / random per request / network standard / network balanced / network accurate | 唯一访客的判定粒度,见《Liwan 1.8 介绍与选型指南》对比 |
| 地理精度 | 国家+城市 / 仅国家 / 不采集 | country/city 字段是否入库 |
| UTM 参数 | 开 / 关 | utm_source 等 5 个归因字段是否入库 |
| 会话指标 | 开 / 关 | 跳出率、停留时长、入口页、出口页是否统计 |
| 数据保留 | 全部历史 / 指定周期 | 过期事件是否被清理 |
| Drop rules | 自定义规则 | 命中规则的流量在入库前直接丢弃 |
UTM 开启时另支持别名映射:source/medium/campaign/content/term 分别映射到对应 utm 字段,ref/referrer/referer 映射到 utm_source。
4.3 prune:把采集设置应用到历史数据
改小采集粒度后,历史数据不会自动裁剪。CLI 的 prune 工具按当前设置清理历史事件(支持先预览):
liwan prune --dry-run
实测回显(服务停止后执行,数据量为安装验证时的 4 条测试事件):
2026-10-30T02:15:15.826926Z WARN liwan::config: Base URL is not using HTTPS
blog: total=4, delete=0, clear_utm=0, clear_geo=0, clear_sessions=0
total: total=4, delete=0, clear_utm=0, clear_geo=0, clear_sessions=0
Dry run only. Re-run without --dry-run to apply changes.
输出逐实体给出将删除的事件数(delete)与将被清除的 UTM/地理/会话字段数,确认无误后去掉 --dry-run 真正执行。
五、duckdb 段与 limits 段:资源旋钮
5.1 duckdb.memory_limit 与 duckdb.threads
memory_limit:DuckDB 查询引擎的内存上限,示例文件注释建议2G量级,小内存服务器可压到1G;留空时用引擎默认值;threads:查询工作线程,留空默认等于 CPU 核数;小核数服务器上显式设 2 可避免查询挤占 Web 请求。- 官方设有专门调优页(liwan.dev/guides/duckdb/)指导大流量实例的参数选择。
5.2 limits 段:报表资源防护
limits 段的 9 个参数全部围绕「报表查询」这个最重的负载设置边界:report_timeout_seconds 同时覆盖排队与执行时间;report_max_concurrency 限制并行报表数(合法区间 1-10);report_max_range_days 默认允许 10 年跨度查询,配合 report_max_datapoints(默认 2000 个时间桶)防止一次查询拖垮引擎;其余三项约束过滤条件规模,report_max_filter_value_bytes 是单个过滤值的长度上限。两个新增的采样阈值(report_min_bounce_rate_sessions=10、report_min_avg_time_on_site_samples=5)用于过滤低样本噪声——样本不足时摘要卡片与维度报表不展示对应指标值,设 0 可关闭该行为(来源:v1.8.0 发布说明与生成配置注释)。
多用户共享一台服务器跑 Liwan 时,建议显式收紧这一段;单用户小站保持默认即可。
六、配置生效与校验
- 修改 TOML 后重启服务生效(systemd 部署为
systemctl restart liwan); - 启动日志是第一手校验面:
Liwan is running on http://localhost:9042 (0.0.0.0:9042)中括号内即实际监听地址;WARN Base URL is not using HTTPS消失说明 base_url 已改为 https; - 环境变量方式部署时,
systemctl show liwan --property=Environment可核对注入值; - 配置文件里的环境变量引用、路径展开均不解析,Liwan 按字面值处理,路径请写绝对路径。
日常排障、反向代理完整配置与备份升级流程见《Liwan 1.8 运维实操指南》。