OpenHabitTracker Docker Compose 部署指南
OpenHabitTracker 1.2.5 官方镜像 Docker Compose 部署实战:镜像选型、环境变量、数据持久化(SQLite+DataProtection)、备份升级回滚与口令坑位,全部步骤在 Ubuntu 22.04 实测通过。
OpenHabitTracker Docker Compose 部署指南
目标:在一台 Linux 服务器上用 Docker Compose 把 OpenHabitTracker 1.2.5 自托管起来,完成「部署 → 登录 → 验证 → 数据持久化 → 升级与备份」的完整闭环。以下所有命令与回显均在 Ubuntu 22.04(x86_64)+ Docker 27 环境、OpenHabitTracker 1.2.5 镜像下实测通过,宿主机服务端口以 8129 为例(可自行替换为未被占用的端口)。
一、环境信息
- 操作系统:Ubuntu 22.04(x86_64),内核 5.15+
- Docker:27.x(Docker Engine 自带 Compose v2 子命令,
docker compose) - 应用版本:OpenHabitTracker 1.2.5(官方镜像
jinjinov/openhabittracker:1.2.5,镜像内为 .NET 10.0.12 运行时) - 部署形态:单容器 Blazor Server 应用,监听容器内 8080 端口,宿主机映射 8129
- 数据存储:SQLite 单文件
OpenHT.db+ ASP.NET Core DataProtection 密钥文件,统一落在挂载目录.OpenHabitTracker/下 - 官方镜像发布渠道:Docker Hub
jinjinov/openhabittracker与 GHCRghcr.io/jinjinov/openhabittracker(README 2026-10-24 查询) - 实验目录约定:本文所有文件都放在服务器的部署目录(示例用
/opt/openhabittracker,按你的目录习惯替换即可)
二、镜像选型说明
官方维护两个发布渠道,tag 策略一致。以下为 Docker Hub 实查的 tag 列表(2026-10-24 查询,共 16 个 tag,节选):
| Tag | 构建日期 | 压缩体积 | 说明 |
|---|---|---|---|
latest | 2026-09-27 | 107 MB | 跟随最新稳定版,当前指向 1.2.5 |
1.2.5 | 2026-09-27 | 107 MB | 当前最新稳定版 |
1.2.4 | 2026-08-13 | 110 MB | |
1.2.3 | 2026-07-10 | 110 MB | |
1.2.2 | 2026-05-25 | 132 MB | |
1.1.8 | 2026-03-28 | 132 MB | |
1.0.0 | 2025-01-27 | 116 MB | 首个正式版 |
选型建议:
- 生产固定版本 tag(如
1.2.5):升级完全由你控制,避免latest意外滚动导致重启后版本漂移; - 个人尝鲜用
latest:拉取即最新,但要在 README 的 Release Notes 里跟进行为变化; - 单用户设计(官方 README 明确 "Docker image contains a Blazor Server app for one user"),不需要挂载数据库外置服务,一个容器即全部;
- 镜像内监听 8080(
ASPNETCORE_HTTP_PORTS=8080,入口进程dotnet OpenHT.dll,工作目录/app,均可由docker inspect复核),无需自行配置 Kestrel 监听地址。
三、前置条件
- 服务器已安装 Docker Engine 24+(含 Compose v2):
docker --version && docker compose version
实测回显:
Docker version 27.3.1, build 942c34b
Docker Compose version v2.39.2
- 规划一个未被占用的宿主机端口(本文以 8129 为例):
ss -ltn | grep 8129 || echo "port free"
实测回显(无输出即空闲):
port free
- 生成 JWT 签名密钥(应用用它签发/校验登录令牌,必须换成强随机值):
openssl rand -base64 32
实测回显(每次生成都不同,取你自己的值):
BI/pnDHJsnvA4kDltCsULSGvXuyFe5HfFhVJhB7y8OE=
- 规划初始账号:用户名、邮箱、口令。口令无复杂度要求(应用侧 Identity 校验已放宽),但对外服务请务必用强口令。
⚠️ 注意:本文演示口径统一用账号
admin/ 口令q1w2e3r4,生产环境请替换为强口令。
四、部署步骤
4.1 建立部署目录与 .env
在服务器上创建部署目录,写入 .env 存放敏感配置(与 compose 文件分离):
mkdir -p /opt/openhabittracker/data/.OpenHabitTracker
cd /opt/openhabittracker
cat > .env <<'EOF'
APPSETTINGS_USERNAME=admin
APPSETTINGS_EMAIL=admin@admin.com
APPSETTINGS_PASSWORD=q1w2e3r4
APPSETTINGS_JWT_SECRET=BI/pnDHJsnvA4kDltCsULSGvXuyFe5HfFhVJhB7y8OE=
EOF
.env 四个变量逐项说明:
| 变量 | 作用 | 示例值 |
|---|---|---|
APPSETTINGS_USERNAME | 初始登录用户名,同时是 watchdog 日志页账号 | admin |
APPSETTINGS_EMAIL | 初始账号邮箱(应用内展示用) | admin@admin.com |
APPSETTINGS_PASSWORD | 初始账号口令,同上也是 watchdog 口令 | q1w2e3r4 |
APPSETTINGS_JWT_SECRET | JWT 签名密钥,泄露可伪造登录令牌 | openssl rand -base64 32 产物 |
4.2 编写 docker-compose.yml
在同目录创建 docker-compose.yml(显式声明项目名,避免多套部署同名互扰):
name: oht-1.2.5-stack
services:
openhabittracker:
image: jinjinov/openhabittracker:1.2.5
container_name: oht-1.2.5-server
ports:
- "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
逐项说明:
ports: "8129:8080":宿主机 8129 → 容器内 8080(应用固定监听 8080);官方示例用 5050,任何空闲端口都可;AppSettings__*:双下划线是 ASP.NET Core 环境变量覆盖配置层级的标准写法,对应appsettings.json的AppSettings节;TZ:容器内时区,影响「今天」的判定与统计口径,务必设为你的 IANA 时区(如Asia/Shanghai);volumes:把应用数据目录挂到宿主机,备份/迁移只需要拷这一个目录;restart: unless-stopped:服务器重启后自动拉起(官方示例未带,生产建议加上)。
4.3 启动
docker compose up -d
实测回显:
Container oht-1.2.5-server Started
⚠️ 国内网络拉取 Docker Hub 超时时:为 Docker 守护进程配置镜像加速器,或通过 HTTP 代理拉取(
docker pull支持走代理的 daemon 配置),后再执行docker compose up -d。
4.4 启动验证
看容器状态:
docker ps --filter name=oht-1.2.5-server --format '{{.Names}} {{.Status}} {{.Ports}}'
实测回显:
oht-1.2.5-server Up 12 seconds 0.0.0.0:8129->8080/tcp, [::]:8129->8080/tcp
看应用启动日志(首次启动会自动建库、跑迁移、创建初始用户):
docker logs oht-1.2.5-server 2>&1 | grep -E 'Now listening|Initializing|already up to date|Default user' | head -5
实测回显(节选,按日志行匹配):
info: Program[0]
Initializing database
No migrations were applied. The database is already up to date.
Default user created successfully.
Now listening on: http://[::]:8080
Application started. Press Ctrl+C to shut down.
HTTP 层验证(首页会 302 跳登录页,登录页本身 200):
curl -s -o /dev/null -w 'GET /: %{http_code} -> %{redirect_url}\n' http://localhost:8129/
curl -s -o /dev/null -w 'GET /login: %{http_code}\n' http://localhost:8129/login
实测回显:
GET /: 302 -> http://localhost:8129/login
GET /login: 200
浏览器打开 http://<服务器IP>:8129/login,用 .env 中的用户名口令登录即进入主界面。登录后同一会话内还可以访问:
- 日志查看页:
http://<服务器IP>:8129/watchdog(账号口令与登录账号一致) - OpenAPI UI(Scalar):
http://<服务器IP>:8129/scalar/v1 - OpenAPI JSON:
http://<服务器IP>:8129/openapi/v1.json
⚠️ 注意:
/scalar/v1与/openapi/v1.json需要浏览器登录态(Cookie)才能访问;用 JWT 令牌直接访问这两个路径会得到 401——这两个入口走的是浏览器 Cookie 认证策略,而数据接口(/api/*)走 JWT Bearer 认证,实测行为见本专栏《OpenHabitTracker 1.2.5 API 使用详解》。
4.5 客户端接入同步
桌面/手机客户端(或官方 PWA)开启同步:应用内菜单 → Data → Online sync → 填服务器地址 http://<服务器IP>:8129、用户名与口令 → 勾选 Remember me → Log in(官方 README 步骤,2026-10-24 查询)。
五、数据持久化说明
应用数据全部集中在挂载目录一个文件夹里(宿主机 ./data/.OpenHabitTracker/,容器内 /app/.OpenHabitTracker/)。首次启动后实查内容:
ls -la /opt/openhabittracker/data/.OpenHabitTracker/
实测回显:
total 152
drwxr-xr-x 2 root root 4096 Oct 24 12:17 .
drwxr-xr-x 3 root root 4096 Oct 24 12:17 ..
-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
两个文件的角色:
| 文件 | 作用 | 丢失后果 |
|---|---|---|
OpenHT.db | SQLite 数据库:习惯/任务/笔记/分类/优先级/设置 + Identity 用户表 + 刷新令牌表 | 数据全丢 |
key-*.xml | ASP.NET Core DataProtection 密钥(加密登录 Cookie) | Cookie 失效,浏览器端需重新登录(数据无损) |
持久化实测:创建一条习惯 → 重启容器 → 数据仍在。
# 重启
docker compose restart
实测回显:
Container oht-1.2.5-server Started
重启后重新登录并读取习惯列表,实测回显:
habits after restart: ['持久化验证习惯']
同时 key-*.xml 文件在重启前后保持不变,浏览器登录态不失效。
六、环境变量表
容器可识别的全部环境变量(AppSettings__* 对应配置节,其余为运行时变量):
| 环境变量 | 默认值(appsettings.json) | 说明 |
|---|---|---|
AppSettings__UserName | admin | 初始账号用户名;仅首次建库生效(见第六章下方 ⚠️) |
AppSettings__Email | admin@admin.com | 初始账号邮箱;仅首次建库生效 |
AppSettings__Password | admin | 初始账号口令;仅首次建库生效(见第六章下方 ⚠️) |
AppSettings__JwtSecret | your-extremely-strong-secret-key | JWT 签名密钥;每次变更会使已签发令牌全部失效 |
TZ | Etc/UTC | 容器时区,影响“今天”判定、统计与通知时间 |
ASPNETCORE_HTTP_PORTS | 8080 | 容器内监听端口(官方镜像默认,一般不改) |
Logging__LogLevel__Default | Information | 日志级别,如调认证细节可设 Logging__LogLevel__Microsoft.AspNetCore.Authentication=Debug |
ASPNETCORE_ENVIRONMENT | Production | 运行环境标识,生产保持默认 |
⚠️ 重要实测结论:
APPSETTINGS_PASSWORD(及用户名/邮箱)只在数据库里还没有同名用户时生效——应用启动逻辑为「用户不存在 → 按环境变量创建」。实测把APPSETTINGS_PASSWORD改成新口令并重启后,旧口令登录返回 200、新口令登录返回 401。也就是说:改口令环境变量不会修改已存在账号的口令。改回环境变量并重启后旧口令恢复正常。
七、配置参数说明
三层配置(优先级从高到低):
- 环境变量(
AppSettings__Key):容器部署首选,改完docker compose up -d重建生效; - appsettings.json(容器内
/app/appsettings.json):官方镜像内置,默认值见上表;如需整文件覆盖可挂载-v ./appsettings.json:/app/appsettings.json:ro; - 应用内设置:登录后在 Settings 页调整(主题、语言、界面显隐等),保存在 SQLite 的 settings 表并随 JSON/YAML 备份导出,优先级高于前两者(只影响应用行为,不影响账号与密钥)。
配置生效的验证方法:环境变量改动后看启动日志是否正常监听、再实测登录(账号类变更的生效与坑位见第六章 ⚠️ 与第十章常见问题)。
八、配置文件挂载
一般场景只需要挂载数据目录(第四章 compose 已包含)。需要定制时追加挂载:
volumes:
- ./data/.OpenHabitTracker:/app/.OpenHabitTracker
# 可选:覆盖应用配置文件(不推荐,环境变量方式更直观)
# - ./appsettings.json:/app/appsettings.json:ro
挂载属主:容器以 root 运行(docker inspect 显示未设 user),宿主机目录权限保持默认 root 属主即可;若以非 root 用户部署,chown 成容器内运行用户(默认 root)或显式加 user: 并同步目录属主。
九、等价 docker run
不想用 Compose 时,等价的一条 docker run(参数与第四章 compose 完全一致):
docker run -d \
--name oht-1.2.5-server \
-p 8129:8080 \
-e AppSettings__UserName=admin \
-e AppSettings__Email=admin@admin.com \
-e AppSettings__Password=q1w2e3r4 \
-e AppSettings__JwtSecret=BI/pnDHJsnvA4kDltCsULSGvXuyFe5HfFhVJhB7y8OE= \
-e TZ=Asia/Shanghai \
-v /opt/openhabittracker/data/.OpenHabitTracker:/app/.OpenHabitTracker \
--restart unless-stopped \
jinjinov/openhabittracker:1.2.5
启动后验证方式与 4.4 相同。生产建议仍用 Compose:配置入文件、便于版本化与升级重建。
十、常用运维命令
以下命令均在部署目录(含 docker-compose.yml)内执行。
# 查看运行状态
docker compose ps
实测回显:
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
oht-1.2.5-server jinjinov/openhabittracker:1.2.5 "dotnet OpenHT.dll" openhabittracker 2 minutes ago Up 2 minutes 0.0.0.0:8129->8080/tcp, [::]:8129->8080/tcp
# 跟踪日志
docker compose logs -f --tail 50
实测回显(节选):
oht-1.2.5-server | Now listening on: http://[::]:8080
oht-1.2.5-server | Application started. Press Ctrl+C to shut down.
# 重启(数据保留)
docker compose restart
实测回显:
Container oht-1.2.5-server Starting
Container oht-1.2.5-server Started
# 停止(数据保留,一并移除网络)
docker compose down
实测回显:
[+] Running 3/3
✔ Container oht-1.2.5-server Removed
✔ Network oht-1.2.5-net Removing
✔ Network oht-1.2.5-net Removed
备份(停机或运行中均可,SQLite 单文件冷拷贝最稳):
# 运行中在线备份(推荐先停写:down 再备份最稳)
tar -czf oht-backup-$(date +%F).tar.gz -C data .OpenHabitTracker
实测回显(无输出即成功,产物在当前目录):
# ls -lh oht-backup-*.tar.gz
-rw-r--r-- 1 root root 6.9K Oct 24 12:36 oht-backup-2026-10-24.tar.gz
恢复:解压回 data/.OpenHabitTracker/ 后 docker compose up -d。
升级(固定 tag 场景:改 compose 中版本号 → 重建):
sed -i 's|image: jinjinov/openhabittracker:1.2.4|image: jinjinov/openhabittracker:1.2.5|' docker-compose.yml
docker compose up -d
实测回显(tag 从 latest 切到 1.2.5 的重建过程):
Container oht-1.2.5-server Starting
Container oht-1.2.5-server Started
升级后数据实测保留(重启后读取习惯列表):
habits after tag switch: ['持久化验证习惯']
回滚:把 compose 里的 tag 改回旧版本号再 docker compose up -d(数据库迁移由应用启动时自动执行,回滚跨多个版本前先用备份验证)。
十一、常见问题(FAQ)
Q1:端口想换成 80,怎么改?
把 compose 中 "8129:8080" 改为 "80:8080" 即可(官方 README 同样建议:默认 5050 可换成 80 或任何空闲端口)。宿主机 80 被占用时用 ss -ltnp | grep :80 找到占用进程处理。
Q2:改了 APPSETTINGS_PASSWORD 为什么新口令登不进?
初始账号只按环境变量创建一次(用户已存在时启动逻辑跳过创建)。实测旧口令 200、新口令 401。要更换口令:在应用 Web 界面内修改(登录后账号页),或接受重建(备份并清空 OpenHT.db 会让所有数据丢失,不推荐)。所以首次部署时就把口令设成最终值。
Q3:拉取镜像很慢或超时? 为 Docker daemon 配置镜像加速器或 HTTP 代理后重试;镜像压缩体积约 107 MB(1.2.5),首次拉取稍慢属正常。
Q4:/openapi/v1.json 用 JWT 访问返回 401?
该路径与 /scalar/v1 由浏览器 Cookie 认证策略保护,JWT 无效——先在浏览器登录 /login,同一会话再访问即可(实测带登录 Cookie 拉取返回完整 OpenAPI 3.1.1 文档,34 个路径)。数据接口 /api/* 才是 JWT Bearer 认证。
Q5:数据能多人共用吗? 官方镜像为单用户设计(一个部署对应一个账号)。多人使用需各自部署一套(不同端口/不同数据目录),或自行改造源码——官方不支持多用户。
Q6:忘记 watchdog 密码?
watchdog 页账号口令与 AppSettings__UserName/AppSettings__Password 一致;因初始账号口令以数据库哈希为准(见 Q2),watchdog 口令同样以首次创建时的口令为准,与后来环境变量里的值无关。
Q7:升级后统计图表异常?
1.2.5 新增了习惯统计图表;如从旧版本升级后图表缺失,先强刷浏览器(Ctrl+F5)排除 PWA 静态资源缓存,再确认版本 tag 已切换(docker inspect <容器名> --format '{{.Config.Image}}')。
十二、参考链接
- 官方 README(Docker 部署一节):https://github.com/Jinjinov/OpenHabitTracker#docker-image-contains-a-blazor-server-app-for-one-user
- Docker Hub:https://hub.docker.com/r/jinjinov/openhabittracker
- GHCR 镜像页:https://github.com/Jinjinov/OpenHabitTracker/pkgs/container/openhabittracker
- Releases(版本对照):https://github.com/Jinjinov/OpenHabitTracker/releases
- 项目介绍与选型:见本专栏《OpenHabitTracker 1.2.5 介绍与选型指南》
- 参数逐项详解:见本专栏《OpenHabitTracker 1.2.5 配置参数详解》
- 接口调用:见本专栏《OpenHabitTracker 1.2.5 API 使用详解》