使用容器部署 fava 实现跨平台记账
本文介绍了如何使用 fava 实现跨平台记帐。首先,文章介绍了如何配置和运行 fava,包括直接部署和容器化部署。接着,文章介绍了如何在 Nginx 中设置反向代理和基本身份验证,以确保安全。
2023-04-13
beancount 作为一个命令行记账工具,本身并不具备跨平台使用的能力。但是得益于其纯文本记账的特性,通过以下几种方式实现跨平台记账:
- 在多处记账然后定期汇总到一处进行处理;
- 将账本文件保存到 iCloud 等工具中;
- 将 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 服务的方法:
- 直接在服务器中使用 python 启动 fava 服务,并利用 systemd 管理 fava 应用服务。
- 容器化部署。
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
容器化部署
如果当前服务器上部署了多个应用,考虑到服务的可移植性以及简化服务管理流程,使用容器化方式部署 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
反向代理和身份认证配置
不论使用哪种方法进行部署,在部署完成后都可以使用下面的脚本验证部署是否成功:
if `curl -s localhost:5000 | grep -q "/beancount/income_statement/"`; then echo "ok"; fi
如果输出为 "ok",则表示部署成功。
为了能够在公网进行访问,首先应该在服务器上开放 5000 端口。接着,可以在浏览器中通过
<ip>:5000
如果有自己的域名,则可以在 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
sudo htpasswd -c /etc/nginx/.htpasswd <username>
注意:输入命令会提示你输入一个密码,Nginx 会使用 bcrypt 加密改密码并将其保存在
/etc/nginx/.htpasswd
auth_basic
一个完整的例子可以参考该 Repo。