首页
/ Maybe 开源个人理财应用:本地开发环境与 Docker 自托管全解析

Maybe 开源个人理财应用:本地开发环境与 Docker 自托管全解析

2026-09-05 22:09:57作者:齐冠琰

Maybe 是一款可直接运行的开源自托管个人理财应用,基于 Rails 7.2 + Hotwire 构建。本文围绕仓库根目录的 README 展开,覆盖其全部核心实操内容——Docker 自托管部署、本地开发环境搭建、演示数据加载与登录方式,并结合 compose.example.ymlDockerfile.env.example 与源码配置深入解析每个环境变量与部署细节的来龙去脉。读完本文,你可以独立完成 Maybe 的本地开发启动,也可以在服务器上部署一套可用的自托管实例并知道如何更新与排错。

需要说明的一点:README 中明确标注该仓库已不再积极维护(官方最终版本为 v0.6.0),因此本文所有操作均以当前仓库的实际文件内容为准确认,读者在引用时应留意这一点。

项目定位:一个可直接运行的理财应用

README 对 Maybe 的定位非常直接:它是一个 fully working 的个人理财应用,既支持 Docker 自托管,也面向贡献者提供完整的本地开发流程。从 Gemfile 可以看到它的技术栈:Rails ~> 7.2.2、PostgreSQL(pg 驱动)、Redis、Sidekiq 后台任务、Puma 服务器、Importmap + Turbo + Stimulus 的前端组合、ViewComponent 与 Lookbook 组件库,以及 Doorkeeper OAuth 与 Rack::Attack 用于外部 API 的安全控制。

应用通过一个 app_mode 配置区分两种运行形态,其定义在 config/application.rb 中:

config.app_mode = (ENV["SELF_HOSTED"] == "true" || ENV["SELF_HOSTING_ENABLED"] == "true" ? "self_hosted" : "managed").inquiry

即当环境变量 SELF_HOSTED=true 时,应用以 self_hosted 模式运行(开启自托管特有功能,如设置页内配置 Synth API Key);否则为 managed 模式(官方托管形态)。这是理解后续所有环境变量的关键开关。

Docker 自托管部署(推荐方式)

自托管用户应直接参考 docs/hosting/docker.md 这份官方指南,其完整流程如下。

前置:安装 Docker

  1. 按官方文档安装 Docker Engine 并启动 Docker 服务;
  2. 用以下命令验证安装:
# 若 Docker 配置正确,此命令将成功
docker run hello-world

创建应用目录并获取示例 Compose 文件

# 创建存放 Docker 文件的目录(名称可自定义)
mkdir -p ~/docker-apps/maybe

# 切换到该目录
cd ~/docker-apps/maybe

# 从 Maybe 仓库下载示例 compose 文件
curl -o compose.yml https://raw.githubusercontent.com/maybe-finance/maybe/main/compose.example.yml

执行后当前目录中应只有一个 compose.yml。该文件即本仓库中的 compose.example.yml,下文会逐段解读其结构。

(可选)配置安全环境变量

默认情况下示例 Compose 文件可以零配置运行;但如果实例运行在局域网之外,官方强烈建议创建 .env 文件以覆盖默认值:

touch .env

应用要求 SECRET_KEY_BASE 这一环境变量(Rails 用于加密 session 等凭据),可用以下任一方式生成:

openssl rand -hex 64
# 或不依赖 openssl 的替代方案:
head -c 64 /dev/urandom | od -An -tx1 | tr -d ' \n' && echo

随后在 .env 中填入:

SECRET_KEY_BASE="上一步生成的字符串"
POSTGRES_PASSWORD="你期望的数据库密码"

启动与后台运行

docker compose up      # 拉取官方镜像并启动,可在终端看到日志
docker compose up -d   # 用 Ctrl+C 停止前台进程后,以 detached 模式后台运行
docker compose ls      # 验证 compose 项目正在运行

一切正常时,访问 http://localhost:3000 即可看到 Maybe 登录页。首次使用需在登录页点击 "create your account",输入邮箱与密码完成注册——自托管模式下没有预置账号,与本地开发模式的种子账号(见下文)不同。

更新与版本钉住

自托管实例的更新机制完全依赖 Compose 文件中的 GHCR 镜像标签。官方推荐两个标签:

  • ghcr.io/maybe-finance/maybe:latest(最新提交)
  • ghcr.io/maybe-finance/maybe:stable(最新 release)

实例默认不会自动更新。更新命令序列为:

cd ~/docker-apps/maybe
docker compose pull                        # 从 GHCR 拉取新镜像
docker compose build                       # 使用更新重建应用
docker compose up --no-deps -d web worker # 以最新版本重启应用

若希望钉住特定版本,只需编辑 compose.yml 中的 image: 字段(例如改为 ...:stable),然后重新执行 pull/build/up 序列即可。

排错:ActiveRecord::DatabaseConnectionError

官方指南给出了一个典型场景:首次启动时若 Postgres 卷被之前失败/不同配置的尝试初始化过(即卷内已存在不同的默认角色),会出现数据库连接错误。解决办法是重置数据库——注意这会删除 Maybe 库中的全部数据

docker compose down
docker volume rm maybe_postgres-data   # 数据库挂载卷的名称
docker compose up
docker exec -it maybe-postgres-1 psql -U maybe -d maybe_production -c "SELECT 1;"  # 验证修复

解读示例 Compose 文件:四个服务如何协作

compose.example.yml 定义了完整的生产形态拓扑,值得逐段理解:

  • web:应用镜像(ghcr.io/maybe-finance/maybe:latest),映射 3000:3000 端口,将 app-storage 卷挂载到 /rails/storage(Active Storage 文件),restart: unless-stopped,并依赖 db 与 redis 健康后才启动;
  • worker:同一镜像以 command: bundle exec sidekiq 覆盖默认命令,专职处理后台任务(同步、导入、AI 聊天等异步作业);
  • dbpostgres:16,数据持久化在 postgres-data 卷,带 pg_isready 健康检查;
  • redisredis:latest,持久化在 redis-data 卷,带 redis-cli ping 健康检查。

所有服务共享一个 maybe_net bridge 网络,并通过 YAML 锚点 x-db-env / x-rails-env 复用数据库与应用环境变量。关键连接参数为 DB_HOST: dbDB_PORT: 5432REDIS_URL: redis://redis:6379/1(注意 Sidekiq 使用 Redis 1 号库)。

环境变量层面有几个值得注意的点:

  • SECRET_KEY_BASE 在示例中有一个内置默认值,仅适合本地网络;对外暴露时必须按上文生成自己的密钥;
  • SELF_HOSTED: "true" 硬编码为 true,即该文件天生面向自托管场景(与 config/application.rb 中的 app_mode 判断呼应);
  • RAILS_FORCE_SSL / RAILS_ASSUME_SSL 默认为 "false",自建反向代理 + TLS 时需自行调整;
  • OPENAI_ACCESS_TOKEN 为可选透传变量,文件内注释明确提醒:启用 OpenAI 后,应用内 AI 功能(聊天、规则)会产生费用,务必先在账户中设置消费上限。

镜像内部:多阶段 Dockerfile 与安全运行

Dockerfile 采用标准的多阶段构建,可作为理解生产镜像的参考:

  1. build 阶段:基于 ruby:3.4.4-slim,安装构建依赖后 bundle installBUNDLE_DEPLOYMENT=1),用 SECRET_KEY_BASE_DUMMY=1 预编译资产(./bin/rails assets:precompile),避免构建时要求真实的密钥;
  2. 运行阶段:仅拷贝构建产物与应用代码,创建 uid/gid 均为 1000 的非 root rails 用户并切换运行;
  3. 入口ENTRYPOINT ["/rails/bin/docker-entrypoint"] 负责准备数据库(首次启动执行迁移等),默认命令为 ./bin/rails server,这也是 Compose 中 worker 服务能通过 command 覆盖来运行 Sidekiq 的原因;
  4. 镜像暴露 3000 端口,Ruby 版本由 ARG RUBY_VERSION=3.4.4 锁定,要求与 .ruby-version 及 Gemfile 保持一致。

本地开发环境搭建(面向贡献者)

README 特别强调:如果你的目标是自托管,请停止阅读本节、转去 Docker 指南;以下内容是贡献者开发流程。

环境要求

  • Ruby 版本以 .ruby-version 文件为准,当前仓库锁定为 3.4.4(与 Dockerfile 中的 RUBY_VERSION 一致);
  • PostgreSQL 9.3 以上,官方建议使用最新稳定版。

基本启动命令

cd maybe
cp .env.local.example .env.local
bin/setup
bin/dev

# 可选:加载演示数据
rake demo_data:default
  • bin/setup 完成依赖安装与数据库准备(对应 CLAUDE.md 中记录的 bin/setup 说明:安装依赖、准备数据库);
  • bin/dev 依据 Procfile.dev 同时拉起三个进程,这是开发期命令组合的关键:
web:    bundle exec ${DEBUG:+rdbg -O -n -c --} bin/rails server -b 0.0.0.0
css:    bundle exec bin/rails tailwindcss:watch 2>/dev/null
worker: bundle exec sidekiq

即 Rails 服务器(绑定 0.0.0.0,且 DEBUG 时自动挂上 debug.rb 断点器)、Tailwind CSS 监听、以及一个本地 Sidekiq worker——本地开发与生产镜像在「web + worker 分离」这一点上是同构的。

启动后访问 http://localhost:3000,可用以下凭据登录(README 注明由 DB seed 生成):

  • 邮箱:user@maybe.local
  • 密码:password

环境变量模板

开发环境模板 .env.local.example 只有两项,语义都很直接:

# 启用 / 禁用自托管功能
SELF_HOSTED=false

# 启用 Synth 市场数据(注意会消耗你的 API 额度)
SYNTH_API_KEY=yourapikeyhere

SELF_HOSTED=false 意味着本地开发默认走 managed 模式;若要在本地模拟自托管形态,将其改为 true 即可触发 config/application.rb 中的 app_mode 切换。完整的自托管变量清单在 .env.example 中,包含 SECRET_KEY_BASE(必需)、SYNTH_API_KEY(汇率与股票价格数据)、PORT(默认 3000,端口冲突时可改)、SMTP 系列变量(SMTP_ADDRESS / SMTP_PORT / SMTP_USERNAME / SMTP_PASSWORD / SMTP_TLS_ENABLED / EMAIL_SENDER,密码重置等邮件场景需要)、DB_HOST / DB_PORT / POSTGRES_USER / POSTGRES_PASSWORDAPP_DOMAIN(邮件链接生成的实例域名)、DISABLE_SSL,以及可选的 Active Record Encryption 密钥(rails db:encryption:init 可生成)。文件还列出了 Active Storage 的对象存储选项:默认磁盘存储,可选 Amazon S3(ACTIVE_STORAGE_SERVICE=amazon)或 Cloudflare R2(ACTIVE_STORAGE_SERVICE=cloudflare)。

演示数据生成器

rake demo_data:default 背后的实现在 lib/tasks/demo_data.rake,它其实提供了三档数据集:

任务 说明
rake demo_data:empty 空的演示家庭(无任何财务数据,但已完成 onboarding)
rake demo_data:new_user 新用户演示家庭(未 onboarding、未订阅,用于调试新手引导流程)
rake demo_data:default 完整且拟真的数据集(默认任务)

default 任务通过 Demo::Generator 生成数据,支持 SEED 环境变量传入随机种子以实现可复现的数据集;生成后还会自动执行一次校验,输出总条目数(期望区间 8k–12k)、交易类条目数(期望 500–1000)以及分类覆盖率(期望不低于 75%)。生成器实现见 app/models/demo/generator.rb,其中明确演示账号 user@maybe.local 即为该家庭创建的用户(create_family_and_users!("Demo Family", "user@maybe.local", onboarded: true, subscribed: true)),这与 README 给出的登录凭据互相印证。[db/seeds.rb](https://gitcode.com/GitHub_Trending/ma/maybe/blob/a90899668ff25bf24d5feb8100809642ce6192ee/db/seeds.rb?utm_source=gitcode_repo_files) 则负责加载 db/seeds/ 下的公共种子文件(如 OAuth 应用),并在开发环境提示运行 demo 数据命令。

日常开发命令速查

除 README 的命令外,仓库的 CLAUDE.md 还系统记录了贡献者的开发约定,与本地环境直接相关:

  • 测试:bin/rails test(全量)、bin/rails test:db(重置数据库)、bin/rails test:system(系统测试,耗时较长,谨慎使用)、bin/rails test test/models/account_test.rb:42(定位单条用例);
  • Lint 与安全:bin/rubocopnpm run lint / npm run lint:fix / npm run format(Biome 配置见 biome.json)、bin/brakeman
  • 数据库:bin/rails db:prepare / db:migrate / db:rollback / db:seed
  • 测试哲学:始终使用 Minitest + fixtures(禁止 RSpec/factories),fixtures 保持最小化,外部 API 用 VCR 录制回放(见 test/vcr_cassettes/)。

许可证与商标

README 末尾说明:Maybe 以 AGPLv3 协议分发(完整协议见 LICENSE),"Maybe" 是 Maybe Finance, Inc. 的商标。自托管、二次开发或对外提供服务时,请以该协议条款为准。

参考资料索引

文件 用途
README 项目入口:自托管指引与本地开发命令
docs/hosting/docker.md Docker 自托管完整指南(安装、配置、更新、排错)
compose.example.yml 自托管示例编排文件(web/worker/db/redis 四服务)
Dockerfile 生产镜像构建(多阶段、非 root、资产预编译)
.env.example 自托管环境变量全量清单与说明
.env.local.example 本地开发环境变量模板
Procfile.dev 本地开发三进程启动定义
CLAUDE.md 开发命令、CI 流程与架构约定速查
lib/tasks/demo_data.rake 演示数据三档任务与自动校验
app/models/demo/generator.rb 演示数据生成器(可复现种子、账号创建)
登录后查看全文
热门项目推荐
相关项目推荐