Gathio 1.6.7 Docker Compose 部署指南
在 Ubuntu 24.04 上用 Docker Compose 部署 Gathio 1.6.7(ghcr.io/lowercasename/gathio:1.6.7 + mongo:7.0)的完整过程:镜像选型、目录与 TOML 配置、持久化挂载、GATHIO_ 环境变量替换、等价 docker run 与验证回显,均实测通过。
Gathio 1.6.7 Docker Compose 部署指南
目标:在 Ubuntu 24.04.5 LTS 上用 Docker Compose 从零部署 Gathio 1.6.7 活动托管平台(应用 + MongoDB 7.0 双服务),完成配置、持久化与端到端验证。全部命令与回显实测于该环境;组件定位与功能面见 《Gathio 1.6.7 介绍与选型指南》。
一、环境信息
- 操作系统:Ubuntu 24.04.5 LTS(x86_64)
- Docker:29.9.2(build a82e528);Docker Compose:v5.6.1
- 应用镜像:
ghcr.io/lowercasename/gathio:1.6.7(449MB,内置 Node.js v22.23.3) - 数据库镜像:
mongo:7.0(1.18GB,服务端 v7.0.45) - 部署目录:
/opt/gathio(compose 项目名gathio) - 端口规划:宿主
8153→ 应用容器3000;MongoDB 27017 仅容器网络内可达、不映射宿主 - 生产访问:应用自身不终结 TLS,公网部署需 Nginx/Caddy 反代 HTTPS 并将
domain配为公网域名(联邦功能硬性要求)
二、镜像选型说明
Gathio 官方在 ghcr.io 发布与版本号一致的镜像标签;官方仓库的 docker-compose.yml 用 build:(context 当前目录 + Dockerfile)从源码构建,自托管日常运行推荐直接用发布镜像,免装 Node/pnpm 工具链:
| 镜像 | 大小 | 内容 | 适用 |
|---|---|---|---|
ghcr.io/lowercasename/gathio:1.6.7 | 449MB | TypeScript 编译产物 + Node.js v22.23.3 运行时 | 生产(当前最新 release) |
ghcr.io/lowercasename/gathio:1.6.6 | 443MB | 同上,上一版本 | 回滚演练/兼容性验证 |
mongo:7.0 | 1.18GB | MongoDB 7.0 系列(实测服务端 v7.0.45) | 官方文档与示例均按 MongoDB 7 口径 |
docker pull ghcr.io/lowercasename/gathio:1.6.7
1.6.7: Pulling from lowercasename/gathio
Digest: sha256:f061733f5688363d1316d76d2b6700cafc4d1936bd67e4d34809a01ef2ee18df
Status: Image is up to date for ghcr.io/lowercasename/gathio:1.6.7
💡 技术拓展:GHCR 镜像的 tag 策略常见三种——
策略 示例 取舍 仅语义化版本 tag 1.6.7(Gathio 实际方式)升级必须显式改 tag,最可控 版本 + latest多数官方镜像 方便但不可复现 版本 + 分支 tag( main)滚动发布项目 尝鲜用,生产避免 本文按第一种:compose 中写死
1.6.7,升级/回滚均改 tag 后up -d(见常用运维命令)。
mongo 不建议用 latest:Gathio 的 Mongoose 5.13 驱动链(mongodb 3.7.4)与 MongoDB 7.0 实测兼容,锁 7.0 系列避免大版本行为漂移。
三、前置条件
3.1 Docker 与 Compose 版本
docker --version
Docker version 29.9.2, build a82e528
docker compose version
Docker Compose version v5.6.1
Compose v2+ 语法(docker compose 子命令)即可,无插件要求。
3.2 端口空闲确认
宿主 8153 未被占用(若被占用,up 时会报 port is already allocated,见「常见问题」):
ss -lnt | grep 8153
# 无输出即空闲
3.3 目录规划
mkdir -p /opt/gathio/config /opt/gathio/static /opt/gathio/images
cd /opt/gathio
三个目录分别承载:TOML 配置、静态页/实例描述 Markdown、活动封面图(容器内 /app/public/events),全部以 bind mount 持久化到宿主。
四、部署步骤
4.1 生成配置文件
Gathio 只认 /app/config/config.toml,镜像自带 config.example.toml 模板。直接从镜像提取:
docker run --rm ghcr.io/lowercasename/gathio:1.6.7 cat /app/config/config.example.toml > /opt/gathio/config/config.toml
按本环境修改两处(其余参数含义见「配置参数说明」):[general] 段 domain = "localhost:8153";[database] 段 mongodb_url = "mongodb://mongo:27017/gathio"(示例默认是 mongodb://localhost:27017/gathio,官方注释明确 Docker 部署要改成 mongo 主机名)。最终配置全文:
[general]
domain = "localhost:8153"
port = "3000"
email = "admin@example.com"
site_name = "Gathio"
is_federated = true
delete_after_days = 7
email_logo_url = ""
show_kofi = false
show_public_event_list = false
max_comment_length = 5000
mail_service = "none"
creator_email_addresses = []
[database]
mongodb_url = "mongodb://mongo:27017/gathio"
[nodemailer]
smtp_server = ""
smtp_port = ""
smtp_username = ""
smtp_password = ""
[sendgrid]
api_key = ""
[mailgun]
domain = ""
api_key = ""
api_url = "https://api.mailgun.net"
[[static_pages]]
title = "Privacy Policy"
path = "/privacy"
filename = "privacy-policy.md"
4.2 编写 docker-compose.yml
/opt/gathio/docker-compose.yml:
volumes:
mongodb_data_db:
services:
gathio:
container_name: gathio-app
image: ghcr.io/lowercasename/gathio:1.6.7
links:
- mongo
environment:
- NODE_ENV=production
ports:
- 8153:3000
volumes:
- ./config:/app/config
- ./static:/app/static
- ./images:/app/public/events
restart: unless-stopped
mongo:
container_name: gathio-db
image: mongo:7.0
volumes:
- mongodb_data_db:/data/db
restart: unless-stopped
要点:links: - mongo 让应用容器获得 DNS 别名 mongo(与 mongodb_url 对应);MongoDB 不写 ports,27017 不出宿主;两容器都设 restart: unless-stopped,宿主机重启后自动拉起。
4.3 启动
cd /opt/gathio && docker compose up -d
Network gathio_default Creating
Volume gathio_mongodb_data_db Creating
Volume gathio_mongodb_data_db Created
Network gathio_default Created
Container gathio-db Creating
Container gathio-db Created
Container gathio-app Creating
Container gathio-app Created
Container gathio-db Starting
Container gathio-db Started
Container gathio-app Starting
Container gathio-app Started
4.4 验证
docker ps --format '{{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}' | grep gathio
gathio-app ghcr.io/lowercasename/gathio:1.6.7 Up 6 seconds 0.0.0.0:8153->3000/tcp, [::]:8153->3000/tcp
gathio-db mongo:7.0 Up 6 seconds 27017/tcp
docker logs gathio-app
> gathio@1.6.7 start
> node dist/start.js
You have not configured this Gathio instance to send emails! This means that event creators will not receive emails when their events are created, which means they may end up locked out of editing events. Consider setting up an email service.
Welcome to gathio! The app is now running on http://localhost:3000
Mongoose connection open!
curl -s -o /dev/null -w "HTTP %{http_code}\n" http://localhost:8153/
HTTP 200
Mongoose connection open! 表示数据库链路就绪;mail_service = "none" 时启动必有邮件警告,属预期(生产建议配 SMTP,见下节)。
4.5 端到端功能验证
创建一个活动并访问活动页(字段说明见 《Gathio 1.6.7 介绍与选型指南》 4.1 节):
curl -s -X POST http://localhost:8153/event \
--data-urlencode "eventName=Team Retro" \
--data-urlencode "eventLocation=Office 3F" \
--data-urlencode "eventStart=2026-11-05T15:00" \
--data-urlencode "eventEnd=2026-11-05T16:00" \
--data-urlencode "timezone=Asia/Shanghai" \
--data-urlencode "eventDescription=Quarterly retro" \
--data-urlencode "creatorEmail=admin@example.com" \
--data-urlencode "hostName=Admin" \
--data-urlencode "joinCheckbox=true" \
--data-urlencode "interactionCheckbox=true"
{"eventID":"cWI7ePnEPxs4JEK45qvbN","editToken":"3a20dzqt3hrxgrudl1qp0nm2tf0z4lqu","url":"/cWI7ePnEPxs4JEK45qvbN?e=3a20dzqt3hrxgrudl1qp0nm2tf0z4lqu"}
curl -s -o /dev/null -w "GET /cWI7ePnEPxs4JEK45qvbN -> HTTP %{http_code}\n" http://localhost:8153/cWI7ePnEPxs4JEK45qvbN
GET /cWI7ePnEPxs4JEK45qvbN -> HTTP 200
浏览器打开响应里的 url(含 ?e= 编辑令牌段)即可管理该活动;妥善保存该 URL,它是无账号体系下唯一的编辑凭证。
五、数据持久化说明
应用容器三组 bind mount + 数据库命名卷,实测挂载关系:
docker inspect gathio-app --format '{{range .Mounts}}{{.Type}} {{.Source}} -> {{.Destination}}{{"\n"}}{{end}}'
bind /opt/gathio/config -> /app/config
bind /opt/gathio/static -> /app/static
bind /opt/gathio/images -> /app/public/events
docker volume ls | grep gathio
local gathio_mongodb_data_db
| 宿主路径/卷 | 容器内路径 | 内容 | 丢失后果 |
|---|---|---|---|
/opt/gathio/config | /app/config | config.toml | 容器进入配置缺失崩溃循环(见常见问题) |
/opt/gathio/static | /app/static | 静态页 Markdown、instance-description-<locale>.md | 自定义页 404、实例描述回落默认 |
/opt/gathio/images | /app/public/events | 活动封面图(<eventID>.jpg) | 活动页图片丢失(元数据仍在库) |
卷 gathio_mongodb_data_db | /data/db | events/eventgroups/logs 三集合 | 全部活动数据丢失 |
⚠️ 注意:
docker compose down -v会删除命名卷(活动数据全丢),日常停止用不带-v的down;备份策略见运维篇。
六、环境变量表
compose environment: 段可用的环境变量:
| 变量 | 作用 | 取值 | 实测行为 |
|---|---|---|---|
NODE_ENV | Node 运行模式 | production | 官方 compose 示例设置;不设不影响启动 |
GATHIO_* 前缀变量 | 供 config.toml 字符串值以 ${GATHIO_名字} 语法引用 | 任意字符串 | 见下方实测 |
配置文件的字符串值支持环境变量替换,仅识别 GATHIO_ 前缀(镜像内示例配置头部注释原文)。实测 mongodb_url = "${GATHIO_MONGODB_URL}" 两种情形:
# 情形一:compose 中设置 GATHIO_MONGODB_URL=mongodb://mongo:27017/gathio
docker logs gathio-app | tail -1
Mongoose connection open!
curl -s -o /dev/null -w "HTTP %{http_code}\n" http://localhost:8153/
HTTP 200
# 情形二:删除该环境变量后重启(输出节选,实测首尾)
docker logs gathio-app | tail -6
Config references environment variable "GATHIO_MONGODB_URL" which is not set. The literal string "${GATHIO_MONGODB_URL}" will be used instead.
Connection error: Invalid connection string
MongoParseError: Invalid connection string
at parseConnectionString (/app/node_modules/.pnpm/mongodb@3.7.4/node_modules/mongodb/lib/core/uri_parser.js:585:21)
docker inspect gathio-app --format 'RestartCount={{.RestartCount}}'
RestartCount=4
解读:变量未设置时应用先告警、再把 ${...} 字面量当连接串使用,MongoDB 驱动解析失败直接崩溃,restart: unless-stopped 使其循环重启(实测 RestartCount 涨到 4)。因此 ${GATHIO_...} 写法必须与 compose 环境变量成对出现;SMTP 密码等敏感值推荐此机制注入:配置写 smtp_password = "${GATHIO_SMTP_PASSWORD}",compose 写 GATHIO_SMTP_PASSWORD 并在宿主 export 提供真实值,明文不落盘。
七、配置参数说明
config.toml 各参数(默认值取自镜像内 config.example.toml 实测输出,行为均经实测核对):
| 段.参数 | 默认值 | 说明 |
|---|---|---|
| general.domain | localhost:3000 | 对外访问域名[:端口],所有绝对链接(含联邦对象)按 https://<domain> 生成,公网部署必须填 HTTPS 域名 |
| general.port | 3000 | 应用监听端口(容器内) |
| general.email | contact@example.com | 实例联系邮箱(页脚/邮件发件人) |
| general.site_name | Gathio | 站点名 |
| general.is_federated | true | ActivityPub 联邦开关 |
| general.delete_after_days | 7 | 活动结束 N 天后自动删除;0 关闭自动删除 |
| general.email_logo_url | "" | 邮件 logo,空=用 https://<domain>/images/gathio-email-logo.gif |
| general.show_kofi | false | 首页显示作者 Ko-Fi 捐赠框 |
| general.show_public_event_list | false | true 时 /events 公开活动列表成为首页;实测 false 时 GET /events → 404 |
| general.max_comment_length | 5000 | 评论/回复最大字符数 |
| general.mail_service | none(示例值) | nodemailer/sendgrid/mailgun/none;none 时启动警告、RSVP 邮件仅打印控制台、群组订阅接口 500 |
| general.creator_email_addresses | [] | 建活动白名单;空数组=任何人可建(实测默认行为) |
| database.mongodb_url | mongodb://localhost:27017/gathio | Docker 部署改 mongodb://mongo:27017/gathio;支持 ${GATHIO_*} 替换 |
| nodemailer.smtp_server/port/username/password | "" | 自建 SMTP 通道参数 |
| sendgrid.api_key | "" | SendGrid 通道参数 |
| mailgun.domain/api_key/api_url | ""/""/https://api.mailgun.net | Mailgun 通道;EU 区改 https://api.eu.mailgun.net |
| [[static_pages]] | 注释示例 | title/path/filename;path 以 / 开头=内部页(渲染 static/<filename>),https:// 开头=页脚外链 |
真实密钥(SMTP 密码、SendGrid/Mailgun API Key)不要明文写进 config.toml:用 ${GATHIO_SMTP_PASSWORD} 等变量引用 + 宿主 export 注入(机制与缺失后果见「环境变量表」实测)。
八、配置文件挂载
三类挂载文件各自的作用与实测验证:
8.1 config.toml
必须存在且 TOML 语法合法,否则进程退出(见常见问题)。改配置后 docker compose restart gathio 即生效(应用启动时一次性读取,无热加载)。
8.2 static/ 静态页与实例描述
[[static_pages]] 声明的内部页渲染 static/<filename>。实测添加:
printf '# Privacy Policy\n\nEvents self-destruct automatically.\n' > /opt/gathio/static/privacy-policy.md
docker compose restart gathio
curl -s -o /dev/null -w "GET /privacy -> HTTP %{http_code}\n" http://localhost:8153/privacy
GET /privacy -> HTTP 200
实例首页描述文案在 static/instance-description-<locale>.md(支持 {{ siteName }} 模板串)。实测坑点:无 locale 后缀的 instance-description.md 不生效,必须写成 instance-description-en.md(对应界面语言),否则回落默认文案 "Gathio is running on Gathio — a simple, federated, privacy-first event hosting platform."。
8.3 images/(容器内 /app/public/events)
活动封面图落盘目录,由应用写入(Jimp 缩放 920px、质量 80,文件名 <eventID>.jpg),宿主侧只读备份即可,无需手工放置文件。
九、等价 docker run
不用 compose 的单机等价部署(网络与 DNS 别名需自行保证)。实测:
docker run -d --name gathio-runtest --network gathio_default -p 8157:3000 \
-e NODE_ENV=production \
-v /opt/gathio/config:/app/config \
-v /opt/gathio/static:/app/static \
-v /opt/gathio/images-run:/app/public/events \
ghcr.io/lowercasename/gathio:1.6.7
9e98702bd73154bed5ec8f3c80c4f09fc5b845f7589ec8b044ba0fa2fcd24ee4
curl -s -o /dev/null -w "GET :8157 -> HTTP %{http_code}\n" http://localhost:8157/
GET :8157 -> HTTP 200
docker logs gathio-runtest | tail -2
Welcome to gathio! The app is now running on http://localhost:3000
Mongoose connection open!
⚠️ 注意:
--link gathio-db:mongo在自定义 bridge 网络上实测不可用,报错docker: Error response from daemon: container 2579b9bca53bcfe5070c5e5c75aaa9f5bcc955b27913619e8994d39c582e476b not attached to default bridge network。正确做法是--network挂到数据库所在网络,mongoDNS 别名由 composelinks:在网络上生成;纯手工场景可给数据库容器加--network-alias mongo。
十、常用运维命令
# 查看状态
docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
gathio-app ghcr.io/lowercasename/gathio:1.6.7 "docker-entrypoint.s…" gathio 10 minutes ago Up 10 minutes 0.0.0.0:8153->3000/tcp, [::]:8153->3000/tcp
gathio-db mongo:7.0 "docker-entrypoint.s…" mongo 16 minutes ago Up 16 minutes 27017/tcp
# 跟踪日志(启动/崩溃定位第一入口)
docker compose logs -f gathio
# 改配置后重启应用
docker compose restart gathio
# 进应用容器排障
docker exec -it gathio-app sh
# 数据库交互式查询
docker exec -it gathio-db mongosh gathio
# 资源占用(空闲基线:app ~100MiB、db ~75MiB)
docker stats --no-stream gathio-app gathio-db
gathio-app 0.00% 100MiB / 15.57GiB
gathio-db 0.27% 74.76MiB / 15.57GiB
# 停止(保留数据)/ 启动
docker compose down
docker compose up -d
升级/回滚(改 tag 后 up -d 自动重建应用容器,数据不受影响)与备份恢复的完整实测流程见本专栏运维文档。
十一、常见问题
11.1 端口被占用
up 时报错:
Error response from daemon: failed to set up container networking: driver failed programming external connectivity on endpoint gathio-app (89433a7a81d12e9313c6dca1849b56a799e527e646e5db0fb5823c362c372742): Bind for 0.0.0.0:8153 failed: port is already allocated
定位:ss -lntp | grep 8153 找出占用进程。解决:释放占用服务,或改 compose ports: 宿主侧端口并同步改 config.toml 的 domain(两者端口必须一致,否则生成的活动链接不可用)。
11.2 config.toml 缺失 → 崩溃循环
现象:docker ps 显示 gathio-app Restarting (1),HTTP 连接拒绝(curl 返回 000),日志尾部红字:
Configuration file not found! Have you renamed './config/config.example.toml' to './config/config.toml'?
解决:按 4.1 从镜像提取示例生成 config.toml,docker compose up -d 恢复。
11.3 TOML 语法错误
日志报错并给出精确位置(行/列/偏移):
Error parsing configuration: [SyntaxError: Expected "=" or [ \t] but "l" found.]
解决:按报错行号修正(常见于把注释/键值写错段、或复制粘贴引入不可见字符),restart 验证。
11.4 MongoDB 连不上
mongodb_url 指向不可达主机时应用照常起(GET / → 200 静态首页),但所有读写 10 秒超时:日志 MongooseError: Operation logs.insertOne() buffering timed out after 10000ms,活动页 GET /<eventID> → 404 且耗时约 10.007s。定位用容器内连通性检查:
docker exec gathio-app nc -zv mongo 27017
mongo (172.24.0.2:27017) open
不通时检查 links/网络与 mongodb_url 主机名。更完整的故障场景复现与处置见本专栏排错 FAQ 文档。
十二、参考链接
- 官方安装文档(镜像内
/app/docs/running-gathio/installation.md):https://docs.gath.io/running-gathio/installation - 配置文档:https://docs.gath.io/running-gathio/configuration
- 仓库与官方 compose:https://github.com/lowercasename/gathio
- 镜像:https://ghcr.io/lowercasename/gathio
- 站内:《Gathio 1.6.7 介绍与选型指南》