Introduction

La formule standard de NextCloud est utile pour bien des usages. Cependant, lorsque la volumétrie des utilisateurs évolue et que l’on arrive à des usages plus intenses de NextCloud, on se rend vite compte des limites de ce service. Dans ce cas, on se retrouve confronté à une problématique de taille, à savoir gérer la quantité d’utilisateurs tout en limitant les coûts. C’est là qu’intervient l’offre GlobalScale de NextCloud.

À l’heure où ces lignes sont rédigées il existe peu de documentation sur le sujet. Nous allons tenter de combler ensemble ce manque avec cet article.

GlobalScale permet de répartir la charge du trafic et donc de gérer une utilisation plus intense de NextCloud. Cela aide énormément lorsque l’on veut utiliser NextCloud dans un cadre professionnel à grande échelle ou lorsque l’on en a une utilisation avancée comme par exemple la mise en place de nombreux plugins ou le stockage de fichiers volumineux.

Points importants

Attention: Cette installation a été réalisée sous NextCloud version 20, nous ne pouvons confirmer la validité de cette procédure pour les versions ultérieures.

Dans cet article, nous nous attarderons seulement sur la mise en place de la partie GlobalScale, nous considérerons que vos serveurs Linux sont déjà en place et que les produits de base sont déjà installés.

Les points suivants ne seront pas traités ici :

  • l’adressage IP
  • le dimmensionnement des serveurs
  • l’installation de l’OS
  • la mise en place d’un Reverse Proxy
  • La gestion des certificats
  • la mise en place des bases de données
  • la supervision ou la métrologie
  • la haute disponibilité

Caractéristiques de l’architecture GlobalScale

Pour la mise en place de cette architecture, nous aurons besoin basiquement pour la partie NextCloud :

  • d’un serveur primaire NextCloud, qui servira de relai pour rediriger l’utilisateur vers le serveur où sont situées ses données/son espace personnel.
  • d’un ou plusieurs serveurs secondaires sur lesquels nous allons répartir les données de nos utilisateurs, c’est en cela que réside la particularité de cette architecture et qui va permettre d’éviter les goulots d’étranglement.
  • un Lookup server qui sera le serveur interrogé pour rediriger les utilisateurs vers le serveur secondaire sur lequel ils disposent d’un espace personnel.

architecture

Évidemment pour pouvoir identifier nos clients il est nécessaire d’inclure dans cette architecture un portail d’authentification Single Sign-On (SSO) ou un serveur LDAP.

Voici la nomenclature qui sera utilisée :

Nom Rôle Application
nextcloud1.app.domain.com Nextcloud Primaire Nextcloud verison 20
nextcloud2.app.domain.com Nextcloud Secondaire Nextcloud version 20
nextcloud3.app.domain.com Nextcloud Secondaire Nextcloud version 20
ls.app.domain.com Lookup Server Nextcloud version 20
keycloak.app.domain.com WebSSO Keycloak
collabora.domain.com Édition Collaborative Collabora Online

Commençons l’installation !

Installation

Prérequis

Dans notre contexte, voici comment va se présenter notre architecture :

  • les différents nœuds NextCloud,
  • OpenLDAP afin de centraliser les comptes et les informations utilisateurs,
  • Keycloak comme WebSSO s’appuyant sur l’annuaire LDAP pour l’authentification des utilisateurs,
  • Collabora Online, un outil collaboratif open-source basé sur LibreOffice Online.

Remarque: Dans le cadre d’une mise en production, nous pourrions intégrer à cette architecture un serveur REDIS pour les caches de sessions mais cela ne sera pas abordé dans cet article.

L’annuaire OpenLDAP

Dans notre architecture, nous allons nous servir d’OpenLDAP pour centraliser les utilisateurs et faciliter la gestion de leurs données.

Chaque utilisateur disposera de sa fiche qui sera présentée comme ceci:

  • cn : nom d’affichage (prénom / nom)
  • sn : nom de famille
  • givenName : prénom
  • mail : adresse mail
  • nclocator : URL Nextcloud vers ses données
  • uid : uid
  • userPassword : mot de passe utilisateur

Exemple :

cn: John DOE
sn: DOE
givenName: John
mail: john.doe@example.com
nclocator : https://nextcloud-2.example.com/
uid : jdoe
userPassword : $HASH$

Keycloak va s’appuyer sur ces fiches afin de gérer les authentifications des clients et gérer efficacement les accès aux espaces personnels de chacun.

Le WebSSO Keycloak

Afin que notre outil de SSO (Single Sign-On) puisse accéder à l’annuaire LDAP pour l’authentification des utilisateurs, il est nécessaire de définir un nouveau fournisseur LDAP comme suit :

Configuration de la Fédération d’utilisateurs

Après avoir défini le nouveau fournisseur, il est nécessaire de faire correspondre les attributs de l’annuaire avec ceux des utilisateurs qui vont être stockés dans Keycloak et qui pourront être transmis aux applications clientes :

LISTE DES ATTIBUTS RÉCUPÉRÉS DU LDAP

Voici la configuration à adopter pour chaque attribut :

LAST NAME

PRENOM

NCLOCATOR

NOM UTILISATEUR

EMAIL

Une fois le mappage terminé, nous allons configurer la partie SAML et définir le noeud principal en tant que client :

Configuration SAML du Nextcloud primaire

Enfin il faut lui donner les éléments que l’on vient de définir pour lui permettre de s’en servir durant la connexion.

ATTRIBUTS TRANSMITS PAR SAML

Que l’on va définir commme ceci :

EMAIL

ROLES

NCLOCATOR

UID

Une fois toutes ces configurations faites, nous pouvons passer à la configuration du noeud primaire NextCloud.

Nextcloud Primaire

En premier lieu, nous devons modifier les Content Security Policy afin de permettre aux instances d’utiliser les iframes d’une instance à une autre. Vous devrez trouver le fichier .php au chemin suivant :

~/lib/public/AppFramework/Http/ContentSecurityPolicy.php

Voici à quoi ressemble notre fichier de conf après modification :

~# cat ./lib/public/AppFramework/Http/ContentSecurityPolicy.php
...
 protected $allowedFrameDomains = [
 'nextcloud1.app.domain.com',
 'nextcloud2.app.domain.com',
 'nextcloud3.app.domain.com',
 'collabora.domain.com',
 ];

 protected $allowedFrameAncestors = [
 'nextcloud1.app.domain.com',
 'nextcloud2.app.domain.com',
 'nextcloud3.app.domain.com',
 'collabora.domain.com',
 ];`

Ensuite il faut commenter les options du X-Frame dans le .htaccess pour autoriser les autres origines :

~# cat .htaccess
# Header always set X-Frame-Options "SAMEORIGIN"`

Du côté de NextCloud, la partie SAML doit être configurée comme ceci :

Authentication SAML Authentication SAML 2

Voici un extrait du config.php modifié pour GlobalScale :

~# cat config/config.php
<?php
$CONFIG = array (
<...>
 'overwriteprotocol' => 'https',
 'overwritehost' => 'nextcloud1.app.domain.com',
<...>
 'overwritewebroot' => '/',
 'trusted_domains' =>
 array (
 0 => 'nextcloud1.app.domain.com',
 1 => 'nextcloud2.app.domain.com',
 2 => 'nextcloud3.app.domain.com',
 ),
 'datadirectory' => '/var/www/nextcloud/data',
 'lookup_server' => 'https://ls.app.domain.com',
<...>
 'overwrite.cli.url' => 'https://nextcloud1.app.domain.com/nextcloud',
<...>
 'app_install_overwrite' =>
 array (
 0 => 'globalsiteselector',
 ),
 'gss.jwt.key' => 'XXXXX',
 'gss.mode' => 'master',
 'gss.master.admin' =>
 array (
 0 => 'admin',
 ),
 'gs.enabled' => true,
 'gss.user.discovery.module' => '\\OCA\\GlobalSiteSelector\\UserDiscoveryModules\\UserDiscoverySAML',
 'gss.discovery.saml.slave.mapping' => 'nclocator',
<...>
);

NextCloud Secondaire

Comme pour le noeud primaire, vous devez modifier les CSP afin d’autoriser l’utilisation des iframes d’une instance à une autre comme ceci :

protected $allowedFrameDomains = [
 'nextcloud1.app.domain.com',
 'nextcloud2.app.domain.com',
 'nextcloud3.app.domain.com',
 'collabora.domain.com',
 ];
 protected $allowedChildSrcDomains = [
 'nextcloud1.app.domain.com',
 'nextcloud2.app.domain.com',
 'nextcloud3.app.domain.com',
 'collabora.domain.com',
 ];
 protected $allowedFrameAncestors = [
 'nextcloud1.app.domain.com',
 'nextcloud2.app.domain.com',
 'nextcloud3.app.domain.com',
 'collabora.domain.com',
 ];

Il est impératif de commenter la ligne suivante dans le .htaccess comme pour le noeud primaire :

~# cat .htaccess
#Header always set X-Frame-Options "SAMEORIGIN"

Contrairement au nœud primaire, les nœuds secondaires doivent être connectés à un annuaire LDAP pour les informations utilisateurs avec un filtre correspondant aux utilisateurs uniquement de cette instance :

LDAP - Page Server

On va ensuite créer un filtre correspondant au nclocator du GlobalScale :

Configuration LDAP - Page Users

Pour le reste, ça reste une configuration classique :

Page Login Attributes

Dans l’onglet Avancé, nous désactiverons la pagination des recherches dans l’annuaire :

Onglet Avancé

Pour simplifier la lecture entre SAML et LDAP, nous avons fait correspondre l’uid de l’utilisateur :

Onglet Expert

Voici un extrait du fichier config.php correspondant aux modifications pour le GlobalScale pour une instance secondaire :

~# cat config/config.php
<?php
$CONFIG = array (
<...>
 'trusted_domains' =>
 array (
 0 => 'nextcloud3.app.domain.com',
 1 => 'nextcloud2.app.domain.com',
 2 => 'nextcloud1.app.domain.com',
 ),
<...>
 'overwrite.cli.url' => 'https://nextcloud2.app.domain.com',
 'installed' => true,
 'app_install_overwrite' =>
 array (
 0 => 'globalsiteselector',
 ),
<...>
 'overwritewebroot' => '/',
 'overwriteprotocol' => 'https',
 'gss.mode' => 'slave',
 'gss.discovery.saml.slave.mapping' => 'nclocator',
 'lookup_server' => 'https://ls.app.domain.com',
 'gss.jwt.key' => 'XXXXXXXX',
 'gss.master.url' => 'https://nextcloud1.app.domain.com/',
<...>
);

Lookup Server

Voici à quoi ressemble le fichier de configuration par défaut :

# cat config/config.php
<?php
// Lookup-Server Config
$CONFIG = [
<...>
 // max user search page. limit the maximum number of pages to avoid scraping.
 'MAX_SEARCH_PAGE' => 100,
 // max requests per IP and 10min.
 'MAX_REQUESTS' => 100000,
 // credential to read the replication log. IMPORTANT!! SET TO SOMETHING SECURE!!
 'REPLICATION_AUTH' => 'XXXXXX',
 // credential to read the slave replication log. Replication slaves are read only and don't get the authkey.
IMPORTANT!! SET TO SOMETHING SECURE!!
 'SLAVEREPLICATION_AUTH' => 'YYYYYYYYYYY',
 // the list of remote replication servers that should be queried in the cronjob
 'REPLICATION_HOSTS' => [],
 // ip black list. usefull to block spammers.
 'IP_BLACKLIST' => [],
 // spam black list. usefull to block spammers.
 'SPAM_BLACKLIST' => [
 ],
 // Email sender address
 'EMAIL_SENDER' => 'www@ttttt.com',
 // Public Server Url
 'PUBLIC_URL' => 'https://ls.app.domain.com',
 // does the lookup server run in a global scale setup
 'GLOBAL_SCALE' => true,
 // auth token
 'AUTH_KEY' => 'ZZZZZZZZZ'
 'TWITTER' => [
 'CONSUMER_KEY' => '',
 'CONSUMER_SECRET' => '',
 'ACCESS_TOKEN' => '',
 'ACCESS_TOKEN_SECRET' => '',
 ],
];

Remarque: La partie Twitter est nécessaire mais peut rester vide.

Durant l’exécution du cron.php de NextCloud, les utilisateurs sont créés via une requête LDAP et sont injectés dans la base de données du Lookup Server comme suit :

MariaDB [lookup]> select * from users where federationId like 'user%' ;
+------+-----------------------------------------+---------------------+
| id | federationId | timestamp |
+------+-----------------------------------------+---------------------+
| 2555 | user1@nextcloud2.app.domain.com | 2021-03-03 17:14:14 |
| 24 | user10@nextcloud2.app.domain.com | 2021-03-03 14:36:07 |
| 2643 | user100@nextcloud2.app.domain.com | 2021-03-03 17:14:56 |
| 544 | user1000@nextcloud2.app.domain.com | 2021-03-03 15:42:14 |
| 1048 | user100001@nextcloud3.app.domain.com | 2021-03-03 15:53:00 |
| 1049 | user100002@nextcloud3.app.domain.com | 2021-03-03 15:53:00 |
| 1050 | user100003@nextcloud3.app.domain.com | 2021-03-03 15:53:00 |
| 1051 | user100004@nextcloud3.app.domain.com | 2021-03-03 15:53:00 |
| 1052 | user100005@nextcloud3.app.domain.com | 2021-03-03 15:53:00 |
| 1053 | user100006@nextcloud3.app.domain.com | 2021-03-03 15:53:00 |
| 1054 | user100007@nextcloud3.app.domain.com | 2021-03-03 15:53:00 |
| 1055 | user100008@nextcloud3.app.domain.com | 2021-03-03 15:53:00 |
| 1056 | user100009@nextcloud3.app.domain.com | 2021-03-03 15:53:00 |
| 1057 | user100010@nextcloud3.app.domain.com | 2021-03-03 15:53:00 |
| 1058 | user100011@nextcloud3.app.domain.com | 2021-03-03 15:53:00 |
| 1059 | user100012@nextcloud3.app.domain.com | 2021-03-03 15:53:00 |
…
| 3028 | user490@nextcloud2.app.domain.com | 2021-03-03 17:17:52 |
| 3029 | user491@nextcloud2.app.domain.com | 2021-03-03 17:17:53 |
| 3030 | user492@nextcloud2.app.domain.com | 2021-03-03 17:17:53 |
| 3031 | user493@nextcloud2.app.domain.com | 2021-03-03 17:17:54 |
| 3032 | user494@nextcloud2.app.domain.com | 2021-03-03 17:17:54 |
| 3033 | user495@nextcloud2.app.domain.com | 2021-03-03 17:17:54 |
| 3034 | user496@nextcloud2.app.domain.com | 2021-03-03 17:17:55 |
| 3035 | user497@nextcloud2.app.domain.com | 2021-03-03 17:17:55 |
| 3036 | user498@nextcloud2.app.domain.com | 2021-03-03 17:17:56 |
| 3037 | user499@nextcloud2.app.domain.com | 2021-03-03 17:17:56 |
| 3038 | user500@nextcloud2.app.domain.com | 2021-03-03 17:17:57 |
+------+---------------------------------------------+---------------------+

On peut alors constater les requêtes de mise à jour via l’API du Lookup Server depuis toutes les instances :

ls.app.domain.com [03/Mar/2021:17:17:55 +0100] "POST /gs/users HTTP/1.1" 200 "-" "Nextcloud Server
Crawler"
ls.app.domain.com [03/Mar/2021:17:17:55 +0100] "POST /gs/users HTTP/1.1" 200 "-" "Nextcloud Server
Crawler"
ls.app.domain.com [03/Mar/2021:17:17:55 +0100] "POST /gs/users HTTP/1.1" 200 "-" "Nextcloud Server
Crawler"
ls.app.domain.com [03/Mar/2021:17:17:55 +0100] "POST /gs/users HTTP/1.1" 200 "-" "Nextcloud Server
Crawler"
ls.app.domain.com [03/Mar/2021:17:17:56 +0100] "POST /gs/users HTTP/1.1" 200 "-" "Nextcloud Server
Crawler"
ls.app.domain.com [03/Mar/2021:17:17:56 +0100] "POST /gs/users HTTP/1.1" 200 "-" "Nextcloud Server
Crawler"
ls.app.domain.com [03/Mar/2021:17:17:56 +0100] "POST /gs/users HTTP/1.1" 200 "-" "Nextcloud Server
Crawler"
ls.app.domain.com [03/Mar/2021:17:17:56 +0100] "POST /gs/users HTTP/1.1" 200 "-" "Nextcloud Server
Crawler"
ls.app.domain.com [03/Mar/2021:17:17:57 +0100] "POST /gs/users HTTP/1.1" 200 "-" "Nextcloud Server
Crawler"
ls.app.domain.com [03/Mar/2021:17:17:57 +0100] "POST /gs/users HTTP/1.1" 200 "-" "Nextcloud Server
Crawler"

Collabora

La spécificité de notre configuration de Collabora ici est qu’elle doit permettre le partage d’iframe d’un NextCLoud à un autre. Pour ce faire, nous allons alors fixer les adresses pouvant utiliser cette option dans notre fichier loolwsd.xml :

~# cat /etc/loolwsd/loolwsd.xml
<...>
 <frame_ancestors desc="Specify who is allowed to embed the LO Online iframe (loolwsd and WOPI host are
always allowed). Separate multiple hosts by space.">https://nextcloud*\.app\.domain\.com</frame_ancestors>
<...>
 <host desc="Regex pattern of hostname to allow or deny." allow="true">nextcloud1\.app\.domain\.com</host>
 <host desc="Regex pattern of hostname to allow or deny." allow="true">nextcloud2\.app\.domain\.com</host>
 <host desc="Regex pattern of hostname to allow or deny." allow="true">nextcloud3\.app\.domain\.com</host>
<...>
 <host desc="Hostname to allow" allow="true">nextcloud1\.app\.domain\.com</host>
 <host desc="Hostname to allow" allow="true">nextcloud2\.app\.domain\.com</host>
 <host desc="Hostname to allow" allow="true">nextcloud3\.app\.domain\.com</host>
<...>
~# systemctl restart loolwsd

Après redémarrage du service, les serveurs NextCloud peuvent désormais ouvrir des accès à leur instance aux autres.

Attention : Pour l’exemple, nous déployons un seul Collabora unique pour tous nos serveurs NextCloud, cependant il est tout à fait possible de les séparer pour que chaque serveur possède un Collabora qui lui est propre.

Cas d’usage

Maintenant que vous avez terminé l’installation de GlobalScale, voici quelques cas d’usage pour Nextcloud.

Tester son installation

Afin de tester notre architecture, nous allons procéder de la façon suivante :

  1. Nous allons d’abord nous rendre sur l’URL du noeud primaire https://nextcloud1.app.domain.com puis nous nous authentifions :

Auth SSO

  1. Si tout se passe bien, nous sommes alors redirigé vers le noeud secondaire :

Redir_SSO

Partager un fichier

Sur NextCloud, nous avons 2 solutions pour partager un fichier : soit via le mail de notre collaborateur, soit via son nom.

share mail

share name

Conclusion

Félicitations ! Si vos tests ont réussi alors vous avez désormais une architecture NextCloud GlobalScale.

Il est important de noter que la disposition mise en place dans ce tutoriel n’est qu’un exemple et reste ajustable selon vos besoins.

Voici ci-après une liste de liens utiles concernant la documentation des différents éléments mise en place dans ce tutoriel.

Liens utiles

Produit URL
NextCloud https://nextcloud.com/
NextCloud config.php https://docs.nextcloud.com/server/stable/admin_manual/
Lookup Server https://github.com/nextcloud/lookup-server
RichDocuments https://github.com/nextcloud/richdocuments
User SAML https://github.com/nextcloud/user_saml
Global Site Selector https://github.com/nextcloud/globalsiteselector
KeyCloak https://www.keycloak.org/
Openldap https://www.openldap.org/