SSD Nodes Learn 8GB de RAM — $66/an
Guides Matt ConnorPar Matt Connor · Mis à jour le 2026-08-02

Installer Actual Budget sur votre VPS avec Docker

Déployez Actual Budget avec Docker Compose sur un VPS : volume de données, HTTPS obligatoire dans le navigateur, premier budget, imports bancaires et sauvegardes.

Ce que vous allez construire

Actual Budget est une application de gestion budgétaire par enveloppes auto-hébergée. C’est généralement la solution recherchée par les personnes qui veulent une alternative à YNAB qu’elles peuvent héberger elles-mêmes. Le serveur se compose d’un conteneur, d’un volume de données et d’un nom HTTPS. Toutes les fonctions nécessaires à un budget standard s’exécutent correctement sur le plus petit VPS disponible à la location, car le serveur stocke principalement des fichiers et les synchronise.

Il est utile de comprendre l’architecture avant de saisir quoi que ce soit. Le budget lui-même est une base de données SQLite présente dans votre navigateur et dans chaque application mobile. Le serveur que vous allez installer est un endpoint de synchronisation. Il contient la liste des comptes, les fichiers de budget et le journal des modifications qui permet à un téléphone et à un ordinateur portable de rester synchronisés. C’est pourquoi l’application continue de fonctionner lorsque le serveur est indisponible. C’est également pourquoi la perte du serveur n’entraîne pas celle de votre budget, tant qu’un client en conserve encore une copie.

Pourquoi le serveur a besoin de HTTPS

Actual exige HTTPS, et ce n’est pas une formalité. Les navigateurs exposent l’API Web Crypto, l’interface qu’Actual utilise pour son chiffrement de bout en bout, uniquement dans ce que la spécification appelle un contexte sécurisé. Un contexte sécurisé est https:// ou http://localhost. Chargez l’application depuis http://203.0.113.10:5006 dans un navigateur sur une autre machine : ces fonctionnalités sont absentes, car le navigateur ne les a jamais transmises à la page. Les versions mobiles officielles refusent également l’URL de serveur http:// non chiffrée.

Deux configurations sont donc possibles. Placez un véritable certificat sur un véritable nom de domaine devant le conteneur, comme dans ce guide. Ou fournissez au serveur un certificat autosigné avec ACTUAL_HTTPS_KEY et ACTUAL_HTTPS_CERT, comme l’indique la documentation du projet, puis acceptez un avertissement du navigateur sur chaque appareil. Un certificat gratuit de Let's Encrypt s’obtient en cinq minutes. Choisissez donc la première option.

Installer Actual Budget avec Docker Compose

Installez d’abord Docker si le serveur est vierge. Si la syntaxe des fichiers Compose est nouvelle pour vous, le guide Notions de base sur Docker Compose pour un VPS présente les champs utilisés ci-dessous.

sudo install -d -m 755 /opt/actual
sudo install -d -m 700 /opt/actual/data

Écrivez /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

Trois éléments de ce fichier sont importants.

L’image est actualbudget/actual-server:latest, publiée par le projet sur Docker Hub et disponible en miroir à l’adresse ghcr.io/actualbudget/actual. Le tag latest-alpine est prévu pour les machines peu puissantes.

Le conteneur écrit toutes ses données sous /data. Vous y trouvez server-files, qui contient account.sqlite avec vos identifiants de connexion et vos jetons de session, ainsi que user-files, qui contient les fichiers de budget. Montez ce chemin, sinon la prochaine commande docker compose pull supprimera votre budget. ACTUAL_DATA_DIR peut le modifier, mais la valeur par défaut convient.

Le port est publié uniquement sur 127.0.0.1. Un simple 5006:5006 le publie sur toutes les interfaces. Docker place ses propres règles avant celles d’ufw. L’application serait donc accessible depuis Internet, même avec un pare-feu qui refuse tout le trafic. Cette particularité est expliquée dans pourquoi les ports publiés par Docker contournent ufw. Une liaison à loopback signifie que seul le reverse proxy du même serveur peut y accéder.

Démarrez le conteneur :

cd /opt/actual
docker compose up --detach
docker compose logs -f actual

Le journal se stabilise lorsque le serveur indique qu’il écoute sur le port 5006. Vérifiez son fonctionnement localement avant de modifier le DNS :

curl -fsS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:5006/

Un 200 signifie que l’application répond. Un curl: (7) Failed to connect signifie que le conteneur n’est pas en cours d’exécution, et docker compose ps indique qu’il s’est arrêté. La cause habituelle est un problème de permissions sur le volume monté, visible sous la forme d’une ligne EACCES dans le journal.

Placez un certificat et un vrai nom de domaine devant

Pointez un enregistrement A vers le VPS, budget.example.com, puis attendez sa résolution. Installez ensuite nginx et émettez le certificat. Le guide Certbot sur Ubuntu 24.04 avec nginx explique en détail l’émission du certificat et le timer de renouvellement.

Le bloc 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 est la ligne que l’on oublie souvent. Le fichier budgétaire est téléversé en entier lors d’une synchronisation complète. Nginx limite par défaut le corps des requêtes à 1 MB. Lorsque le fichier dépasse cette taille, la synchronisation échoue avec 413 Request Entity Too Large dans le journal d’accès nginx, tandis que l’application n’affiche qu’une erreur de synchronisation générique. Le serveur applique ses propres limites distinctes : ACTUAL_UPLOAD_FILE_SYNC_SIZE_LIMIT_MB vaut 20 par défaut et ACTUAL_UPLOAD_SYNC_ENCRYPTED_FILE_SYNC_SIZE_LIMIT_MB vaut 50 par défaut. Définissez donc la limite nginx au-dessus de celle qui s’applique à votre cas.

Rechargez la configuration et testez :

sudo nginx -t && sudo systemctl reload nginx
curl -fsS -o /dev/null -w '%{http_code}\n' https://budget.example.com/

Première exécution : le mot de passe et votre premier fichier budgétaire

Ouvrez https://budget.example.com dans un navigateur. Le premier écran vous demande de définir un mot de passe serveur. Ce mot de passe unique protège l’ensemble du serveur. Générez-en un long et aléatoire, puis conservez-le dans un endroit où vous pourrez le retrouver, par exemple dans un gestionnaire de mots de passe Vaultwarden auto-hébergé. Vous n’avez aucun compte utilisateur à créer. Le serveur Actual est conçu pour utiliser un seul mot de passe. Partager un budget revient donc à partager ce mot de passe.

Créez ensuite un fichier budgétaire. Actual vous demande si vous souhaitez activer le chiffrement de bout en bout. Répondez oui. Le serveur ne stockera alors que du texte chiffré, ce qui convient aux données financières hébergées sur une machine louée. Cette protection a un coût réel : le mot de passe de chiffrement n’est jamais transmis au serveur. Si vous le perdez, le fichier est irrécupérable et aucune réinitialisation n’est possible. Notez-le avant de quitter cet écran.

Définissez vos soldes de départ à partir des montants actuels indiqués par votre banque, au lieu d’importer des années d’historique. La méthode du budget par enveloppes part de l’argent dont vous disposez maintenant. L’absence d’historique ne vous pénalise donc pas.

Importer des transactions

C’est ici que l’honnêteté compte davantage que l’enthousiasme, car l’importation est la principale raison pour laquelle les utilisateurs abandonnent les outils de gestion budgétaire auto-hébergés.

La saisie manuelle est la méthode de base et elle fonctionne toujours. Avec la méthode des enveloppes, c’est même probablement le but, car saisir un achat vous oblige à en prendre conscience.

L’importation de fichiers traite la majeure partie des transactions. Actual lit les formats CSV, QIF, OFX et QFX, et chaque banque en propose au moins un. Importez les données compte par compte depuis l’écran du compte, associez les colonnes une seule fois, puis Actual mémorise cette configuration pour le compte.

La synchronisation automatique avec les banques existe, mais elle nécessite un service tiers, car le serveur ne peut pas communiquer directement avec les banques. Actual prend en charge SimpleFIN Bridge pour les banques nord-américaines, Enable Banking pour l’Europe, Akahu pour la Nouvelle-Zélande et Pluggy.ai pour le Brésil. GoCardless reste pris en charge, mais n’accepte plus de nouveaux comptes. Vous devez créer vous-même un compte auprès du fournisseur, générer les identifiants, puis les ajouter au serveur. En juillet 2026, SimpleFIN Bridge facture 15 dollars US par an pour un maximum de 25 établissements. Les autres services appliquent des tarifs différents.

Vous devez accepter deux limites avant de vous appuyer sur cette fonctionnalité. Les identifiants d’API sont stockés sur le serveur et ne sont pas couverts par le chiffrement de bout en bout, car le serveur doit les utiliser. De plus, Actual n’effectue pas d’interrogation périodique : la synchronisation se lance en appuyant sur un bouton, et non comme une tâche en arrière-plan.

Les sauvegardes, parce qu’il ne s’agit que de fichiers

Tout ce qui vous importe se trouve sous /opt/actual/data. Il n’y a pas d’étape d’export ni de dump de base de données à automatiser.

Le seul piège concerne SQLite. Copier account.sqlite pendant que le serveur y écrit peut capturer une transaction incomplète. Vous ne le découvrirez qu’au moment de tenter une restauration. Arrêtez le conteneur pendant les quelques secondes nécessaires à la copie :

cd /opt/actual
docker compose stop
restic -r sftp:backup@backup.example.com:/srv/restic backup /opt/actual/data
docker compose start

Planifiez cette opération en suivant l’approche présentée dans les sauvegardes restic sur un VPS. Cette approche couvre la configuration du dépôt, la rétention et le test de restauration. Effectuez le test de restauration. Une sauvegarde que vous n’avez jamais restaurée n’est qu’une supposition.

Les sauvegardes côté client d’Actual constituent un mécanisme distinct qu’il est utile de connaître. Le navigateur conserve des copies récentes du fichier de budget, accessibles depuis le menu des fichiers. Cela permet de résoudre le problème « j’ai supprimé une catégorie par erreur » sans toucher au serveur.

Mise à jour du serveur

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

Compose recrée le conteneur à partir de la nouvelle image et rattache le même volume. Les données sont donc conservées. Mettez également les clients à jour. Les versions du serveur et de l’application doivent rester proches. Un client beaucoup plus ancien que le serveur peut refuser la synchronisation et afficher un message d’incompatibilité de version. Effectuez une sauvegarde avant un saut de version majeur. Les migrations s’exécutent au premier démarrage et aucun retour à une version antérieure n’est possible.

Ce qui ne fonctionne pas et ce que vous verrez

L’application se charge, mais la synchronisation ne se termine jamais. Surveillez le journal d’accès nginx pour 413. Cela signifie que client_max_body_size est trop bas. Un 502 signifie plutôt que nginx fonctionne, mais que le conteneur ne fonctionne pas.

Les options de chiffrement sont absentes ou l’application mobile refuse l’URL. La page n’est pas dans un contexte sécurisé. La barre d’adresse affiche http:// avec une adresse IP ou un nom d’hôte qui n’est pas localhost. Corrigez le certificat au lieu de contourner le problème.

Un message indique que le fichier de budget n’est pas compatible avec cette version. Les versions du client et du serveur ne correspondent plus. Mettez-les à jour vers la même release, puis rechargez la page.

Le conteneur redémarre en boucle. Consultez docker compose logs actual. Une erreur d’autorisation sur /data signifie que le répertoire monté n’est pas accessible en écriture pour l’utilisateur du conteneur. Une erreur indiquant que l’adresse est déjà utilisée signifie qu’un autre processus utilise déjà le port 5006 sur l’interface loopback.

Le premier chargement semble lent. Le navigateur télécharge l’intégralité du fichier de budget lorsque vous l’ouvrez. Il s’agit d’un transfert important, suivi de lectures locales. Ce n’est pas un problème de dimensionnement du serveur, et ajouter de la RAM ne changera rien.

FAQ

Actual Budget a-t-il besoin de HTTPS pour fonctionner ?

Oui, en pratique. Le chiffrement de bout en bout d'Actual utilise la Web Crypto API du navigateur. Les navigateurs ne l'exposent que dans un contexte sécurisé, c'est-à-dire https:// ou http://localhost. En HTTP simple depuis une autre machine, ces fonctionnalités sont indisponibles. Les applications mobiles officielles refusent également l'URL d'un serveur en HTTP simple. Utilisez un certificat Let's Encrypt sur un vrai hostname, ou un certificat auto-signé avec ACTUAL_HTTPS_KEY et ACTUAL_HTTPS_CERT si vous utilisez uniquement un navigateur de bureau.

Actual peut-il importer automatiquement les transactions de ma banque ?

Uniquement via un service tiers auquel vous vous inscrivez vous-même : SimpleFIN Bridge en Amérique du Nord, Enable Banking en Europe, Akahu en Nouvelle-Zélande ou Pluggy.ai au Brésil. GoCardless est pris en charge, mais n'accepte plus de nouveaux comptes. Ces identifiants d'API sont stockés sur votre serveur et ne sont pas couverts par le chiffrement de bout en bout. La synchronisation est également manuelle : vous appuyez sur un bouton et aucun processus n'interroge le service en arrière-plan. L'importation de fichiers CSV, QIF, OFX et QFX ne nécessite aucun tiers.

Que dois-je sauvegarder exactement ?

Le répertoire de données monté, qui est /opt/actual/data dans ce guide. Il contient server-files/account.sqlite avec les identifiants de connexion et les sessions, ainsi que user-files avec les fichiers de budget. Arrêtez le container avant la copie. La copie d'une base de données SQLite active peut capturer une écriture partielle. Aucun autre élément du serveur ne contient de données persistantes.

Que se passe-t-il si je perds le mot de passe de chiffrement ?

Le fichier ne peut pas être récupéré. Le mot de passe n'atteint jamais le serveur, ce qui est précisément le but du chiffrement de bout en bout. Il n'existe donc ni procédure de réinitialisation ni solution via le support. Enregistrez-le dans un gestionnaire de mots de passe dès que vous créez le fichier. Conservez également une copie à un emplacement qui ne dépend pas de ce même serveur.

De quelles ressources serveur Actual Budget a-t-il besoin ?

De très peu. Le container fournit les ressources statiques et les fichiers. Les calculs du budget sont effectués dans le navigateur. Un vCPU partagé avec 1 GB de RAM suffit à l'exécuter sans problème. Le répertoire de données d'un budget familial contenant plusieurs années d'historique reste de l'ordre de quelques dizaines de mégaoctets. La pression sur le disque vient de vos sauvegardes et de vos autres containers, pas d'Actual.