SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor · 更新于 2026-10-28

如何在自己的 VPS 上部署 Actual Budget

使用 Docker Compose 自托管 Actual Budget,了解数据卷、HTTPS 与 Web Crypto API 的关系,创建首个预算文件,导入银行数据,并配置备份。

构建内容

Actual Budget 是一款自行托管的信封预算应用。人们寻找可自行托管的 YNAB 替代方案时,通常会选择它。服务器只需运行一个容器、使用一个数据卷,并配置一个 HTTPS 域名。普通预算所需的全部功能都可在最小规格的 VPS 上稳定运行,因为服务器主要负责存储文件和同步数据。

在执行任何操作前,应先了解其架构。预算本身是一个 SQLite 数据库,存储在浏览器和每个移动应用中。即将安装的服务器是一个同步端点:它保存账户列表、预算文件和变更日志,使手机与笔记本电脑保持一致。这就是服务器不可用时应用仍能工作的原因。只要仍有一个客户端保留副本,服务器丢失也不会导致预算丢失。

服务器为什么需要 HTTPS

Actual 需要 HTTPS,这不是形式要求。Actual 必须依赖浏览器中的一项名为 SharedArrayBuffer 的功能才能运行,而浏览器只有在页面处于跨源隔离状态,并且符合规范所称的安全上下文时,才会启用该功能。安全上下文是 https:// 或 http://localhost。在另一台机器的浏览器中从 http://203.0.113.10:5006 加载应用时,浏览器不会将该功能提供给页面,因此预算数据无法加载。手机也不例外。Actual 的 FAQ 说明,官方 iOS 应用目前处于 beta 测试阶段,可以连接到您自己的服务器;目前还没有官方 Android 应用。因此,在大多数手机上,您使用的仍是同一个 Web 应用,只是将其作为渐进式 Web 应用安装到主屏幕上,同样适用安全上下文规则。

因此,有两种可行的部署方式。在容器前端的真实域名上配置真实证书,这是本指南采用的方式。或者使用 ACTUAL_HTTPS_KEY 和 ACTUAL_HTTPS_CERT 为服务器配置自签名证书,这是项目文档说明的方式,但每台设备上的浏览器都会显示警告。Let's Encrypt 提供的免费证书只需 5 分钟即可获取,因此选择第一种方式。

使用 Docker Compose 安装 Actual Budget

如果服务器是全新安装的,请先安装 Docker。如果您不熟悉 Compose 文件语法,请参阅 VPS 的 Docker Compose 基础知识,其中介绍了下面使用的字段。

sudo install -d -m 755 /opt/actual
sudo install -d -m 700 /opt/actual/data

写入 /opt/actual/docker-compose.yml:

services:
  actual:
    image: actualbudget/actual-server:latest
    container_name: actual
    restart: unless-stopped
    ports:
      - '127.0.0.1:5006:5006'
    volumes:
      - ./data:/data

该文件中有 3 个细节需要注意。

镜像为 actualbudget/actual-server:latest,由项目发布到 Docker Hub,并镜像到 ghcr.io/actualbudget/actual。对于低功耗设备,还提供 latest-alpine 标签。

容器会将所有内容写入 /data。其中,server-files 保存包含登录信息和会话令牌的 account.sqlite,user-files 保存预算文件本身。请挂载该路径,否则下一个 docker compose pull 会丢失您的预算。ACTUAL_DATA_DIR 可以移动该路径,但默认值已经足够。

端口仅发布到 127.0.0.1。直接使用 5006:5006 会将端口发布到所有网络接口。Docker 会在 ufw 之前写入自身的规则,因此即使防火墙默认拒绝所有连接,该应用仍会暴露在互联网中。Docker 发布的端口为何会绕过 ufw 解释了这一点。绑定到回环地址后,只有同一台服务器上的反向代理可以访问它。

启动服务:

cd /opt/actual
docker compose up --detach
docker compose logs -f actual

服务器报告正在监听 5006 端口后,日志通常就不会再出现启动问题。修改 DNS 前,先在本机检查:

curl -fsS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:5006/

返回 200 表示应用正在提供服务。返回 curl: (7) Failed to connect 表示 127.0.0.1:5006 上没有进程接受连接。请运行 docker compose ps --all,因为普通的 docker compose ps 只会列出正在运行的容器。如果容器显示为已退出,通常是因为挂载卷的权限有问题;日志中会出现 EACCES 行。

在前面配置证书和真实域名

将 A 记录指向 VPS,budget.example.com,然后等待解析生效。接着安装 nginx 并签发证书。Ubuntu 24.04 使用 nginx 配置 Certbot指南详细介绍了证书签发和续期计时器。

代理配置块:

server {
    listen 443 ssl;
    http2 on;
    server_name budget.example.com;

    ssl_certificate     /etc/letsencrypt/live/budget.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/budget.example.com/privkey.pem;

    client_max_body_size 100m;

    location / {
        proxy_pass http://127.0.0.1:5006;
        proxy_set_header Host              $host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

client_max_body_size 是人们最容易忘记的配置项。日常同步只会发送您的更改,但首次向服务器注册预算时,以及重置同步时,都会上传整个预算文件。Nginx 默认将请求正文限制为 1 MB。文件超过此大小后,完整上传会失败;nginx 访问日志中会显示 413 Request Entity Too Large,而应用只会显示通用的同步错误。服务器还有单独的限制:ACTUAL_UPLOAD_FILE_SYNC_SIZE_LIMIT_MB 默认为 20,ACTUAL_UPLOAD_SYNC_ENCRYPTED_FILE_SYNC_SIZE_LIMIT_MB 默认为 50。因此,应将 nginx 限制设置为高于适用于您的那个值。

重新加载并测试:

sudo nginx -t && sudo systemctl reload nginx
curl -fsS -o /dev/null -w '%{http_code}\n' https://budget.example.com/

首次运行:密码和第一个预算文件

在浏览器中打开 https://budget.example.com。首个界面会要求您设置服务器密码。这个密码保护整个服务器,因此请生成一个足够长的随机密码,并将其保存在您之后能找到的位置,例如使用自行托管的 Vaultwarden 密码管理器。默认情况下无需创建用户账户:服务器只有一个密码,因此共享预算就意味着共享该密码。只有连接 OpenID 提供商后,才能使用单独的登录凭据;Actual 支持通过这种方式配置多用户环境。

然后创建预算文件。Actual 会询问是否启用端到端加密。请选择启用。这样服务器只会存储密文,这对于存放在租用机器上的财务数据是正确的选择。代价也很实际:加密密码不会发送到服务器,因此一旦丢失该密码,文件就无法恢复,也不存在重置方式。请在跳过该界面之前记下密码。

请根据银行当前的余额设置起始余额,不要导入多年的历史记录。信封预算从您当前拥有的资金开始向前计算,因此没有历史记录不会造成损失。

导入交易

这里需要实事求是,因为导入体验是很多人放弃自托管记账的主要原因。

手动录入是基础方式,而且始终可用。对于信封预算方法,这可以说正是其核心,因为录入一笔购买记录会促使您注意这笔支出。

文件导入可以处理大批量交易。Actual 支持读取 CSV、QIF、OFX、QFX 和 CAMT,而每家银行至少会导出其中一种格式。在账户页面中按账户导入;如果文件是 CSV,请映射列。

Actual 支持自动同步银行账户,但需要第三方服务,因为服务器无法自行连接银行。Actual 支持北美银行使用 SimpleFIN Bridge,欧洲使用 Enable Banking,新西兰使用 Akahu,巴西使用 Pluggy.ai。仍支持 GoCardless,但不再接受新账户。您需要自行向服务提供商注册、生成凭据,然后将凭据添加到服务器。以 2026 年 10 月为准,SimpleFIN Bridge 每年收费 15 美元,另加税费,最多支持 25 家机构;其他服务的定价不同。

在依赖此功能前,请接受以下两项限制。API 凭据存储在服务器上,不受端到端加密保护,因为服务器必须使用这些凭据。Actual 关闭时不会同步任何内容:自动同步默认关闭;启用后,也只会在应用保持打开期间运行,因此服务器不会自行轮询银行。

备份,因为这里只涉及文件

所有需要备份的内容都位于 /opt/actual/data 下。不需要执行导出,也不需要编写数据库转储脚本。

唯一需要注意的是 SQLite。在服务器写入 account.sqlite 时复制该文件,可能会捕获未完成的事务。只有尝试恢复时,才会发现备份已损坏。复制只需几秒,因此请在复制期间停止容器:

cd /opt/actual
docker compose stop
restic -r sftp:backup@backup.example.com:/srv/restic backup /opt/actual/data
docker compose start

按照 VPS 上的 restic 备份 中的方法设置定时任务。该方法涵盖存储库设置、保留策略和恢复演练。请执行恢复演练。从未恢复过的备份,无法证明可用。

Actual 自带的自动备份是另一项功能,也值得了解,但仅存在于桌面应用中。它最多保留预算文件最近的 10 个副本,可通过 File > Load Backup 访问。即使误删了某个类别,也可以直接使用这些副本恢复,无需操作服务器。浏览器中的 Web 应用不会保留这类副本。因此,如果家中的所有人都使用浏览器,上述服务器备份就是你唯一拥有的备份。

更新服务器

cd /opt/actual
docker compose pull
docker compose up --detach

Compose 会使用新镜像重新创建容器,并重新挂载同一个卷,因此数据会保留。客户端也要更新。如果客户端版本早于它接收的数据版本,就会停止应用更改,并显示 “Update Required” 消息。进行大版本升级前先备份,因为迁移会在首次启动时运行,并且无法降级。对于浮动的 latest 标签,Actual 可以较为宽容,因为它的状态存储为文件目录;而携带真实数据库的应用则不能这样处理。自托管 Chatwoot 介绍了这种情况下应使用的固定标签和升级前转储。

会出现哪些问题,以及您将看到什么

应用可以加载,但同步始终无法完成。 检查 nginx 访问日志中的 413。这表示 client_max_body_size 设置得过低。502 则表示 nginx 未从上游获取到可用响应。最常见的原因是容器已停止,或未监听 5006,因此应先检查 docker compose ps --all 和容器日志。

应用无法在另一台设备上加载,或提示缺少 SharedArrayBuffer。 页面不在安全上下文中。地址栏会显示带有 IP 地址或主机名的 http://,但该地址不是 localhost。请修复证书,不要绕过此问题。

提示预算文件与此版本不兼容。 该文件已在比您当前使用的客户端更新的 Actual 版本中打开。请将客户端更新到至少该版本,或恢复在新版本处理该文件之前创建的备份,然后重新加载。

容器不断循环重启。 查看 docker compose logs actual。/data 出现权限错误,表示挂载目录对容器用户不可写。出现地址已被占用错误,则表示其他程序已在回环地址上占用 5006。

首次加载速度较慢。 打开预算文件时,整个文件都会下载到浏览器。这是一次较大的传输,之后由本地读取完成。问题不在于服务器规格,增加 RAM 也不会改变加载速度。

FAQ

Actual Budget 是否必须使用 HTTPS 才能运行?

实际上必须使用。Actual 需要浏览器的 SharedArrayBuffer 功能才能运行,而浏览器只会在安全上下文中启用该功能,也就是 https:// 或 http://localhost。从其他机器通过普通 HTTP 访问时,应用无法加载。官方 iOS 应用目前正在进行 beta 测试,暂时没有官方 Android 应用,因此大多数手机使用同一个 Web 应用,也会受到相同规则的限制。(FAQ)请在真实主机名上使用 Let's Encrypt 证书;如果可以接受每台设备都显示证书警告,也可以使用自签名证书,并配置 ACTUAL_HTTPS_KEY 和 ACTUAL_HTTPS_CERT。

Actual 能否自动导入我的银行交易记录?

只能通过你自行注册的第三方服务实现:北美使用 SimpleFIN Bridge,欧洲使用 Enable Banking,新西兰使用 Akahu,巴西使用 Pluggy.ai。Actual 支持 GoCardless,但该服务目前不再接受新账户。这些 API 凭据存储在你的服务器上,不受端到端加密保护。自动同步默认关闭;启用后,也只会在 Actual 打开期间运行,因此服务器不会在后台轮询。导入 CSV、QIF、OFX、QFX 和 CAMT 文件完全不需要第三方服务。

我具体需要备份哪些内容?

需要备份挂载的数据目录,本指南中该目录是 /opt/actual/data。其中包含存储登录信息和会话的 server-files/account.sqlite,以及存储预算文件的 user-files。复制前请停止容器,因为复制正在使用的 SQLite 数据库可能会捕获未完成的写入。服务器上的其他位置不保存状态数据。

如果丢失加密密码,会发生什么?

该文件无法恢复。密码不会传输到服务器,这正是端到端加密的目的,因此没有重置方式,也没有支持渠道。创建文件后立即将密码保存到密码管理器中,并在不依赖同一台服务器的位置保留一份副本。

Actual Budget 需要什么配置的服务器?

需求很低。容器只提供静态资源和文件,预算计算在浏览器中完成。1 个共享 vCPU 和 1 GB RAM 即可稳定运行;对于包含数年历史记录的家庭预算,数据目录通常只有几十 MB。磁盘空间主要会被备份和其他容器占用,而不是 Actual。如果你要配置一台还需同时运行更高负载服务的服务器,通常由照片服务器决定最低配置,因此请先查看 PhotoPrism 和 Immich 实际需要多少 RAM,再选择方案。媒体栈也是同样的情况:决定方案的是转码需求,而 Halcyon 可将 Jellyfin 媒体库转换为可浏览的 90 年代视频商店 这样的浏览器前端,资源消耗与 Actual 基本一样低。

这篇文章对您有帮助吗?