cover

使用容器部署 fava 实现跨平台记账

本文介绍了如何使用 fava 实现跨平台记帐。首先,文章介绍了如何配置和运行 fava,包括直接部署和容器化部署。接着,文章介绍了如何在 Nginx 中设置反向代理和基本身份验证,以确保安全。

2023-04-13

beancount 作为一个命令行记账工具,本身并不具备跨平台使用的能力。但是得益于其纯文本记账的特性,通过以下几种方式实现跨平台记账:

  1. 在多处记账然后定期汇总到一处进行处理;
  2. 将账本文件保存到 iCloud 等工具中;
  3. 将 fava 部署到公网上,直接在 fava 客户端中进行记账。

本文将介绍如何将 fava 部署到公网以实现跨平台记账的功能。

fava 是一个 beancount 的 web 客户端。相比于在命令行下使用 beancount 进行记账,fava 更为方便,满足了大多数人记账的需求。fava 具有以下功能特性:

  • 提供简单易用的 web 页面;
  • 支持按账户、标签和币种进行过滤和搜索交易记录;
  • 支持多种财务报表及图表可视化财务数据;
  • 支持导入导出 Beancount 文件;
  • 支持 beancount 的插件体系,并提供了其他的插件(如预算功能);
  • 多语言支持(包括中文)。

对于那些不善于使用命令行操作的用户,fava 的图形化操作界面大大提高了操作的简便性。此外,通过 fava,用户可以更清晰直观地查看记账报表。

fava 的基本用法如下:

pip install fava fava <path/to/main.book> # 使用浏览器访问 localhost:5000

接下来介绍两种在服务器上部署 fava 服务的方法:

  1. 直接在服务器中使用 python 启动 fava 服务,并利用 systemd 管理 fava 应用服务。
  2. 容器化部署。
heading

Python + Systemd 部署

如果服务器只是用来部署 fava 应用,那么使用 python 和 Systemd 部署是最简单的部署方式。

请使用以下的脚本进行部署:

# 确保系统安装了 Python pip install fava # 创建服务文件使 fava 服务能够开机自启动 sudo touch /etc/systemd/system/fava.service sudo echo '[Unit] Description=fava [Service] Type=simple ExecStart=/usr/local/bin/fava <path/to/main.book> RestartSec=10 StartLimitInterval=300 StartLimitBurst=10 [Install] WantedBy=multi-user.target' > /etc/systemd/system/fava.service sudo systemctl daemon-reload sudo systemctl enable fava.service sudo systemctl start fava.service
heading

容器化部署

如果当前服务器上部署了多个应用,考虑到服务的可移植性以及简化服务管理流程,使用容器化方式部署 fava 会更好。

由于 fava 官方没有提供 Docker 镜像,因此需要手动构建,具体方法请参考下面的脚本。

# 下载最新源码 TAG=`wget --no-check-certificate -qO- -t1 -T2 "https://api.github.com/repos/beancount/fava/tags" | jq '.[0].name' | tr -d '"'` wget https://ghproxy.com/https://github.com/beancount/fava/archive/refs/tags/${TAG}.tar.gz tar Cxzvf ${TAG}.tar.gz && rm ${TAG}.tar.gz # 构建 Docker 镜像 pushd fava-${TAG:1}/contrib/docker docker build -t fava . popd rm -rf fava-${TAG:1}

构建完成后,即可使用以下脚本启动容器:

docker run \ --name fava \ -p 5000:5000 \ # 端口映射 -v <path/to/books>:/data/books/ \ # 存放账本的路径挂载到容器中 -e BEANCOUNT_FILE=/data/books/main.book \ # 通过环境变量设置主账本的路径 fava
heading

反向代理和身份认证配置

不论使用哪种方法进行部署,在部署完成后都可以使用下面的脚本验证部署是否成功:

if `curl -s localhost:5000 | grep -q "/beancount/income_statement/"`; then echo "ok"; fi

如果输出为 "ok",则表示部署成功。

为了能够在公网进行访问,首先应该在服务器上开放 5000 端口。接着,可以在浏览器中通过

<ip>:5000
访问 fava 的 Web 客户端。

如果有自己的域名,则可以在 DNS 控制台中添加一条 A 记录,将其指向服务器的 IP 地址。然后添加如下 Nginx 配置:

server { server_name <domain>; listen 80; # 如果需要配置 SSL,则添加证书路径 # listen 443 default ssl; # ssl_certificate <path/to/crt>; # ssl_certificate_key <path/to/key>; add_header Strict-Transport-Security max-age=2592000; location / { # 添加基本身份认证 # auth_basic "Restricted Content"; # auth_basic_user_file /etc/nginx/.htpasswd; # 配置反向代理 proxy_pass http://127.0.0.1:5000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Scheme $scheme; proxy_connect_timeout 1; proxy_send_timeout 30; proxy_read_timeout 30; } }
.artifacts/nginx/fava.example.com

由于 fava 没有内置身份认证的功能,因此需要额外配置身份认证功能,虽然 fava 官方文档提到了可以使用 oauth-proxy 实现认证,但是 oauth-proxy 内置的 Provider 在国内都无法正常访问。 如果只是个人使用的话,可以通过 Nginx 提供的

auth_basic
指令设置基础身份认证。 首先在 Nginx 配置文件所在的目录中执行以下命令用于生成访问密码:

sudo htpasswd -c /etc/nginx/.htpasswd <username>

注意:输入命令会提示你输入一个密码,Nginx 会使用 bcrypt 加密改密码并将其保存在

/etc/nginx/.htpasswd
文件中。如果想添加另一个用户,则可以省略 -c 标志。 然后在 nginx 的配置文件中移除
auth_basic
的注释。

一个完整的例子可以参考该 Repo