Rybbit Docker Compose 部署指南
Rybbit v2.9.2 Docker Compose 生产级部署实录:镜像选型、端口规划、环境变量表、数据持久化、注册建站与数据上报全链路验证,附 Origin 校验、Bot 拦截、端口冲突三大实测排障。
Rybbit Docker Compose 部署指南
目标:在一台 Linux 服务器上从零完成 Rybbit v2.9.2 的 Docker Compose 生产级部署,涵盖镜像选型、端口规划、环境变量、数据持久化、首次注册与数据上报全链路验证,并沉淀部署实测中的三处高频踩坑(Origin 校验、Bot 拦截、端口冲突)。全部命令与回显均在 Ubuntu 22.04 服务器(Docker 27 + Compose v5.6.1)实测通过,实测日期 2026-10-30。
一、环境信息
| 项目 | 本次实测环境 |
|---|---|
| 操作系统 | Ubuntu 22.04(内核 5.15+) |
| 服务器 IP | 192.168.1.200(局域网,无域名场景演示) |
| Docker | Docker 27.x + Docker Compose v5.6.1 |
| Rybbit 版本 | v2.9.2(2026-10-24 发布,官方最新稳定版,来源 releases.atom) |
| 依赖组件版本 | ClickHouse 26.3.17.4 / PostgreSQL 17.4 / Redis 8.6.4-alpine(官方 compose 锁定) |
| 内存/磁盘 | 16GB 内存 / NVMe SSD(Rybbit 全家桶建议 4GB 内存起步) |
| 端口规划 | Web 看板 8128 → 容器 3002;API 后端 8129 → 容器 3001;PostgreSQL 15432(宿主 5432 已被占用) |
| 实测账号 | admin@example.com / Q1w2E3r4T!(注册接口实测拒绝弱口令,见 10.4) |
二、镜像选型说明
官方在 v2.9.2 的 docker-compose.yml 中锁定了如下镜像组合,全部来自 GHCR/Docker Hub 官方命名空间(来源:v2.9.2 源码包 docker-compose.yml,实测 pull 全部命中):
| 服务 | 镜像 | 作用 | 必选 |
|---|---|---|---|
| client | ghcr.io/rybbit-io/rybbit-client:v2.9.2 | Next.js 看板前端,容器端口 3002 | 是 |
| backend | ghcr.io/rybbit-io/rybbit-backend:v2.9.2 | Node.js API/写入/认证,容器端口 3001 | 是 |
| clickhouse | clickhouse/clickhouse-server:26.3.17.4 | 事件数据列式存储 | 是 |
| postgres | postgres:17.4 | 用户/组织/站点等元数据 | 是 |
| redis | redis:8.6.4-alpine | 会话/粘性身份/bot 计数,AOF 持久化 | 是 |
| caddy | caddy:2.10.0 | 内置反代与自动 HTTPS | 否(profiles 隔离,默认不启动) |
选型要点:
- 必须锁版本 tag 而非 latest:backend/client 镜像发布
v2.9.2与latest双 tag,本次实测docker pull ghcr.io/rybbit-io/rybbit-backend:v2.9.2直接命中(digestsha256:e5fc900b…)。生产升级时改.env中IMAGE_TAG即可全栈同版本切换。 - ClickHouse 是资源大头:官方在 compose 里已内置三份 XML config(网络监听、日志裁剪、资源上限),把
max_server_memory_usage_to_ram_ratio限到 0.80。本次实测额外补了mem_limit: 2560m双保险,16GB 宿主机上 5 容器总内存占用可控。 - Caddy 默认不启动:官方把 caddy 服务放进
profiles: ["with-webserver"],docker compose up -d不会拉起它。无自有反代的用户建议启用(见第十章常见问题),本文主线路径按「已有/暂无反代、先跑通数据链路」的直连模式展开。
三、前置条件
# 1. 确认 Docker 与 Compose 版本(低于 v2.23 不支持 compose 内嵌 configs 语法)
docker --version && docker compose version
实测回显:
Docker version 27.5.1, build 9f9e405
Docker Compose version v5.6.1
# 2. 规划端口:确认 8128/8129 未被占用(避开 ClickHouse 默认 8123 与常见业务端口)
ss -ltn | grep -E ':(8128|8129)\b' || echo '端口空闲'
# 3. 内存余量确认(全家桶建议可用内存 ≥4GB)
free -h | grep Mem
实测回显:
端口空闲
Mem: 15Gi 7.9Gi 2.6Gi
四、部署步骤
4.1 建目录并获取官方编排文件
Rybbit 官方不单独发布 compose 产物,编排文件随源码仓库发布。不 clone 仓库的话,直接下载官方源码包解包取文件(本文采用,实测 65MB):
mkdir -p /opt/rybbit && cd /opt/rybbit
curl -fsSL -o rybbit-2.9.2.tar.gz https://codeload.github.com/rybbit-io/rybbit/tar.gz/refs/tags/v2.9.2
tar xzf rybbit-2.9.2.tar.gz
cp rybbit-2.9.2/docker-compose.yml rybbit-2.9.2/Caddyfile .
⚠️ 网络说明:codeload.github.com 在部分网络环境直连较慢,实测可走的降级链是「直连 → 代理
http://192.168.1.62:7897」(curl -x http://192.168.1.62:7897 ...),两个渠道 2026-10-30 实测均可用。
4.2 编写 .env
在 /opt/rybbit/.env 写入(全部为本次实测值,可直接替换 IP 后使用):
# 浏览器实际访问 Rybbit 的基础地址(也是后端可信 Origin,必须与访问地址完全一致)
BASE_URL=http://192.168.1.200:8129
BETTER_AUTH_SECRET=rybbit-lab-9f3c7a1e5d2b8460-secret
DISABLE_SIGNUP=false
DISABLE_TELEMETRY=true
# 端口映射:看板 8128、API 8129(按宿主空闲端口改)
HOST_BACKEND_PORT=8129:3001
HOST_CLIENT_PORT=8128:3002
# 数据库凭据(生产务必改掉官方默认值)
CLICKHOUSE_DB=analytics
CLICKHOUSE_USER=default
CLICKHOUSE_PASSWORD=frog
POSTGRES_DB=analytics
POSTGRES_USER=frog
POSTGRES_PASSWORD=frog
REDIS_PASSWORD=rybbitRedis2026
# 镜像版本锁
IMAGE_TAG=v2.9.2
BETTER_AUTH_SECRET 生成方式(官方文档推荐):
openssl rand -hex 32
4.3 定制 compose(推荐三处)
官方 docker-compose.yml 可直接使用,但生产部署建议做三处实测验证过的定制(本节改动与实测一一对应):
- 显式项目名(防多套栈互相误删):
name: rybbit-2.9.2-stack
- 显式子网(防与其他业务网段冲突):
networks:
default:
name: rybbit-292-net
driver: bridge
ipam:
config:
- subnet: 10.89.58.0/24
- 资源上限与端口避让:clickhouse 服务加
mem_limit: 2560m;若宿主 5432 已被占用,把 postgres 的端口映射改为"127.0.0.1:15432:5432"。本次实测宿主 5432 被占用,直接沿用官方映射会导致 postgres 容器起不来——这是小内存多业务宿主的高频坑。
4.4 拉镜像并启动
cd /opt/rybbit
docker compose pull
docker compose up -d
docker compose up -d 实测回显(节选):
Container backend Running
Container client Running
Container clickhouse Running
Container rybbit-292-stack-postgres-1 Running
Container redis Healthy
Container clickhouse Healthy
启动顺序由 depends_on + healthcheck 编排保证:ClickHouse 与 Redis 健康后 backend 才启动,backend 起后 client 启动。首次启动到 backend healthy 实测约 40 秒。
4.5 部署验证
# 1. 容器状态
docker compose ps --format 'table {{.Name}}\t{{.Status}}'
实测回显:
NAME STATUS
backend Up 43 seconds (healthy)
clickhouse Up 49 seconds (healthy)
client Up 43 seconds
redis Up 49 seconds (healthy)
rybbit-292-stack-postgres-1 Up 49 seconds (healthy)
# 2. 后端健康检查端点
curl -s http://127.0.0.1:8129/api/health
实测回显:
OK
# 3. 看板页面与 tracker 脚本可达性
curl -s -o /dev/null -w 'client HTTP %{http_code}\n' http://127.0.0.1:8128/
curl -s -o /dev/null -w 'script.js HTTP %{http_code} | %{size_download} bytes | %{content_type}\n' http://127.0.0.1:8129/api/script.js
实测回显:
client HTTP 200
script.js HTTP 200 | 33968 bytes | application/javascript; charset=utf-8
五、数据持久化说明
官方 compose 定义了三个命名卷,宿主目录由 Docker 管理(位于 /var/lib/docker/volumes/):
卷名(前缀 rybbit-292-stack_) | 容器挂载点 | 内容 |
|---|---|---|
clickhouse-data | /var/lib/clickhouse | 全部页面浏览/事件/回放数据(核心资产) |
postgres-data | /var/lib/postgresql/data | 用户、组织、站点、API Key 元数据 |
redis-data | /data | 会话与 bot 计数(AOF everysec) |
备份与迁移建议:
# 核心数据备份(ClickHouse 原生备份方式,停写窗口极小)
docker exec clickhouse clickhouse-client --password frog \
-q "BACKUP TABLE analytics.events TO Disk('backups', 'events-$(date +%F).zip')"
💡 技术拓展:命名卷 vs 绑定挂载——命名卷由 Docker 统一管理生命周期、可随
docker volume工具迁移快照,是数据库类服务的推荐形态;绑定挂载(-v /opt/rybbit/data:/var/lib/clickhouse)则便于直接用 rsync 做文件级备份但要注意 UID 权限对齐。Rybbit 官方选择命名卷,自建备份脚本用docker run --rm -v rybbit-292-stack_clickhouse-data:/data ...挂卷导出即可,无需进入容器。
六、环境变量表
以下为 v2.9.2 官方 .env.example 与 compose 联动整理的完整变量表(「实测」列标注本次部署的实际取值与验证结果):
| 变量 | 默认值 | 说明 | 实测 |
|---|---|---|---|
BASE_URL | 无(必填) | 浏览器访问的基址,同时是后端唯一可信 Origin | http://192.168.1.200:8129,不匹配时注册直接 403 |
BETTER_AUTH_SECRET | 无(必填) | 认证签名密钥,32+ 随机字符 | openssl rand -hex 32 生成 |
DISABLE_SIGNUP | false | 关闭公开注册(建好管理员后建议 true) | false,注册成功 |
DISABLE_TELEMETRY | 未设 | 关闭产品遥测上报 | true |
DOMAIN_NAME | 未设 | Caddy 模式的域名(自动 HTTPS 依赖它) | 未启用 Caddy,不设 |
HOST_BACKEND_PORT | 127.0.0.1:3001 | 后端宿主端口映射 | 8129:3001 |
HOST_CLIENT_PORT | 127.0.0.1:3002 | 前端宿主端口映射 | 8128:3002 |
CLICKHOUSE_DB | analytics | 事件库名 | analytics |
CLICKHOUSE_USER / CLICKHOUSE_PASSWORD | default / frog | ClickHouse 管理凭据 | 保持默认(内网隔离) |
CLICKHOUSE_QUERY_PASSWORD | 同上 | 最低权限查询用户 rybbit_query 的密码 | 未设(自动随主密码开通) |
POSTGRES_DB/USER/PASSWORD | analytics / frog / frog | 元数据库凭据 | 保持默认 |
REDIS_PASSWORD | changeme | Redis 密码(compose 启动参数注入 requirepass) | rybbitRedis2026 |
IMAGE_TAG | latest | backend/client 镜像 tag | v2.9.2 |
MAPBOX_TOKEN | 空 | 地图/地球可视化增强,可选 | 空(看板自动降级为平面地图) |
CLUSTER_WORKERS | 4 | 后端 Node 集群 worker 数 | 默认 4 |
LITE_DASHBOARD | 未设 | 精简看板模式(低配机器建议 true) | 未设 |
DEPLOYMENT | 未设 | 部署形态标识(cloud/self-host 差异化逻辑) | 未设 |
OPENROUTER_API_KEY / OPENROUTER_MODEL | 空 | AI 辅助自定义查询功能 | 空 |
七、配置参数说明
三处与部署强相关的编排参数,实测口径如下:
- healthcheck 参数:backend 用
wget --spider http://127.0.0.1:3001/api/health,间隔 3 秒、超时 5 秒、重试 5 次、启动宽限 10 秒;ClickHouse 同款结构 pinghttp://localhost:8123/ping。调整start_period可容忍慢盘冷启动——本次实测首次启动 40 秒即 healthy,无需调整。 - ClickHouse 内嵌 configs:官方通过 compose
configs:段落把 4 份 XML 直接注入容器(网络监听0.0.0.0、日志裁剪到 warning、内存上限 80% RAM、async_insert=1+max_threads=16profile)。这套参数无需改动即可投产;数据量上 TB 后优先调max_memory_usage(默认 32GB 上限,小内存机器需下调)。 - Redis 运行参数:
--requirepass $REDIS_PASSWORD --appendonly yes --appendfsync everysec --maxmemory-policy noeviction。noeviction是刻意选择——会话键带 30 分钟 TTL,内存有界,拒绝淘汰以保证粘性身份与 bot 计数不丢。
八、配置文件挂载
官方 compose 的挂载共两类:
- 命名卷三类(见第五章);
- Caddyfile 绑定挂载:
./Caddyfile:/etc/caddy/Caddyfile——仅在启用 caddy profile 时生效。启用 Caddy 模式的完整步骤:
# 1. 编辑 Caddyfile,把 {$DOMAIN} 换成你的域名
sed -i 's/{$DOMAIN}/analytics.example.com/' Caddyfile
# 2. .env 增加 BASE_URL 与域名
# BASE_URL=https://analytics.example.com
# 3. 带 profile 启动(Caddy 会自动签发 Let's Encrypt 证书)
docker compose --profile with-webserver up -d
实测说明:本次实验宿主 80/443 已被占用且无公网域名,主线按直连模式完成全链路验证;Caddy 模式的价值在「单域名统一入口」,这也是规避第十章 Origin 踩坑的根治方案。
九、等价 docker run
理解编排等价性的单容器拆解(生产仍建议 compose;参数与 compose 定义一致):
# ClickHouse(关键点:注入官方同款网络监听与异步插入配置)
docker run -d --name clickhouse \
--memory 2560m \
-e CLICKHOUSE_DB=analytics -e CLICKHOUSE_USER=default -e CLICKHOUSE_PASSWORD=frog \
-e CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT=1 \
-v clickhouse-data:/var/lib/clickhouse \
clickhouse/clickhouse-server:26.3.17.4
# 后端(关键点:三个依赖地址 + BASE_URL 可信 Origin)
docker run -d --name backend \
-p 8129:3001 \
-e NODE_ENV=production \
-e CLICKHOUSE_HOST=http://clickhouse:8123 \
-e CLICKHOUSE_DB=analytics -e CLICKHOUSE_PASSWORD=frog \
-e POSTGRES_HOST=postgres -e POSTGRES_DB=analytics \
-e POSTGRES_USER=frog -e POSTGRES_PASSWORD=frog \
-e REDIS_HOST=redis -e REDIS_PASSWORD=rybbitRedis2026 \
-e BETTER_AUTH_SECRET=rybbit-lab-9f3c7a1e5d2b8460-secret \
-e BASE_URL=http://192.168.1.200:8129 \
-e CLUSTER_WORKERS=4 \
ghcr.io/rybbit-io/rybbit-backend:v2.9.2
# 前端(关键点:仅依赖 backend 可达性)
docker run -d --name client \
-p 8128:3002 \
-e NODE_ENV=production \
-e NEXT_PUBLIC_BACKEND_URL=http://192.168.1.200:8129 \
ghcr.io/rybbit-io/rybbit-client:v2.9.2
十、常用运维命令与首次使用
10.1 日常运维命令
cd /opt/rybbit
docker compose ps # 栈健康状态
docker compose logs -f backend # 跟随后端日志(track/查询错误都在这)
docker compose restart backend client # 只重启应用层(数据层不动)
docker compose down # 停栈保留数据卷
docker compose pull && docker compose up -d # 升级到 .env 指定的新版本
10.2 注册管理员与建站
浏览器打开 http://192.168.1.200:8128 进入看板(无头服务器可用 API 走通全流程,以下为实测命令):
# 1. 注册(Origin 头必须与 BASE_URL 一致,见 10.3 踩坑一)
curl -s -c /opt/rybbit/cookies.txt -X POST http://127.0.0.1:8129/api/auth/sign-up/email \
-H 'Content-Type: application/json' -H 'Origin: http://192.168.1.200:8129' \
-d '{"name":"admin","email":"admin@example.com","password":"Q1w2E3r4T!"}'
实测回显(节选):
{"token":"MADSPPrOjRclxgEG7TUfBHEoE23HwA6f","user":{"name":"admin","email":"admin@example.com",...,"id":"VtzR6oiIVkL5xQREuwAxutXfY4XUAwfd"}}
# 2. 创建组织
curl -s -b /opt/rybbit/cookies.txt -X POST http://127.0.0.1:8129/api/auth/organization/create \
-H 'Content-Type: application/json' -H 'Origin: http://192.168.1.200:8129' \
-d '{"name":"Demo Org","slug":"demo-org"}'
实测回显(节选):
{"name":"Demo Org","slug":"demo-org",...,"id":"lL3zKTX9RuNjYrSN1ahjXeAXBXfHiJzU","members":[{"role":"owner",...}]}
# 3. 在组织下建站(用上一步返回的组织 id)
curl -s -b /opt/rybbit/cookies.txt -X POST \
http://127.0.0.1:8129/api/organizations/lL3zKTX9RuNjYrSN1ahjXeAXBXfHiJzU/sites \
-H 'Content-Type: application/json' -H 'Origin: http://192.168.1.200:8129' \
-d '{"name":"Demo Site","domain":"demo.example.com"}'
实测回显(节选):
{"id":"2c0b9eb7c6a2","siteId":1,"name":"Demo Site",...,"blockBots":true,...}
10.3 数据上报与统计验证
# 4. 上报一条页面浏览事件(site_id 用建站返回的短 id 2c0b9eb7c6a2)
curl -s -X POST http://127.0.0.1:8129/api/track \
-H 'Content-Type: application/json' \
-H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/140.0 Safari/537.36' \
-d '{"type":"pageview","site_id":"2c0b9eb7c6a2","hostname":"demo.example.com","pathname":"/posts/hello-1","page_title":"测试文章","screenWidth":1920,"screenHeight":1080,"language":"zh-CN","anonymous_id":"visitor-1"}'
实测回显:
{"success":true}
批量上报 5 条 pageview + 3 个访客后,用 API Key 查询汇总(Key 创建与用法详见本专栏 API 篇):
curl -s -H "Authorization: Bearer <你的APIKey>" 'http://127.0.0.1:8129/api/sites/1/overview?period=24h'
实测回显(与注入数据 3 访客/5 PV 精确吻合):
{"data":{"sessions":3,"pages_per_session":1.6666666666666667,"bounce_rate":33.33333333333333,"session_duration":0,"pageviews":5,"users":3}}
10.4 常见问题(实测排障实录)
问题一:注册/登录报 {"error":"Origin not allowed"}(403)
后端生产模式把可信 Origin 钉死为 BASE_URL(v2.9.2 server/src/lib/cors.ts 逻辑实测验证)。两种触发场景:① curl 调用时 Origin 头与 BASE_URL 不一致;② 浏览器从「看板端口 8128」跨端口请求「API 端口 8129」——API 请求会带 Origin: http://IP:8128,被后端拒绝,浏览器侧看板无法登录。根治方案是把看板与 API 收进同一域名(启用内置 Caddy,或在自有 Nginx 上把 /api 反代到 backend、其余路径反代到 client),让 BASE_URL 等于浏览器地址栏的统一入口。临时方案(纯 API 集成、无浏览器场景)是请求头带 Origin: $BASE_URL。
问题二:/api/track 返回 success 但看板数据始终为 0
先查 ClickHouse:docker exec clickhouse clickhouse-client --password frog -q "SELECT count() FROM analytics.bot_events"——实测 6 条测试事件全部躺在 bot_events。原因:新站点默认 blockBots: true,而服务端模拟请求没有浏览器端 tracker 注入的 bot 信号位,被判 bot 转存。处理:PUT /api/sites/<siteId>/config 传 {"blockBots":false} 关闭(实测回显 "message":"Site configuration updated successfully"),重发事件 6 秒内(写入队列 1 秒 flush + 异步插入合并)即出现在看板。真实浏览器流量不受此影响,生产站点无需关闭。
问题三:postgres 容器起不来,日志报端口绑定失败
宿主 5432 被其他 PostgreSQL 实例占用所致(本次实测宿主确实有 5432 监听)。把 compose 中 postgres 的映射改为 "127.0.0.1:15432:5432"。同理 ClickHouse 的 127.0.0.1:8123:8123、Redis 的 127.0.0.1:6379:6379 也可能撞车,这两者只在本机排障时有用,干脆删掉映射、仅保留容器网络内访问更安全。
问题四:弱口令注册被拒
实测 password: q1w2e3r4 无法注册(Better Auth 内置密码强度校验),改用强口令 Q1w2E3r4T! 成功。部署文档与自动化脚本中的演示账号密码需按此口径编写。
问题五:/api/sites/1/metric 返回 500 INTERNAL_ERROR
该端点除 type 外还需要 parameter 参数(如 type=pages¶meter=pathname),缺参会触发后端空指针(v2.9.2 实测 bug,已实测复现),补齐参数即返回正常数据。升级版本时应关注官方 Release Notes 是否修复。
问题六:compose up 时刷 The "MAPBOX_TOKEN" variable is not set 告警
无害告警:compose 对 .env 中未定义变量的默认空值提示,可在 .env 补 MAPBOX_TOKEN= 等空定义消除,不影响任何功能。
十一、参考链接
- 官方自托管文档:https://rybbit.com/docs/self-hosting
- v2.9.2 源码包(含 docker-compose.yml 与 .env.example):https://github.com/rybbit-io/rybbit/releases/tag/v2.9.2
- Releases Atom 源(版本取证):https://github.com/rybbit-io/rybbit/releases.atom
- 官方镜像:https://github.com/rybbit-io/rybbit/pkgs/container/rybbit-backend
- 本专栏选型篇:《Rybbit 介绍与选型指南》
- 本专栏配置篇:《Rybbit 2.9.2 配置参数详解》
- 本专栏 API 篇:《Rybbit 2.9.2 API 使用详解》
- 同类方案部署参考:《Plausible Docker Compose 部署指南》、《Aptabase Docker Compose 部署指南》