news 2026/9/12 16:36:07

Actual sync-server 自托管部署与 CLI 实战:从 npm 安装到密码重置的完整指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Actual sync-server 自托管部署与 CLI 实战:从 npm 安装到密码重置的完整指南

Actual sync-server 自托管部署与 CLI 实战:从 npm 安装到密码重置的完整指南

【免费下载链接】actualA local-first personal finance app项目地址: https://gitcode.com/GitHub_Trending/ac/actual

导读

本文围绕 Actual 开源仓库中的 packages/sync-server/README.md 展开,系统讲解 Actual 官方同步服务器(@actual-app/sync-server)的定位、CLI 工具的安装与使用、配置体系、Docker 部署方式及底层实现。读完本文,你将掌握如何在自己的服务器上运行 Actual 同步服务、通过--config定制运行参数、使用--reset-password重置密码,并能从源码层面理解端口、数据目录、HTTPS、登录方式等关键配置的真实生效机制。

Actual 同步服务器:local-first 理念的落地载体

Actual 是一款本地优先(local-first)的个人财务管理应用,完全免费开源,使用 Node.js 编写。所谓"本地优先",意味着你的账本数据默认保存在本地,应用无需依赖云端即可完成记账、预算等核心操作;而sync-server包(对应 packages/sync-server/package.json 中名为@actual-app/sync-server的发布包)则在此基础上增加了一个同步服务器组件,用于持久化变更并把数据同步到所有设备,让手机、平板、电脑之间的数据保持一致,"不需要任何繁重操作即可在设备间移动变更"。

从仓库结构看,sync-server 不是独立于 Actual 的旁支模块,而是整个 monorepo 的组成部分:它的依赖列表中包含了@actual-app/crdt(同步所需的 CRDT 实现,见 packages/crdt/src/crdt)与@actual-app/web(Actual 的前端构建产物,用于服务器直接托管 Web 客户端)。因此,运行 sync-server 就等于同时获得了最新版的 Actual Web 应用与跨设备同步能力。

环境要求与 CLI 安装

官方 README 明确要求:使用@actual-app/sync-servernpm 包需要 Node.js v22 或更高版本。这一约束在 packages/sync-server/package.json 的engines字段中同样有声明("node": ">=22"),属于硬性前提。

安装方式为全局安装:

npm install --location=global @actual-app/sync-server

安装完成后,npm 会根据 packages/sync-server/package.json 中bin字段的映射("actual-server": "./build/bin/actual-server.js")在 PATH 中注册actual-server可执行命令,之后便可以在终端中直接调用。

如果想从源码自行构建运行,也可以使用仓库提供的 npm 脚本(见 packages/sync-server/package.json 的scripts):

yarn build && node build/app.js

提示:从源码启动时,入口 packages/sync-server/app.ts 会先执行数据库迁移再启动应用——它先调用runMigrations(),成功后才动态import('./src/app.js')并运行,避免因迁移未完成导致应用在缺表状态下启动。

actual-server 命令行:四个核心选项

actual-server的命令行用法非常简洁:

actual-server [options]

官方 README 提供的选项如下表:

命令说明
-h--help打印帮助列表并退出
-v--version打印版本号并退出
--config指定配置文件路径
--reset-password重置你的密码

场景一:默认配置直接运行

actual-server

不传任何参数时,服务器以默认配置启动:端口5006、监听地址::(IPv6 通配,通常同时覆盖 IPv4)、数据目录优先使用/data(若存在),否则使用项目根目录。这些默认值来自 packages/sync-server/src/load-config.js 的 convict schema(port默认 5006、hostname默认::dataDir默认取ACTUAL_DATA_DIR/data)。

场景二:自定义配置文件

actual-server --config ./config.json

通过--config传入配置文件路径。从 packages/sync-server/src/load-config.js 的加载逻辑可以看到完整的配置来源优先级:

  1. 若设置了环境变量ACTUAL_CONFIG_PATH,直接使用其指向的路径;
  2. 否则尝试<项目根目录>/config.json
  3. 若该文件不存在,回退到<数据目录>/config.json
  4. 配置加载后,<VAR>_FILE形式的环境变量(见下文"挂载式密钥")会覆盖 config.json 与普通环境变量;
  5. 最后通过configSchema.validate({ allowed: 'strict' })做严格校验,未知字段会直接报错。

因此,--config本质上是在默认路径之外显式指定 config.json 的位置,便于把配置放在与数据分离的目录,或在一个机器上跑多份实例。

场景三:重置密码

actual-server --reset-password

密码重置的底层逻辑在 packages/sync-server/src/scripts/reset-password.js 中:

  • 若服务器尚未设置密码needsBootstrap()为真),交互式提示你输入新密码并执行bootstrap({ password })完成初始化,输出Password set!
  • 已存在密码,则调用changePassword(password)完成重置,并输出提示:你需要在所有当前已登录的浏览器或设备上使用新密码重新登录

该脚本对应的 npm 命令为yarn reset-password(见 packages/sync-server/package.json)。README 中关于 CLI 的全部命令与示例均由此脚本支撑,属于"开箱即用"的运维入口。

配置体系:config.json 与环境变量

sync-server 的配置采用 convict 库管理(convict出现在 packages/sync-server/package.json 的 dependencies 中),所有配置项均可在 config.json 与同名环境变量之间二选一。下面列出 packages/sync-server/src/load-config.js 中 schema 的核心配置项及其默认值:

配置项环境变量默认值说明
portACTUAL_PORT5006服务监听端口
hostnameACTUAL_HOSTNAME::监听地址,默认 IPv6 通配
dataDirACTUAL_DATA_DIR/data(不存在则用项目根目录)数据目录
serverFilesACTUAL_SERVER_FILES<dataDir>/server-files服务器端文件(含同步数据)
userFilesACTUAL_USER_FILES<dataDir>/user-files用户文件
webRootACTUAL_WEB_ROOT@actual-app/web构建目录Web 前端静态资源位置
loginMethodACTUAL_LOGIN_METHODpassword登录方式:password/header/openid
trustedProxiesACTUAL_TRUSTED_PROXIES内网网段列表(10.0.0.0/8等)可信反向代理 IP 网段
https.keyACTUAL_HTTPS_KEYHTTPS 私钥(证书内容或路径)
https.certACTUAL_HTTPS_CERTHTTPS 证书(证书内容或路径)
upload.fileSizeLimitMBACTUAL_UPLOAD_FILE_SIZE_LIMIT_MB20JSON 请求体大小上限(MB)
upload.fileSizeSyncLimitMBACTUAL_UPLOAD_FILE_SYNC_SIZE_LIMIT_MB20同步请求体上限(MB)
upload.syncEncryptedFileSizeLimitMBACTUAL_UPLOAD_SYNC_ENCRYPTED_FILE_SYNC_SIZE_LIMIT_MB50加密文件同步上限(MB)
token_expirationACTUAL_TOKEN_EXPIRATIONnever登录令牌过期时间,支持neveropenid-provider或毫秒数
userCreationModeACTUAL_USER_CREATION_MODEmanual用户创建模式:manual/login
corsProxy.enabledACTUAL_CORS_PROXY_ENABLEDfalse是否开启 CORS 代理端点(供前端插件使用)
github.tokenACTUAL_GITHUB_TOKENGitHub API 令牌

这些环境变量的命名与取值直接对应 README 之外、config.json的字段,例如在 config.json 中可写作:

{ "port": 5006, "hostname": "::", "https": { "key": "/data/selfhost.key", "cert": "/data/selfhost.crt" }, "upload": { "fileSizeLimitMB": 20, "fileSizeSyncLimitMB": 20, "syncEncryptedFileSizeLimitMB": 50 } }

上传限制与请求体的关联

三个上传限制并非摆设:在 packages/sync-server/src/app.ts 中,Express 分别针对三种 body 类型设置了对应上限——express.json({ limit: ...fileSizeLimitMB })处理普通 JSON、application/actual-sync类型使用fileSizeSyncLimitMBapplication/encrypted-file类型使用syncEncryptedFileSizeLimitMB。也就是说,配置项直接决定了同步大数据量账本时服务器能否接受请求。

挂载式密钥:_FILE环境变量

对于ACTUAL_OPENID_CLIENT_SECRETACTUAL_GITHUB_TOKEN这类敏感配置,packages/sync-server/src/config-file-env.ts 提供了_FILE变体(如ACTUAL_OPENID_CLIENT_SECRET_FILEACTUAL_GITHUB_TOKEN_FILE):值指向一个文件路径,运行时读取文件内容(自动trim()去除首尾空白)作为配置值。文件不可读时直接抛错,避免静默失败。这一机制非常适合 Docker 中通过挂载 secret 文件注入凭据,仓库的 upcoming-release-notes/support-file-mounted-secrets.md 也印证了该能力是近期重点演进方向。

Docker 一键部署

除了 npm 全局安装,仓库提供了官方 Docker Compose 编排文件 packages/sync-server/docker-compose.yml,适合生产环境或不想污染本机 Node 环境的用户:

services: actual_server: image: docker.io/actualbudget/actual-server:latest ports: - '5006:5006' # 前面数字可改,后面 5006 是容器内端口 environment: # - ACTUAL_HTTPS_KEY=/data/selfhost.key # - ACTUAL_HTTPS_CERT=/data/selfhost.crt # - ACTUAL_PORT=5006 # - ACTUAL_UPLOAD_FILE_SYNC_SIZE_LIMIT_MB=20 # - ACTUAL_UPLOAD_SYNC_ENCRYPTED_FILE_SYNC_SIZE_LIMIT_MB=50 # - ACTUAL_UPLOAD_FILE_SIZE_LIMIT_MB=20 volumes: - ./actual-data:/data # 宿主机目录挂载到容器内 /data healthcheck: test: ['CMD-SHELL', 'node scripts/health-check.js'] interval: 60s timeout: 10s retries: 3 start_period: 20s restart: unless-stopped

几个关键点:

  • 端口映射:宿主机端口(第一个数字)可随意修改,容器内固定为5006
  • 数据持久化:容器内的/data目录是 Actual 默认的数据存放位置,务必挂载到宿主机目录(如./actual-data)防止容器重建导致数据丢失;这也与load-config.jsdataDir默认取/data的逻辑完全对应;
  • HTTPS:若使用自签证书,healthcheck 需要额外注入NODE_EXTRA_CA_CERTS=/data/selfhost.crt(Compose 文件中有对应注释行);
  • 健康检查:通过node scripts/health-check.js验证实例存活,对应 packages/sync-server/package.json 中的health-check脚本。

启动方式:

docker compose up -d

随后浏览器访问http://localhost:5006即可进入 Actual Web 客户端。

服务器内部:路由、限流与安全头

理解 sync-server 的行为,有助于判断自托管时的网络与安全配置。packages/sync-server/src/app.ts 展示了完整的 Express 应用骨架:

核心路由挂载

app.use('/sync', syncApp.handlers); // 数据同步 app.use('/account', accountApp.handlers); // 账户/登录 app.use('/gocardless', goCardlessApp.handlers); // GoCardless 银行同步 app.use('/simplefin', simpleFinApp.handlers); // SimpleFIN app.use('/pluggyai', pluggai.handlers); // Pluggy.ai app.use('/akahu', akahuApp.handlers); // Akahu app.use('/enablebanking', enableBankingApp.handlers); // Enable Banking app.use('/secret', secretApp.handlers); // 密钥管理 app.use('/admin', adminApp.handlers); // 管理端 app.use('/openid', openidApp.handlers); // OpenID

从路径结构可以推断,sync-server 不仅承担同步职责,还集成了多家银行数据源提供商的接入端点(GoCardless、SimpleFIN、Pluggy、Akahu、Enable Banking),这也是 Actual 自动对账/拉取交易功能的服务器侧基础。

限流与安全

  • development环境下启用express-rate-limit:每分钟窗口最多 500 次请求(见 packages/sync-server/src/app.ts);
  • 禁用x-powered-by头,设置trust proxytrustedProxies配置,方便在反向代理(Nginx/Caddy)后正确识别客户端 IP;
  • 统一附加Cross-Origin-Opener-Policy: same-originCross-Origin-Embedder-Policy: require-corp与 CSP 响应头。

运维端点

  • GET /health:返回{ status: 'UP' },供负载均衡器或 Docker healthcheck 使用;
  • GET /metrics:返回内存使用与进程运行时长;
  • GET /info:返回构建包名、描述与版本号(从最近的@actual-app/sync-serverpackage.json 向上查找);
  • GET /mode:返回当前运行模式(development/test)。

生产/开发双模式development模式将前端请求代理到本地 Vite 开发服务器(http://localhost:3001,含 HMR WebSocket);生产模式则直接以静态文件方式托管webRoot下的 React 构建产物,并对任意未匹配路径回退到index.html,即单页应用路由。

HTTPS 支持:当同时配置了https.keyhttps.cert时,run()使用node:https创建 HTTPS 服务器;parseHTTPSConfig支持直接传入 PEM 内容(以-----BEGIN开头)或证书文件路径两种写法。

密码机制与首次引导

第一次使用自托管实例时,需要设置管理员密码,这是所有后续登录的基础。密码引导/重置的完整流程在 packages/sync-server/src/scripts/reset-password.js 中:

  1. 运行actual-server --reset-password
  2. 脚本调用needsBootstrap()判断是否已初始化;
  3. 未初始化 → 提示"还没有设置密码,现在来设置一个吧!",交互输入密码后调用bootstrap({ password })
  4. 已初始化 → 提示"已经有密码了,现在来重置它!",输入新密码后调用changePassword(password)
  5. 成功后会明确提醒:所有已登录的浏览器和设备都需要使用新密码重新登录

密码通过 argon2/bcrypt 等库进行哈希存储(二者均出现在 packages/sync-server/package.json 的 dependencies 中),不会以明文落盘。忘记密码时,这是官方提供的唯一自助恢复途径。

数据目录与数据库迁移

服务器运行会产生两类关键数据,默认都位于dataDir下:

  • server-files/:同步的账本文件数据;
  • user-files/:用户文件。

首次启动(含升级后启动)会自动执行数据库迁移。迁移逻辑位于 packages/sync-server/src/migrations.ts:

  • 通过 Vite 的import.meta.glob在构建期静态收集migrations/目录下全部迁移脚本(见 packages/sync-server/migrations),每个迁移独立成 chunk,运行时按文件名排序后逐个执行;
  • 迁移状态记录在<dataDir>/.migrate(测试模式下为.migrate-test),支持up/down双向操作;
  • 对应的运维命令为yarn db:migrateyarn db:downgrade(见 packages/sync-server/package.json)。

由于入口 packages/sync-server/app.ts 保证"先迁移、后启动",升级版本时无需手工干预;只有显式回滚时才需要执行db:downgrade

自托管实践建议

结合上述实现,给出几条可直接落地的运维建议:

  1. 数据安全第一:无论采用 npm 还是 Docker 部署,务必把server-filesuser-files(即整个数据目录)纳入定期备份,同时保护好.migrate迁移状态文件;
  2. 公网访问务必上 HTTPS:通过https.key/https.cert配置或前置反向代理终结 TLS;trustedProxies默认已覆盖常见内网网段,若反向代理位于其他网段需追加;
  3. 按需调整上传限制:账本文件较大或多设备高频同步时,可将ACTUAL_UPLOAD_FILE_SYNC_SIZE_LIMIT_MB从默认 20 调大(Docker Compose 文件中已预留注释示例);
  4. 健康检查接入编排:使用/health端点或官方 health-check 脚本纳入监控告警;
  5. 开放 OpenID 时先看 enforceACTUAL_OPENID_ENFORCE(对应enforceOpenId,默认false)决定是否强制所有用户走 OpenID,开启前需确认discoveryURL或各 endpoint 均已配置(openId配置完整时,run()会在启动阶段调用bootstrap({ openId })预配置提供方)。

小结

@actual-app/sync-server用极简的 CLI 面(四个选项)封装了完整的自托管同步方案:npm 全局安装后一条actual-server即可运行,--config对接 convict 驱动的丰富配置体系,--reset-password提供密码恢复通道,Docker Compose 文件则给出生产级的一键部署参考。底层上,load-config.js 定义了全部可调参数与优先级,app.ts 承载了同步、银行对接、健康检查与 HTTPS 等全部路由,migrations.ts 保障了版本升级的平滑性——这正是"本地优先 + 跨设备同步"这一设计在服务器端的完整实现。

【免费下载链接】actualA local-first personal finance app项目地址: https://gitcode.com/GitHub_Trending/ac/actual

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/12 16:35:51

TradingAgents-CN 怎么配置股票基础信息每日定时同步任务?

TradingAgents-CN 怎么配置股票基础信息每日定时同步任务&#xff1f; 【免费下载链接】TradingAgents-CN 基于多智能体LLM的中文金融交易框架 - TradingAgents中文增强版 项目地址: https://gitcode.com/GitHub_Trending/tr/TradingAgents-CN 在 TradingAgents-CN 中&a…

作者头像 李华
网站建设 2026/9/12 16:29:35

LightGBM二手车价格预测实战:高维稀疏特征与非线性衰减建模

简介&#xff1a;本资源是一份面向计算机及相关专业本科生的Python机器学习实战项目&#xff0c;聚焦二手车价格预测这一典型回归任务&#xff0c;适用于期末大作业提交、课程设计实践或算法入门训练。压缩包共19个文件&#xff0c;含9个CSV格式数据集&#xff08;如used_car_t…

作者头像 李华
网站建设 2026/9/12 16:29:17

TVS钳位电压如何影响DC-DC芯片选型与BOM成本

1. 这不是玄学&#xff0c;是电源工程师天天在算的账&#xff1a;一颗TVS怎么让整机BOM降5毛&#xff1f;你拆过电源板吗&#xff1f;尤其是带DC-DC降压模块的消费类主板——比如智能音箱主控板、车载记录仪主控、工业PLC的IO扩展模块。打开外壳&#xff0c;翻到背面&#xff0…

作者头像 李华