Kaneo 2.48.0 Docker Compose 部署指南

用 Docker Compose 部署 Kaneo 2.48.0(含 PostgreSQL 16 依赖链):编排文件、环境变量注入、健康检查、数据持久化、备份升级与常见问题实测。

KaneoKaneoDockerDocker ComposePostgreSQL项目管理2026/10/28

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 主机)
DockerServer 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 没有任何需挂载的配置文件——全部服务端配置经环境变量注入,前端注入由镜像入口脚本完成。需要落到宿主机管理的只有两类:

  1. /opt/kaneo/docker-compose.yml 与 /opt/kaneo/.env(编排与密钥,建议入配置管理);
  2. 可选的密钥文件(如用 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"],调试完去掉。生产不要把库端口暴露到公网。

十二、参考链接