MAATRIX / Блог / Actual Budget в Docker Compose: готовый файл

Actual Budget в Docker Compose: готовый файл

MAATRIX

Вести бюджет в таблице Excel надоедает через месяц, а платить $8-10 в месяц за YNAB и доверять чужому облаку баланс своей карты хочется не всем. Actual Budget — open-source приложение для бюджетирования по методу envelope (конвертов), которое можно развернуть на своём сервере за один docker-compose.yml и получить интерфейс не хуже платных аналогов, но без подписки и с данными под своим контролем. Ниже — рабочий конфиг, разбор что писать в переменные окружения и на что обратить внимание с бэкапами: тут речь о финансовых данных, ошибки дороже, чем с обычным сайтом.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Что такое Actual Budget и чем он отличается от Firefly III

Actual реализует метод envelope budgeting: вы заранее распределяете весь доход по категориям-«конвертам» (аренда, продукты, развлечения) и тратите строго в рамках того, что в конверте осталось, а не смотрите на общий баланс карты постфактум. Это тот же подход, что в YNAB, только open-source и без обязательной подписки.

Технически Actual устроен необычно для self-hosted приложений: это не классическое клиент-сервер приложение с общей базой, а local-first система. Каждый бюджет — это SQLite-файл, который живёт локально в браузере или приложении пользователя, а сервер работает как реле синхронизации через CRDT (merkle-дерево изменений). Это даёт заметный на практике эффект: интерфейс отвечает мгновенно, потому что все операции идут в локальную копию, а не ждут round-trip к серверу, и приложение продолжает работать даже если сервер временно недоступен — изменения досинхронизируются, когда связь восстановится.

Если на этом же блоге вы уже смотрели статью про установку Firefly III, разница в философии станет понятнее:

  • Firefly III — это бухгалтерская книга с двойной записью, отчётами по категориям и правилами импорта банковских выписок. Хорош, когда нужна точная картина «куда ушли деньги» постфактум, и требует отдельной MySQL/PostgreSQL базы.
  • Actual Budget — про планирование вперёд: сколько денег осталось в конверте «продукты» до конца месяца. Интерфейс быстрее и приятнее для ежедневного использования, а серверная часть — один лёгкий Node.js-контейнер без внешней СУБД, потому что каждый бюджет уже сам себе SQLite-база.

Для семейного бюджета и личных финансов обычно ближе Actual, для учёта бизнеса с отчётностью и импортом выписок из десятка банков — Firefly III. Ничего не мешает поднять оба на одном сервере, они не конкурируют за ресурсы.

Готовый docker-compose.yml для быстрого старта

Официальный образ actualbudget/actual-server — это весь сервер целиком: и сам Node-процесс синхронизации, и раздача статики веб-клиента. Внешняя база не нужна.

version: "3.8"

services:
  actual_server:
    image: docker.io/actualbudget/actual-server:latest
    container_name: actual_server
    restart: unless-stopped
    ports:
      - "5006:5006"
    volumes:
      - ./actual-data:/data
    environment:
      ACTUAL_PORT: "5006"
      # Лимиты на размер синхронизируемого файла бюджета, в МБ
      ACTUAL_UPLOAD_FILE_SYNC_SIZE_LIMIT_MB: "20"
      ACTUAL_UPLOAD_SYNC_ENCRYPTED_FILE_SYNC_SIZE_LIMIT_MB: "50"
      ACTUAL_UPLOAD_FILE_SIZE_LIMIT_MB: "20"

Как и в любом образе с плавающим тегом, latest удобен для первого теста, но для боевой эксплуатации зафиксируйте конкретную версию — откройте страницу образа на Docker Hub, возьмите актуальный тег (у Actual используется календарное версионирование, что-то вроде 25.x.x) и пропишите его явно. Так обновление версии станет осознанным шагом, а не тем, что происходит само при пересоздании контейнера.

Запуск:

mkdir -p ~/actual-budget && cd ~/actual-budget
mkdir -p actual-data
# вставляем docker-compose.yml из примера выше
docker compose up -d
docker compose logs -f actual_server

Через 10-20 секунд сервер поднимается и слушает на http://ваш-ip:5006. Каталог ./actual-data — это всё, что нужно бэкапить: там появятся подпапки server-files (служебная база сервера, включая хэш пароля входа) и user-files (файлы каждого созданного бюджета).

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Первый запуск: пароль сервера и создание бюджета

При первом заходе на адрес сервера Actual попросит задать пароль — это не пароль конкретного бюджета, а мастер-пароль доступа к самому серверу синхронизации. Без него интерфейс работать не начнёт, так что пропустить этот шаг нельзя, и это правильно: без пароля любой, кто найдёт открытый порт 5006, получил бы доступ к вашим финансам.

После входа вы попадаете на экран выбора бюджета. Можно:

  • создать новый бюджет с нуля и настроить категории под себя;
  • импортировать данные из YNAB (есть готовый импортёр форматов nYNAB и старого YNAB4);
  • импортировать из CSV-выгрузки банка.

При создании бюджета Actual предложит включить сквозное шифрование (end-to-end encryption) отдельным паролем для этого конкретного файла. Это важный нюанс: пароль сервера защищает вход в интерфейс, а пароль шифрования файла защищает содержимое конкретного бюджета так, что даже сам сервер хранит его как непрозрачный блоб и не может прочитать данные. Минус — если забудете этот пароль, расшифровать бюджет без него не получится никак, бэкдора и восстановления через админку нет.

Дальше desktop- и мобильные приложения Actual (Windows/macOS/Linux/iOS/Android) подключаются к тому же серверу — в настройках приложения указываете URL вашего сервера и мастер-пароль, дальше синхронизация идёт автоматически в фоне.

HTTPS и reverse proxy: без этого часть функций не заработает

Actual — прогрессивное веб-приложение (PWA) с сервис-воркером, а современные браузеры разрешают часть возможностей service worker (в том числе офлайн-режим и фоновую синхронизацию) только по HTTPS — исключение делается лишь для localhost. Если открыть сервер по обычному http://ip:5006 с телефона или ноутбука не через localhost, часть local-first магии просто не включится, а некоторые мобильные клиенты и вовсе откажутся подключаться к незащищённому адресу.

Проще всего отдать HTTPS уже работающему на сервере reverse proxy — например, Caddy с автоматическим Let's Encrypt. Держим Actual на локальном порту и добавляем блок:

    ports:
      - "127.0.0.1:5006:5006"   # только локально, наружу не торчит
budget.example.com {
    reverse_proxy 127.0.0.1:5006
}

Домен в А-записи должен указывать на IP сервера, порты 80/443 — быть свободны. Если сервер стоит за прокси, добавьте в окружение Actual переменную с адресом прокси, чтобы приложение правильно определяло реальный IP клиента для логов:

    environment:
      ACTUAL_TRUSTED_PROXIES: "127.0.0.1"

Если reverse proxy на сервере пока нет и заводить его ради одного приложения не хочется, у самого образа есть встроенная поддержка HTTPS напрямую через ACTUAL_HTTPS_KEY и ACTUAL_HTTPS_CERT (указываете пути к смонтированным файлам сертификата и ключа) — вариант рабочий, но обновлять сертификат в этом случае придётся руками или отдельным cron-скриптом с certbot, тогда как reverse proxy делает это сам.

Несколько бюджетов на одном сервере и общий доступ семьи

Один сервер Actual спокойно держит несколько независимых бюджетов — например, личный и семейный, или отдельные для каждого члена семьи. Каждый бюджет создаётся со своим шифрованием (или без него) и виден только тем, кто знает мастер-пароль сервера и, если включено, пароль шифрования конкретного файла.

Важное ограничение, которое стоит понимать заранее: по умолчанию (ACTUAL_LOGIN_METHOD: password) у сервера один общий мастер-пароль на всех, а не отдельные учётки с ролями, как в банковском приложении. Для семьи из двух-трёх человек, которым можно доверять друг другу пароль, это не проблема. Если нужно разграничение — кто-то видит только свой бюджет, а не все — начиная с версий, где появилась поддержка ACTUAL_LOGIN_METHOD: header, можно вынести аутентификацию на внешний SSO-прокси (например, Authelia) и разруливать доступ уже на его уровне, но это заметно усложняет схему ради функции, которую сам Actual изначально не проектировал как многопользовательскую с ролями.

Практичнее для большинства семей: один мастер-пароль знают все, кому доверяете доступ к серверу, а приватность внутри бюджета (если она вообще нужна) достигается просто отдельными бюджетными файлами с разными паролями шифрования на каждый.

Бэкапы и обновление версии: тут осторожность важнее скорости

Это финансовые данные, поэтому бэкап-стратегия должна быть надёжнее, чем «раз в неделю как получится». Бэкапить нужно весь каталог /data — в нём и служебная база сервера, и SQLite-файлы всех бюджетов:

tar -czf actual-backup-$(date +%F).tar.gz -C ~/actual-budget actual-data

Для регулярных бэкапов с дедупликацией и шифрованием удобнее не городить cron с tar вручную, а поднять рядом BorgBackup в отдельном контейнере — он умеет ежедневные снапшоты с ротацией и не раздувает диск, в отличие от полных архивов каждый день.

Про обновление версии — здесь стоит явная рекомендация: не ставьте Actual Budget на автообновление через watchtower или аналоги. При обновлении сервер применяет миграции к SQLite-файлам бюджетов, и если миграция упадёт на середине (баг в новой версии, нехватка места на диске, обрыв), файл может остаться в промежуточном состоянии. С финансовыми данными это не тот риск, который стоит автоматизировать вслепую. Правильный порядок:

# 1. Бэкап перед обновлением — всегда
tar -czf actual-backup-pre-update-$(date +%F).tar.gz -C ~/actual-budget actual-data

# 2. Смотрим changelog новой версии на GitHub actualbudget/actual — 
# были ли breaking changes или ручные шаги миграции

# 3. Обновляем
docker compose pull actual_server
docker compose up -d actual_server
docker compose logs -f actual_server

Если после обновления в логах ошибки миграции или интерфейс не открывается — останавливаем контейнер, разворачиваем бэкап каталога /data поверх текущего и разбираемся уже без спешки, с рабочей копией под рукой.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Нужна ли для Actual Budget отдельная база данных вроде PostgreSQL?

Нет, это ключевое отличие от того же Firefly III. Каждый бюджет — самостоятельный SQLite-файл, сервер только синхронизирует изменения между вашими устройствами. Внешняя СУБД не нужна, и это упрощает и бэкап, и восстановление — весь объект бэкапа это папка /data.

Что будет с данными, если сервер недоступен несколько дней?

Ничего критичного — приложение на устройстве работает с локальной копией бюджета полностью автономно, вы продолжаете вносить операции. Как только сервер снова станет доступен, изменения досинхронизируются автоматически через merkle-дерево без ручного разрешения конфликтов в большинстве случаев.

Хватит ли самого дешёвого VPS?

С запасом. Actual — лёгкий Node.js-процесс без тяжёлой СУБД, для одного-двух бюджетов и нескольких пользователей достаточно 512 МБ - 1 ГБ RAM и минимального CPU. Требования растут только с числом одновременных клиентов, синхронизирующихся часто, а не с размером самого бюджета.

Можно ли забыть пароль сквозного шифрования и восстановить бюджет?

Нет, и это осознанный компромисс безопасности — сервер хранит зашифрованный файл, не может расшифровать его сам и, соответственно, не может помочь его восстановить. Держите пароли шифрования в менеджере паролей отдельно от мастер-пароля сервера.

Как перенести Actual с одного сервера на другой?

Останавливаете контейнер, копируете весь каталог /data (сам том с server-files и user-files) на новый сервер, поднимаете тот же docker-compose.yml с тем же образом и версией, указываете новый volume — сервер подхватит существующие бюджеты и пароль входа как есть, без экспорта-импорта.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →