Ouvre une voie d'hébergement hors YunoHost, en disant ce qu'elle coûte
Un tiers veut installer le projet sur un Synology, où rien du paquet `_ynh` n'existe. L'application n'étant qu'un processus et un fichier SQLite, un `Dockerfile` suffit — mais l'essentiel n'est pas là. Sans portail SSO, il n'y a pas d'identité, et l'application ne s'en invente pas : les données personnelles se ferment, les communes non. Mesuré plutôt que supposé, et écrit comme tel : les deux replis (utilisateur simulé, en-tête injecté) n'authentifient personne, et le port ne doit être publié que sur la boucle locale. Le déploiement de référence reste `mabibli_ynh`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,11 @@
|
|||||||
|
# Le contexte de build ne doit porter que les sources : recopier les `bin/` et `obj/` de
|
||||||
|
# la machine de développement ralentit le build et, pire, peut faire réutiliser des
|
||||||
|
# artefacts compilés pour un autre système.
|
||||||
|
**/bin/
|
||||||
|
**/obj/
|
||||||
|
.git/
|
||||||
|
.idea/
|
||||||
|
.claude/
|
||||||
|
*.db
|
||||||
|
*.db-wal
|
||||||
|
*.db-shm
|
||||||
@@ -2054,6 +2054,62 @@ lui-même** pour les afficher dans son catalogue et son interface d'administrati
|
|||||||
compilation, et rien n'est recompilé sur le serveur. Le manifeste déclare donc
|
compilation, et rien n'est recompilé sur le serveur. Le manifeste déclare donc
|
||||||
l'application en `full_domain`.
|
l'application en `full_domain`.
|
||||||
|
|
||||||
|
## Héberger hors YunoHost — voie SECONDAIRE, ajoutée le 2026-08-21
|
||||||
|
|
||||||
|
Demande venue d'un tiers voulant installer le projet sur un **Synology**. `Dockerfile`,
|
||||||
|
`.dockerignore` et `compose.yaml` sont à la racine du dépôt du code, et la marche à suivre
|
||||||
|
est dans `README.md` (« Installer ailleurs que sur YunoHost »).
|
||||||
|
|
||||||
|
⚠️ **Le déploiement de référence reste `mabibli_ynh`, et cela ne se discute pas** : c'est le
|
||||||
|
seul qui apporte une **authentification**. Cette voie-ci n'en apporte aucune, et il ne faut
|
||||||
|
pas la présenter comme une seconde façon d'installer « la même chose ».
|
||||||
|
|
||||||
|
### Ce que l'absence de portail coûte exactement
|
||||||
|
|
||||||
|
Mesuré, pas supposé : sans `YNH_USER`, `UtilisateurCourant.Anonyme` circule, et les données
|
||||||
|
**personnelles** se ferment (`400` avec un message lisible sur les envies, aucun statut de
|
||||||
|
lecture), tandis que tout ce qui est **commun** au foyer continue de fonctionner. C'est la
|
||||||
|
triple portée du projet — commune / personnelle / trace — qui devient visible à l'usage.
|
||||||
|
|
||||||
|
Deux replis, et **aucun des deux n'authentifie** :
|
||||||
|
|
||||||
|
| Repli | Quand |
|
||||||
|
|---|---|
|
||||||
|
| `Identite__UtilisateurSimule` en variable d'environnement | mono-utilisateur ; c'est le mécanisme de développement, qui n'a rien de spécifique à `Development` — c'est de la configuration ordinaire |
|
||||||
|
| en-tête `YNH_USER` injecté par le proxy inversé | dès qu'un proxy authentifiant existe (Authelia…), il n'y a plus qu'à recopier son `Remote-User` — **l'application ne change pas** |
|
||||||
|
|
||||||
|
⚠️ Le corollaire est le même que sur YunoHost et il est **plus facile à rater** ici : le port
|
||||||
|
ne doit être publié que sur `127.0.0.1`. Quiconque atteint le port *est* l'utilisateur
|
||||||
|
déclaré. Dans un conteneur, écouter sur `+:8080` est sans danger — c'est la **publication**
|
||||||
|
du port qui décide de l'exposition, pas l'écoute.
|
||||||
|
|
||||||
|
### Trois décisions d'image
|
||||||
|
|
||||||
|
- **Pas de `--self-contained`** dans le conteneur, contrairement au paquet YunoHost. Le
|
||||||
|
self-contained sert à ne rien exiger d'un serveur qu'on ne maîtrise pas ; l'image `aspnet`
|
||||||
|
fournit déjà le runtime, et l'embarquer une seconde fois ne servirait qu'à grossir.
|
||||||
|
- **Pas d'`ASPNETCORE_URLS`** : l'image écoute déjà sur 8080, et le poser journalise un
|
||||||
|
avertissement `Overriding HTTP_PORTS` à chaque démarrage — du bruit dans les logs, sur la
|
||||||
|
voie précisément destinée à qui ne connaît pas le projet.
|
||||||
|
- **Aucun `dotnet workload install`** n'est nécessaire : vérifié, la machine de
|
||||||
|
développement n'a **aucune** charge de travail installée et le publish Blazor WASM
|
||||||
|
(trimming compris) passe avec le SDK nu.
|
||||||
|
|
||||||
|
### Les trois contraintes reconduites telles quelles
|
||||||
|
|
||||||
|
x86_64 (le publish visé est `linux-x64`), **HTTPS** sans quoi le scan caméra ne s'ouvre
|
||||||
|
jamais, et un **nom d'hôte entier** — `<base href="/">` et les empreintes du service worker
|
||||||
|
sont figés à la compilation, exactement ce qui impose `full_domain` à YunoHost.
|
||||||
|
|
||||||
|
### Vérifié en exécution le 2026-08-21
|
||||||
|
|
||||||
|
Image construite, conteneur démarré sur une base neuve : migrations appliquées dans le
|
||||||
|
volume, `/` et `_framework/blazor.webassembly.js` en 200, et les trois états d'identité
|
||||||
|
(simulée, absente, en-tête `YNH_USER`) rendus par `GET /api/moi` conformément au tableau
|
||||||
|
ci-dessus. ⚠️ **Rien n'a été éprouvé sur un Synology réel** — ni Container Manager, ni le
|
||||||
|
proxy inversé de DSM, ni son certificat. Ce sont des gestes de DSM, pas du code, mais le
|
||||||
|
README doit continuer de le dire.
|
||||||
|
|
||||||
## Historique du projet (pourquoi ces choix)
|
## Historique du projet (pourquoi ces choix)
|
||||||
|
|
||||||
L'utilisateur a testé deux solutions existantes avant de se lancer dans un projet custom :
|
L'utilisateur a testé deux solutions existantes avant de se lancer dans un projet custom :
|
||||||
|
|||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
# Image pour héberger MaBibli AILLEURS que sur YunoHost (Synology, NAS, VPS…).
|
||||||
|
#
|
||||||
|
# ⚠️ Ce n'est PAS le chemin de déploiement de référence : celui-ci reste le paquet
|
||||||
|
# `mabibli_ynh`, qui déploie un publish self-contained sans conteneur (voir README,
|
||||||
|
# « Mettre en production »). Cette image existe pour les hébergements qui n'ont pas de
|
||||||
|
# portail SSO — et elle n'apporte donc AUCUNE authentification. Lire impérativement
|
||||||
|
# « Installer ailleurs que sur YunoHost » dans le README avant de l'exposer.
|
||||||
|
|
||||||
|
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
|
||||||
|
WORKDIR /src
|
||||||
|
|
||||||
|
# `MaBibli.Api` référence `MaBibli.Client` : le client Blazor WebAssembly est compilé au
|
||||||
|
# passage et atterrit dans `wwwroot/`. Un seul projet à publier suffit pour les trois.
|
||||||
|
# Aucun `dotnet workload install` n'est nécessaire : le SDK .NET 10 résout l'outillage
|
||||||
|
# WebAssembly tout seul (vérifié — aucune charge de travail n'est installée en local).
|
||||||
|
COPY . .
|
||||||
|
RUN dotnet publish MaBibli.Api --configuration Release --output /app
|
||||||
|
|
||||||
|
# Pas de `--self-contained` ici, contrairement au paquet YunoHost : l'image `aspnet`
|
||||||
|
# embarque déjà le runtime. Le self-contained sert à ne rien exiger d'un serveur qu'on
|
||||||
|
# ne maîtrise pas ; dans un conteneur, la question ne se pose pas.
|
||||||
|
FROM mcr.microsoft.com/dotnet/aspnet:10.0
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=build /app .
|
||||||
|
|
||||||
|
# La base vit dans un volume, jamais à côté des binaires : c'est ce qui la fait survivre
|
||||||
|
# au remplacement de l'image. Même règle que le `data_dir` de YunoHost.
|
||||||
|
ENV ConnectionStrings__MaBibli="Data Source=/data/mabibli.db"
|
||||||
|
VOLUME ["/data"]
|
||||||
|
|
||||||
|
# L'image `aspnet` écoute déjà sur 8080 : poser `ASPNETCORE_URLS` ne ferait qu'écraser ce
|
||||||
|
# réglage et journaliser un avertissement à chaque démarrage. Pour changer de port,
|
||||||
|
# `ASPNETCORE_HTTP_PORTS`. ⚠️ Écouter sur toutes les interfaces est sûr DANS un conteneur —
|
||||||
|
# c'est la publication du port qui décide de l'exposition, voir `compose.yaml`.
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
ENTRYPOINT ["dotnet", "MaBibli.Api.dll"]
|
||||||
@@ -71,6 +71,10 @@ pour les trois (`MaBibli.Client`, `MaBibli.Shared`, `MaBibli.Api`). `--self-cont
|
|||||||
embarque le runtime .NET dans le dossier produit : aucun `dotnet-runtime` n'est requis
|
embarque le runtime .NET dans le dossier produit : aucun `dotnet-runtime` n'est requis
|
||||||
côté serveur.
|
côté serveur.
|
||||||
|
|
||||||
|
Pour un hébergement **sans YunoHost** (Synology, VPS), voir « Installer ailleurs que sur
|
||||||
|
YunoHost » plus bas : le `Dockerfile` de la racine fait ce même publish, mais sans
|
||||||
|
`--self-contained` — dans un conteneur, l'image `aspnet` fournit déjà le runtime.
|
||||||
|
|
||||||
⚠️ **Ne jamais compiler sur le serveur YunoHost lui-même** : ce serait imposer le SDK
|
⚠️ **Ne jamais compiler sur le serveur YunoHost lui-même** : ce serait imposer le SDK
|
||||||
complet à une machine qui n'en a pas besoin, pour une compilation lente. Voir
|
complet à une machine qui n'en a pas besoin, pour une compilation lente. Voir
|
||||||
`CLAUDE.md`, section « Chaîne de publication ».
|
`CLAUDE.md`, section « Chaîne de publication ».
|
||||||
@@ -468,6 +472,103 @@ Les trois doivent être négatifs. Le domaine, lui, reste déclaré dans YunoHos
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Installer ailleurs que sur YunoHost (Synology, NAS, VPS)
|
||||||
|
|
||||||
|
Le déploiement de référence reste le paquet `mabibli_ynh` : c'est lui qui est éprouvé, et
|
||||||
|
c'est le seul qui apporte une **authentification**. Ce qui suit sert aux hébergements qui
|
||||||
|
n'ont pas de portail SSO. `Dockerfile`, `.dockerignore` et `compose.yaml`, à la racine de
|
||||||
|
ce dépôt, existent pour ça.
|
||||||
|
|
||||||
|
L'application n'est qu'**un processus et un fichier SQLite** : `MaBibli.Api` sert lui-même
|
||||||
|
le client Blazor. Il n'y a donc rien à orchestrer.
|
||||||
|
|
||||||
|
### ⚠️ Hors YunoHost, il n'y a AUCUNE authentification
|
||||||
|
|
||||||
|
C'est le point à comprendre avant tout le reste, et il ne se contourne pas par la
|
||||||
|
configuration. `FournisseurUtilisateurSsowat` lit l'en-tête `YNH_USER` que le portail
|
||||||
|
injecte ; sans portail, il n'y a pas d'identité, et l'application **ne s'en invente pas**.
|
||||||
|
|
||||||
|
Conséquence exacte, vérifiée en exécution :
|
||||||
|
|
||||||
|
| | Sans identité |
|
||||||
|
|---|---|
|
||||||
|
| Catalogue, auteurs, séries, revues, prêts (**communs** au foyer) | fonctionnent |
|
||||||
|
| Statuts de lecture, listes d'envies (**personnels**) | refusés — `400 « Impossible d'ajouter une envie sans savoir à qui elle appartient. »` |
|
||||||
|
|
||||||
|
Deux façons de rendre une identité, **aucune des deux n'authentifie qui que ce soit** :
|
||||||
|
|
||||||
|
- `Identite__UtilisateurSimule` en variable d'environnement. C'est le mécanisme prévu pour
|
||||||
|
le développement, mais c'est de la configuration ordinaire : elle vaut aussi en
|
||||||
|
production. Mono-utilisateur.
|
||||||
|
- l'en-tête `YNH_USER` injecté par le proxy inversé (DSM : *Portail des applications >
|
||||||
|
Proxy inversé > En-tête personnalisé*). Même niveau de sécurité, mais si un proxy
|
||||||
|
authentifiant est ajouté un jour (Authelia, authentik), il n'y a plus qu'à lui faire
|
||||||
|
recopier son `Remote-User` vers `YNH_USER` : l'application n'a rien à changer.
|
||||||
|
|
||||||
|
⚠️ Dans les deux cas, **quiconque atteint le port EST cet utilisateur**. Le port ne doit
|
||||||
|
donc être publié que sur la boucle locale (`127.0.0.1:8080:8080`), le proxy inversé restant
|
||||||
|
le seul chemin d'accès. C'est la transposition exacte de la contrainte d'écoute que le
|
||||||
|
paquet YunoHost pose comme dure.
|
||||||
|
|
||||||
|
### Trois prérequis qui ne se négocient pas
|
||||||
|
|
||||||
|
- **Une machine x86_64.** Le publish visé est `linux-x64` : les NAS ARM (les modèles « j »
|
||||||
|
notamment) demanderaient de republier en `linux-arm64`, ce qui n'est pas éprouvé ici.
|
||||||
|
- **HTTPS**, sans quoi le scan du code-barres ne s'ouvrira **jamais** : la caméra exige un
|
||||||
|
contexte sécurisé. Sur Synology, cela veut dire proxy inversé + certificat Let's Encrypt
|
||||||
|
sur un nom DDNS (`mabibli.xxx.synology.me`).
|
||||||
|
- **Un nom d'hôte entier, pas un sous-chemin** — `mabibli.xxx.synology.me`, jamais
|
||||||
|
`nas.xxx.synology.me/mabibli`. La raison est la même que pour le `full_domain` de
|
||||||
|
YunoHost, et elle est développée plus bas : `<base href="/">` et les empreintes du
|
||||||
|
service worker sont figés à la compilation.
|
||||||
|
|
||||||
|
### La marche à suivre
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone <ce dépôt> mabibli && cd mabibli
|
||||||
|
# éditer compose.yaml : nom d'utilisateur, chemin du volume
|
||||||
|
docker compose up -d --build
|
||||||
|
```
|
||||||
|
|
||||||
|
Sur Synology, le même `compose.yaml` se colle dans *Container Manager > Projet*, en
|
||||||
|
remplaçant `./donnees` par un chemin réel (`/volume1/docker/mabibli`).
|
||||||
|
|
||||||
|
Les migrations EF Core s'appliquent seules au premier démarrage : la base se crée dans le
|
||||||
|
volume, et c'est **le volume seul** qui la fait survivre au remplacement de l'image.
|
||||||
|
|
||||||
|
### Ce qu'il faut savoir avant de s'y mettre
|
||||||
|
|
||||||
|
- **La sauvegarde ne se fait pas en copiant le `.db`.** SQLite tourne en mode WAL : copier
|
||||||
|
le seul fichier d'une base active peut ne rien sauvegarder du tout. Il faut arrêter le
|
||||||
|
conteneur, ou passer par `sqlite3 … ".backup"` — c'est ce que fait le paquet YunoHost, et
|
||||||
|
la raison est écrite dans `mabibli_ynh/doc/ADMIN.md`.
|
||||||
|
- **Il n'y a pas de mécanisme de mise à jour.** Ni `yunohost app upgrade`, ni release, ni
|
||||||
|
vérification de `sha256` : à chaque version, `git pull` puis `docker compose up -d
|
||||||
|
--build`. Les données ne bougent pas, elles sont dans le volume.
|
||||||
|
- **L'image est construite depuis les sources, pas depuis une release.** Elle ne porte donc
|
||||||
|
aucun numéro de version, et « À propos » affiche honnêtement « version de développement ».
|
||||||
|
Pour un vrai numéro, passer `-p:Version=X.Y.Z -p:MaBibliDateBuild=…` au `dotnet publish`
|
||||||
|
du `Dockerfile` — voir `CLAUDE.md`, « Y — l'application dit sa version ».
|
||||||
|
|
||||||
|
### Vérifié en exécution le 2026-08-21
|
||||||
|
|
||||||
|
Image construite et démarrée localement, base neuve dans un volume monté :
|
||||||
|
|
||||||
|
| Cas | Résultat |
|
||||||
|
|---|---|
|
||||||
|
| Migrations au premier démarrage | appliquées, `mabibli.db` créé dans le volume |
|
||||||
|
| `GET /` et `_framework/blazor.webassembly.js` | **200**, `<base href="/">` intact |
|
||||||
|
| `GET /api/moi` avec `Identite__UtilisateurSimule` | `{"identifiant":"prenom","simule":true}` |
|
||||||
|
| `GET /api/moi` sans rien | `{"identifiant":null,"affichage":"inconnu"}` |
|
||||||
|
| `GET /api/moi` avec en-tête `YNH_USER: camille` | `{"identifiant":"camille","simule":false}` |
|
||||||
|
| `POST /api/souhaits` sans identité | **400**, message lisible |
|
||||||
|
|
||||||
|
⚠️ **Ce qui n'a PAS été vérifié** : l'installation sur un Synology réel, le proxy inversé de
|
||||||
|
DSM et le certificat. Ce sont des gestes de DSM, pas du code — mais personne ne les a
|
||||||
|
éprouvés ici.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Contraintes permanentes du paquet — ce ne sont pas des tâches
|
## Contraintes permanentes du paquet — ce ne sont pas des tâches
|
||||||
|
|
||||||
### Le dépôt du code doit rester public
|
### Le dépôt du code doit rester public
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# Déploiement hors YunoHost — voir README, « Installer ailleurs que sur YunoHost ».
|
||||||
|
# Sur Synology : Container Manager > Projet > créer un projet à partir de ce fichier.
|
||||||
|
|
||||||
|
services:
|
||||||
|
mabibli:
|
||||||
|
build: .
|
||||||
|
container_name: mabibli
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
# ⚠️ Le port n'est publié QUE sur la boucle locale du NAS. L'application n'a aucune
|
||||||
|
# authentification (voir ci-dessous) : quiconque atteint ce port EST l'utilisateur
|
||||||
|
# déclaré. Le seul chemin d'accès doit être le proxy inversé, en HTTPS.
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:8080:8080"
|
||||||
|
|
||||||
|
# La bibliothèque vit ici, et nulle part ailleurs. À adapter au NAS
|
||||||
|
# (`/volume1/docker/mabibli` est la convention Synology).
|
||||||
|
volumes:
|
||||||
|
- ./donnees:/data
|
||||||
|
|
||||||
|
environment:
|
||||||
|
# ⚠️ CE N'EST PAS UNE AUTHENTIFICATION. Sans portail SSO, l'application n'a aucune
|
||||||
|
# identité à lire : sans cette valeur, la liste d'envies et les statuts de lecture
|
||||||
|
# sont refusés (le catalogue et les prêts, eux, sont communs et fonctionnent).
|
||||||
|
# L'alternative, si un proxy authentifiant est en place, est de lui faire injecter
|
||||||
|
# l'en-tête `YNH_USER` et de retirer ces trois lignes.
|
||||||
|
Identite__UtilisateurSimule: "prenom"
|
||||||
|
Identite__EmailSimule: "prenom@example.org"
|
||||||
|
Identite__NomCompletSimule: "Prénom Nom"
|
||||||
Reference in New Issue
Block a user