OpenHabitTracker 1.2.5 配置参数详解

OpenHabitTracker 1.2.5 配置参数详解:环境变量与 appsettings.json 四层配置、账号与 JWT 密钥实测坑位(仅首次生效/轮换登出)、TZ 与日志级别、Settings 表 56 列与 SQLite 数据模型,实测验证。

OpenHabitTracker习惯追踪配置2026/10/24

OpenHabitTracker 1.2.5 配置参数详解

目标:把自托管 OpenHabitTracker 1.2.5 时会用到的全部配置讲透——容器环境变量、内置 appsettings.json 默认值、数据目录里的 SQLite 与密钥文件、应用内设置,以及「改了为什么没生效」的实测结论。全部参数行为在 Ubuntu 22.04 + 官方镜像 jinjinov/openhabittracker:1.2.5(.NET 10.0.12)部署实例上实测验证,服务端口以 8129 为例。

一、环境信息

  • 应用版本:OpenHabitTracker 1.2.5(镜像 jinjinov/openhabittracker:1.2.5,程序集 OpenHT.dll,运行时 .NET 10.0.12)
  • 实测环境:Ubuntu 22.04(x86_64)+ Docker 27.3.1,服务端口 8129 → 容器内 8080
  • 配置源码基线:1.2.5 tag 的 OpenHabitTracker.Blazor.Web/appsettings.json 与 Program.cs(GitHub 实查,2026-10-24)
  • 数据库:SQLite(OpenHT.db),ASP.NET Core DataProtection 密钥与数据库同目录存放
  • 前提:已完成部署并可用(未部署请先按本专栏《OpenHabitTracker Docker Compose 部署指南》完成,本文复用其部署目录与 .env 约定)

二、前置条件

  1. 能进入部署目录并重建容器(改配置的主要手段是改环境变量后重建):
cd /opt/openhabittracker   # 换成你的部署目录
docker compose ps --format '{{.Name}} {{.Image}} {{.Status}}'

实测回显:

oht-1.2.5-server   jinjinov/openhabittracker:1.2.5   Up 3 minutes
  1. 能读取挂载的数据目录(备份与存储布局核对用):
ls -la data/.OpenHabitTracker/

实测回显:

-rw------- 1 root root   1001 Oct 24 12:17 key-a0f0a8f2-ebd0-4156-9f2d-aa9d84ca1b43.xml
-rw-r--r-- 1 root root 143360 Oct 24 12:17 OpenHT.db
  1. (可选)服务器上有 sqlite3 或 python3,用于只读核对数据表(本文实测用 python3 内置 sqlite3 模块,只读打开,不写库)。

三、参数查看与修改方式

OpenHabitTracker 的配置分四层,优先级从高到低:

层载体查看方式修改方式生效时机
环境变量AppSettings__*、TZ、Logging__* 等docker inspect <容器> --format '{{.Config.Env}}'改 compose/.env 后重建docker compose up -d 重建后
配置文件容器内 /app/appsettings.jsondocker exec <容器> cat /app/appsettings.json挂载覆盖(不推荐)重启后
数据库层SQLite 各表(账号、刷新令牌、应用设置)只读查询 OpenHT.db应用界面操作(设置页);数据库直改有风险即时/重启后
应用内设置Settings 页 UI登录 → Settings界面开关保存即生效

内置 appsettings.json 全文(1.2.5 实查源码,容器内一致):

{
  "AppSettings": {
    "UserName": "admin",
    "Email": "admin@admin.com",
    "Password": "admin",
    "JwtSecret": "your-extremely-strong-secret-key"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}

环境变量覆盖规则(ASP.NET Core 标准约定):__(双下划线)替代配置层级分隔符,如 AppSettings__JwtSecret 覆盖 AppSettings:JwtSecret。这就是 compose 中四个 AppSettings__* 变量的由来。

四、参数总览

参数位置默认值作用风险等级
AppSettings__UserName环境变量admin初始账号用户名 + watchdog 日志页账号低(仅首次建库生效)
AppSettings__Email环境变量admin@admin.com初始账号邮箱低(仅首次建库生效)
AppSettings__Password环境变量admin初始账号口令 + watchdog 口令高(仅首次建库生效,见 5.1)
AppSettings__JwtSecret环境变量your-extremely-strong-secret-keyJWT 签发/校验密钥极高(泄露可伪造令牌;轮换即全端登出,见 5.2)
TZ环境变量Etc/UTC容器时区中(影响「今天」判定与统计)
Logging__LogLevel__Default环境变量Information全局日志级别低
Logging__LogLevel__Microsoft.AspNetCore环境变量Warning框架日志级别低
ASPNETCORE_HTTP_PORTS镜像内置8080容器内监听端口低(一般不动,改端口映射即可)
ASPNETCORE_ENVIRONMENT镜像内置Production运行环境中(Development 会开放异常详情,勿对外)
AllowedHostsappsettings.json*允许的 Host 头中(对外可收紧为域名)
应用内 SettingsSettings 页 / Settings 表界面默认主题/语言/通知/过滤等全部行为低

五、核心参数分类详解

5.1 账号参数:UserName / Email / Password

三者只在数据库中不存在同名用户时生效:应用每次启动会执行「按 AppSettings.UserName 查用户 → 不存在则用环境变量创建」。启动日志可确认:

docker logs oht-1.2.5-server 2>&1 | grep -E 'Default user'

实测回显(首次启动):

Default user created successfully.

**实测坑位:改环境变量口令不会更新已有账号。**把 .env 中 APPSETTINGS_PASSWORD 改为新口令并重建容器后:

curl -s -X POST http://localhost:8129/api/Auth/jwt-token -H 'Content-Type: application/json' -d '{"username":"admin","password":"q1w2e3r4"}' -o /dev/null -w 'old: %{http_code}\n'
curl -s -X POST http://localhost:8129/api/Auth/jwt-token -H 'Content-Type: application/json' -d '{"username":"admin","password":"NewPass123456"}' -o /dev/null -w 'new: %{http_code}\n'

实测回显:

old: 200
new: 401

结论:口令哈希存于 SQLite 的 AspNetUsers.PasswordHash,环境变量只在创建时用一次。因此首次部署就设最终口令;后续换口令走应用内界面修改。实测改回 .env 原口令并重建后,原口令恢复可用(restored old password: 200)。

账号数据落库实查(只读):

python3 -c "import sqlite3; con=sqlite3.connect('file:data/.OpenHabitTracker/OpenHT.db?mode=ro', uri=True); print([r[1] for r in con.execute('PRAGMA table_info(AspNetUsers)')])"

实测回显:

['Id', 'UserName', 'NormalizedUserName', 'Email', 'NormalizedEmail', 'EmailConfirmed', 'PasswordHash', 'SecurityStamp', 'ConcurrencyStamp', 'PhoneNumber', 'PhoneNumberConfirmed', 'TwoFactorEnabled', 'LockoutEnd', 'LockoutEnabled', 'AccessFailedCount', 'LastChangeAt']

5.2 JwtSecret:令牌签名密钥

用途:登录 API(POST /api/Auth/jwt-token)签发 JWT、服务端校验令牌签名(签发方与校验方同源此密钥,签发的令牌有效期 1 天;刷新令牌有效期 90 天,存 RefreshTokens 表)。

**实测结论:轮换 JwtSecret 会使所有已签发 JWT 立即失效。**轮换前把登录返回的令牌存入 token.txt(获取方式见本专栏《OpenHabitTracker 1.2.5 API 使用详解》认证一节),改密钥重建后用旧令牌调数据接口:

curl -s -o /dev/null -w 'old-token with new secret: %{http_code}\n' http://localhost:8129/api/DataAccess/notes -H "Authorization: Bearer $(cat token.txt)"

实测回显:

old-token with new secret: 401

恢复原密钥并重新登录后,接口恢复 200。运维要点:

  • 密钥生成用 openssl rand -base64 32,不要用示例占位值;
  • 轮换密钥 = 所有客户端(PWA/桌面/手机)同时登出,需重新登录,数据无损;
  • 泄露必须轮换(攻击者可自签任意令牌)。

💡 技术拓展:JWT 签名算法常见选择对比——

算法原理特点本文项目实际采用
HS256(HMAC-SHA256)对称密钥,签发/校验同一把钥匙简单;密钥必须在签发与校验方共享是(源码 SecurityAlgorithms.HmacSha256,单服务自洽场景合理)
RS256/ES256非对称,私钥签名公钥校验适合多服务分发公钥验签否(单服务无必要)

OpenHabitTracker 是单体单用户服务,签发与校验在同一进程,HS256 足够。

5.3 时区:TZ

影响统计的「今天」边界、日历图与通知时间。实测容器内:

docker exec oht-1.2.5-server date

实测回显(TZ=Asia/Shanghai):

Sat Oct 24 12:31:57 CST 2026

不设置时容器走 UTC,国内傍晚产生的记录会被算到「明天」。设为你的 IANA 时区(如 Asia/Shanghai)并在改后重建容器。

5.4 日志参数:Logging__LogLevel__*

默认级别:全局 Information、ASP.NET Core 框架 Warning(appsettings.json 默认)。排障时可临时提高认证日志级别:

    environment:
      - Logging__LogLevel__Microsoft.AspNetCore.Authentication=Debug

重建后访问一次受保护接口,日志即可看到认证细节(实测节选):

dbug: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[2]
      Successfully validated the token.
info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[12]
      AuthenticationScheme: Bearer was challenged.

这两行是定位「令牌有效但接口仍 401」类问题的关键证据(本文实测曾据此区分出「令牌校验失败」与「令牌有效但授权策略不认」两种 401)。排障完建议去掉 Debug 级别。

5.5 运行时参数:端口/环境/Host/HTTPS

  • ASPNETCORE_HTTP_PORTS=8080:镜像内置监听端口,改宿主机端口只需动 compose 的 ports 映射(如 "8129:8080"),不必动它;
  • ASPNETCORE_ENVIRONMENT:保持 Production。生产模式下异常返回精简 JSON(API 路径)或跳转 /Error 页面;Development 会暴露异常堆栈(应用对 /api 异常返回 message+stackTrace 的 JSON),切勿对外开放;
  • AllowedHosts: *:默认接受任意 Host 头;已配反向代理 + 域名时建议改为具体域名,防 Host 头注入;
  • HTTPS:应用启用了 UseHttpsRedirection 与 HSTS(源码默认),但官方镜像内无证书,重定向中间件在无配置端口时仅告警不生效(实测启动日志有 warn: Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionMiddleware)。对外服务请在前面挂 Nginx/Caddy 等 TLS 网关终结 HTTPS,容器保持 HTTP 内网通信。

5.6 应用内设置:Settings 表全参数

登录后在 Settings 页调整的项保存在 SQLite Settings 表(按用户一行)。实测表结构共 56 列(只读查询 PRAGMA table_info(Settings)),按用途归类如下:

类别代表列说明
外观IsDarkMode、Theme、Color(行背景)、HorizontalMargin/VerticalMargin26 套 Bootswatch 主题 + 深浅色
语言与本地化Culture、FirstDayOfWeek20 种语言;周起始日
启动行为StartPage、StartSidebar、FoldSection启动进入哪个页面/侧栏、折叠区
列表显隐ShowItemList、ShowPriority、ShowCategory、ShowColor、ShowCreatedUpdated、HideCompletedTasks、ShowGroupedByCategory、ShowLastTimeDone每行显示哪些字段
日历ShowSmallCalendar、ShowLargeCalendar、MaxSmallCalendarDays列表旁日历开关与天数
习惯统计ShowHabitStatistics、ShowHabitCharts、SelectedRatio、SelectedRatioMin/Max、ShowOnlyOverSelectedRatioMin、ShowOnlyUnderSelectedRatioMax周统计、图表、按超期百分比过滤
日期过滤DoneFromDayOffset/DoneToDayOffset、PlannedFromDayOffset/PlannedToDayOffset、ShowDoneInRange「距今天数」式过滤器(保存后不过期)
通知NotificationContent、NotificationHabitThreshold、NotificationIncludeOverdueTasks、NotificationLeadMinutes、NotificationMinimumPriority、NotificationTime每日摘要内容/时间、任务提醒提前量与优先级下限
同步BaseUrl、RefreshToken、RememberMe、Username客户端指向的服务器地址与刷新令牌
编辑行为InsertTabsInNoteContent、DisplayNoteContentAsMarkdown、UncheckAllItemsOnHabitDone、ShowHelpMarkdown 渲染、习惯完成时清单重置等

要点:

  • 这些设置随 JSON/YAML 备份一并导出并参与同步(官方 README 明确),换设备不必重调;
  • Settings 表按 UserId 区分——单用户部署就是一行。

5.7 数据存储布局:OpenHT.db 表结构

实测表清单(只读查询 sqlite_master):

tables: ['AspNetRoleClaims', 'AspNetRoles', 'AspNetUserClaims', 'AspNetUserLogins', 'AspNetUserRoles', 'AspNetUserTokens', 'AspNetUsers', 'Categories', 'Contents', 'Items', 'Priorities', 'RefreshTokens', 'Settings', 'Times', '__EFMigrationsHistory', '__EFMigrationsLock', 'sqlite_sequence']

核心业务表解读:

表角色实测关键列
Contents习惯/笔记/任务三合一主表(EF Core TPH 继承,Discriminator 区分行类型)Id, CategoryId, Title, Color, Priority, IsDeleted, CreatedAt, UpdatedAt, Discriminator + 习惯专属(RepeatCount/RepeatInterval/RepeatPeriod/TargetQuantity/DisplayMetric/StartAt)+ 任务专属(PlannedAt, TaskEntity_Duration, StartedAt, CompletedAt)+ 笔记专属(Content)
Items清单项(任务的 checklist)Id, ParentId, Title, DoneAt
Times习惯完成流水Id, HabitId, StartedAt, CompletedAt, Quantity
Categories / Priorities分类与优先级字典用户可自定义扩展
Settings应用内设置(按用户一行,见 5.6)56 列
RefreshTokens登录刷新令牌(90 天轮换,含旧令牌 60 秒宽限列)Username, Token, ExpiryDate, PreviousToken, PreviousTokenValidUntil
AspNetUsers 等 AspNet*ASP.NET Core Identity 标准表口令哈希、角色、外部登录

💡 技术拓展:把多类实体存进一张表的常见方案对比——

方案原理取舍本文项目实际采用
TPH(Table per Hierarchy)所有子类共用一张表,用鉴别列区分查询快(无 join)、列有 NULL 冗余是(Contents.Discriminator)
TPT(Table per Type)每类一张表外键关联结构干净、查询要 join否
分表每类独立表简单直接,但跨类统一查询/过滤困难否(而本项目要跨三类统一搜索排序)

笔记/任务/习惯要共用「搜索、过滤、排序、分类、优先级」,TPH 单表最贴合这个产品需求。

备份即拷贝整个 .OpenHabitTracker/ 目录(OpenHT.db + key-*.xml);应用内另提供 JSON/YAML/TSV/Markdown 导出作为跨版本/跨应用迁移格式。

六、生产配置模板

适用场景:个人/家庭单用户自托管(2 核 CPU、1GB 内存、10GB 磁盘即可长期稳定运行;SQLite 单文件随数据量增长,纯文本数据一年量级在数十 MB 内)。

name: oht-1.2.5-stack
services:
  openhabittracker:
    image: jinjinov/openhabittracker:1.2.5
    container_name: oht-1.2.5-server
    ports:
      - "8129:8080"            # 或 "127.0.0.1:8129:8080" 仅本机+反代可达
    environment:
      - AppSettings__UserName=${APPSETTINGS_USERNAME}
      - AppSettings__Email=${APPSETTINGS_EMAIL}
      - AppSettings__Password=${APPSETTINGS_PASSWORD}
      - AppSettings__JwtSecret=${APPSETTINGS_JWT_SECRET}
      - TZ=Asia/Shanghai
    volumes:
      - ./data/.OpenHabitTracker:/app/.OpenHabitTracker
    restart: unless-stopped

敏感四项经 .env 注入(实际值示例,首次部署前替换为你自己的口令与密钥——口令按 5.1 结论一次设对,密钥用 openssl rand -base64 32 现场生成):

APPSETTINGS_USERNAME=admin
APPSETTINGS_EMAIL=admin@admin.com
APPSETTINGS_PASSWORD=q1w2e3r4
APPSETTINGS_JWT_SECRET=BI/pnDHJsnvA4kDltCsULSGvXuyFe5HfFhVJhB7y8OE=

⚠️ 若前面有 TLS 网关,建议把映射改为 127.0.0.1:8129:8080 只监听本机回环,由网关对外。

上线前检查清单:口令已设最终值、JwtSecret 已随机生成、TZ 正确(docker exec oht-1.2.5-server date 核对)、数据目录挂载成功(ls data/.OpenHabitTracker/ 有 OpenHT.db)、登录验证通过、备份计划(cron 拷贝目录或 docker compose down 后冷备)已安排。

七、常见问题(FAQ)

Q1:改了环境变量为什么不生效? 环境变量在容器创建时读取,docker compose restart 不重建容器配置——用 docker compose up -d(检测到配置变化会重建)。核对实际注入值:docker inspect <容器> --format '{{.Config.Env}}'。

Q2:改口令环境变量后新口令登不进? 见 5.1 实测:口令只在首次创建账号时生效,之后以数据库哈希为准。换口令走应用界面。

Q3:轮换 JwtSecret 后所有设备被登出? 正常现象(实测旧令牌 401)。重新登录即可,数据无损。这也是密钥泄露后的应急手段。

Q4:统计数据里的「今天」差 8 小时? TZ 未设或设错(容器默认 UTC)。按 5.3 设置 TZ=Asia/Shanghai 重建。

Q5:直接改 OpenHT.db 行不行? 技术可行(SQLite 标准文件),但表结构受 EF Core 迁移管理、且含口令哈希/令牌等敏感数据。建议只读查询(加 ?mode=ro),写操作走应用界面或 API,避免绕过应用校验造成脏数据。

Q6:如何把数据从浏览器 PWA 迁到自托管? PWA/客户端内 Data 页导出 JSON → 自托管实例登录后导入 JSON(应用内导入导出功能,格式含设置与全部内容)。

Q7:升级版本需要动配置吗? 不需要,配置全在环境变量与数据目录里。升级=改镜像 tag 重建(流程见部署指南第十章);应用启动时自动执行数据库迁移(启动日志可见 migration 过程)。

八、参考链接