chore(ops): move instance state to /var/lib/homarr without touching the image

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
zacharyandClaude Opus 5 committed 2026-09-13 22:43:37 +02:00
1 parent 34d45d7448
commit a029760f66
3 files changed
+119 -20

No files matched your search

+28
View File
@@ -24,6 +24,34 @@ Après déploiement, le contrôle qui compte n'est pas que le nouveau widget
s'affiche : c'est que les intégrations **préexistantes** fonctionnent encore.
C'est la seule preuve que `SECRET_ENCRYPTION_KEY` n'a pas bougé.
## Déplacer l'état hors de /appdata
`/appdata` vient de l'image Docker, où c'est un point de montage. Sur une
machine, il ne suit aucune convention : l'état d'un service se range sous
`/var/lib`. La correction se fait sur l'**instance installée**, jamais dans le
dépôt — ni le code ni le Dockerfile ne sont touchés, sans quoi chaque rebase sur
l'amont rouvrirait le sujet.
```bash
sudo ops/use-var-lib-homarr.sh /opt/homarr # ou /opt/homarr-dev
```
Le script réécrit `/appdata` en `/var/lib/homarr` dans le `run.sh` et le
`redis.conf` de l'instance, sauvegarde chaque fichier avant de le toucher, et
ajoute `LOCAL_CERTIFICATE_PATH` au démarrage. Cette dernière ligne n'est pas
cosmétique : le chemin des certificats n'est pas lu par `run.sh` mais par
l'application, qui retombe sur le dossier de l'image dès qu'il manque — elle
recréerait donc `/appdata` au premier certificat chargé.
Le script ne déplace **pas** les données ; il imprime les commandes à passer une
fois, service arrêté. Sur cette installation, `/appdata` ne contient qu'un
fichier : le certificat racine qui valide la console UniFi locale. Le contrôle
d'après-déplacement est donc tout trouvé — si le widget UniFi OS répond encore,
le certificat a suivi.
À relancer après chaque assemblage : `ops/assemble-standalone.sh` recopie le
`run.sh` du dépôt quand l'instance n'en a pas, et celui-là parle de `/appdata`.
## Suivre les mises à jour d'Homarr
Aujourd'hui `origin` pointe sur le dépôt d'Homarr lui-même et **aucune copie
+87
View File
@@ -0,0 +1,87 @@
#!/usr/bin/env bash
#
# Fait pointer une instance Homarr installée sur /var/lib/homarr au lieu de
# /appdata.
#
# `/appdata` vient de l'image Docker, où c'est un point de montage. Sur une
# machine, il ne suit aucune convention : l'état d'un service se range sous
# /var/lib. Ce script agit sur l'INSTANCE INSTALLÉE — son `run.sh`, son
# `redis.conf` — et jamais sur le dépôt : ni le code source ni le Dockerfile ne
# sont touchés, pour que le fork reste rebasable sur l'amont.
#
# Idempotent : le relancer ne fait rien de plus.
#
# Usage : ops/use-var-lib-homarr.sh <répertoire de l'instance>
# ex. : sudo ops/use-var-lib-homarr.sh /opt/homarr
# sudo ops/use-var-lib-homarr.sh /opt/homarr-dev
#
set -euo pipefail
DIR="${1:?usage: ops/use-var-lib-homarr.sh <dossier-instance>}"
STATE="${HOMARR_STATE_DIR:-/var/lib/homarr}"
stamp="$(date +%F-%H%M%S)"
[ -d "$DIR" ] || { echo "$DIR n'existe pas." >&2; exit 1; }
[ -f "$DIR/run.sh" ] || { echo "$DIR/run.sh introuvable — est-ce bien une instance assemblée ?" >&2; exit 1; }
changed=0
for file in run.sh redis.conf; do
target="$DIR/$file"
[ -f "$target" ] || continue
grep -q '/appdata' "$target" || continue
cp -a "$target" "$target.bak-$stamp"
sed -i "s#/appdata#$STATE#g" "$target"
echo "== $file"
diff -u "$target.bak-$stamp" "$target" | sed -n '4,$p' || true
changed=1
done
# Le chemin des certificats n'est pas lu par run.sh mais par l'application, qui
# retombe sur /appdata/trusted-certificates quand la variable est absente.
# Réécrire les `mkdir` ne suffit donc pas : sans cette ligne, Homarr créerait à
# nouveau /appdata au premier chargement de certificat.
if ! grep -q 'LOCAL_CERTIFICATE_PATH' "$DIR/run.sh"; then
[ -f "$DIR/run.sh.bak-$stamp" ] || cp -a "$DIR/run.sh" "$DIR/run.sh.bak-$stamp"
awk -v value="$STATE/trusted-certificates" '
NR == 1 {
print
print ""
print "# Chemin des certificats de confiance. Sans cette ligne, l'\''application"
print "# retombe sur le dossier de l'\''image et le recrée au premier certificat lu."
print "export LOCAL_CERTIFICATE_PATH=\"${LOCAL_CERTIFICATE_PATH:-" value "}\""
next
}
{ print }
' "$DIR/run.sh" > "$DIR/run.sh.new"
cat "$DIR/run.sh.new" > "$DIR/run.sh" # préserve les droits et le propriétaire
rm -f "$DIR/run.sh.new"
echo "== run.sh : LOCAL_CERTIFICATE_PATH ajouté ($STATE/trusted-certificates)"
changed=1
fi
if [ "$changed" -eq 0 ]; then
echo "Rien à faire : $DIR ne référence déjà plus /appdata."
exit 0
fi
mkdir -p "$STATE/trusted-certificates"
cat <<EOF
Instance $DIR réglée sur $STATE. Sauvegardes : *.bak-$stamp
Il reste les DONNÉES, que ce script ne déplace pas — c'est à faire une fois,
service arrêté, et c'est irréversible sans sauvegarde :
sudo systemctl stop homarr
sudo mv /appdata/trusted-certificates/*.pem $STATE/trusted-certificates/ 2>/dev/null || true
sudo find /appdata -type f # doit ne RIEN afficher avant la suite
sudo rm -rf /appdata
sudo systemctl start homarr
Le contrôle qui compte ensuite : l'intégration UniFi OS doit toujours répondre.
C'est elle qui valide son certificat avec le CA déplacé — si elle fonctionne,
le déplacement a réussi.
EOF
+4 -20
View File
@@ -1,25 +1,9 @@
#!/usr/bin/env bash
# Create the directories this instance will actually write to.
#
# Derived from the configuration rather than hard-coded, so an installation that
# stores its state elsewhere — a bare-metal one under /var/lib, say — does not
# get an empty /appdata recreated behind its back at every start. The defaults
# reproduce the image's layout exactly: the Dockerfile sets DB_URL to
# /appdata/db/db.sqlite and DB_DIALECT to sqlite, and REDIS_IS_EXTERNAL to false.
mkdir -p "${LOCAL_CERTIFICATE_PATH:-/appdata/trusted-certificates}"
# Only for SQLite: on any other engine DB_URL is a connection string, and its
# dirname would be a meaningless path.
if [ "${DB_DIALECT:-sqlite}" = "sqlite" ]; then
mkdir -p "$(dirname "${DB_URL:-/appdata/db/db.sqlite}")"
fi
# The bundled Redis reads its directory from redis.conf; creating it when an
# external server is used would leave an empty directory nobody writes to.
if [ "$REDIS_IS_EXTERNAL" != "true" ]; then
mkdir -p /appdata/redis
fi
# Create sub directories in volume
mkdir -p /appdata/db
mkdir -p /appdata/redis
mkdir -p /appdata/trusted-certificates
# Run migrations
if [ "$DB_MIGRATIONS_DISABLED" = "true" ]; then