Kaneo 2.48.0 Docker Compose 部署指南
用 Docker Compose 部署 Kaneo 2.48.0(含 PostgreSQL 16 依赖链):编排文件、环境变量注入、健康检查、数据持久化、备份升级与常见问题实测。
Kaneo 2.48.0 Docker Compose 部署指南
目标:用 Docker Compose 编排部署一套生产可用的 Kaneo 2.48.0(开源项目管理/看板工具),覆盖 Kaneo 应用与 PostgreSQL 16 依赖链的编排、环境变量注入、健康检查、数据持久化、备份与升级,已在 Ubuntu 26.04 + Docker 29.9 环境实测通过。
一、环境信息
| 项目 | 实测值 |
|---|---|
| 操作系统 | Ubuntu 26.04.1 LTS(Docker 主机) |
| Docker | Server 29.9.2(compose 插件随附) |
| Kaneo 镜像 | ghcr.io/usekaneo/kaneo:2.48.0(digest sha256:e52b4d48…66386def) |
| 数据库镜像 | postgres:16-alpine(实测 16.15) |
| 应用运行时 | 镜像内置 Node.js v24.22.1 |
| 对外端口 | 8142(映射到应用 5173,Web 与 API 同端口同域) |
| 内网网段 | 10.89.67.0/24(编排自动创建的 bridge 网络) |
| 数据卷 | 命名卷 kaneo-2.48.0-pgdata(PostgreSQL 数据目录) |
| 部署目录 | /opt/kaneo(compose 文件与 .env 所在目录) |
| 演示账号 | root@kaneo.local / q1w2e3r4(首个注册账号自动成为实例管理员) |
Kaneo 是 Hono(API)+ React(Web)+ PostgreSQL 的单镜像应用,官方只有一个全量镜像 ghcr.io/usekaneo/kaneo,Web 静态资源与 API 由同一进程、同一端口(5173)对外服务,API 挂在 /api 路径下。产品定位与选型对比见《Kaneo 2.48.0 介绍与选型指南》。
二、镜像选型说明
| 候选 | 说明 | 结论 |
|---|---|---|
ghcr.io/usekaneo/kaneo:2.48.0 | 官方唯一发行镜像,含 Web + API + 数据库迁移 | 本文采用 |
ghcr.io/usekaneo/kaneo:latest | 滚动标签,跟随最新稳定版 | 不推荐生产使用,Kaneo 发版极密(两周 5 个版本),应锁定小版本 |
源码构建(Dockerfile.kaneo) | pnpm monorepo 自行构建 | 仅定制需求时考虑 |
数据库侧选 postgres:16-alpine:Kaneo 官方 compose 示例即用 PostgreSQL 16, drizzle 迁移在该版本实测通过;alpine 变体体积小(约 90MB),功能无差异。Kaneo 不支持 MySQL/SQLite,PostgreSQL 是强依赖(用户、工作区、项目、任务、会话全部入库),Redis 仅多实例横向扩展时可选。
💡 技术拓展:自建 PostgreSQL 时的「应用连带数据库」编排有两种常见做法——compose 内嵌数据库服务(本文方案,生命周期随栈管理、网络内部互通)与外挂已有数据库(只给应用配
DATABASE_URL,适合公司已有 DBA 维护的 PG 集群)。Kaneo 两者都支持,外挂时去掉 compose 里的 postgres 服务、只保留DATABASE_URL即可。
三、前置条件
- 已安装 Docker Engine 20.10+ 与 compose v2 插件;本文实测为 Docker 29.9.2。
- 8142 端口未被占用(
ss -ltn | grep 8142无输出);应用容器内固定监听 5173,宿主端口可自选。 - 服务器浏览器可达地址:本文用
http://192.168.1.71:8142(局域网 IP),生产替换为你的域名。该地址会写进KANEO_CLIENT_URL,直接决定登录回调、CORS 与 WebSocket 来源校验,必须填浏览器最终访问的那个源。 - 磁盘:镜像合计约 1GB,数据卷按任务/附件量增长。
四、部署步骤
4.1 准备部署目录与 .env
mkdir -p /opt/kaneo
cd /opt/kaneo
创建 /opt/kaneo/.env 存放敏感值(compose 会自动读取同目录 .env 做变量插值,文件权限收紧):
cat > /opt/kaneo/.env <<'EOF'
POSTGRES_PASSWORD=q1w2e3r4
AUTH_SECRET=9f2c4b7e1a8d3f605c9e2b4a7d1f8e3c6a9b2d5f8e1c4a7d0b3f6e9c2a5d8b1f
EOF
chmod 600 /opt/kaneo/.env
AUTH_SECRET 用 openssl rand -hex 32 生成,至少 32 字符。生成后必须保持稳定:它会签发所有登录会话,改值后全员掉线;丢失后无法恢复会话与 API Key 校验。
4.2 编写 docker-compose.yml
文件 /opt/kaneo/docker-compose.yml(实测逐行可用):
name: kaneo-2.48.0-stack
services:
postgres:
image: postgres:16-alpine
container_name: kaneo-2.48.0-postgres
restart: unless-stopped
environment:
POSTGRES_DB: kaneo
POSTGRES_USER: kaneo
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- kaneo-pgdata:/var/lib/postgresql/data
networks:
- kaneo-net
healthcheck:
test: ["CMD-SHELL", "pg_isready -U kaneo -d kaneo"]
interval: 10s
timeout: 5s
retries: 5
kaneo:
image: ghcr.io/usekaneo/kaneo:2.48.0
container_name: kaneo-2.48.0-app
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
ports:
- "8142:5173"
environment:
KANEO_CLIENT_URL: http://192.168.1.71:8142
DATABASE_URL: postgresql://kaneo:${POSTGRES_PASSWORD}@postgres:5432/kaneo
AUTH_SECRET: ${AUTH_SECRET}
DISABLE_EMAIL_OTP_SIGN_IN: "true"
networks:
- kaneo-net
healthcheck:
test: ["CMD", "wget", "-Y", "off", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:5173/api/health"]
interval: 30s
timeout: 5s
start_period: 60s
retries: 3
volumes:
kaneo-pgdata:
name: kaneo-2.48.0-pgdata
networks:
kaneo-net:
name: kaneo-2.48.0-net
关键设计点:
name: kaneo-2.48.0-stack显式固定 compose 项目名,避免与其他项目的 compose 目录同名互相影响。depends_on: condition: service_healthy保证 PostgreSQL 先就绪再启动应用;Kaneo 首次启动会自动执行全部 drizzle 数据库迁移,无需手工建表。DATABASE_URL中的主机名postgres是 compose 网络内的服务名解析;密码经.env插值注入,不直接写死在 yml 里。DISABLE_EMAIL_OTP_SIGN_IN=true:未配置 SMTP 时必须开启,否则登录方式默认走「邮箱验证码」,收不到码就无法登录;开启后使用账号密码登录(邀请与密码重置邮件仍需 SMTP,详见常见问题 Q4)。- postgres 服务不暴露宿主端口(无
ports:),只有 kaneo 应用经内网访问它,减小暴露面。
4.3 拉取镜像并启动
cd /opt/kaneo
docker compose pull
docker compose up -d
实测输出:
Image ghcr.io/usekaneo/kaneo:2.48.0 Pulled
Image postgres:16-alpine Pulled
Network kaneo-2.48.0-net Created
Container kaneo-2.48.0-postgres Created
Container kaneo-2.48.0-app Created
Container kaneo-2.48.0-postgres Started
Container kaneo-2.48.0-postgres Healthy
Container kaneo-2.48.0-app Started
4.4 验证容器状态与启动日志
docker compose ps
实测输出:
NAME IMAGE STATUS PORTS
kaneo-2.48.0-app ghcr.io/usekaneo/kaneo:2.48.0 Up 20 seconds (healthy) 0.0.0.0:8142->5173/tcp
kaneo-2.48.0-postgres postgres:16-alpine Up 30 seconds (healthy) 5432/tcp
查看应用日志确认迁移与插件初始化完成:
docker logs kaneo-2.48.0-app
实测关键日志(节选,按时间顺序):
KANEO_API_URL not set — derived from KANEO_CLIENT_URL: http://192.168.1.71:8142/api
Public web configuration prepared.
🔄 Migrating database...
✅ Database migrated successfully!
🔄 Checking apikey table reference_id migration...
✅ API key reference_id migration completed successfully!
Initializing plugins...
✓ Registered plugin: GitHub
✓ Registered plugin: Gitea
✓ Registered plugin: GitLab
✓ Registered plugin: Slack
✓ Registered plugin: Mattermost
✓ Registered plugin: Discord
✓ Registered plugin: Generic Webhook
✓ Registered plugin: Telegram
⏰ Scheduler started (deferred integration edits every minute, reminders every 5 minutes, seat reconciliation and trial reminders hourly)
📡 WebSockets Initialized using: "InMemoryBroadcastAdapter"
⚡ API is running at http://192.168.1.71:8142/api
API is ready
日志解读:首行说明未显式设置 KANEO_API_URL 时镜像入口脚本自动按 KANEO_CLIENT_URL + /api 推导;Database migrated successfully 表示 schema 迁移完成;8 个集成插件(GitHub/Gitea/GitLab/Slack 等)注册但仅展示的未配置项不启用;未配 Redis 时 WebSocket 广播用进程内适配器(单实例够用);最后一行 API is ready 代表服务就绪。
⚠️ 注意:日志里
WARN [Better Auth]: Social provider github/google/discord is missing clientId or clientSecret为预期告警——未配置对应 OAuth 凭据时 SSO 按钮自动隐藏,不影响账号密码登录。
4.5 健康检查与首次注册
接口级健康检查:
curl -s http://192.168.1.71:8142/api/health
实测输出:
{"status":"ok"}
实例初始化状态(无需登录,公开接口):
curl -s http://192.168.1.71:8142/api/instance/status
实测输出:
{"hasUsers":true,"hasAdmin":true}
浏览器打开 http://192.168.1.71:8142 注册第一个账号(本文用 root@kaneo.local / q1w2e3r4)。首个非访客注册账号自动成为实例管理员,注册后即完成实例初始化,无需额外 setup 向导。也可直接用 API 注册(等效于页面操作):
curl -s -H 'Content-Type: application/json' \
-d '{"email":"root@kaneo.local","password":"q1w2e3r4","name":"root"}' \
http://192.168.1.71:8142/api/auth/sign-up/email
实测返回(节选):
{"token":"pGiHPM1NfBXznMa10vERH7rE9iAwJOEd","user":{"name":"root","email":"root@kaneo.local","role":"user","id":"DWV4ls5Iqeaw1nOcABrbVeKARJd4jpW3"}}
注册接口返回的 role 字段暂时显示 user,实例管理员的提升在首次登录建立会话后完成;用 SQL 复核可见角色已是 admin:
docker exec kaneo-2.48.0-postgres psql -U kaneo -d kaneo -c 'select email, name, role from "user";'
实测输出:
email | name | role
------------------+------+-------
root@kaneo.local | root | admin
五、数据持久化说明
Kaneo 自身的全部业务数据(用户、会话、工作区、项目、任务、评论、标签、时间记录、API Key)都在 PostgreSQL 里,应用镜像本身无状态、无需挂卷。唯一必须持久化的是 postgres 服务的 /var/lib/postgresql/data,本方案用命名卷 kaneo-2.48.0-pgdata。
验证卷落盘位置:
docker volume inspect kaneo-2.48.0-pgdata --format '{{.Mountpoint}}'
实测输出:
/var/lib/docker/volumes/kaneo-2.48.0-pgdata/_data
重启栈数据不丢实测:先通过 API 建一个任务(见第十章),然后整栈重建:
docker compose down
docker compose up -d
待健康后查询任务仍在:
docker exec kaneo-2.48.0-postgres psql -U kaneo -d kaneo -tc 'select count(*) from task; select title from task;'
实测输出:
1
首页视觉稿定稿
⚠️ 注意:
docker compose down -v会连卷一起删除,等于清空整套系统数据;日常停用只用down,绝不要加-v。
六、环境变量表
以下为部署最小集与常用可选项(完整 60+ 项含 SSO/SMTP/S3/Redis/计费见《Kaneo 2.48.0 配置参数详解》):
| 变量 | 必填 | 默认 | 说明 |
|---|---|---|---|
KANEO_CLIENT_URL | 是 | 无 | 浏览器访问应用的完整源(协议+主机+端口),决定登录回调/CORS/WebSocket 来源校验 |
KANEO_API_URL | 否 | KANEO_CLIENT_URL + /api | 仅前后端分离部署时显式设置 |
DATABASE_URL | 是* | 无 | PG 连接串;设置后覆盖 POSTGRES_* 派生 |
POSTGRES_DB/USER/PASSWORD | 是* | kaneo/kaneo/无 | 不配 DATABASE_URL 时用于派生连接串(需含 POSTGRES_PASSWORD) |
POSTGRES_HOST / POSTGRES_PORT | 否 | postgres / 5432 | 派生模式下的库地址 |
AUTH_SECRET | 是 | 无(镜像可临时生成) | ≥32 字符随机会话密钥,必须稳定 |
DISABLE_EMAIL_OTP_SIGN_IN | 建议 | false | 无 SMTP 时设 true 保持密码登录 |
DISABLE_REGISTRATION | 否 | false | 关闭公开注册(首个管理员不受限) |
DATABASE_POOL_MAX | 否 | 10 | 每 API 进程 PG 连接上限,最小 2 |
TRUSTED_PROXIES | 否 | 127.0.0.0/8, ::1/128 | 反代后的可信代理 IP/CIDR |
REDIS_URL | 否 | 无 | 多实例 WebSocket 广播才需要 |
七、配置参数说明
- URL 双变量:一体化镜像只需
KANEO_CLIENT_URL;入口脚本env.sh会把KANEO_API_URL、KANEO_CLIENT_URL、KANEO_TURNSTILE_SITE_KEY三个值在启动时替换进前端静态资源——改这三个值后必须重建容器(up -d --force-recreate),仅重启进程不生效。 - 数据库连接两种写法互斥:显式
DATABASE_URL优先级最高;派生模式要求至少提供POSTGRES_PASSWORD(或POSTGRES_PASSWORD_FILE),只给POSTGRES_DB/USER不会启用派生。本文 compose 用的是显式DATABASE_URL。 - 密钥文件变体:
AUTH_SECRET_FILE、POSTGRES_PASSWORD_FILE支持从文件读密钥(适配 Docker secrets),非空直写值优先于文件。 - CORS_ORIGINS:默认只放行
KANEO_CLIENT_URL;有第二个访问域名(如同时走 IP 与域名)时用逗号分隔追加。
八、配置文件挂载
Kaneo 没有任何需挂载的配置文件——全部服务端配置经环境变量注入,前端注入由镜像入口脚本完成。需要落到宿主机管理的只有两类:
/opt/kaneo/docker-compose.yml与/opt/kaneo/.env(编排与密钥,建议入配置管理);- 可选的密钥文件(如用
AUTH_SECRET_FILE=/run/secrets/auth_secret,把密钥文件 bind mount 进容器)。
数据库侧如需自定义 PG 参数(如 max_connections),可在 postgres 服务加 command: postgres -c max_connections=200,或挂 postgresql.conf 到 /etc/postgresql/postgresql.conf 并配合 command: postgres -c config_file=/etc/postgresql/postgresql.conf。
九、等价 docker run
不用 compose 时,等价命令如下(先建网络,两容器逐个启动):
docker network create kaneo-2.48.0-net
docker run -d --name kaneo-2.48.0-postgres \
--network kaneo-2.48.0-net \
--restart unless-stopped \
-e POSTGRES_DB=kaneo \
-e POSTGRES_USER=kaneo \
-e POSTGRES_PASSWORD=q1w2e3r4 \
-v kaneo-2.48.0-pgdata:/var/lib/postgresql/data \
postgres:16-alpine
docker run -d --name kaneo-2.48.0-app \
--network kaneo-2.48.0-net \
--restart unless-stopped \
-p 8142:5173 \
-e KANEO_CLIENT_URL=http://192.168.1.71:8142 \
-e DATABASE_URL=postgresql://kaneo:q1w2e3r4@kaneo-2.48.0-postgres:5432/kaneo \
-e AUTH_SECRET=9f2c4b7e1a8d3f605c9e2b4a7d1f8e3c6a9b2d5f8e1c4a7d0b3f6e9c2a5d8b1f \
-e DISABLE_EMAIL_OTP_SIGN_IN=true \
ghcr.io/usekaneo/kaneo:2.48.0
注意纯 docker run 模式下没有 compose 的 service_healthy 依赖编排,需先等 PostgreSQL 就绪(docker exec kaneo-2.48.0-postgres pg_isready -U kaneo 返回 accepting connections)再启动应用;且 DATABASE_URL 主机名要改成容器名 kaneo-2.48.0-postgres(compose 模式下服务名即 postgres)。
十、常用运维命令
10.1 日志与状态
docker compose logs -f kaneo # 跟踪应用日志
docker compose logs --tail 50 postgres
docker compose ps # 服务状态总览
10.2 数据库备份(pg_dump 逻辑备份)
docker exec kaneo-2.48.0-postgres pg_dump -U kaneo -d kaneo > /opt/kaneo/kaneo-backup-$(date +%F).sql
实测产物(约 93KB 的干净实例)文件头:
--
-- PostgreSQL database dump
--
-- Dumped from database version 16.15
-- Dumped by pg_dump version 16.15
恢复(重建空库后灌入):
docker exec -i kaneo-2.48.0-postgres psql -U kaneo -d kaneo < /opt/kaneo/kaneo-backup-2026-10-28.sql
10.3 升级版本
cd /opt/kaneo
sed -i 's#ghcr.io/usekaneo/kaneo:2.48.0#ghcr.io/usekaneo/kaneo:2.49.0#' docker-compose.yml
docker compose pull
docker compose up -d
Kaneo 启动时自动执行增量迁移,无需手工跑 SQL。升级前先用 10.2 备份,并核对 GitHub Release Notes 是否标注 security/breaking(Kaneo 发版极密,跨多个小版本升级时逐条看)。
10.4 进入数据库排障
docker exec -it kaneo-2.48.0-postgres psql -U kaneo -d kaneo
常用检查:\dt 看表(约 60 张)、select count(*) from task;、select email, role from "user";。
十一、常见问题
Q1:docker compose ps 中 kaneo 一直 unhealthy、日志卡在 Waiting for API to be ready...?
多为数据库连接失败。检查 DATABASE_URL 密码与 postgres 服务 POSTGRES_PASSWORD 是否一致、主机名是否为 postgres(compose 服务名);用 docker compose logs postgres 确认库已 ready to accept connections。
Q2:浏览器能打开页面但登录/注册报 CORS 或 MISSING_OR_NULL_ORIGIN?
KANEO_CLIENT_URL 与浏览器地址栏不一致(含端口、http/https)。改 .env/compose 里该值后必须 docker compose up -d --force-recreate kaneo 重建容器使前端资源重新注入。
Q3:重启后全员被踢下线、API Key 失效?
AUTH_SECRET 变了(或首次未设置、镜像随机生成后容器重建)。恢复为原值;以后把它当密钥备份。未设置时镜像日志会有临时密钥提示,生产必须显式固定。
Q4:收不到邀请/密码重置邮件?
未配置 SMTP(SMTP_HOST/PORT/USER/PASSWORD/FROM)。配好即可;无 SMTP 时管理员可在 UI 里直接复制邀请链接发给同事,不依赖邮件投递。
Q5:DATABASE_POOL_MAX 报错导致启动失败?
该值最小为 2 且必须为整数;多副本部署时注意「连接池 × 副本数 ≤ PG max_connections」。
Q6:想暴露 PostgreSQL 到宿主机调试?
临时在 postgres 服务加 ports: ["15432:5432"],调试完去掉。生产不要把库端口暴露到公网。
十二、参考链接
- 官方文档-自托管安装:https://kaneo.app/docs/core/installation
- 官方环境变量参考:https://kaneo.app/docs/core/installation/environment-variables
- 官方 compose 示例:https://github.com/usekaneo/kaneo/blob/main/compose.yml
- GitHub 仓库:https://github.com/usekaneo/kaneo
- 镜像仓库:https://ghcr.io/usekaneo/kaneo
- 本站专栏:《Kaneo 2.48.0 介绍与选型指南》(版本与选型事实以 2026-10-28 实查为准,当日最新稳定版即 v2.48.0)