Merge pull request #5275 from okxlin/feat/actual-budget-1panel-batch52

feat: add Actual Budget app
This commit is contained in:
okxlin
2026-07-28 23:39:22 +08:00
committed by GitHub
17 changed files with 344 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
PANEL_APP_PORT_HTTP=5006
APP_DATA_DIR=./data
CONTAINER_NAME=
+35
View File
@@ -0,0 +1,35 @@
additionalProperties:
formFields:
- default: 5006
edit: true
envKey: PANEL_APP_PORT_HTTP
labelEn: Port
labelZh: 端口
label:
en: Port
zh: 端口
zh-Hant: 埠
ja: ポート
ko: 포트
ru: Порт
ms: Port
pt-br: Porta
required: true
rule: paramPort
type: number
- default: ./data
edit: true
envKey: APP_DATA_DIR
labelEn: Data Directory
labelZh: 数据目录
label:
en: Data Directory
zh: 数据目录
zh-Hant: 資料目錄
ja: データディレクトリ
ko: 데이터 디렉터리
ru: Каталог данных
ms: Direktori Data
pt-br: Diretório de dados
required: true
type: text
@@ -0,0 +1,31 @@
services:
actual-budget:
image: "actualbudget/actual-server:26.7.0@sha256:e18b7fbfec6157a368fad4146563f397502e9da70a120aeaeac63b4977405d1c"
container_name: ${CONTAINER_NAME}
restart: unless-stopped
user: "1001:1001"
networks:
- 1panel-network
ports:
- "${PANEL_APP_PORT_HTTP}:5006"
read_only: true
tmpfs:
- /tmp:size=64m,mode=1777
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
volumes:
- "${APP_DATA_DIR}:/data"
healthcheck:
test: ["CMD-SHELL", "node scripts/health-check.js"]
interval: 60s
timeout: 10s
retries: 3
start_period: 20s
labels:
createdBy: "Apps"
networks:
1panel-network:
external: true
+55
View File
@@ -0,0 +1,55 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
ENV_FILE="${ENV_FILE:-$ROOT_DIR/.env}"
read_env_value() {
local key="$1"
local value
[[ -f "$ENV_FILE" ]] || return 0
value="$(sed -n "s/^${key}=//p" "$ENV_FILE" | tail -n 1)"
case "$value" in
\"*\") value="${value#\"}"; value="${value%\"}" ;;
\'*\') value="${value#\'}"; value="${value%\'}" ;;
esac
printf '%s\n' "$value"
}
raw="${APP_DATA_DIR:-}"
if [[ -z "$raw" ]]; then
raw="$(read_env_value APP_DATA_DIR)"
fi
raw="${raw:-./data}"
[[ -n "$raw" ]] || {
printf 'APP_DATA_DIR must not be empty\n' >&2
exit 1
}
if [[ "$raw" = /* ]]; then
printf 'APP_DATA_DIR must be relative to the application version directory\n' >&2
exit 1
fi
path="$(realpath -m -- "$ROOT_DIR/${raw#./}")"
case "$path" in
"$ROOT_DIR"/*) ;;
*)
printf 'APP_DATA_DIR must remain inside the application version directory\n' >&2
exit 1
;;
esac
install -d -m 0700 "$path"
path="$(realpath -e -- "$path")"
case "$path" in
"$ROOT_DIR"/*) ;;
*)
printf 'APP_DATA_DIR resolves outside the application version directory\n' >&2
exit 1
;;
esac
chmod 0700 "$path"
chown -R --no-dereference 1001:1001 "$path"
+2
View File
@@ -0,0 +1,2 @@
#!/usr/bin/env bash
set -euo pipefail
+4
View File
@@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -euo pipefail
"$(dirname "$0")/init.sh"
+53
View File
@@ -0,0 +1,53 @@
# Actual Budget
## 产品介绍
Actual Budget 是隐私优先的开源个人财务应用,提供信封预算、账户与交易管理、规则、报表和多设备同步。
## 主要功能
- 信封预算与灵活预算管理
- 账户、交易、分类、规则和报表
- 预算导入导出、本地备份与多设备同步
## 访问说明
安装后通过 `http://<服务器 IP>:<端口>` 访问,实际端口以 `PANEL_APP_PORT_HTTP` 为准。首次打开时应立即设置服务器密码;在完成密码设置和反向代理 HTTPS 配置前,不要将端口暴露到不可信网络。
## 数据持久化
`APP_DATA_DIR` 保存服务器账户数据库、预算文件和同步数据。该路径必须位于应用版本目录内;初始化脚本会拒绝绝对路径、路径穿越和符号链接逃逸,并为上游容器用户 `1001:1001` 准备权限。卸载不会删除该目录,请定期独立备份。
## 安全与部署风险
- 容器以 UID/GID `1001:1001` 运行,丢弃全部 Linux capabilities,并启用只读根文件系统和 `no-new-privileges`。
- 当前官方 `26.7.0` 镜像的新鲜 Trivy 扫描仍包含上游未修复漏洞。其中两份受 `CVE-2026-59873` 影响的 `node-tar` 分别属于 npm CLI 和仅由 `node-gyp` 导入的构建链;Actual 的运行时导入、备份和同步上传路径使用 `AdmZip` 或限长后原样存储,未调用 `node-tar`。该结论是默认运行路径例外,不代表镜像中不存在漏洞。
- 如果在容器内手动运行 npm/node-gyp、增加执行外部命令的插件或改变官方入口,上述可达性结论将不再成立。镜像摘要变更时必须重新扫描。
## Introduction
Actual Budget is a privacy-focused open-source personal finance app with envelope budgeting, account and transaction management, rules, reports, and multi-device synchronization.
## Features
- Envelope and flexible budgeting
- Accounts, transactions, categories, rules, and reports
- Budget import/export, local backups, and multi-device synchronization
## Usage Notes
- Access the service at `http://<server-ip>:<port>` and set the server password immediately on first use. Do not expose it to an untrusted network before password setup and HTTPS reverse-proxy configuration are complete.
- `APP_DATA_DIR` stores the account database, budget files, and synchronization data. It must remain inside the application version directory and should be backed up independently.
- The container runs as UID/GID `1001:1001`, drops all Linux capabilities, and uses a read-only root filesystem plus `no-new-privileges`.
## Security Note
The current official image contains upstream vulnerabilities. Two `node-tar` copies affected by `CVE-2026-59873` belong to the npm CLI and the `node-gyp` build chain; Actual's runtime import, backup, and sync-upload paths use `AdmZip` or bounded opaque storage and do not invoke them. This is a default-path reachability exception, not a claim that the packages are absent. Running npm/node-gyp inside the container or replacing the official entrypoint invalidates the exception.
## References
- Project: <https://github.com/actualbudget/actual>
- Docker installation: <https://actualbudget.org/docs/install/docker/>
- Official Compose: <https://github.com/actualbudget/actual/blob/master/packages/sync-server/docker-compose.yml>
- License: <https://github.com/actualbudget/actual/blob/master/LICENSE.txt> (MIT)
- Security advisory: <https://github.com/advisories/GHSA-23hp-3jrh-7fpw>
+31
View File
@@ -0,0 +1,31 @@
name: Actual Budget
tags:
- 财务
title: 隐私优先的开源个人财务应用
description: 隐私优先的开源个人财务应用
additionalProperties:
key: actual-budget
name: Actual Budget
tags:
- Tool
shortDescZh: 隐私优先的开源个人财务应用
shortDescEn: Privacy-focused open-source personal finance app
description:
en: Privacy-focused open-source personal finance app
zh: 隐私优先的开源个人财务应用
zh-Hant: 隱私優先的開源個人理財應用程式
ja: プライバシー重視のオープンソース個人資産管理アプリ
ko: 개인정보 보호를 중시하는 오픈소스 개인 재무 앱
ru: Конфиденциальное приложение с открытым кодом для личных финансов
ms: Aplikasi kewangan peribadi sumber terbuka yang mengutamakan privasi
pt-br: Aplicativo de finanças pessoais de código aberto com foco em privacidade
type: website
crossVersionUpdate: true
limit: 0
recommend: 0
website: https://actualbudget.org/
github: https://github.com/actualbudget/actual
document: https://actualbudget.org/docs/install/docker/
architectures:
- amd64
- arm64
+3
View File
@@ -0,0 +1,3 @@
PANEL_APP_PORT_HTTP=5006
APP_DATA_DIR=./data
CONTAINER_NAME=
+35
View File
@@ -0,0 +1,35 @@
additionalProperties:
formFields:
- default: 5006
edit: true
envKey: PANEL_APP_PORT_HTTP
labelEn: Port
labelZh: 端口
label:
en: Port
zh: 端口
zh-Hant: 埠
ja: ポート
ko: 포트
ru: Порт
ms: Port
pt-br: Porta
required: true
rule: paramPort
type: number
- default: ./data
edit: true
envKey: APP_DATA_DIR
labelEn: Data Directory
labelZh: 数据目录
label:
en: Data Directory
zh: 数据目录
zh-Hant: 資料目錄
ja: データディレクトリ
ko: 데이터 디렉터리
ru: Каталог данных
ms: Direktori Data
pt-br: Diretório de dados
required: true
type: text
@@ -0,0 +1,31 @@
services:
actual-budget:
image: "actualbudget/actual-server:latest@sha256:e18b7fbfec6157a368fad4146563f397502e9da70a120aeaeac63b4977405d1c"
container_name: ${CONTAINER_NAME}
restart: unless-stopped
user: "1001:1001"
networks:
- 1panel-network
ports:
- "${PANEL_APP_PORT_HTTP}:5006"
read_only: true
tmpfs:
- /tmp:size=64m,mode=1777
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
volumes:
- "${APP_DATA_DIR}:/data"
healthcheck:
test: ["CMD-SHELL", "node scripts/health-check.js"]
interval: 60s
timeout: 10s
retries: 3
start_period: 20s
labels:
createdBy: "Apps"
networks:
1panel-network:
external: true
+55
View File
@@ -0,0 +1,55 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
ENV_FILE="${ENV_FILE:-$ROOT_DIR/.env}"
read_env_value() {
local key="$1"
local value
[[ -f "$ENV_FILE" ]] || return 0
value="$(sed -n "s/^${key}=//p" "$ENV_FILE" | tail -n 1)"
case "$value" in
\"*\") value="${value#\"}"; value="${value%\"}" ;;
\'*\') value="${value#\'}"; value="${value%\'}" ;;
esac
printf '%s\n' "$value"
}
raw="${APP_DATA_DIR:-}"
if [[ -z "$raw" ]]; then
raw="$(read_env_value APP_DATA_DIR)"
fi
raw="${raw:-./data}"
[[ -n "$raw" ]] || {
printf 'APP_DATA_DIR must not be empty\n' >&2
exit 1
}
if [[ "$raw" = /* ]]; then
printf 'APP_DATA_DIR must be relative to the application version directory\n' >&2
exit 1
fi
path="$(realpath -m -- "$ROOT_DIR/${raw#./}")"
case "$path" in
"$ROOT_DIR"/*) ;;
*)
printf 'APP_DATA_DIR must remain inside the application version directory\n' >&2
exit 1
;;
esac
install -d -m 0700 "$path"
path="$(realpath -e -- "$path")"
case "$path" in
"$ROOT_DIR"/*) ;;
*)
printf 'APP_DATA_DIR resolves outside the application version directory\n' >&2
exit 1
;;
esac
chmod 0700 "$path"
chown -R --no-dereference 1001:1001 "$path"
+2
View File
@@ -0,0 +1,2 @@
#!/usr/bin/env bash
set -euo pipefail
+4
View File
@@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -euo pipefail
"$(dirname "$0")/init.sh"
Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB