SSD Nodes Learn Hosting plans →
Руководства Matt ConnorАвтор: Matt Connor · Обновлено 2026-10-28

Установка Actual Budget на свой VPS через Docker

Пошаговое руководство по развертыванию Actual Budget с помощью Docker Compose. Разберем настройку HTTPS, подключение томов данных, импорт банковских выписок и создание бэкапов.

Что вы создаете

Actual Budget — это приложение для ведения бюджета методом конвертов с возможностью самостоятельного хостинга. Это стандартный выбор для тех, кто ищет альтернативу YNAB, которую можно развернуть на собственных мощностях. Сервер состоит из одного контейнера, одного тома данных и одного HTTPS-имени. Все функции, необходимые для ведения бюджета, стабильно работают на самом дешевом VPS, так как сервер в основном занимается хранением и синхронизацией файлов.

Перед началом работы важно понять архитектуру системы. Сам бюджет представляет собой базу данных SQLite, которая хранится в браузере и в каждом мобильном приложении. Сервер, который вы собираетесь установить, выступает в роли точки синхронизации: он хранит список счетов, файлы бюджета и журнал изменений, позволяющий синхронизировать данные между телефоном и ноутбуком. Именно поэтому приложение продолжает работать при недоступности сервера, а потеря сервера не приводит к потере бюджета, если хотя бы у одного клиента осталась его копия.

Почему серверу нужен HTTPS

Actual требует HTTPS, и это не формальность. Для работы Actual необходима функция браузера под названием SharedArrayBuffer, а браузеры активируют её только в том случае, если страница изолирована в рамках кросс-доменного контекста и находится в том, что спецификация называет безопасным контекстом. Безопасный контекст — это https:// или http://localhost. Если загрузить приложение с http://203.0.113.10:5006 в браузере на другом компьютере, браузер не предоставит странице эту функцию, поэтому бюджет не загрузится. Для телефонов исключений нет. В FAQ Actual указано, что официальное приложение для iOS находится на стадии бета-тестирования и подключается к вашему серверу, а официального приложения для Android пока нет. Поэтому на большинстве телефонов вы используете то же веб-приложение, установленное на главный экран как Progressive Web App, и к нему применяется то же правило безопасного контекста.

Существует два рабочих варианта настройки. Первый — установить настоящий сертификат на реальное доменное имя перед контейнером, что и описывается в этом руководстве. Второй — выпустить для сервера самоподписанный сертификат с помощью ACTUAL_HTTPS_KEY и ACTUAL_HTTPS_CERT, как описано в документации проекта, и принимать предупреждение браузера на каждом устройстве. Бесплатный сертификат от Let's Encrypt настраивается за пять минут, поэтому выберите первый вариант.

Установка Actual Budget с помощью Docker Compose

Если сервер новый, сначала установите Docker. Если синтаксис файлов Compose вам в новинку, руководство Основы Docker Compose для VPS содержит описание полей, используемых ниже.

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

В этом файле важны три детали.

Используется образ 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 добавляет свои правила в iptables раньше правил ufw, поэтому приложение окажется доступным из интернета даже при политике deny-all в брандмауэре. Этот нюанс подробно описан в статье почему опубликованные порты Docker обходят ufw. Привязка к loopback означает, что доступ к приложению будет только у reverse proxy, работающего на том же сервере.

Запустите сервис:

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 означает, что соединение на 127.0.0.1:5006 не было принято. Выполните docker compose ps --all, так как обычная команда docker compose ps показывает только запущенные контейнеры. Если контейнер находится в состоянии exited, наиболее вероятная причина — проблемы с правами доступа к смонтированному тому, что будет видно по строке EACCES в логах.

Настройка сертификата и доменного имени

Направьте A-запись на ваш VPS, budget.example.com, и дождитесь обновления DNS. Затем установите nginx и выпустите сертификат. Руководство Certbot в Ubuntu 24.04 с nginx содержит полную информацию о выпуске сертификатов и таймере их автоматического обновления.

Блок конфигурации прокси:

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. Как только файл превышает этот размер, полная загрузка завершается с ошибкой 413 Request Entity Too Large в access log nginx, а приложение отображает общую ошибку синхронизации. У сервера есть собственные лимиты: 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. По умолчанию создавать учетные записи пользователей не нужно: у сервера один пароль, поэтому совместное использование бюджета означает передачу этого пароля. Раздельные учетные записи возможны только при подключении провайдера OpenID, который Actual поддерживает для многопользовательских конфигураций.

Затем создайте файл бюджета. Actual спросит, нужно ли включить сквозное шифрование. Соглашайтесь: сервер будет хранить только зашифрованные данные, что является правильным решением для финансовых сведений на арендованном оборудовании. Цена этого решения реальна: пароль шифрования никогда не передается на сервер, поэтому, если вы его потеряете, файл будет утрачен без возможности восстановления. Запишите его, прежде чем переходить к следующему экрану.

Установите начальные балансы на основе текущих данных вашего банка, а не импортируйте историю за несколько лет. Конвертное бюджетирование работает с деньгами, которые у вас есть сейчас, поэтому отсутствие истории никак не повлияет на процесс.

Импорт транзакций

Здесь честность важнее энтузиазма, так как процесс импорта — основная причина, по которой пользователи отказываются от self-hosted систем бюджетирования.

Ручной ввод — это базовый метод, который работает всегда. Для конвертного метода это, по сути, и есть главная цель, так как именно ввод покупки заставляет вас обратить на неё внимание.

Импорт файлов справляется с большими объёмами данных. Actual поддерживает форматы CSV, QIF, OFX, QFX и CAMT, а каждый банк экспортирует данные как минимум в одном из них. Импортируйте данные для каждого счёта отдельно с экрана счетов и сопоставляйте столбцы, если файл имеет формат CSV.

Автоматическая синхронизация с банками существует, но для неё требуется сторонний сервис, так как сервер не может взаимодействовать с банками напрямую. Actual поддерживает SimpleFIN Bridge для банков Северной Америки, Enable Banking для Европы, Akahu для Новой Зеландии и Pluggy.ai для Бразилии. GoCardless по-прежнему поддерживается, но новые аккаунты не принимает. Вы самостоятельно регистрируетесь у провайдера, создаёте учётные данные и добавляете их на сервер. По состоянию на октябрь 2026 года 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

Настройте расписание для этого процесса, используя подход из резервного копирования restic на VPS, где описаны настройка репозитория, правила хранения и процедура восстановления. Обязательно проведите тестовое восстановление. Резервная копия, которую вы никогда не восстанавливали, — это лишь предположение.

Автоматические резервные копии самого Actual — это отдельная функция, о которой стоит знать, но она доступна только в десктопном приложении. Оно хранит до 10 последних копий файла бюджета, доступных через File > Load Backup. Это позволяет исправить ситуацию, если вы случайно удалили категорию, не затрагивая сервер. Веб-приложение в браузере такие копии не сохраняет, поэтому, если все пользователи в доме работают через браузер, резервная копия сервера, описанная выше, является вашей единственной защитой.

Обновление сервера

cd /opt/actual
docker compose pull
docker compose up --detach

Compose пересоздает контейнер из нового образа и повторно подключает тот же том, поэтому данные сохраняются. Обновите также клиенты. Клиент, версия которого старше получаемых им данных, перестает применять изменения и выводит сообщение Update Required. Перед переходом на мажорную версию сделайте резервную копию, так как миграции выполняются при первом запуске, а пути для отката не существует. Actual допускает использование плавающего тега latest, поскольку его состояние представляет собой каталог файлов, в то время как приложение, использующее полноценную базу данных, — нет; в руководстве self-hosting Chatwoot описаны работа с фиксированными тегами и создание дампа перед обновлением, которые требуются в подобных случаях.

Что может сломаться и что вы увидите

Приложение загружается, но синхронизация не завершается. Проверьте лог доступа nginx на наличие 413. Это означает, что client_max_body_size установлено слишком низким. Ошибка 502 означает, что nginx не получил корректный ответ от апстрима. Чаще всего это происходит из-за того, что контейнер остановлен или не слушает порт 5006, поэтому в первую очередь проверьте docker compose ps --all и лог контейнера.

Приложение не загружается на другом устройстве или сообщает об отсутствии SharedArrayBuffer. Страница не находится в безопасном контексте. В адресной строке отображается http:// с IP-адресом или именем хоста, отличным от localhost. Исправьте сертификат, вместо того чтобы пытаться обойти это ограничение.

Сообщение о том, что файл бюджета несовместим с этой версией. Файл был открыт в более новой версии Actual, чем та, которую вы используете сейчас. Обновите клиент как минимум до этой версии или восстановите резервную копию, созданную до того, как файл был изменен более новой версией, а затем перезагрузите страницу.

Контейнер перезапускается в цикле. Прочитайте docker compose logs actual. Ошибка прав доступа к /data означает, что у пользователя контейнера нет прав на запись в смонтированную директорию. Ошибка «адрес уже используется» означает, что какой-то другой процесс уже занял порт 5006 на loopback-интерфейсе.

Первая загрузка кажется медленной. Весь файл бюджета загружается в браузер при его открытии. Это одна большая передача данных, после которой следуют локальные операции чтения. Это не проблема производительности сервера, и добавление оперативной памяти не ускорит процесс.

FAQ

Нужен ли Actual Budget HTTPS для работы?

Да, на практике нужен. Actual требует наличия функции SharedArrayBuffer в браузере, а браузеры активируют её только в безопасном контексте, то есть при использовании https:// или http://localhost. При подключении по обычному HTTP с другого устройства приложение не загрузится. Официальное приложение для iOS находится на стадии бета-тестирования, а официального приложения для Android пока нет, поэтому большинство пользователей телефонов используют то же веб-приложение и сталкиваются с тем же ограничением. (FAQ) Используйте сертификат Let's Encrypt для реального доменного имени или самоподписанный сертификат с ACTUAL_HTTPS_KEY и ACTUAL_HTTPS_CERT, если вы готовы мириться с предупреждением о сертификате на каждом устройстве.

Может ли Actual импортировать банковские транзакции автоматически?

Только через сторонний сервис, на который вы подписываетесь самостоятельно: SimpleFIN Bridge в Северной Америке, Enable Banking в Европе, Akahu в Новой Зеландии или Pluggy.ai в Бразилии. GoCardless поддерживается, но новые аккаунты не принимает. Эти API-учётные данные хранятся на вашем сервере и не защищены сквозным шифрованием. Автоматическая синхронизация по умолчанию отключена, а после включения работает только при открытом Actual, поэтому в фоновом режиме на сервере ничего не опрашивается. Для импорта файлов CSV, QIF, OFX, QFX и CAMT сторонние сервисы не требуются.

Что именно нужно резервировать?

Смонтированный каталог данных, который в этом руководстве обозначен как /opt/actual/data. Он содержит server-files/account.sqlite с данными для входа и сессиями, а также user-files с файлами бюджета. Остановите контейнер перед копированием, так как при копировании работающей базы данных SQLite можно захватить частичную запись. Никакие другие данные на сервере не хранят состояние приложения.

Что будет, если я потеряю пароль шифрования?

Файл восстановить невозможно. Пароль никогда не передаётся на сервер, в этом и заключается смысл сквозного шифрования, поэтому функции сброса или поддержки не существует. Сохраните пароль в менеджере паролей сразу после создания файла и держите копию в месте, которое не зависит от этого же сервера.

Какие требования к серверу у Actual Budget?

Минимальные. Контейнер отдаёт статические ресурсы и файлы, а вычисления бюджета происходят в браузере. Одно общее vCPU с 1 ГБ оперативной памяти справляется без проблем, а каталог данных для семейного бюджета с историей за несколько лет занимает десятки мегабайт. Нагрузка на диск зависит от ваших резервных копий и других контейнеров, а не от Actual. Если вы подбираете сервер для запуска чего-то более ресурсоёмкого, обычно нижнюю планку определяет фотосервер, поэтому ознакомьтесь с тем, сколько оперативной памяти на самом деле нужно PhotoPrism и Immich, прежде чем выбирать тариф. Та же логика применима к медиа-стеку: план определяет транскодирование, в то время как фронтенд для браузера, такой как Halcyon, превращающий библиотеку Jellyfin в интерактивный видеомагазин 90-х, требует столько же ресурсов, сколько и Actual.

Была ли эта статья полезной?