Gancio 1.28.2 Docker Compose 部署指南

Gancio 1.28.2 的 Docker Compose 部署实测全流程:官方模板与发布渠道选型、首次启动自动建库迁移、设置向导与管理员初始化、数据持久化、HTTPS 反向代理接入、升级回滚与常见排错。

GancioGancioDocker ComposeDocker日历自托管2026/11/02

Gancio 1.28.2 Docker Compose 部署指南

目标:用 Docker Compose 把 Gancio 1.28.2 跑起来并完成初始化,覆盖官方模板获取、首启自动建库迁移、设置向导与管理员账号、数据持久化、HTTPS 反向代理接入、升级回滚与日常运维命令。全程在真实环境实测:官方发布 cisti/gancio:1.28.2(运行时 Node.js v20.19.6)、宿主端口 8149 → 服务端口 13120、SQLite 后端,建库迁移、向导初始化、API 登录与 RSS/ICS 订阅验证全部通过。产品定位与选型论证见《Gancio 介绍与选型指南》。

一、环境信息

  • 操作系统:Linux(内核 5.15+,x86_64)
  • Docker:Docker Engine + Docker Compose v2(docker compose 子命令)
  • 部署载体:cisti/gancio:1.28.2(Docker Hub 官方发布,digest sha256:8cbf23952cf86de5a41cfb1361aa848d5741061163aed7c0da30b704ccb43b73,压缩包约 148 MB、解压约 898 MB;内置 Node.js v20.19.6)
  • 宿主端口:8149 → 服务端口 13120
  • 持久化:bind 挂载 /opt/gancio/data → 服务内 /home/node/data
  • 数据库:SQLite(data/gancio.sqlite,compose 环境变量指定)
  • 实测账号:管理员 admin / q1w2e3r4(用户名就是 admin,不是邮箱)

⚠️ 网络说明:实测当日宿主机直连 gancio.org 与 hub.docker.com 超时不通,需经代理 http://192.168.1.72:7897 访问;官方发布包的拉取走 Docker 守护进程配置的代理即可。国内环境请按自身网络情况处理。

二、发布渠道选型

Gancio 官方维护多种安装通道,Docker 是其中唯一持续更新、且自带全部依赖的事实标准:

渠道形态评价
Docker Compose(本文)官方发布 cisti/gancio,tag 与上游版本一一对应官方文档「Install using Docker」推荐路径,升级/回滚只动 tag
Debian 包yarn global add gancio.org/latest.tgz + systemd需自管 Node.js 运行时,官方文档另列
NixOS / YunoHost / fly.io社区/官方维护的第三方通道按自身发行版选择
npm 包 gancio版本停留在 1.6.13,严重滞后非官方发布渠道,勿用

tag 现状(查询日期 2026-11-01):1.28.2(2025-12-17 发布)为 1.x 末代稳定版,latest 与其同代;2.0.0-beta.8(2026-10-23)为 2.0 预览线。生产部署固定版本 tag,不要用 latest。

三、前置条件

  1. 宿主已安装 Docker Engine 与 Compose v2 插件:docker compose version 能正常输出版本号。
  2. 端口规划:本指南用 8149 做宿主端口,占用确认 ss -ltn | grep :8149 无输出;换端口时同步改 compose 文件映射即可。
  3. 目录规划:本文所有文件放在 /opt/gancio/。
  4. 生产环境建议准备:公网域名(联邦与 webfinger 必需,见 4.6)、可用的 SMTP 服务(可选,用于邮件通知)。

四、部署步骤

4.1 获取官方 Compose 模板

官方按数据库方言提供三份模板(sqlite / postgres / mariadb 三选一),本文以 SQLite 为例:

mkdir -p /opt/gancio && cd /opt/gancio
DB=sqlite
wget https://gancio.org/docker/$DB/docker-compose.yml

官方模板实测获取内容如下:

version: '3'

services:
  gancio:
    restart: always
    image: cisti/gancio
    container_name: gancio
    environment:
      - PATH=$PATH:/home/node/.yarn/bin
      - GANCIO_DATA=/home/node/data
      - NODE_ENV=production
      - GANCIO_DB_DIALECT=sqlite
      - GANCIO_DB_STORAGE=./gancio.sqlite
    volumes:
      - ./data:/home/node/data
    ports:
      - "127.0.0.1:13120:13120"

要点:模板默认只绑 127.0.0.1(生产经反向代理对外);数据全部落在 ./data bind 目录;restart: always 是初始化流程的依赖项(见 4.4)。

4.2 定制 Compose 文件

在模板基础上做三处修改:固定版本 tag 为 1.28.2、宿主端口按规划改为 8149、删除已过时的 version 行。最终文件 /opt/gancio/docker-compose.yml:

services:
  gancio:
    restart: always
    image: cisti/gancio:1.28.2
    container_name: gancio
    environment:
      - PATH=$PATH:/home/node/.yarn/bin
      - GANCIO_DATA=/home/node/data
      - NODE_ENV=production
      - GANCIO_DB_DIALECT=sqlite
      - GANCIO_DB_STORAGE=./gancio.sqlite
    volumes:
      - ./data:/home/node/data
    ports:
      - "8149:13120"

💡 若只经本机 Nginx 反代对外,建议把端口行收紧为 "127.0.0.1:8149:13120"(官方模板默认形态)。

⚠️ 环境变量陷阱:社区流传的 compose 示例常带 GANCIO_URL、GANCIO_NAME、GANCIO_LOCALE、GANCIO_TIMEZONE、GANCIO_EMAIL、GANCIO_ORIGIN,这些变量在 1.28.2 全部源码中无任何引用,设置不会生效;站点名/语言/时区实际存在数据库 settings 表(向导或管理界面设置)。代码实际读取的只有 GANCIO_DATA、GANCIO_HOST、GANCIO_PORT、GANCIO_DB_*、GANCIO_PROXY_*,逐键详解见《Gancio 1.28.2 配置参数详解》。

4.3 首次启动:自动建库迁移

cd /opt/gancio && docker compose up -d

实测回显:

 Container gancio  Running

状态确认(实测):

docker compose ps
NAME     IMAGE                 COMMAND                  SERVICE   CREATED       STATUS       PORTS
gancio   cisti/gancio:1.28.2   "/home/node/server/c…"   gancio    3 hours ago   Up 3 hours   0.0.0.0:8149->13120/tcp, [::]:8149->13120/tcp

空库首启会自动执行全部建库迁移(实测共 54 个迁移脚本,从 20191025133803-tags 到 20250324211014-to_notify 逐个执行),启动日志节选(实测):

📅 gancio - v1.28.2 - A shared agenda for local communities (nodejs: v20.19.6)
ℹ > Reading configuration from: /home/node/data/config.json
ℹ > Configuration file does not exists...
ℹ Modern bundles are detected. Modern mode (server) is enabled now.
ℹ Listening on: http://172.19.0.2:13120/

 ERROR  Server not ready

    at routes (nuxt.config.js:80:15)
    at promisifyRoute (node_modules/@nuxtjs/sitemap/lib/cache.js:59:17)
    ...

debug: == 20191025133803-tags: migrating =======
debug: == 20191025133803-tags: migrated (0.006s)
debug: == 20191025134318-places: migrating =======
debug: == 20191025134318-places: migrated (0.005s)
debug: == 20191025135631-settings: migrating =======
debug: == 20191025135631-settings: migrated (0.005s)
...
debug: == 20250324211014-to_notify: migrating =======
debug: == 20250324211014-to_notify: migrated (0.005s)

两处首启噪音说明(均无害,服务照常就绪):

  • ERROR Server not ready:@nuxtjs/sitemap 在数据库迁移完成前就尝试拉取路由表产生的启动期报错,不影响后续就绪(实测 Server not ready 之后迁移照常跑完、/api/ping 返回 OK)。
  • The Express 'trust proxy' setting is true ... ERR_ERL_PERMISSIVE_TRUST_PROXY:应用全开了 trust proxy,express-rate-limit 打出的告警,每次有请求进来就刷一条,属已知日志噪音(见九、FAQ Q4)。

持续看日志可用官方文档给的姿势(winston 按天滚动,落在持久化目录里):

tail -f /opt/gancio/data/logs/gancio.log

4.4 设置向导与管理员初始化

服务就绪后访问首页会被重定向进设置向导:

curl -sI http://127.0.0.1:8149/ | grep -iE '^HTTP|^location'

实测回显:

HTTP/1.1 302 Found
Location: /setup/1

浏览器打开 http://<服务器IP>:8149/ 进入 /setup/1 向导:依次完成数据库检查、站点基本设置(标题、简介、时区、语言等——这些值最终写入数据库 settings 表,而不是环境变量),确认后向导触发初始化重启。

实测 API 等价流程(无浏览器环境可用):

curl -s -X POST http://127.0.0.1:8149/api/setup/db

若数据库已被首启迁移建好,此步返回告警并拒绝重复初始化(HTTP 400):

⚠  Non empty db! Please move your current db elsewhere than retry.

此时直接执行重启初始化即可:

curl -s -X POST http://127.0.0.1:8149/api/setup/restart

实测返回(一次性展示管理员凭据,界面/响应只显示这一次,务必留存):

{"password":"ymx3cmubdosc","email":"admin"}

随后服务写生成 data/config.json、进程主动退出,由 compose 的 restart: always 策略拉起,进入 READY 状态。实测生成的 config.json 关键内容:

{
  "baseurl": "http://127.0.0.1:8149",
  "hostname": "127.0.0.1",
  "server": { "host": "0.0.0.0", "port": 13120 },
  "log_level": "debug",
  "log_path": "/home/node/data/logs",
  "db": {
    "dialect": "sqlite",
    "storage": "/home/node/data/gancio.sqlite",
    "logging": false,
    "dialectOptions": { "autoJsonMap": true },
    "retry": { "max": 15 }
  },
  "user_locale": "/home/node/data/user_locale",
  "upload_path": "/home/node/data/uploads",
  "proxy": { "protocol": "", "hostname": "", "host": "", "port": "" }
}

⚠️ 注意两点:① 管理员用户名固定为 admin(不是邮箱),密码为随机生成;② 若随机密码没留存,用内置 CLI 重置或重建账号(实测命令与回显见 4.5)。

4.5 重建管理员账号(实测)

密码遗失时用内置 CLI 处理。CLI 的调用姿势是进入服务的工作目录执行 gancio 命令:

docker exec --workdir /home/node/data gancio gancio users reset-password admin

若账号状态混乱,直接删除重建(本文实测用固定口令 q1w2e3r4 重建):

docker exec --workdir /home/node/data gancio gancio users remove admin
docker exec --workdir /home/node/data gancio gancio users create admin q1w2e3r4 admin

实测回显:

User "admin" created with role admin

确认账号列表:

docker exec --workdir /home/node/data gancio gancio users list

实测回显:

1	role: admin	enabled: true	email: admin

CLI 全部子命令与参数详解见《Gancio 1.28.2 常用 CLI/运维命令详解》。

4.6 部署后验证(实测回显)

探活:

curl -s http://127.0.0.1:8149/api/ping
OK

登录换 token(注意端点是 /oauth/login,不带 /api 前缀;请求体必须是 application/x-www-form-urlencoded 且带内置公共客户端 client_id=self,发 JSON 或缺 client 一律 Unauthorized):

curl -s -X POST http://127.0.0.1:8149/oauth/login \
  -d 'grant_type=password&client_id=self&username=admin&password=q1w2e3r4'
{"access_token":"uuchn7oqlud4g0cj5wpfri3nc0bi5j41","refresh_token":"swotig398mpkgkzxwvfqk7o1cx90vss4","username":"admin","token_type":"Bearer"}

用 token 发一条活动(时间字段为 Unix 秒;地点需 place_name + place_address):

TOKEN=<上一步的 access_token>
curl -s -X POST http://127.0.0.1:8149/api/event \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"title":"社区技术分享会","description":"Gancio 部署实践交流","start_datetime":1794762000,"end_datetime":1794772800,"place_name":"罗马社区中心","place_address":"Via dei Test 1, Roma","confirmed":true}'

随后公开接口即可见:

curl -s http://127.0.0.1:8149/api/events

实测回显(节选):

[{"id":1,"title":"社区技术分享会","start_datetime":1794762000,"end_datetime":1794772800,"place":{"id":1,"name":"罗马社区中心","address":"Via dei Test 1, Roma"},"tags":[]}]

ICS 订阅源(可直接被日历客户端订阅):

curl -s http://127.0.0.1:8149/feed/ics | head -12

实测回显:

BEGIN:VCALENDAR
VERSION:2.0
CALSCALE:GREGORIAN
PRODID:adamgibbons/ics
METHOD:PUBLISH
X-PUBLISHED-TTL:PT1H
BEGIN:VEVENT
UID:1@127.0.0.1
SUMMARY:社区技术分享会
DTSTAMP:20261101T151147Z
DTSTART:20261115T170000Z
DTEND:20261115T200000Z

RSS 同理:curl -s http://127.0.0.1:8149/feed/rss 实测返回标准 RSS 2.0,channel 标题即向导里设置的站点名,条目形如 [2026-11-15] 社区技术分享会 @ 罗马社区中心。

4.7 HTTPS 反向代理接入(生产必做)

Gancio 本体是 Express 明文监听(实测响应头无 HSTS,无内置 TLS),生产必须经 Nginx/Caddy 反代终结 HTTPS。nginx 最小参考配置:

server {
    listen 443 ssl http2;
    server_name gancio.example.org;
    ssl_certificate     /etc/letsencrypt/live/gancio.example.org/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/gancio.example.org/privkey.pem;

    client_max_body_size 10m;   # 活动图片上传

    location / {
        proxy_pass http://127.0.0.1:8149;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

反代接入后还需把站点地址改到公网域名——baseurl/hostname 存在数据库 settings 表(首启时按访问地址写入,实测为 http://127.0.0.1:8149 / 127.0.0.1),改法:

docker exec --workdir /home/node/data gancio gancio settings set baseurl '"https://gancio.example.org"'
docker exec --workdir /home/node/data gancio gancio settings set hostname '"gancio.example.org"'
docker compose restart gancio

⚠️ 三个实测要点:① settings set 的值必须是合法 JSON(字符串要带内层双引号,裸串会报 SyntaxError,见 CLI 篇);② settings 改动必须重启才生效;③ Fediverse 联邦要求公网域名:实测用 IP 访问 webfinger 返回 Bad request. Please make sure "acct:USER@DOMAIN" is what you are sending as the "resource" query parameter.,127.0.0.1 形态下联邦不可用,只影响联邦、不影响本地网站与 feed。

五、数据持久化说明

全部可变状态集中在 bind 目录 /opt/gancio/data(服务内 /home/node/data),实测内容:

路径内容说明
gancio.sqliteSQLite 数据库站点设置(settings 表 47 键)、活动、用户全在这里
config.json运行时配置向导初始化时生成,之后优先于环境变量(见第六节)
logs/winston 日志gancio.log 按天滚动为 gancio.YYYY-MM-DD.log,另有 audit.json
uploads/活动图片原图与缩略图
user_locale/用户自定义文案按需生成
plugins/外部插件目录内置插件不在此(随发布包分发)

删掉 compose 项目不会丢数据(docker compose down 不动 bind 目录),备份与恢复实操见《Gancio 1.28.2 常用 CLI/运维命令详解》备份章节。

六、环境变量与 config.json 的关系

  • 环境变量只在首次启动生成 config.json 之前决定数据库连接与数据目录;config.json 一旦生成,端口、日志、数据库等以文件内容为准。
  • 代码实际读取的环境变量共 17 个:GANCIO_DATA、GANCIO_HOST、GANCIO_PORT、GANCIO_DB_DIALECT/HOST/PORT/DATABASE/USERNAME/PASSWORD/STORAGE、GANCIO_PROXY_*(grep -rn "process.env.GANCIO" server/ 实测结果)。
  • GANCIO_URL/ORIGIN/NAME/LOCALE/TIMEZONE/EMAIL 等社区示例残留变量全部无效(源码零引用)。
  • 切 PostgreSQL 只需改 GANCIO_DB_DIALECT=postgres + GANCIO_DB_HOST/PORT/DATABASE/USERNAME/PASSWORD 后首启(或改 config.json 的 db 段后重启),逐键详解见《Gancio 1.28.2 配置参数详解》。

七、升级与回滚

官方口径(Docker 安装页):升级前先备份,然后:

cd /opt/gancio
docker compose pull && docker compose up -d

新版本启动时自动执行增量迁移(实测升级日志出现 Running migrations 后无脚本则代表 schema 已是目标版本)。

本文做过完整的降级/升级演练(实测):compose 中 tag 改为 1.27.0 重新拉起,横幅变为:

📅 gancio - v1.27.0 - A shared agenda for local communities (nodejs: v20.19.2)

数据完好;改回 1.28.2 再拉起:

📅 gancio - v1.28.2 - A shared agenda for local communities (nodejs: v20.19.6)

/api/events 仍返回既有活动,验证通过。

⚠️ 两点纪律:① 升级前务必备份 data 目录(官方文档原话「Backup your data is generally a good thing to do and this is especially true before upgrading」);② 1.x → 2.0 是大版本换代(2.0 截至 2026-10 仍为 beta),不要盲目把 tag 换成 latest 或 beta。

八、常用运维命令速查

以下命令均在 /opt/gancio/ 目录内实测:

docker compose ps                          # 状态与端口
docker compose logs -f gancio              # 实时日志(含启动横幅与迁移)
tail -f data/logs/gancio.log               # 应用内滚动日志(官方推荐姿势)
docker compose restart gancio              # 重启(settings 改动后必须)
docker compose stop && docker compose up -d
docker compose down                        # 停止并移除服务,data 目录保留
docker exec --workdir /home/node/data gancio gancio --help   # 内置 CLI 入口

CLI 的用户管理、settings 读写、迁移等全部子命令见《Gancio 1.28.2 常用 CLI/运维命令详解》。

九、常见问题

Q1:启动时警告 the attribute version is obsolete, it will be ignored。 官方模板仍带 version: '3' 行,Compose v2 已废弃该属性(仅告警不影响运行),删掉该行即可,本文 4.2 的成品文件已删。

Q2:docker compose up -d 端口冲突。 回显 bind: address already in use。ss -ltnp | grep 8149 找占用进程,或改 compose 端口映射左侧为空闲端口。

Q3:首启日志里 ERROR Server not ready 是什么? @nuxtjs/sitemap 早于数据库迁移完成拉路由产生的启动期噪音,实测不影响建库与就绪,可忽略(见 4.3)。

Q4:日志反复刷 ERR_ERL_PERMISSIVE_TRUST_PROXY。 应用代码全开了 trust proxy,express-rate-limit 对每个请求打一条 ERROR。功能不受影响,但意味着 IP 限速可被伪造 X-Forwarded-For 绕过——反代场景务必只信任自己反代的地址、并在反代层做限速(见 4.7)。

Q5:POST /api/setup/db 报 Non empty db!。 说明数据库已被首启迁移建好,此步本就可跳过,直接 POST /api/setup/restart 完成初始化(实测流程见 4.4)。

Q6:登录 401 Unauthorized。 检查三件事:端点必须是 /oauth/login(不带 /api)、Content-Type 必须是 form-urlencoded、必须带 client_id=self。用户名是 admin 而非邮箱。

Q7:设置了 GANCIO_NAME/GANCIO_LOCALE 等环境变量但界面没变化。 这些变量在 1.28.2 源码中零引用(见 4.2 陷阱说明),站点名称/语言/时区请用管理界面或 gancio settings set instance_locale '"zh"' 修改并重启。

十、参考链接

站内相关阅读:

Gancio 1.28.2 Docker Compose 部署指南 - Quzuo