dream team

Auto-héberger son cloud perso pour quelques watts

On va tâcher à présent de procéder à l’installation des différents logiciels serveur qui vont motoriser notre cloud Nextcloud.

Cette procédure est entièrement basée sur la documentation d’installation officielle.

Avant tout on va rafraichir le cache des paquets apt:

apt update

Et on va mettre à jour éventuellement les paquets déjà dans l’installation de base:

apt upgrade

Navigation

Installation et configuration de mariadb

Ça commence par l’installation du serveur de base de données. C’est mariadb qui sera utilisée, mais le projet Nextcloud supporte d’autres SGBD, aussi chacun choisira selon ses préférences.

Installation du serveur mariadb:

apt install mariadb-server

Cette commande suffit pour l’installation de tous les outils nécessaires, qui seront installés par dépendance.

La suite se passe dans le prompt de mariadb, qu’on appelle avec le client mariadb (la commande pour utiliser le client est « mysql »; n’oublions pas que mariadb est un fork de mysql).

mysql -u root -p

Création de la base de données dédiée au projet Nextcloud:

CREATE DATABASE nextcloud;

Création d’un l’utilisateur quelconque de base de données:

CREATE USER nc_db_user@localhost IDENTIFIED BY 'nc_db_mot_de_passe_secret';

Et attribution des droits sur la base de données fraîchement créée à cet utilisateur:

GRANT ALL PRIVILEGES ON nextcloud.* TO nc_db_user@localhost;

Nextcloud 21 recommande que le jeu de caractères de la base de données doit-être au format utf8mb4 ce qui est le cas par défaut avec mariadb sous Armbian. De même que l’option innodb_file_per_table=1 qui fait que chaque table de la base de données est représentée par un fichier dans le système de fichiers (bien sûr, le moteur de stockage utilisé est innodb par défaut aussi).

Toujours dans les recommandations de Nextcloud, le projet conseille de passer le niveau d’isolation des transactions au paramètre TRANSACTION_READ_COMMITTED pour éviter des pertes de données en cas de forte charge sur le système, ainsi que de passer le format des fichiers de transaction à ROW. Il faut également activer le support des préfixes longs pour permettre des préfixes de clés d’index jusqu’à 3Ko de longueur. Enfin, on force le format de fichier innodb au nouveau format barracuda permettant notamment le format compressé des lignes.

Cela se passe dans le fichier /etc/mysql/mariadb.conf.d/50-server.cnf, on rajoute les quatre directives suivantes sous la rubrique [mysqld] :

transaction_isolation = READ-COMMITTED
binlog_format = ROW
innodb_large_prefix=on
innodb_file_format=barracuda

Un petit restart du démon pour prendre tout ça en compte:

systemctl restart mariadb

C’est tout pour la partie mariadb. Le démon est configuré par défaut pour écouter l’interface de loopback, ce qui est parfait ici car notre base de données est sur la même machine que l’application. On aurait pu configurer la base de données pour écouter sur un socket Unix afin d’éviter de passer par la pile IP du système, mais le manuel de mariadb indique qu’utiliser l’interface de loopback pose moins de soucis de compatibilité, et n’est pas moins sécurisé qu’utiliser un socket Unix; aussi on va conserver le réglage par défaut.

Installation de PHP

Pour être tranquille, on ne va pas faire dans la dentelle, et on va installer PHP ainsi que tous les modules de ce dernier obligatoires pour Nextcloud, ainsi que la plupart des modules conseillés et optionnels.

La version de PHP fournie par Armbian Buster est la 7.3. Bien que Nextcloud 21 recommande PHP 7.4, il supporte officiellement PHP 7.3. On va donc s’en tenir là, et ne pas chercher à backporter PHP 7.4 sur Buster. J’espère que je ne vais pas le regretter lors d’une future mise à jour de Nextcloud, vers une version qui abandonne le support de PHP 7.3. Enfin, on verra bien, mais je pense que j’ai le temps.

apt install php7.3 php7.3-curl php7.3-xml php7.3-gd php7.3-json php7.3-mbstring php7.3-zip php7.3-bz2 php7.3-mysql php7.3-intl php7.3-ldap php-smbclient php-net-ftp php7.3-imap php7.3-bcmath php7.3-gmp php-imagick

Installation et configuration de nginx

Installation

Nextcloud recommande d’utiliser le serveur web apache, mais pour des raisons d’optimisation de l’installation vis-à-vis de notre matériel, on va utiliser à la place le serveur nginx. Celui-ci, en plus d’être léger et réputé pour ses performances, permettra de customiser l’installation pour y ajuster les paramètres idéaux pour la plateforme odroid-HC1.

En plus de nginx, il faut installer le module php-fpm qui va exécuter le code PHP de l’application pour nginx.

apt install nginx php7.3-fpm

Création d’un certificat SSL temporaire, auto-signé

Il va servir à sécuriser les accès https vers l’application, le temps qu’on ait un vrai certificat.

openssl req -x509 -sha256 -nodes -days 3650 -newkey rsa:4096 -keyout nextcloud-perso.key -out nextcloud-perso.crt

On répond aux questions en fonction de ses préférences, perso j’ai mis ça:

Country Name (2 letter code) [AU]:FR
State or Province Name (full name) [Some-State]:Golden Coast
Locality Name (eg, city) []:Longeault City
Organization Name (eg, company) [Internet Widgits Pty Ltd]:cinquantehuit corp
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:minicloud
Email Address []:admin@minicloud

La paire certificat / clé privée doit être placée dans un endroit arbitraire, accessible à nginx, et la clé privée lisible uniquement pour celui-ci:

mkdir /etc/ssl/nginx

mv nextcloud-perso.key nextcloud-perso.crt /etc/ssl/nginx

chown www-data:www-data /etc/ssl/nginx/nextcloud-perso.key /etc/ssl/nginx/nextcloud-perso.crt

chmod 600 /etc/ssl/nginx/nextcloud-perso.key

Configuration de nginx

La documentation de Nextcloud fournit un exemple de configuration d’un hôte nginx. Ça va servir de base ici pour créer le fichier de configuration /etc/nginx/sites-available/nextcloud. Les personnalisations sont en couleur.

upstream php-handler {
    server unix:/run/php/php7.3-fpm.sock;
}

server {
    listen 80;
    listen [::]:80;
    server_name minicloud;

    # Enforce HTTPS
    return 301 https://$server_name$request_uri;
}

server {
    listen 443      ssl http2;
    listen [::]:443 ssl http2;
    server_name minicloud;

    # Use Mozilla's guidelines for SSL/TLS settings
    # https://mozilla.github.io/server-side-tls/ssl-config-generator/
    ssl_certificate     /etc/ssl/nginx/nextcloud-perso.crt;
    ssl_certificate_key /etc/ssl/nginx/nextcloud-perso.key;

    # HSTS settings
    # WARNING: Only add the preload option once you read about
    # the consequences in https://hstspreload.org/. This option
    # will add the domain to a hardcoded list that is shipped
    # in all major browsers and getting removed from this list
    # could take several months.
    #add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;" always;

    # set max upload size
    client_max_body_size 512M;
    fastcgi_buffers 64 4K;

    # Enable gzip but do not remove ETag headers
    gzip on;
    gzip_vary on;
    gzip_comp_level 4;
    gzip_min_length 256;
    gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
    gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;

    # Pagespeed is not supported by Nextcloud, so if your server is built
    # with the `ngx_pagespeed` module, uncomment this line to disable it.
    #pagespeed off;

    # HTTP response headers borrowed from Nextcloud `.htaccess`
    add_header Referrer-Policy                      "no-referrer"   always;
    add_header X-Content-Type-Options               "nosniff"       always;
    add_header X-Download-Options                   "noopen"        always;
    add_header X-Frame-Options                      "SAMEORIGIN"    always;
    add_header X-Permitted-Cross-Domain-Policies    "none"          always;
    add_header X-Robots-Tag                         "none"          always;
    add_header X-XSS-Protection                     "1; mode=block" always;

    # Remove X-Powered-By, which is an information leak
    fastcgi_hide_header X-Powered-By;

    # Path to the root of your installation
    root /var/www/nextcloud;

    # Specify how to handle directories -- specifying `/index.php$request_uri`
    # here as the fallback means that Nginx always exhibits the desired behaviour
    # when a client requests a path that corresponds to a directory that exists
    # on the server. In particular, if that directory contains an index.php file,
    # that file is correctly served; if it doesn't, then the request is passed to
    # the front-end controller. This consistent behaviour means that we don't need
    # to specify custom rules for certain paths (e.g. images and other assets,
    # `/updater`, `/ocm-provider`, `/ocs-provider`), and thus
    # `try_files $uri $uri/ /index.php$request_uri`
    # always provides the desired behaviour.
    index index.php index.html /index.php$request_uri;

    # Rule borrowed from `.htaccess` to handle Microsoft DAV clients
    location = / {
        if ( $http_user_agent ~ ^DavClnt ) {
            return 302 /remote.php/webdav/$is_args$args;
        }
    }

    location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;
    }

    # Make a regex exception for `/.well-known` so that clients can still
    # access it despite the existence of the regex rule
    # `location ~ /(\.|autotest|...)` which would otherwise handle requests
    # for `/.well-known`.
    location ^~ /.well-known {
        # The following 6 rules are borrowed from `.htaccess`

        location = /.well-known/carddav     { return 301 /remote.php/dav/; }
        location = /.well-known/caldav      { return 301 /remote.php/dav/; }
        # Anything else is dynamically handled by Nextcloud
        location ^~ /.well-known            { return 301 /index.php$uri; }

        try_files $uri $uri/ =404;
    }

    # Rules borrowed from `.htaccess` to hide certain paths from clients
    location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/)  { return 404; }
    location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console)              { return 404; }

    # Ensure this block, which passes PHP files to the PHP process, is above the blocks
    # which handle static assets (as seen below). If this block is not declared first,
    # then Nginx will encounter an infinite rewriting loop when it prepends `/index.php`
    # to the URI, resulting in a HTTP 500 error response.
    location ~ \.php(?:$|/) {
        fastcgi_split_path_info ^(.+?\.php)(/.*)$;
        set $path_info $fastcgi_path_info;

        try_files $fastcgi_script_name =404;

        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $path_info;
        fastcgi_param HTTPS on;

        fastcgi_param modHeadersAvailable true;         # Avoid sending the security headers twice
        fastcgi_param front_controller_active true;     # Enable pretty urls
        fastcgi_pass php-handler;

        fastcgi_intercept_errors on;
        fastcgi_request_buffering off;
    }

    location ~ \.(?:css|js|svg|gif)$ {
        try_files $uri /index.php$request_uri;
        expires 6M;         # Cache-Control policy borrowed from `.htaccess`
        access_log off;     # Optional: Don't log access to assets
    }

    location ~ \.woff2?$ {
        try_files $uri /index.php$request_uri;
        expires 7d;         # Cache-Control policy borrowed from `.htaccess`
        access_log off;     # Optional: Don't log access to assets
    }

    location / {
        try_files $uri $uri/ /index.php$request_uri;
    }
}

Pour l’instant les seules personnalisations effectuées dans le modèle fichier de configuration donnée par la documentation de Nextcloud sont:

  • la directive server : dans l’exemple fournit par la documentation, elle demande au démon nginx de se connecter au moteur php-fm sur la boucle locale IP. Ici nous la configurons pour que nginx communique avec php-fpm sur un socket Unix, comme les deux éléments sont sur la même machine. Il faudra penser à configurer php-fpm en conséquence.
  • les deux directives server_name : j’ai mis pour l’instant minicloud, qui est le nom d’hôte que j’ai donné à la machine. Pour l’instant on se connectera dessus en utilisant ce nom (en considérant que le nom est bien résolu dans le réseau).
  • les deux directives ssl_certificate et ssl_certificate_key pour indiquer le chemin vers respectivement notre certificat auto signé et la clé privée qui va avec.

L’exemple de configuration entend que les fichiers de l’application Nextcloud sont déposés dans /var/www/nextcloud. On ne le créé pas tout de suite, car il le sera au moment de l’installation de l’application.

Enfin, il faut rendre le nouveau virtual host nginx disponible pour la production (on en profite également pour désactiver le virtual host par défaut), et recharger la configuration:

ln -s /etc/nginx/sites-available/nextcloud /etc/nginx/sites-enabled/nextcloud

rm -f /etc/nginx/sites-enabled/default

systemctl reload nginx

Configuration de php-fpm

C’est lui qui va interpréter le code PHP de l’applicatif Nextcloud, et qui transmettra à nginx les pages ainsi générées.

Le paquet Debian propose un pool par défaut dont le fichier de configuration se trouve ici : /etc/php/7.3/fpm/pool.d/www.conf .

Dans un premier temps on va juste vérifier que la directive listen pointe bien un socket Unix, et qu’il soit le même que celui configuré dans nginx précédemment.

listen = /run/php/php7.3-fpm.sock

Il faut également bien penser à mapper certaines variables d’environnement, qui ne le sont pas automatiquement avec php-fpm. Toujours dans le fichier /etc/php/7.3/fpm/pool.d/www.conf,  il faut décommenter les lignes suivantes:

env[HOSTNAME] = $HOSTNAME
env[PATH] = /usr/local/bin:/usr/bin:/bin
env[TMP] = /tmp
env[TMPDIR] = /tmp
env[TEMP] = /tmp

Enfin, on va essayer de paramétrer la gestion des processus php-fpm pour l’adapter à notre environnement. Ce paramétrage doit prendre en compte le matériel (surtout sa quantité de RAM, mais aussi le nombre de coeurs de la CPU), et le trafic qui va avoir lieu sur l’application web Nextcloud. Et pour ce point, ça n’est pas évident à évaluer. En effet, on a dit que notre cloud perso allait servir 4 à 6 personnes, mais on ne sait pas combien de périphériques synchronisables auront ces personnes, ni avec quelle fréquence ils feront leurs synchronisations. Bref, en gros le paramétrage va se passer principalement de manière empirique, et il devra être ajusté (si possible) en fonction de la charge sur l’applicatif.

Quoi qu’il en soit, le governor va être positionné sur dynamic, qui est je pense celui qui sera le plus adapté ici.

pm = dynamic

Ensuite, pour ce mode dynamic, on va partir sur les valeurs de gestion des processus suivantes:

pm.start_servers = 18 # trois fois plus de processus que d'utilisateurs au démarrage

pm.max_children = 36 # jusqu'à six fois plus de  processus que d'utilisateurs au maximum

pm.min_spare_servers = 6 # 6 processus en attente minimum

pm.max_spare_servers = 18 # 18 processus en attente maximum

pm.process_idle_timeout = 60s # un processus qui ne fait rien est killé au bout de 60 secondes

On s’est permis ici de dimensionner la gestion des processus en fonction du nombre d’utilisateurs parce qu’on connait leur nombre, ce qui est rare. Mais ici on peut. Maintenant honnêtement je n’ai aucune idée de ce que ça va donner en situation réelle, on verra à l’usage, si ces réglages conviennent à servir correctement tous les utilisateurs, et n’aboutissent pas à une saturation de la RAM. Pour comparaison, la documentation de Nextcloud propose des valeurs à titre d’exemple pour un système disposant de deux fois plus de RAM que notre système; certaines valeurs de réglages sont en cohérence avec les notres, d’autres diffèrent beaucoup.

On redémarre  php-fpm et nginx pour prendre en compte les nouveaux paramètres:

systemctl restart php7.3-fpm.service nginx

Activation de l’OPcache de PHP

Pour optimiser le temps de réponse de PHP, et décharger la CPU, on peut utiliser l’OPcache de PHP qui va stocker en RAM les instructions compilées de PHP, pour ne pas avoir à les recompiler pour une prochaine utilisation. On peut paramétrer l’empreinte en RAM, et je pense que ça vaut le coup d’utiliser cette technologie. Pour l’activer, ça se passe dans le fichier /etc/php/7.3/fpm/php.ini. Les valeurs proposées dans la documentation de Nextcloud sont assez élevées pour notre système, mais on va utiliser les mêmes car l’application se plaint si on ne met pas ces valeurs. J’espère que ça ne pénalisera pas trop la RAM du système.

opcache.enable=1
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=10000
opcache.memory_consumption=128
opcache.save_comments=1
opcache.revalidate_freq=1

Les programmes serveur nécessaires au fonctionnement de l’application sont à présent installés et configurés, passons à la page suivante pour le plat de résistance : l’installation de Nextcloud !

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *