0 Votes

Code source wiki de Nextcloud

Version 2.1 par john le 2026/09/26 14:00

Afficher les derniers auteurs
1 {{toc depth="2"/}}
2
3 Cloud personnel, utilisé pour les notes et la veille technologique. Déployé avec Nextcloud All-in-One (AIO) derrière [[SWAG>>Wiki Batcave John.Infrastructure.ServeurPrincipal.SWAG.WebHome]].
4
5 == Pourquoi AIO ==
6
7 AIO remplace l'image LinuxServer.io et l'image communautaire ##nextcloud## :
8
9 * image maintenue par Nextcloud GmbH, testée avec chaque version de Nextcloud ;
10 * composants intégrés et configurés automatiquement : sauvegarde Borg, Collabora, serveur Talk haute performance (HPB) avec TURN, Imaginary (aperçus), Whiteboard, notify_push ;
11 * base PostgreSQL et Redis fournies, sans stack à maintenir à côté ;
12 * mises à jour de Nextcloud, des conteneurs et des applications pilotées depuis une seule interface, précédées d'une sauvegarde.
13
14 L'image ##nextcloud## ne fournit que l'application : base, cache, bureautique, Talk et sauvegarde restent à assembler et à maintenir à la main.
15
16 == Architecture ==
17
18 Un seul conteneur est déclaré dans Portainer : le //mastercontainer//. Il crée et pilote les autres via le socket Docker.
19
20 |=Conteneur|=Rôle
21 |nextcloud-aio-mastercontainer|Interface d'administration AIO, orchestration des autres conteneurs
22 |nextcloud-aio-apache|Point d'entrée HTTP, cible du reverse proxy (port 11000)
23 |nextcloud-aio-nextcloud|Application (PHP-FPM)
24 |nextcloud-aio-database|Base PostgreSQL
25 |nextcloud-aio-redis|Cache et verrous
26 |nextcloud-aio-notify-push|Notifications push vers les clients
27 |nextcloud-aio-collabora|Édition bureautique en ligne
28 |nextcloud-aio-talk|Serveur Talk HPB et TURN (port 3478)
29 |nextcloud-aio-imaginary|Génération des aperçus
30 |nextcloud-aio-whiteboard|Serveur temps réel du tableau blanc
31 |nextcloud-aio-borgbackup|Sauvegarde Borg, démarré uniquement pendant une sauvegarde ou une restauration
32 |nextcloud-aio-domaincheck|Vérification du domaine, démarré uniquement avant la première installation
33
34 Les conteneurs créés par AIO sont reliés au réseau interne ##nextcloud-aio##. ##nextcloud-aio-apache## est en plus relié au réseau du reverse proxy.
35
36 == Variables d'environnement ==
37
38 |=Variable|=Valeur|=Rôle
39 |##APACHE_PORT##|##11000##|Port d'écoute d'Apache, en HTTP, pour le reverse proxy
40 |##APACHE_IP_BINDING##|##127.0.0.1##|Apache n'est publié que sur la boucle locale de l'hôte : aucun accès direct depuis le réseau
41 |##APACHE_ADDITIONAL_NETWORK##|##<RESEAU_SWAG>##|Réseau Docker du reverse proxy, auquel AIO relie ##nextcloud-aio-apache## pour que SWAG l'atteigne par son nom
42 |##SKIP_DOMAIN_VALIDATION##|##false##|La validation du domaine reste active (elle fonctionne grâce à la correction du hairpin NAT, voir plus bas)
43 |##NEXTCLOUD_DATADIR##|##<APPDATA>/Nextcloud-AIO/data##|Dossier hôte des fichiers utilisateurs. **Non modifiable après la première installation**
44 |##NEXTCLOUD_UPLOAD_LIMIT##|##16G##|Taille maximale d'un envoi
45 |##NEXTCLOUD_MEMORY_LIMIT##|##1024M##|Limite mémoire PHP
46
47 AIO ne lit ces variables que sur le mastercontainer : les autres conteneurs sont configurés depuis l'interface AIO.
48
49 == Stack ==
50
51 {{code language="yaml"}}
52 services:
53 nextcloud-aio-mastercontainer:
54 image: ghcr.io/nextcloud-releases/all-in-one:latest
55 container_name: nextcloud-aio-mastercontainer # nom imposé par AIO
56 init: true
57 restart: always
58 ports:
59 - "<IP_LAN>:<PORT_AIO>:8080" # interface AIO, LAN uniquement
60 volumes:
61 - nextcloud_aio_mastercontainer:/mnt/docker-aio-config
62 - /var/run/docker.sock:/var/run/docker.sock:ro
63 environment:
64 APACHE_PORT: 11000
65 APACHE_IP_BINDING: 127.0.0.1
66 APACHE_ADDITIONAL_NETWORK: <RESEAU_SWAG>
67 SKIP_DOMAIN_VALIDATION: "false"
68 NEXTCLOUD_DATADIR: <APPDATA>/Nextcloud-AIO/data
69 NEXTCLOUD_UPLOAD_LIMIT: 16G
70 NEXTCLOUD_MEMORY_LIMIT: 1024M
71 labels:
72 - com.centurylinklabs.watchtower.enable=false
73
74 volumes:
75 nextcloud_aio_mastercontainer:
76 name: nextcloud_aio_mastercontainer # nom imposé par AIO
77 {{/code}}
78
79 * Le nom du conteneur (##nextcloud-aio-mastercontainer##) et celui du volume (##nextcloud_aio_mastercontainer##) sont imposés : AIO les recherche sous ces noms exacts. Sans la clé ##name:##, Compose préfixerait le volume du nom de la stack et AIO refuserait de démarrer.
80 * Le port interne ##8080## sert l'interface AIO en HTTPS avec un certificat auto-signé. Le port hôte ##<PORT_AIO>## est libre, lié à l'IP LAN pour ne jamais être exposé à Internet.
81 * ##NEXTCLOUD_DATADIR## doit être fixé **avant le premier démarrage** : AIO l'enregistre à l'installation et ne le change plus ensuite. Le dossier est créé sur l'hôte avant de déployer la stack ; AIO lui applique lui-même le propriétaire ##www-data##.
82
83 === Premier démarrage ===
84
85 1. Déployer la stack dans Portainer.
86 1. Ouvrir ##https:~/~/<IP_LAN>:<PORT_AIO>## et accepter le certificat auto-signé.
87 1. Noter la phrase de passe AIO affichée (elle protège l'interface AIO) et la ranger dans le gestionnaire de mots de passe.
88 1. Saisir le domaine ##<DOMAINE_NEXTCLOUD>##. Le conteneur ##nextcloud-aio-domaincheck## vérifie qu'il atteint bien cette instance à travers le reverse proxy : la conf SWAG doit donc être en place avant cette étape.
89 1. Choisir les composants : Collabora, Talk, Imaginary, Whiteboard. Laisser ClamAV, la recherche plein texte, l'enregistrement Talk et le proxy du socket Docker désactivés s'ils ne servent pas.
90 1. Régler le fuseau horaire et, pour Collabora, les dictionnaires (##fr_FR##).
91 1. Si une version majeure est proposée, choisir une version supérieure ou égale à celle de l'ancienne instance (voir [[Pièges>>||anchor="HPiE8gesrencontrE9s"]]).
92 1. Démarrer les conteneurs, puis noter le mot de passe du compte ##admin## créé par AIO.
93
94 == Reverse proxy (SWAG) ==
95
96 Fichier ##<APPDATA>/swag/config/nginx/proxy-confs/20-nextcloud.subdomain.conf## :
97
98 {{code language="nginx"}}
99 server {
100 listen 443 ssl;
101 listen [::]:443 ssl;
102 server_name <DOMAINE_NEXTCLOUD>;
103 include /config/nginx/ssl.conf;
104 client_max_body_size 0;
105
106 location / {
107 include /config/nginx/proxy.conf;
108 include /config/nginx/resolver.conf;
109 set $upstream_app nextcloud-aio-apache;
110 set $upstream_port 11000;
111 set $upstream_proto http;
112 proxy_pass $upstream_proto://$upstream_app:$upstream_port;
113 }
114 }
115 {{/code}}
116
117 * L'upstream est ##nextcloud-aio-apache:11000## en **HTTP** : SWAG termine le TLS, Apache d'AIO n'écoute qu'en clair derrière lui. Le nom se résout parce que ##APACHE_ADDITIONAL_NETWORK## place ce conteneur sur le réseau de SWAG.
118 * ##client_max_body_size 0## retire la limite de taille de nginx ; c'est ##NEXTCLOUD_UPLOAD_LIMIT## qui s'applique.
119 * Pas d'include Authelia : les clients de bureau et mobiles, WebDAV, CalDAV/CardDAV, Collabora et Talk ne savent pas passer une authentification placée devant Nextcloud. La protection repose sur la connexion Nextcloud, la 2FA et l'anti-bruteforce.
120
121 == Commandes occ ==
122
123 AIO n'a pas de raccourci ##occ## : on appelle PHP dans le conteneur applicatif, avec l'utilisateur ##www-data## :
124
125 {{code language="bash"}}
126 docker exec --user www-data nextcloud-aio-nextcloud php occ status # version, état
127 docker exec --user www-data nextcloud-aio-nextcloud php occ db:add-missing-indices # après l'avertissement « index manquants »
128 docker exec --user www-data nextcloud-aio-nextcloud php occ maintenance:mode --on # avant une opération lourde (--off ensuite)
129 docker exec --user www-data nextcloud-aio-nextcloud php occ files:scan --all # fichiers ajoutés hors de Nextcloud
130 docker exec --user www-data nextcloud-aio-nextcloud php occ config:system:get trusted_proxies
131 {{/code}}
132
133 Ne pas lancer ##occ upgrade## ni ##app:update --all## à la main : AIO s'en charge lors de ses mises à jour.
134
135 == Sécurité ==
136
137 * Interface AIO accessible uniquement depuis le LAN (port lié à ##<IP_LAN>##), protégée par la phrase de passe AIO.
138 * Apache publié sur ##127.0.0.1## uniquement : tout le trafic externe passe par SWAG.
139 * Double authentification TOTP (application ##twofactor_totp##). Elle n'est pas transférée par ##user_migration## : chaque compte doit la réactiver dans //Paramètres personnels > Sécurité// après la migration.
140 * ##trusted_proxies## contient le sous-réseau Docker du reverse proxy, pour que l'anti-bruteforce voie la vraie IP des clients (voir [[Pièges>>||anchor="HPiE8gesrencontrE9s"]]).
141
142 == Sauvegarde ==
143
144 * Sauvegarde Borg intégrée à AIO, quotidienne à ##<HEURE>##, vers ##<CHEMIN_BORG>## sur l'hôte. Elle arrête les conteneurs, sauvegarde la base, le dossier de données et la configuration, puis relance tout ; si l'option est cochée dans l'interface AIO, elle applique ensuite les mises à jour disponibles.
145 * Le mot de passe du dépôt Borg est affiché dans l'interface AIO après la première sauvegarde. **Le conserver hors du serveur** (gestionnaire de mots de passe) : sans lui, le dépôt est illisible et la restauration impossible si le serveur est perdu.
146 * La restauration se fait depuis l'interface AIO d'une installation neuve : chemin du dépôt, mot de passe Borg, choix de l'archive.
147 * Le dépôt ##<CHEMIN_BORG>## est à inclure dans la [[Sauvegarde>>Wiki Batcave John.Infrastructure.Sauvegarde.WebHome]] externe : un dépôt sur le même disque ne protège pas d'une panne du serveur.
148
149 == Exploitation ==
150
151 * **TURN** : rediriger le port ##3478## en **TCP et UDP** de la box vers le serveur, sinon les appels Talk échouent hors du LAN. ##nextcloud-aio-talk## le publie directement sur l'hôte, sans passer par SWAG.
152 * **Mises à jour** : gérées par AIO (sauvegarde quotidienne suivie de la mise à jour, ou bouton dans l'interface AIO). Les conteneurs AIO sont exclus de [[Watchtower>>Wiki Batcave John.Infrastructure.ServeurPrincipal.Watchtower.WebHome]].
153 * **SMTP** : à configurer dans //Administration > Paramètres de base > Serveur de messagerie//. AIO ne lit aucune variable d'environnement SMTP.
154 * **Avertissements de la vue d'ensemble à ignorer** :
155 ** Talk HPB signalé en retard par rapport à Nextcloud 35 : l'image ##aio-talk## suit avec un décalage, le service fonctionne ;
156 ** passerelle SIP non configurée : non utilisée ;
157 ** serveur d'enregistrement Talk non configuré : composant désactivé volontairement.
158
159 == Migration depuis l'image LinuxServer.io ==
160
161 Faite avec l'application ##user_migration##, compte par compte. Choisie parce que l'instance est petite (deux comptes) : cette méthode évite la conversion de la base MariaDB vers PostgreSQL et n'exige pas la même version de Nextcloud des deux côtés, contrairement à une migration complète (base + dossier de données).
162
163 L'archive contient notamment les fichiers, agendas et contacts du compte. Ne sont pas repris : l'appartenance aux groupes (dont ##admin##), la 2FA, les partages entre comptes.
164
165 === 1. Export sur l'ancienne instance ===
166
167 Activer ##user_migration## sur l'ancienne instance, puis :
168
169 {{code language="bash"}}
170 # dossier d'export, créé en root par docker exec : le donner à l'utilisateur du serveur web (abc sur LinuxServer.io)
171 docker exec <ANCIEN_CONTENEUR> mkdir -p /data/export
172 docker exec <ANCIEN_CONTENEUR> chown abc:abc /data/export
173
174 # export d'un compte ; php occ appelé directement pour les identifiants contenant un espace
175 docker exec --user abc <ANCIEN_CONTENEUR> php /app/www/public/occ user:export "<IDENTIFIANT>" /data/export
176 {{/code}}
177
178 Attendre la fin : l'archive finale est ##<IDENTIFIANT>.zip##. Un fichier ##.zip.part## est un export incomplet.
179
180 === 2. Création des comptes sur AIO ===
181
182 Créer chaque compte avec **exactement** le même identifiant, casse et espaces compris :
183
184 {{code language="bash"}}
185 docker exec -it --user www-data nextcloud-aio-nextcloud php occ user:add --display-name="<NOM_AFFICHE>" "<IDENTIFIANT>"
186 {{/code}}
187
188 === 3. Import ===
189
190 Copier l'archive dans le dossier de données AIO, puis l'importer dans le compte créé :
191
192 {{code language="bash"}}
193 mkdir -p <APPDATA>/Nextcloud-AIO/data/import
194 cp <ARCHIVE>/<IDENTIFIANT>.zip <APPDATA>/Nextcloud-AIO/data/import/
195 chown -R 33:33 <APPDATA>/Nextcloud-AIO/data/import # www-data dans le conteneur
196
197 docker exec --user www-data nextcloud-aio-nextcloud php occ user:import --user "<IDENTIFIANT>" "/mnt/ncdata/import/<IDENTIFIANT>.zip"
198 {{/code}}
199
200 ##/mnt/ncdata## est le point de montage de ##NEXTCLOUD_DATADIR## dans ##nextcloud-aio-nextcloud##. Supprimer le dossier ##import## une fois les comptes vérifiés.
201
202 === 4. Après l'import ===
203
204 {{code language="bash"}}
205 # le groupe admin n'est pas migré
206 docker exec --user www-data nextcloud-aio-nextcloud php occ group:adduser admin "<IDENTIFIANT>"
207 {{/code}}
208
209 * Les agendas sont recréés sous le nom ##migrated-<nom_d_origine>## : les renommer si besoin et mettre à jour les abonnements CalDAV des appareils.
210 * Réactiver la 2FA de chaque compte.
211 * Reconnecter les clients (bureau, mobile, DAVx⁵) : l'URL ne change pas, mais leurs sessions appartenaient à l'ancienne instance.
212 * Arrêter l'ancienne stack une fois tout vérifié, puis retirer son dump de la [[Sauvegarde>>Wiki Batcave John.Infrastructure.Sauvegarde.WebHome]].
213
214 == Pièges rencontrés ==
215
216 |=Problème|=Cause|=Solution
217 |Import dans un compte vide ou dossier introuvable|Les identifiants sont sensibles à la casse : le dossier de données suit la casse exacte de l'identifiant|Créer le compte AIO avec la casse exacte de l'ancien identifiant
218 |Export d'un identifiant contenant un espace : « user not found »|Le raccourci ##occ## de LinuxServer.io relaie mal les arguments et coupe l'identifiant à l'espace|Appeler ##php /app/www/public/occ## directement, avec ##~-~-user abc## et l'identifiant entre guillemets
219 |Export en échec : permission refusée|Le dossier d'export créé par ##docker exec## appartient à root|##chown## vers l'utilisateur du serveur web (##abc## côté LinuxServer.io, ##www-data## / uid 33 côté AIO)
220 |Import en échec ou données tronquées|Un fichier ##.zip.part## est un export encore en cours ou interrompu|Ne jamais importer un ##.zip.part## ; relancer l'export jusqu'à obtenir le ##.zip##
221 |Import refusé|Archive produite par une version de Nextcloud plus récente que la cible|Installer une version majeure d'AIO supérieure ou égale à celle de l'ancienne instance
222 |Page d'administration Whiteboard en erreur « Provided key is too short »|EuroOffice embarque sa propre bibliothèque JWT, chargée à la place de celle de Whiteboard|Remplacer EuroOffice par Collabora dans l'interface AIO
223 |Tableau blanc qui ne se connecte pas|Le secret partagé du serveur Whiteboard n'est pas renseigné côté Nextcloud|Récupérer le secret avec ##docker exec nextcloud-aio-whiteboard printenv JWT_SECRET_KEY## et le saisir dans //Administration > Tableau blanc//
224 |Collabora, Talk ou Whiteboard injoignables depuis Nextcloud ; validation du domaine en échec|Hairpin NAT : les conteneurs résolvent ##<DOMAINE_NEXTCLOUD>## vers l'IP publique, que la box ne renvoie pas vers le LAN|Voir [[Hairpin NAT>>||anchor="HHairpinNAT"]]
225 |Connexions lentes pour tout le monde, délais anti-bruteforce|Sans ##trusted_proxies##, toutes les requêtes semblent venir de l'IP de SWAG : un échec de connexion ralentit tous les utilisateurs|Voir [[trusted_proxies>>||anchor="Htrusted_proxies"]]
226 |Conteneurs AIO mis à jour ou recréés hors d'AIO|Watchtower ne voit pas le label d'exclusion, présent seulement sur le mastercontainer|Voir [[Watchtower>>||anchor="HWatchtower"]]
227 |Réglages SMTP ignorés|AIO ne lit pas de variables SMTP|Configurer le serveur de messagerie dans //Administration > Paramètres de base//
228
229 === Hairpin NAT ===
230
231 Le DNS local (voir [[AdGuard Home>>Wiki Batcave John.Infrastructure.RaspberryPi.AdGuard Home.WebHome]]) réécrit ##<DOMAINE_NEXTCLOUD>## vers ##<IP_LAN>## du serveur. Docker est configuré pour l'utiliser comme résolveur de tous les conteneurs, dans ##/etc/docker/daemon.json## :
232
233 {{code language="json"}}
234 {
235 "hosts": ["unix:///var/run/docker.sock"],
236 "log-driver": "json-file",
237 "log-opts": { "max-size": "50m", "max-file": "3" },
238 "dns": ["<IP_DNS_LOCAL>", "<DNS_SECOURS>"],
239 "min-api-version": "1.24"
240 }
241 {{/code}}
242
243 La clé ##dns## s'applique après ##systemctl restart docker##, qui redémarre tous les conteneurs. Vérification :
244
245 {{code language="bash"}}
246 docker exec nextcloud-aio-nextcloud getent hosts <DOMAINE_NEXTCLOUD> # doit renvoyer <IP_LAN>
247 {{/code}}
248
249 Le DNS de secours n'est interrogé que si le DNS local ne répond pas ; dans ce cas le domaine repasse sur l'IP publique et le problème réapparaît jusqu'au retour du DNS local.
250
251 === trusted_proxies ===
252
253 Ajouter le sous-réseau du réseau Docker de SWAG, à l'index suivant les entrées déjà posées par AIO :
254
255 {{code language="bash"}}
256 docker network inspect <RESEAU_SWAG> --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}' # -> <SOUS_RESEAU_PROXY>
257 docker exec --user www-data nextcloud-aio-nextcloud php occ config:system:get trusted_proxies # repérer le prochain index libre
258 docker exec --user www-data nextcloud-aio-nextcloud php occ config:system:set trusted_proxies <INDEX> --value="<SOUS_RESEAU_PROXY>"
259 {{/code}}
260
261 Reprendre le masque exact du réseau : un masque plus large ferait confiance à l'en-tête ##X-Forwarded-For## envoyé par d'autres machines.
262
263 === Watchtower ===
264
265 AIO crée ses conteneurs sans le label ##com.centurylinklabs.watchtower.enable=false## : il faut les lister nommément dans la variable ##WATCHTOWER_DISABLE_CONTAINERS## de Watchtower :
266
267 {{code language="bash"}}
268 WATCHTOWER_DISABLE_CONTAINERS=nextcloud-aio-apache,nextcloud-aio-borgbackup,nextcloud-aio-collabora,nextcloud-aio-database,nextcloud-aio-domaincheck,nextcloud-aio-eurooffice,nextcloud-aio-imaginary,nextcloud-aio-mastercontainer,nextcloud-aio-nextcloud,nextcloud-aio-notify-push,nextcloud-aio-redis,nextcloud-aio-talk,nextcloud-aio-whiteboard
269 {{/code}}
270
271 Ajouter tout nouveau conteneur ##nextcloud-aio-*## à cette liste lors de l'activation d'un composant (ClamAV, recherche plein texte, enregistrement Talk…).