如何在自己的 VPS 上部署 Actual Budget
使用 Docker Compose 自托管 Actual Budget,了解数据卷、HTTPS 与 Web Crypto API 的关系,创建首个预算文件,导入银行数据,并配置备份。
构建内容
Actual Budget 是一款自行托管的信封预算应用。人们寻找可自行托管的 YNAB 替代方案时,通常会选择它。服务器只需运行一个容器、使用一个数据卷,并配置一个 HTTPS 域名。普通预算所需的全部功能都可在最小规格的 VPS 上稳定运行,因为服务器主要负责存储文件和同步数据。
在执行任何操作前,应先了解其架构。预算本身是一个 SQLite 数据库,存储在浏览器和每个移动应用中。即将安装的服务器是一个同步端点:它保存账户列表、预算文件和变更日志,使手机与笔记本电脑保持一致。这就是服务器不可用时应用仍能工作的原因。只要仍有一个客户端保留副本,服务器丢失也不会导致预算丢失。
服务器为什么需要 HTTPS
Actual 请求使用 HTTPS,这不是形式要求。浏览器只会在规范所称的安全上下文中提供 Web Crypto API;Actual 通过该接口实现端到端加密。安全上下文是 https:// 或 http://localhost。如果在另一台计算机的浏览器中从 http://203.0.113.10:5006 加载应用,这些功能不会出现,因为浏览器根本没有将它们提供给页面。官方移动版也会拒绝普通的 http:// 服务器 URL。
因此,有两种可行的配置。将真实证书配置在容器前面的真实域名上,本指南采用这种方式。或者使用 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 表示容器未运行,docker compose ps 可以显示容器已退出。最常见的原因是挂载卷权限不正确,日志中会显示一行 EACCES。
在前端配置证书和正式域名
将 A 记录指向 VPS,budget.example.com,然后等待 DNS 解析生效。接着安装 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 密码管理器。无需创建用户账户。Actual 的服务器采用单密码设计,因此共享预算就意味着共享该密码。
然后创建预算文件。Actual 会询问是否启用端到端加密。请选择启用。这样服务器只会存储密文;对于租用机器上的财务数据,这是正确的选择。代价也很明确:加密密码不会发送到服务器,因此一旦丢失,该文件就无法恢复,也不存在重置方式。在点击离开该界面前,请先记下密码。
根据银行当前显示的金额设置初始余额,不要导入多年的历史记录。信封预算从您当前拥有的资金开始计算,因此没有历史记录也不会造成损失。
导入交易
这里需要如实说明,而不是过度乐观,因为导入体验是用户放弃自托管预算工具的主要原因。
手动录入是基础方式,而且始终可用。对于信封预算方法,这可以说正是其核心,因为录入一笔消费会让您注意到这笔支出。
文件导入负责处理大批量交易。Actual 支持读取 CSV、QIF、OFX 和 QFX,而每家银行至少会导出其中一种格式。在账户页面中按账户导入,首次映射列后,Actual 会记住该账户的映射布局。
自动同步银行交易也可用,但需要第三方服务,因为服务器无法自行连接银行。Actual 支持面向北美银行的 SimpleFIN Bridge、面向欧洲的 Enable Banking、面向新西兰的 Akahu,以及面向巴西的 Pluggy.ai。GoCardless 仍受支持,但不再接受新账户。您需要自行在服务提供商处注册,生成凭据,然后将其添加到服务器。以 2026 年 7 月为准,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 自带的客户端备份是另一项功能,也值得了解。浏览器会保留预算文件的近期副本,可从文件菜单访问。即使误删了某个类别,也可以使用这些副本恢复,无需接触服务器。
更新服务器
cd /opt/actual
docker compose pull
docker compose up --detachCompose 会使用新镜像重新创建容器,并重新挂载同一个卷,因此数据会保留。客户端也要一并更新。服务器和应用版本应保持接近;如果客户端版本明显早于服务器,可能会因版本不匹配而拒绝同步。进行大版本升级前先备份,因为迁移会在首次启动时运行,而且无法降级。Actual 对浮动的 latest 标签比较宽容,因为它的状态存储在文件目录中;而携带真实数据库的应用则不同。自托管 Chatwoot 介绍了应使用固定标签并在升级前导出数据库的操作方式。
会出现哪些问题,以及你将看到什么
应用可以加载,但同步始终无法完成。 检查 nginx 访问日志中的 413。这表示 client_max_body_size 设置得过低。相反,如果看到 502,则表示 nginx 已启动,但容器未启动。
加密选项缺失,或移动应用拒绝该 URL。 页面不处于安全上下文中。地址栏会显示带有 IP 地址或非 localhost 主机名的 http://。应修复证书,不要绕过该问题。
提示预算文件与此版本不兼容。 客户端和服务器版本已不一致。将两者更新到同一版本,然后重新加载。
容器不断循环重启。 查看 docker compose logs actual。如果 /data 出现权限错误,表示挂载目录对容器用户不可写。如果出现地址已被占用错误,表示回环接口上的 5006 端口已被其他进程占用。
首次加载感觉较慢。 打开预算文件时,整个文件都会下载到浏览器。随后读取的是本地数据。这不是服务器规格不足导致的问题,增加 RAM 也不会改变速度。
FAQ
Actual 必须使用 HTTPS 才能运行吗?
实际上需要。Actual 的端到端加密依赖浏览器的 Web Crypto API,而浏览器只会在安全上下文中提供该 API,也就是 https:// 或 http://localhost。从其他机器通过普通 HTTP 访问时,这些功能不可用,官方移动应用也会拒绝普通 HTTP 服务器 URL。请在真实主机名上使用 Let's Encrypt 证书;如果只使用桌面浏览器,也可以配合 ACTUAL_HTTPS_KEY 和 ACTUAL_HTTPS_CERT 使用自签名证书。
Actual 能自动导入我的银行交易吗?
只能通过您自行注册的第三方服务导入:北美使用 SimpleFIN Bridge,欧洲使用 Enable Banking,新西兰使用 Akahu,巴西使用 Pluggy.ai。GoCardless 受支持,但目前不再接受新账户。这些 API 凭据存储在您的服务器上,不受端到端加密保护。同步也需要手动执行,因此您需要按下按钮,后台不会自动轮询。导入 CSV、QIF、OFX 和 QFX 完全不需要第三方服务。
我具体需要备份哪些内容?
备份挂载的数据目录。本指南中该目录为 /opt/actual/data。其中,server-files/account.sqlite 保存登录信息和会话,user-files 保存预算文件。复制前请停止容器,因为复制正在运行的 SQLite 数据库可能会得到不完整的写入内容。服务器上的其他位置不保存状态数据。
如果我丢失了加密密码,会发生什么?
无法恢复该文件。密码不会发送到服务器,这正是端到端加密的目的,因此没有重置方式,也没有支持渠道。创建文件后,请立即将密码存入密码管理器,并在不依赖此服务器的位置保留一份副本。
Actual 需要多少服务器资源?
很少。容器负责提供静态资源和文件,预算计算在浏览器中完成。1 个共享 vCPU 和 1 GB RAM 即可稳定运行;包含数年历史记录的家庭预算,其数据目录通常只有几十 MB。磁盘压力主要来自备份和其他容器,而不是 Actual。如果您要配置一台还需要同时运行更高负载服务的服务器,通常由照片服务器决定最低配置,因此请先查看 PhotoPrism 和 Immich 实际需要多少 RAM,再选择方案。媒体栈也遵循同样的原则:决定方案的是转码,而像 Halcyon(可将 Jellyfin 媒体库转换为可浏览的 90 年代录像店) 这样的浏览器前端,资源消耗大致与 Actual 一样低。