Jak zainstalować Actual Budget na własnym VPS
Dowiedz się, jak uruchomić Actual Budget przy użyciu Docker Compose. Poradnik wyjaśnia konfigurację wolumenów, wymóg HTTPS dla Web Crypto API oraz proces synchronizacji danych.
Co budujesz
Actual Budget to samodzielnie hostowana aplikacja do budżetowania metodą kopertową. Jest to najczęściej wybierana alternatywa dla YNAB, którą można uruchomić na własnej infrastrukturze. Serwer składa się z jednego kontenera, jednego wolumenu danych oraz jednej nazwy HTTPS. Wszystkie funkcje niezbędne do prowadzenia budżetu działają wydajnie na najmniejszym dostępnym serwerze VPS, ponieważ serwer pełni głównie rolę magazynu plików i punktu synchronizacji.
Przed rozpoczęciem konfiguracji warto zrozumieć architekturę rozwiązania. Sam budżet jest bazą danych SQLite, która znajduje się wewnątrz przeglądarki oraz każdej aplikacji mobilnej. Serwer, który zainstalujesz, jest punktem końcowym synchronizacji: przechowuje listę kont, pliki budżetu oraz dziennik zmian, który zapewnia spójność danych między telefonem a laptopem. Dzięki temu aplikacja działa nawet wtedy, gdy serwer jest niedostępny, a utrata serwera nie oznacza utraty budżetu, o ile przynajmniej jeden klient posiada jego kopię.
Dlaczego serwer wymaga HTTPS
Actual wymaga HTTPS i nie jest to jedynie formalność. Do poprawnego działania Actual potrzebuje funkcji przeglądarki o nazwie SharedArrayBuffer. Przeglądarki udostępniają tę funkcję tylko wtedy, gdy strona jest odizolowana między źródłami (cross-origin isolated) w kontekście, który specyfikacja określa jako bezpieczny. Bezpieczny kontekst to https:// lub http://localhost. W przypadku załadowania aplikacji z http://203.0.113.10:5006 w przeglądarce na innym urządzeniu, przeglądarka nie udostępni tej funkcji stronie, przez co moduł budżetu nie zostanie załadowany. Zasada ta dotyczy również urządzeń mobilnych. FAQ projektu Actual informuje, że oficjalna aplikacja na system iOS znajduje się w fazie testów beta i łączy się z własnym serwerem, natomiast oficjalna aplikacja na system Android jeszcze nie istnieje. W związku z tym na większości telefonów korzysta się z tej samej aplikacji internetowej, zainstalowanej na ekranie głównym jako Progressive Web App, do której stosuje się ta sama zasada bezpiecznego kontekstu.
Istnieją dwie możliwe konfiguracje. Pierwszą z nich, opisaną w tym przewodniku, jest umieszczenie kontenera za serwerem proxy z poprawnym certyfikatem przypisanym do rzeczywistej nazwy domenowej. Drugą opcją jest użycie certyfikatu z podpisem własnym z ACTUAL_HTTPS_KEY i ACTUAL_HTTPS_CERT, co zostało opisane w dokumentacji projektu, przy czym należy zaakceptować ostrzeżenie przeglądarki na każdym urządzeniu. Uzyskanie darmowego certyfikatu z Let's Encrypt zajmuje pięć minut, dlatego zaleca się wybór pierwszej opcji.
Instalacja Actual Budget przy użyciu Docker Compose
Jeśli serwer jest świeżo zainstalowany, najpierw należy zainstalować Docker. Jeśli składnia pliku Compose jest nowa, przewodnik Podstawy Docker Compose dla VPS omawia pola użyte poniżej.
sudo install -d -m 755 /opt/actual
sudo install -d -m 700 /opt/actual/dataUtwórz plik /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:/dataW tym pliku istotne są trzy szczegóły.
Obraz to actualbudget/actual-server:latest, publikowany przez projekt w Docker Hub i dostępny w mirrorze ghcr.io/actualbudget/actual. Dostępny jest tag latest-alpine dla maszyn o niskiej wydajności.
Kontener zapisuje wszystkie dane w /data. Wewnątrz znajduje się server-files, który przechowuje account.sqlite z danymi logowania i tokenami sesji, oraz user-files, gdzie znajdują się pliki budżetu. Należy zamontować tę ścieżkę, w przeciwnym razie docker compose pull spowoduje utratę danych budżetu. ACTUAL_DATA_DIR pozwala na zmianę lokalizacji, ale ustawienie domyślne jest poprawne.
Port jest publikowany wyłącznie na 127.0.0.1. Zwykłe 5006:5006 publikuje port na wszystkich interfejsach, a Docker dodaje własne reguły przed ufw, więc aplikacja byłaby dostępna z Internetu nawet przy zaporze typu deny-all. To zjawisko wyjaśniono w dlaczego publikowane porty Dockera omijają ufw. Powiązanie z interfejsem loopback oznacza, że tylko reverse proxy na tym samym serwerze może uzyskać dostęp do usługi.
Uruchom usługę:
cd /opt/actual
docker compose up --detach
docker compose logs -f actualDziennik ustabilizuje się, gdy serwer zgłosi nasłuchiwanie na porcie 5006. Sprawdź działanie lokalnie przed konfiguracją DNS:
curl -fsS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:5006/Kod 200 oznacza, że aplikacja działa poprawnie. curl: (7) Failed to connect oznacza, że nikt nie zaakceptował połączenia na 127.0.0.1:5006. Uruchom docker compose ps --all, ponieważ zwykłe docker compose ps wyświetla tylko uruchomione kontenery. Jeśli kontener ma status exited, najczęstszą przyczyną jest problem z uprawnieniami do zamontowanego wolumenu, widoczny jako linia EACCES w dzienniku.
Konfiguracja certyfikatu i nazwy domenowej
Skieruj rekord A na adres IP serwera VPS, budget.example.com, i poczekaj na propagację DNS. Następnie zainstaluj nginx i wygeneruj certyfikat. Przewodnik Certbot w systemie Ubuntu 24.04 z serwerem nginx szczegółowo opisuje proces wydawania certyfikatu oraz harmonogram jego odnawiania.
Blok proxy:
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 to dyrektywa, o której często zapominają administratorzy. Codzienna synchronizacja przesyła tylko zmiany, jednak cały plik budżetu jest wysyłany podczas pierwszej rejestracji budżetu na serwerze oraz po każdym zresetowaniu synchronizacji. Domyślny limit rozmiaru treści żądania w nginx wynosi 1 MB, więc gdy plik przekroczy ten rozmiar, pełne wysyłanie kończy się błędem 413 Request Entity Too Large w logu dostępu nginx, podczas gdy aplikacja wyświetla jedynie ogólny błąd synchronizacji. Serwer posiada własne limity: ACTUAL_UPLOAD_FILE_SYNC_SIZE_LIMIT_MB domyślnie wynosi 20, a ACTUAL_UPLOAD_SYNC_ENCRYPTED_FILE_SYNC_SIZE_LIMIT_MB domyślnie 50, dlatego należy ustawić limit w nginx na wartość wyższą niż stosowany limit serwera.
Przeładuj konfigurację i przetestuj:
sudo nginx -t && sudo systemctl reload nginx
curl -fsS -o /dev/null -w '%{http_code}\n' https://budget.example.com/Pierwsze uruchomienie: hasło i pierwszy plik budżetu
Otwórz https://budget.example.com w przeglądarce. Pierwszy ekran wymaga ustawienia hasła serwera. To jedno hasło zabezpiecza cały serwer, więc wygeneruj długie, losowe hasło i przechowaj je w bezpiecznym miejscu, na przykład w samodzielnie hostowanym menedżerze haseł Vaultwarden. Domyślnie nie ma możliwości tworzenia kont użytkowników: serwer posiada jedno hasło, więc udostępnienie budżetu oznacza udostępnienie tego hasła. Osobne loginy są możliwe tylko po połączeniu z dostawcą OpenID, co Actual wspiera w konfiguracjach wieloużytkownikowych.
Następnie utwórz plik budżetu. Actual zapyta, czy włączyć szyfrowanie end-to-end. Wybierz tak, aby serwer przechowywał wyłącznie szyfrogram, co jest właściwym rozwiązaniem dla danych finansowych na wynajmowanej maszynie. Koszt jest realny: hasło szyfrujące nigdy nie trafia na serwer, więc w razie jego utraty plik przepada bez możliwości resetu. Zapisz je przed przejściem do kolejnego ekranu.
Ustaw salda początkowe na podstawie aktualnych danych z banku, zamiast importować historię z wielu lat. Budżetowanie kopertowe działa w oparciu o środki posiadane obecnie, więc brak historii nie stanowi żadnej przeszkody.
Wprowadzanie transakcji
W tym miejscu uczciwość jest ważniejsza niż entuzjazm, ponieważ proces importu jest głównym powodem, dla którego użytkownicy rezygnują z samodzielnie hostowanych narzędzi do budżetowania.
Ręczne wprowadzanie danych to podstawa, która zawsze działa. W przypadku metody kopertowej można argumentować, że jest to wręcz kluczowy element, ponieważ samodzielne wpisywanie wydatku sprawia, że użytkownik zwraca na niego uwagę.
Import plików obsługuje masowe operacje. Actual odczytuje formaty CSV, QIF, OFX, QFX oraz CAMT, a każdy bank eksportuje dane w przynajmniej jednym z nich. Importu dokonuje się dla każdego konta z poziomu ekranu konta, a w przypadku plików CSV należy zmapować kolumny.
Dostępna jest automatyczna synchronizacja z bankami, która wymaga zewnętrznej usługi, ponieważ serwer nie może samodzielnie komunikować się z bankami. Actual wspiera SimpleFIN Bridge dla banków z Ameryki Północnej, Enable Banking dla Europy, Akahu dla Nowej Zelandii oraz Pluggy.ai dla Brazylii. GoCardless jest nadal wspierany, ale nie przyjmuje nowych kont. Użytkownik rejestruje się u dostawcy samodzielnie, generuje dane uwierzytelniające i dodaje je do serwera. Według stanu na październik 2026 roku, SimpleFIN Bridge kosztuje 15 dolarów amerykańskich rocznie plus podatek za maksymalnie 25 instytucji, a pozostali dostawcy stosują inne cenniki.
Przed poleganiem na tym rozwiązaniu należy zaakceptować dwa ograniczenia. Dane uwierzytelniające API znajdują się na serwerze i nie są objęte szyfrowaniem end-to-end, ponieważ serwer musi ich używać. Ponadto nic nie synchronizuje się, gdy Actual jest zamknięty: automatyczna synchronizacja jest domyślnie wyłączona, a po jej włączeniu działa tylko wtedy, gdy aplikacja jest otwarta, więc serwer nigdy nie odpytuje banków samodzielnie.
Kopie zapasowe, ponieważ to tylko pliki
Wszystkie istotne dane znajdują się w /opt/actual/data. Nie jest wymagany żaden proces eksportu ani skryptowanie zrzutów bazy danych.
Jedynym zagrożeniem jest SQLite. Kopiowanie account.sqlite w trakcie zapisu przez serwer może spowodować utrwalenie niepełnej transakcji, co wyjdzie na jaw dopiero podczas próby przywracania. Należy zatrzymać kontener na kilka sekund potrzebnych na wykonanie kopii:
cd /opt/actual
docker compose stop
restic -r sftp:backup@backup.example.com:/srv/restic backup /opt/actual/data
docker compose startNależy zaplanować to zadanie zgodnie z podejściem opisanym w kopie zapasowe restic na VPS, które obejmuje konfigurację repozytorium, retencję oraz procedurę odtwarzania danych. Należy przeprowadzić próbne odtwarzanie. Kopia zapasowa, która nigdy nie została przywrócona, jest jedynie przypuszczeniem.
Własne automatyczne kopie zapasowe Actual stanowią odrębny mechanizm i warto o nich wiedzieć, jednak są one dostępne wyłącznie w aplikacji desktopowej. Przechowuje ona do 10 ostatnich kopii pliku budżetu, dostępnych z poziomu File > Load Backup, co pozwala na rozwiązanie problemu typu "przypadkowe usunięcie kategorii" bez ingerencji w serwer. Aplikacja webowa w przeglądarce nie przechowuje takich kopii, więc jeśli wszyscy domownicy korzystają z przeglądarki, powyższa kopia zapasowa serwera jest jedynym zabezpieczeniem.
Aktualizacja serwera
cd /opt/actual
docker compose pull
docker compose up --detachNarzędzie Compose odtwarza kontener z nowego obrazu i ponownie podłącza ten sam wolumen, dzięki czemu dane zostają zachowane. Należy również zaktualizować klientów. Klient starszy niż dane, które otrzymuje, przestaje stosować zmiany i wyświetla komunikat Update Required. Przed wykonaniem przeskoku do nowej wersji głównej należy wykonać kopię zapasową, ponieważ migracje uruchamiane są przy pierwszym starcie i nie ma możliwości powrotu do poprzedniej wersji. Aplikacja Actual wybacza użycie zmiennego tagu latest, ponieważ jej stan jest katalogiem plików, podczas gdy aplikacja korzystająca z rzeczywistej bazy danych nie jest tak elastyczna, a self-hosting Chatwoot szczegółowo opisuje użycie przypiętych tagów oraz wykonanie zrzutu bazy przed aktualizacją, co jest zalecaną praktyką.
Co ulega awarii i co zobaczysz
Aplikacja ładuje się, ale synchronizacja nigdy się nie kończy. Sprawdź log dostępu nginx pod kątem 413. Oznacza to, że client_max_body_size jest ustawione na zbyt niską wartość. Z kolei 502 oznacza, że nginx nie otrzymał użytecznej odpowiedzi od backendu. Najczęściej wynika to z faktu, że kontener jest zatrzymany lub nie nasłuchuje na porcie 5006, więc przed podjęciem innych działań sprawdź docker compose ps --all oraz logi kontenera.
Aplikacja nie ładuje się na innym urządzeniu lub zgłasza brak SharedArrayBuffer. Strona nie znajduje się w bezpiecznym kontekście. Pasek adresu wyświetli http:// wraz z adresem IP lub nazwą hosta, która nie jest localhost. Napraw certyfikat, zamiast stosować obejścia.
Komunikat o tym, że plik budżetu nie jest zgodny z tą wersją. Plik został otwarty w nowszej wersji Actual niż ta, której obecnie używasz. Zaktualizuj klienta do co najmniej tej wersji lub przywróć kopię zapasową wykonaną przed otwarciem pliku w nowszej wersji, a następnie przeładuj stronę.
Kontener restartuje się w pętli. Przeczytaj docker compose logs actual. Błąd uprawnień w /data oznacza, że zamontowany katalog nie jest zapisywalny dla użytkownika kontenera. Błąd "address-in-use" oznacza, że inny proces zajmuje już port 5006 na interfejsie loopback.
Pierwsze ładowanie wydaje się powolne. Cały plik budżetu jest pobierany do przeglądarki w momencie otwarcia. Jest to jeden duży transfer, po którym następują odczyty lokalne. Nie jest to problem z wydajnością serwera, a zwiększenie ilości pamięci RAM nie przyniesie zmiany.
FAQ
Czy Actual Budget wymaga HTTPS do działania?
Tak, w praktyce. Actual wymaga funkcji przeglądarki SharedArrayBuffer do działania, a przeglądarki udostępniają ją tylko w bezpiecznym kontekście, czyli https:// lub http://localhost. Przy połączeniu przez zwykłe HTTP z innej maszyny aplikacja się nie załaduje. Oficjalna aplikacja na iOS jest w fazie testów beta, a oficjalna aplikacja na Androida jeszcze nie istnieje, więc większość telefonów korzysta z tej samej aplikacji webowej i podlega tej samej zasadzie. (FAQ) Należy użyć certyfikatu Let’s Encrypt dla rzeczywistej nazwy hosta lub certyfikatu z podpisem własnym z ACTUAL_HTTPS_KEY i ACTUAL_HTTPS_CERT, jeśli akceptowalne jest wyświetlanie ostrzeżenia o certyfikacie na każdym urządzeniu.
Czy Actual może automatycznie importować transakcje bankowe?
Tylko za pośrednictwem zewnętrznej usługi, w której użytkownik rejestruje się samodzielnie: SimpleFIN Bridge w Ameryce Północnej, Enable Banking w Europie, Akahu w Nowej Zelandii lub Pluggy.ai w Brazylii. GoCardless jest obsługiwany, ale nie przyjmuje nowych kont. Te dane uwierzytelniające API znajdują się na serwerze i nie są objęte szyfrowaniem end-to-end. Automatyczna synchronizacja jest domyślnie wyłączona, a po włączeniu działa tylko wtedy, gdy Actual jest otwarty, więc w tle na serwerze nie odbywa się żadne odpytywanie. Import plików CSV, QIF, OFX, QFX oraz CAMT nie wymaga żadnej strony trzeciej.
Co dokładnie muszę archiwizować?
Zamontowany katalog danych, który w tym przewodniku oznaczono jako /opt/actual/data. Zawiera on server-files/account.sqlite z danymi logowania i sesjami oraz user-files z plikami budżetu. Przed kopiowaniem należy zatrzymać kontener, ponieważ kopiowanie działającej bazy danych SQLite może skutkować zapisem niepełnych danych. Żaden inny element na serwerze nie przechowuje stanu.
Co się stanie, jeśli zgubię hasło szyfrowania?
Pliku nie da się odzyskać. Hasło nigdy nie trafia na serwer, co jest istotą szyfrowania end-to-end, więc nie ma możliwości resetu ani ścieżki wsparcia technicznego. Należy zapisać je w menedżerze haseł w momencie tworzenia pliku i przechowywać kopię w miejscu niezależnym od tego samego serwera.
Jakich zasobów serwerowych wymaga Actual Budget?
Bardzo niewielkich. Kontener serwuje statyczne zasoby i pliki, a obliczenia budżetowe odbywają się w przeglądarce. Jeden współdzielony vCPU z 1 GB pamięci RAM wystarcza do bezproblemowego działania, a katalog danych dla budżetu domowego z kilkuletnią historią zajmuje zaledwie kilkadziesiąt megabajtów. Obciążenie dysku wynika z kopii zapasowych i innych kontenerów, a nie z samego Actual. Przy doborze parametrów maszyny, która ma obsługiwać również bardziej wymagające usługi, zazwyczaj to serwer zdjęć wyznacza minimalne wymagania, dlatego przed wyborem planu warto sprawdzić ile pamięci RAM faktycznie potrzebują PhotoPrism i Immich. Ta sama logika dotyczy stosu multimedialnego: o planie decyduje transkodowanie, podczas gdy frontend przeglądarkowy, taki jak Halcyon, który zmienia bibliotekę Jellyfin w wirtualną wypożyczalnię wideo z lat 90., wymaga równie mało zasobów co Actual.