Come installare Actual Budget su un VPS con Docker
Installa Actual Budget su un VPS con Docker Compose: volume dati, HTTPS obbligatorio nel browser, primo budget, importazioni bancarie e backup.
Cosa stai per realizzare
Actual Budget è un'app di budgeting a buste ospitata autonomamente. È la risposta abituale per chi cerca un'alternativa a YNAB che possa gestire in autonomia. Il server è costituito da un solo container, un solo volume dati e un solo nome HTTPS. Tutto ciò che serve a un normale budget funziona senza problemi sul VPS più piccolo disponibile, perché il server archivia principalmente file e li sincronizza.
È utile comprendere l'architettura prima di eseguire qualsiasi comando. Il budget è un database SQLite che risiede nel browser e in ogni app mobile. Il server che stai per installare è un endpoint di sincronizzazione: conserva l'elenco degli account, i file del budget e il registro delle modifiche che consente a uno smartphone e a un laptop di mantenere gli stessi dati. Per questo l'app continua a funzionare quando il server è inattivo. Per lo stesso motivo, la perdita del server non comporta la perdita del budget, purché almeno un client ne conservi ancora una copia.
Perché il server richiede HTTPS
Actual richiede HTTPS e non si tratta di una formalità. I browser espongono la Web Crypto API, l’interfaccia che Actual usa per la crittografia end-to-end, soltanto in quello che la specifica definisce contesto sicuro. Un contesto sicuro è https:// o http://localhost. Se si apre l’applicazione da http://203.0.113.10:5006 in un browser su un altro computer, queste funzionalità non sono semplicemente disponibili, perché il browser non le ha messe a disposizione della pagina. Anche le build mobili ufficiali rifiutano l’URL di un server http:// non protetto.
Esistono quindi due configurazioni funzionanti. La prima consiste nel configurare un certificato valido per un nome DNS reale davanti al container, come previsto da questa guida. La seconda consiste nell’assegnare al server un certificato autofirmato con ACTUAL_HTTPS_KEY e ACTUAL_HTTPS_CERT, come documentato dal progetto, accettando un avviso del browser su ogni dispositivo. Un certificato gratuito di Let's Encrypt richiede cinque minuti: è quindi preferibile la prima opzione.
Installare Actual Budget con Docker Compose
Installare prima Docker se il server è nuovo. Se la sintassi dei file Compose è nuova per te, la guida Nozioni di base su Docker Compose per un VPS descrive i campi usati di seguito.
sudo install -d -m 755 /opt/actual
sudo install -d -m 700 /opt/actual/dataScrivere /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:/dataIn quel file sono importanti tre dettagli.
L'immagine è actualbudget/actual-server:latest, pubblicata dal progetto su Docker Hub e disponibile anche su ghcr.io/actualbudget/actual. È disponibile il tag latest-alpine per le macchine a basso consumo.
Il container scrive tutto sotto /data. Al suo interno trovi server-files, che contiene account.sqlite con le credenziali di accesso e i token di sessione, e user-files, che contiene i file dei budget. Montare quel percorso; in caso contrario, il comando successivo docker compose pull elimina il budget. ACTUAL_DATA_DIR può spostarlo, ma il valore predefinito va bene.
La porta viene pubblicata solo su 127.0.0.1. Un 5006:5006 senza indirizzo pubblica la porta su tutte le interfacce. Docker inserisce le proprie regole prima di ufw, quindi l'applicazione sarebbe esposta a Internet anche con un firewall che nega tutto il traffico. Questo comportamento è spiegato nella guida perché le porte pubblicate da Docker ignorano ufw. Il binding sull'interfaccia di loopback consente di raggiungerla solo al reverse proxy sullo stesso server.
Avviarlo:
cd /opt/actual
docker compose up --detach
docker compose logs -f actualIl log si stabilizza quando il server segnala di essere in ascolto sulla porta 5006. Verificarlo localmente prima di modificare il DNS:
curl -fsS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:5006/Un 200 indica che l'applicazione sta rispondendo. curl: (7) Failed to connect indica che il container non è in esecuzione e docker compose ps mostra che è terminato. La causa usuale è un problema di permessi sul volume montato, visibile come una riga EACCES nel log.
Pubblica il servizio con un certificato e un nome reale
Punta un record A al VPS, budget.example.com, e attendi che la risoluzione sia completata. Installa quindi nginx e genera il certificato. La guida Certbot su Ubuntu 24.04 con nginx descrive in dettaglio la generazione del certificato e il timer per il rinnovo.
Il blocco 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 è la riga che viene dimenticata più spesso. Durante una sincronizzazione completa, il file del budget viene caricato per intero. Per impostazione predefinita, nginx limita il corpo della richiesta a 1 MB. Quando il file supera questa dimensione, la sincronizzazione non riesce e nel log degli accessi di nginx compare 413 Request Entity Too Large, mentre l'applicazione mostra soltanto un errore generico di sincronizzazione. Il server applica limiti separati: ACTUAL_UPLOAD_FILE_SYNC_SIZE_LIMIT_MB è impostato per impostazione predefinita su 20 e ACTUAL_UPLOAD_SYNC_ENCRYPTED_FILE_SYNC_SIZE_LIMIT_MB su 50. Imposta quindi il limite di nginx sopra il valore applicabile nel tuo caso.
Ricarica la configurazione ed esegui il test:
sudo nginx -t && sudo systemctl reload nginx
curl -fsS -o /dev/null -w '%{http_code}\n' https://budget.example.com/Prima esecuzione: la password e il primo file di budget
Apri https://budget.example.com in un browser. La prima schermata chiede di impostare una password per il server. Questa password protegge l'intero server, quindi generane una lunga e casuale e conservala in un luogo che potrai ritrovare, ad esempio in un gestore di password Vaultwarden self-hosted. Non è necessario creare account utente. Il server di Actual utilizza una sola password per progettazione: condividere un budget significa quindi condividere quella password.
Crea quindi un file di budget. Actual chiede se vuoi abilitare la crittografia end-to-end. Rispondi di sì: il server memorizzerà soltanto dati cifrati, che è la scelta corretta per i dati finanziari archiviati su una macchina a noleggio. Il compromesso è concreto: la password di crittografia non raggiunge mai il server. Se la perdi, il file non può essere recuperato e non esiste una procedura di reimpostazione. Annotala prima di proseguire oltre quella schermata.
Imposta i saldi iniziali usando i valori aggiornati della tua banca, invece di importare anni di cronologia. Il metodo del budget a buste parte dal denaro che hai ora, quindi una cronologia vuota non comporta alcuna perdita.
Importazione delle transazioni
Qui è importante essere realistici, non entusiasti, perché l’importazione è il motivo principale per cui molte persone abbandonano il budgeting self-hosted.
L’inserimento manuale è la base e funziona sempre. Con il metodo a buste è probabilmente il punto centrale: digitare un acquisto aiuta a rendersi conto della spesa.
L’importazione da file gestisce la maggior parte delle transazioni. Actual legge CSV, QIF, OFX e QFX, e ogni banca consente di esportare almeno uno di questi formati. Esegui l’importazione per account dalla schermata dell’account, associa le colonne una sola volta e Actual memorizzerà quel layout per l’account.
È disponibile anche la sincronizzazione automatica con le banche, ma richiede un servizio di terze parti perché il server non può comunicare direttamente con le banche. Actual supporta SimpleFIN Bridge per le banche nordamericane, Enable Banking per l’Europa, Akahu per la Nuova Zelanda e Pluggy.ai per il Brasile. GoCardless è ancora supportato, ma non accetta nuovi account. Devi registrarti direttamente presso il provider, generare le credenziali e aggiungerle al server. A luglio 2026 SimpleFIN Bridge costa 15 dollari statunitensi all’anno per un massimo di 25 istituti; gli altri servizi applicano prezzi diversi.
Prima di fare affidamento su questa funzione, considera due limitazioni. Le credenziali API risiedono sul server e non sono protette dalla crittografia end-to-end, perché il server deve utilizzarle. Inoltre Actual non esegue il polling: la sincronizzazione si avvia premendo un pulsante, non tramite un job in background.
Backup, perché si tratta solo di file
Tutto ciò che serve si trova in /opt/actual/data. Non è necessario esportare dati né creare un dump del database tramite script.
L’unico aspetto critico è SQLite. Copiare account.sqlite mentre il server sta scrivendo al suo interno può acquisire una transazione non completata. Te ne accorgerai solo quando proverai a eseguire il ripristino. Arresta il container per i pochi secondi necessari alla copia:
cd /opt/actual
docker compose stop
restic -r sftp:backup@backup.example.com:/srv/restic backup /opt/actual/data
docker compose startPianifica questa operazione seguendo l’approccio descritto in backup restic su un VPS, che illustra la configurazione del repository, la conservazione dei backup e la procedura di ripristino. Esegui la procedura di ripristino. Un backup che non hai mai ripristinato è solo un’ipotesi.
I backup lato client di Actual sono un’altra cosa e vale la pena conoscerli. Il browser conserva copie recenti del file del budget, accessibili dal menu dei file. Questo consente di gestire il caso in cui elimini per errore una categoria senza intervenire sul server.
Aggiornamento del server
cd /opt/actual
docker compose pull
docker compose up --detachCompose ricrea il container dalla nuova immagine e ricollega lo stesso volume, quindi i dati restano disponibili. Aggiorna anche i client. È previsto che le versioni del server e dell’applicazione restino allineate; un client molto più vecchio del server può rifiutare la sincronizzazione e mostrare un messaggio di incompatibilità delle versioni. Esegui un backup prima di un salto di versione principale, perché le migrazioni vengono eseguite al primo avvio e non è possibile effettuare il downgrade. Actual tollera il tag mobile latest perché il suo stato è costituito da una directory di file. Un’applicazione che utilizza un database reale, invece, non offre la stessa tolleranza. La guida self-hosting di Chatwoot descrive i tag fissati e il dump preliminare all’aggiornamento richiesti in questo caso.
Cosa non funziona e cosa vedrai
L'applicazione si carica, ma la sincronizzazione non termina mai. Controlla nel log degli accessi di nginx la voce 413. Questo indica che client_max_body_size è impostato su un valore troppo basso. Un 502, invece, indica che nginx è attivo ma il container non lo è.
Mancano le opzioni di crittografia oppure l'app mobile rifiuta l'URL. La pagina non viene eseguita in un contesto sicuro. Nella barra degli indirizzi comparirà http:// con un indirizzo IP o un nome host che non è localhost. Correggi il certificato invece di aggirare il problema.
Viene visualizzato un messaggio che indica che il file di budget non è compatibile con questa versione. Le versioni del client e del server non sono più allineate. Aggiorna entrambi alla stessa release e ricarica la pagina.
Il container si riavvia in un ciclo continuo. Leggi docker compose logs actual. Un errore di autorizzazione su /data indica che la directory montata non è scrivibile dall'utente del container. Un errore di indirizzo già in uso indica che un altro processo sta già usando la porta 5006 sull'interfaccia di loopback.
Il primo caricamento sembra lento. Quando apri il file di budget, l'intero file viene scaricato nel browser. Prima viene eseguito un unico trasferimento di grandi dimensioni, poi le letture locali. Non è un problema di dimensionamento del server e aggiungere RAM non cambierà il comportamento.
FAQ
Actual Budget ha bisogno di HTTPS per funzionare?
Sì, in pratica. La crittografia end-to-end di Actual usa la Web Crypto API del browser, che i browser espongono solo in un contesto sicuro, cioè https:// o http://localhost. In HTTP non cifrato da un altro computer, queste funzionalità non sono disponibili e le app mobili ufficiali rifiutano l'URL di un server HTTP non cifrato. Usa un certificato Let's Encrypt su un hostname reale oppure un certificato autofirmato con ACTUAL_HTTPS_KEY e ACTUAL_HTTPS_CERT se utilizzi esclusivamente un browser desktop.
Actual può importare automaticamente le transazioni bancarie?
Solo tramite un servizio di terze parti a cui ti registri personalmente: SimpleFIN Bridge in Nord America, Enable Banking in Europa, Akahu in Nuova Zelanda oppure Pluggy.ai in Brasile. GoCardless è supportato, ma non accetta nuovi account. Queste credenziali API risiedono sul tuo server e non sono coperte dalla crittografia end-to-end. Anche la sincronizzazione è manuale: devi premere un pulsante e non viene eseguito alcun polling in background. L'importazione di file CSV, QIF, OFX e QFX non richiede servizi di terze parti.
Che cosa devo includere esattamente nei backup?
La directory dei dati montata, che in questa guida è /opt/actual/data. Contiene server-files/account.sqlite, con gli accessi e le sessioni, e user-files, con i file del budget. Arresta il container prima di copiarla, perché la copia di un database SQLite in uso può includere una scrittura parziale. Nessun altro elemento sul server contiene dati persistenti.
Che cosa succede se perdo la password di crittografia?
Il file non può essere recuperato. La password non raggiunge mai il server, che è l'obiettivo della crittografia end-to-end; quindi non è possibile reimpostarla e non esiste una procedura di recupero tramite il supporto. Salvala in un password manager subito dopo aver creato il file e conserva una copia in un luogo che non dipenda dallo stesso server.
Di quante risorse server ha bisogno Actual Budget?
Di poche. Il container distribuisce risorse statiche e file, mentre i calcoli del budget vengono eseguiti nel browser. Un vCPU condiviso con 1 GB di RAM è sufficiente per eseguirlo senza problemi e la directory dei dati di un budget familiare con diversi anni di cronologia rimane nell'ordine di alcune decine di megabyte. La pressione sul disco dipende dai backup e dagli altri container, non da Actual. Se stai dimensionando un server che deve eseguire anche un'applicazione più esigente, di solito è un photo server a determinare il requisito minimo; quindi verifica quanta RAM richiedono effettivamente PhotoPrism e Immich prima di scegliere un piano.