Douze constructions

Un Nextcloud privé sur NVMe avec stockage d'objets derrière

Nextcloud sur une instance Ryzen avec Postgres et Redis sur NVMe local, chaque fichier utilisateur vivant dans un bucket sur un nœud de stockage, relié par un tunnel privé.

Ce que cela construit

Deux machines. Une instance Ryzen exécute Nextcloud, PHP-FPM, Postgres et Redis, le tout sur du NVMe Gen4 local, là où vit le travail sensible à la latence. Le nœud de stockage à côté contient le contenu réel des fichiers dans un bucket d'objets, là où vivent les téraoctets bon marché. Entre eux se trouve un tunnel WireGuard, donc rien dans cet agencement n'est exposé à autre chose.

Cette répartition importe parce que Nextcloud avec un stockage d'objets principal cesse complètement d'écrire les données utilisateur sur le disque local. Votre NVMe contient la base de données et le code ; le bucket contient chaque octet que quelqu'un téléverse. Passer de deux cents gigaoctets à vingt téraoctets devient alors une mise à niveau du nœud de stockage plutôt qu'une migration.

Avant de commencer

  • Un R-8 pour l'application et un S-50 pour le bucket, idéalement dans la même ville afin que l'aller-retour du tunnel soit inférieur à une milliseconde.
  • Un tunnel entre eux. Le guide WireGuard construit exactement cela ; utilisez 10.9.0.1 pour l'application et 10.9.0.2 pour le nœud de stockage.
  • Un nom d'hôte pointant vers l'instance de l'application, cloud.example.com ci-dessous.

1. Stockage d'objets sur le nœud de stockage

MinIO est un binaire unique et n'a besoin de rien d'autre. Téléchargez-le, vérifiez-le, installez-le :

cd /usr/local/bin
wget https://dl.min.io/server/minio/release/linux-amd64/minio
wget https://dl.min.io/server/minio/release/linux-amd64/minio.sha256sum
sha256sum -c minio.sha256sum
chmod +x minio
useradd -r -s /sbin/nologin minio
install -d -o minio -g minio /srv/objects

Le niveau de capacité sur un nœud de stockage est monté séparément du NVMe. Placez le bucket sur le niveau de capacité et laissez le NVMe pour le cache d'écriture, c'est à cela qu'il sert. Ensuite, l'unité, à /etc/systemd/system/minio.service :

[Unit]
Description=MinIO
After=network-online.target [email protected]
Wants=network-online.target

[Service]
User=minio
Group=minio
Environment=MINIO_ROOT_USER=nextcloud
Environment=MINIO_ROOT_PASSWORD=<forty random characters>
ExecStart=/usr/local/bin/minio server /srv/objects --address 10.9.0.2:9000
Restart=always
LimitNOFILE=65535
NoNewPrivileges=yes
ProtectSystem=strict
ReadWritePaths=/srv/objects

[Install]
WantedBy=multi-user.target

Se lier à l'adresse du tunnel plutôt qu'à tout est la ligne importante. Le stockage d'objets n'a aucune raison de répondre sur l'interface publique, et de cette façon une erreur de pare-feu ne peut pas l'exposer.

systemctl daemon-reload && systemctl enable --now minio
ss -ltn | grep 9000

2. Hôte de l'application : paquets

Sur l'instance Ryzen :

apt update && apt install -y nginx postgresql redis-server unzip \
  php8.4-fpm php8.4-pgsql php8.4-gd php8.4-curl php8.4-zip php8.4-xml \
  php8.4-mbstring php8.4-intl php8.4-bcmath php8.4-gmp php8.4-imagick \
  php8.4-redis php8.4-apcu

3. Base de données

sudo -u postgres psql -c "CREATE USER nextcloud WITH PASSWORD '<a long password>';"
sudo -u postgres psql -c "CREATE DATABASE nextcloud OWNER nextcloud TEMPLATE template0 ENCODING UTF8;"

Les paramètres par défaut de Postgres conviennent à cette échelle. Si ce Nextcloud finit par servir quelques centaines de personnes, le guide de réglage de Postgres s'applique et les chiffres qu'il contient valent une heure.

4. Nextcloud, configuré avant l'installation

cd /var/www
wget https://download.nextcloud.com/server/releases/latest.zip
unzip -q latest.zip && rm latest.zip
chown -R www-data:www-data /var/www/nextcloud

Maintenant la partie qui doit se faire avant que l'installateur s'exécute, car un stockage d'objets principal ne peut pas être ajouté à une instance existante sans déplacer chaque fichier à la main. Créez /var/www/nextcloud/config/config.php :

<?php
$CONFIG = array(
  "objectstore" => array(
    "class" => "\\OC\\Files\\ObjectStore\\S3",
    "arguments" => array(
      "bucket" => "nextcloud",
      "autocreate" => true,
      "key" => "nextcloud",
      "secret" => "<the same forty characters>",
      "hostname" => "10.9.0.2",
      "port" => 9000,
      "use_ssl" => false,
      "use_path_style" => true,
      "region" => "local",
    ),
  ),
);

use_ssl est faux délibérément. Le trafic traverse un tunnel WireGuard déjà authentifié et chiffré, et terminer TLS une seconde fois sur le nœud de stockage n'achète rien d'autre que des cycles CPU et un certificat à oublier de renouveler. Si les deux machines devaient un jour être dans des villes différentes, activez-le.

chown www-data:www-data /var/www/nextcloud/config/config.php
chmod 640 /var/www/nextcloud/config/config.php
cd /var/www/nextcloud
sudo -u www-data php occ maintenance:install --database pgsql \
  --database-name nextcloud --database-user nextcloud \
  --database-pass "<a long password>" \
  --admin-user admin --admin-pass "<another long password>"

5. Cache, cron et les derniers paramètres

sudo -u www-data php occ config:system:set memcache.local --value "\\OC\\Memcache\\APCu"
sudo -u www-data php occ config:system:set memcache.distributed --value "\\OC\\Memcache\\Redis"
sudo -u www-data php occ config:system:set memcache.locking --value "\\OC\\Memcache\\Redis"
sudo -u www-data php occ config:system:set redis host --value /run/redis/redis-server.sock
sudo -u www-data php occ config:system:set redis port --value 0
sudo -u www-data php occ config:system:set trusted_domains 0 --value cloud.example.com
sudo -u www-data php occ config:system:set overwrite.cli.url --value https://cloud.example.com
sudo -u www-data php occ background:cron

Redis via une socket Unix plutôt que TCP économise un aller-retour d'appel système à chaque opération de verrouillage, et Nextcloud prend beaucoup de verrous. Ajoutez www-data au groupe redis pour qu'il puisse atteindre la socket, puis branchez le travail d'arrière-plan sur une minuterie :

usermod -aG redis www-data
systemctl restart php8.4-fpm redis-server
echo "*/5 * * * * php -f /var/www/nextcloud/cron.php" | crontab -u www-data -

Les défauts de PHP-FPM supposent une machine partagée. La vôtre n'est pas partagée, donc dans /etc/php/8.4/fpm/pool.d/www.conf définissez pm = dynamic, pm.max_children = 60, pm.start_servers = 12, pm.min_spare_servers = 8 et pm.max_spare_servers = 20, et augmentez memory_limit à 1G dans /etc/php/8.4/fpm/php.ini. Les téléversements veulent upload_max_filesize et post_max_size à 16G à moins que vous n'aimiez expliquer pourquoi une vidéo a échoué à quatre-vingt-dix pour cent.

Vérifier

Le but de cette construction est que les fichiers utilisateur ne soient pas sur le serveur d'application. Prouvez-le, en trois commandes.

sudo -u www-data php occ status
du -sh /var/www/nextcloud/data

Le statut doit indiquer installé et non en mode maintenance. Le répertoire de données doit faire quelques mégaoctets et le rester pour toujours ; il contient des journaux et rien d'autre une fois le stockage d'objets principal.

Maintenant, téléversez quelque chose et regardez où cela atterrit :

head -c 50M /dev/urandom > /tmp/test.bin
curl -u admin -T /tmp/test.bin https://cloud.example.com/remote.php/dav/files/admin/test.bin
du -sh /var/www/nextcloud/data

Le téléversement réussit, et le répertoire de données n'a pas grandi de cinquante mégaoctets. Sur le nœud de stockage, l'objet est visible directement :

ls -R /srv/objects/nextcloud | tail -5
du -sh /srv/objects/nextcloud

Les objets sont nommés urn:oid: suivi de l'identifiant du fichier, c'est pourquoi le bucket n'est pas une copie parcourable des dossiers de l'utilisateur et pourquoi vous sauvegardez la base de données et le bucket ensemble ou pas du tout.

Ensuite

Prenez le module de sauvegarde hors nœud pour le dump Postgres et le bucket, ou exécutez le vôtre vers un troisième site. Un bucket sans sa base de données est un tas de blobs numérotés, et une base de données sans son bucket est un index de fichiers qui n'existent plus. Perdre l'un, c'est perdre les deux.

Prêt quand vous l'êtes

Choisissez une ville. Choisissez une taille. Payez en crypto.

Aucun formulaire sur votre identité, pas d'attente d'approbation humaine, pas d'appel téléphonique pour vérifier quoi que ce soit. La facture est réglée et les identifiants arrivent dans votre boîte mail.