← Retour au homelab
Nutry Sauvegarde

Autohéberger le backend de Nutry

Le service, la séparation du code et des données, les sauvegardes, et un déploiement qui garde la version précédente.

Date 4 octobre 2026
Lecture 4 min

Nutry a un client web et un client iPhone. Les deux parlent à un backend hébergé sur la VM des services. Cet article décrit comment ce backend tourne, comment il est sauvegardé, et comment une nouvelle version remplace l’ancienne sans effacer les données. Les dossiers réels ne sont pas nommés. On parle seulement de trois emplacements : le code, les données, la configuration.

Le service est une unité systemd de l’utilisateur, pas de root. Le linger est activé, donc le service démarre sans qu’une session soit ouverte. Au relevé du 4 octobre 2026, il était actif depuis 12 h 59, et il n’avait pas redémarré depuis. L’unité est pourtant réglée pour redémarrer en cas d’échec, après 5 secondes. L’arrêt propre est accepté.

La pile logicielle

L’application est un Next.js 16.2.12 en sortie standalone, avec React 19.2.6. Elle est lancée par Node.js 24.13.0, installé via nvm, avec node server.js. La base est SQLite, via better-sqlite3 en version 12, en mode WAL. Les photos sont dans un dossier de données à part, pas dans le dossier du code.

Code, données et configuration sont trois dossiers distincts. La configuration est un fichier d’environnement aux droits restreints au seul compte du service. L’intérêt de cette coupe est mécanique : remplacer tout le code ne peut pas écraser les données ni la configuration. C’est la condition pour qu’un déploiement soit réversible.

L’unité durcit un peu le processus. Elle interdit les nouveaux privilèges, isole un dossier temporaire privé, et protège le système en lecture. L’écriture n’est autorisée que dans le dossier de données. L’extrait suivant illustre ces réglages. Ce n’est pas le fichier installé, et il ne contient aucun chemin réel.

[Service]
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=full
Restart=on-failure
RestartSec=5
ExecStart=node server.js

Sauvegardes

Un minuteur de l’utilisateur lance une sauvegarde 10 minutes après le démarrage, puis toutes les 6 heures. Le rattrapage est activé si la machine a manqué une échéance, et un décalage aléatoire de 5 minutes évite de tomber toujours sur la même seconde. Le script pose d’abord un verrou. Il fait une copie cohérente de la base avec la commande de backup de sqlite3. Il vérifie cette copie avec un contrôle d’intégrité. Il écrit un manifeste : empreinte SHA-256, et nombre de lignes de chaque table. Il copie aussi les photos et la configuration.

La rétention est de 56 instantanés, soit 14 jours. Un script de restauration fait un essai à blanc par défaut. Il ne remplace les données qu’avec une option explicite, et seulement après avoir mis de côté une copie d’urgence de ce qui est en place. On peut donc regarder une sauvegarde sans l’appliquer.

# Étapes observées, avec des noms fictifs.
sqlite3 base.sqlite ".backup sauvegarde.sqlite"
sqlite3 sauvegarde.sqlite "PRAGMA integrity_check;"
# puis manifeste : empreinte et nombre de lignes par table

Déployer, et pouvoir revenir

Les traces sur le serveur montrent le déroulé suivant. Le build est npm run build, puis un script de post-build prépare le dossier standalone. Le serveur garde la version active et la précédente, dans deux dossiers distincts. Avant chaque déploiement, il conserve une copie horodatée de l’ancien standalone, une copie de la base, et le nombre de lignes de chaque table. Le commit déployé est noté dans un fichier, puis le service utilisateur est redémarré. Le dernier déploiement relevé date du 3 octobre 2026, à 17 h 04.

Garder la version précédente est le rollback. Si la nouvelle ne répond pas, on peut remettre l’ancienne à côté des données, qui n’ont pas bougé de leur dossier. Le contrôle des lignes, avant et après, dit si la base a changé de volume pendant l’opération.

Deux choses n’ont pas été trouvées : l’endroit exact du build, sur la VM ou ailleurs avant copie, et l’outil qui fait la bascule. Le déroulé ci-dessus vient des traces laissées sur le serveur, pas d’un journal de pipeline. Nutry a par ailleurs été migré depuis une autre VM Debian vers celle-ci autour du 23 septembre 2026. Un dossier de reprise porte cette date.

Le client iPhone, lui, ne part pas de cette VM. Il suit Xcode Cloud et TestFlight, comme Wavy. C’est le sujet de l’article sur la chaîne iOS. Ici, le backend se résume à trois idées : un service utilisateur qui survit à la déconnexion, des données séparées du code, et une sauvegarde vérifiée avant d’être digne de confiance.

Les autres articles