Sommaire

Bonjour à tous !

Dans cet article, je vais vous guider pas à pas sur comment faire une installation de Nextcloud propre et fonctionnelle sous Ubuntu 23.04 en utilisant Nginx.


Pour les fervents utilisateurs de Debian, ce tutoriel fonctionne aussi sous Debian12 !



Pourquoi Nginx ?

Car, selon moi, il est incomparablement mieux que Apache. Il est léger, extrêmement puissant, et lorsqu'on regarde le nombre de failles de sécurité (CVE) entre Apache et Nginx, on se rend compte qu'il est aussi bien plus sécurisé




Prérequis





Commençons


À partir de maintenant, je suppose que vous êtes dans une console, connecté en tant que root. Si ce n'est pas le cas, exécutez la commande :

su


I- La base


On met à jour notre système

sudo apt update
sudo apt full-upgrade -y



1- Nginx


On installe Nginx ainsi que quelques autres petites choses dont on se servira

sudo apt-get -y install nginx ffmpeg mariadb-server gpg bzip2

Nginx est notre serveur web. Pour faire simple, c'est lui qui récupère toutes les connexions sur le serveur et fournit les bonnes pages web



Afin de donner la bonne valeur à Nginx, on récupère le nombre de coeurs du processeur.

sudo grep processor /proc/cpuinfo | wc -l


Puis on modifie le fichier de configuration Nginx.

sudo nano /etc/nginx/nginx.conf

Pour enregistrer et quitter sur Nano, c'est CTRL+S puis CTRL+X.

user www-data;
worker_processes 2;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
                    
events {
    worker_connections 768;
    # multi_accept on;
}
                    
http {
                    
    ##
    # Basic Settings
    ##
                    
    sendfile on;
    tcp_nopush on;
    types_hash_max_size 2048;
    server_tokens off;
                        
    # server_names_hash_bucket_size 64;
    # server_name_in_redirect off;


.....
                

Il est recommandé de mettre autant de worker_processes que de cœurs disponibles sur votre serveur.
server_tokens permet de masquer la version de Nginx, ce qui est une bonne pratique de sécurité.
Donc, retirez le # devant la ligne afin de la décommenter.



2- Nextcloud


On se place maintenant dans le dossier qui accueillera les fichiers de Nextcloud et on les télécharge.

cd /var/www
sudo wget https://download.nextcloud.com/server/releases/latest.tar.bz2
sudo wget https://download.nextcloud.com/server/releases/latest.tar.bz2.sha256

sha256sum -c latest.tar.bz2.sha256 < latest.tar.bz2

Après l'exécution de cette dernière commande, on vérifie que le hash est bon.

latest.tar.bz2: OK


Si tout est bon, on vérifie la signature PGP

sudo wget https://download.nextcloud.com/server/releases/latest.tar.bz2.asc
sudo wget https://nextcloud.com/nextcloud.asc
gpg --import nextcloud.asc
gpg --verify latest.tar.bz2.asc latest.tar.bz2

                gpg: Signature made Thu 21 Sep 2023 09:08:13 AM UTC
                gpg:                using RSA key 28806A878AE423A28372792ED75899B9A724937A
                gpg: Good signature from "Nextcloud Security " [unknown]
                gpg: WARNING: This key is not certified with a trusted signature!
                gpg:          There is no indication that the signature belongs to the owner.
                Primary key fingerprint: 2880 6A87 8AE4 23A2 8372  792E D758 99B9 A724 937A
                

Si tout est bon, la sortie doit contenir Good signature



Enfin, on extrait l'archive

sudo tar -xvf latest.tar.bz2
sudo rm latest.tar.bz2* nextcloud.asc



II- Droits d'acces sous linux


Par défaut, un serveur web fait tourner tous les sites sous un utilisateur à part du système (souvent www-data). En cas de compromission d'un des sites, le pirate n'a que des accès restreints. Il ne peut, par exemple, pas visiter votre dossier personnel ni installer une application.
Mais, comme tous les sites tournent sur le même utilisateur, si un site est compromis, il peut compromettre les autres sites, accéder à vos données. C'est pourquoi, on va créer un utilisateur réservé à Nextcloud. Lui seul aura accès aux données de votre Nextcloud.


sudo adduser nextcloud

Créez un bon mot de passe. Et s'il vous plaît, ne réutilisez pas vos mots de passe. Utilisez un gestionnaire si vous le souhaitez.
(Je recommande Bitwarden).


On donne donc la propriété du dossier Nextcloud à l'utilisateur Nextcloud. Puis on retire les permissions aux autres.

sudo chown -R nextcloud:www-data /var/www/nextcloud
sudo chmod -R o-rwx /var/www/nextcloud


III- PHP


On télécharge php

sudo apt install php8.2-{fpm,ctype,curl,dom,gd,mbstring,posix,simplexml,xmlreader,xmlwriter,zip,mysql,bz2,intl,imap,bcmath,gmp,imap,ftp,ldap,gmp,exif,apcu,memcached,redis,imagick,phar}



On crée la configuration de php pour nextcloud

sudo nano /etc/php/8.2/fpm/pool.d/nextcloud.conf

[nextcloud]
listen = /var/run/nextcloud.sock

listen.owner = nextcloud
listen.group = www-data

user = nextcloud
group = www-data

pm = ondemand
pm.max_children = 200
pm.process_idle_timeout = 60s
pm.max_requests = 500


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

request_terminate_timeout = 3600
catch_workers_output = yes
php_flag[display_errors] = on
php_admin_value[error_log] = /var/log/fpm-php.log
php_admin_flag[log_errors] = on
                

Si vous observez des problèmes de stabilité, modifiez la variable pm.max_children. vous pouvez allez voir https://spot13.com/pmcalculator/

sudo systemctl edit php8.2-fpm.service


Dans ce fichier, ajoutez les lignes suivantes

[Service]
UMask=0027

Enfin, on réactive PHP

sudo systemctl reenable php8.2-fpm.service


IV- MariaDB


On s'attaque maintenant à la base de données.

sudo mysql_secure_installation

                    
NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB
SERVERS IN PRODUCTION USE!  PLEASE READ EACH STEP CAREFULLY!

In order to log into MariaDB to secure it, we'll need the current
password for the root user. If you've just installed MariaDB, and
haven't set the root password yet, you should just press enter here.

Enter current password for root (enter for none):[TOUCHE ENTRER] 
OK, successfully used password, moving on...

Setting the root password or using the unix_socket ensures that nobody
can log into the MariaDB root user without the proper authorisation.

You already have your root account protected, so you can safely answer 'n'.

Switch to unix_socket authentication [Y/n] n
... skipping.

You already have your root account protected, so you can safely answer 'n'.

Change the root password? [Y/n] Y
New password: Un bon mot de passe !
Re-enter new password:
Password updated successfully!
Reloading privilege tables..
... Success!


By default, a MariaDB installation has an anonymous user, allowing anyone
to log into MariaDB without having to have a user account created for
them.  This is intended only for testing, and to make the installation
go a bit smoother.  You should remove them before moving into a
production environment.

Remove anonymous users? [Y/n] Y
... Success!

Normally, root should only be allowed to connect from 'localhost'.  This
ensures that someone cannot guess at the root password from the network.

Disallow root login remotely? [Y/n] Y
... Success!

By default, MariaDB comes with a database named 'test' that anyone can
access.  This is also intended only for testing, and should be removed
before moving into a production environment.

Remove test database and access to it? [Y/n]Y
- Dropping test database...
... Success!
- Removing privileges on test database...
... Success!

Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.

Reload privilege tables now? [Y/n] Y
... Success!

Cleaning up...

All done!  If you've completed all of the above steps, your MariaDB
installation should now be secure.

Thanks for using MariaDB!

                

Maintenant que MariaDB est configuré, on peut créer notre base de données.

sudo mysql -u root -p

Ici, le mot de passe est le mot de passe root créé lors de mariadb_secure_installation


Puis, dans MariaDB, exécutez une par une les commandes ci-dessous.

CREATE USER 'nextcloud'@'localhost' IDENTIFIED BY 'motdepasse';
CREATE DATABASE IF NOT EXISTS nextcloud CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
GRANT ALL PRIVILEGES ON nextcloud.* TO 'nextcloud'@'localhost';
FLUSH PRIVILEGES;
quit;


On modifie un petit peu la configuration

sudo nano /etc/mysql/conf.d/mysql.cnf

[mysql]

[mysqld]
innodb_buffer_pool_size=1G
innodb_io_capacity=4000
                

J'ai remarqué que sans l'ajout de ces lignes, nextcloud crash lorsqu'il charge de nombreux fichiers.

sudo systemctl restart mysqld


V- SSL avec certbot


SSL est le protocole qui gère le httpS.


Nginx fonctionne avec des fichiers de configuration. Pour faire les choses proprement, un fichier par site.
On va donc créer celui de Nextcloud.
Pour ne pas se prendre la tête, on va créer une configuration vide, générer le certificat SSL, puis mettre la vraie configuration paramétrée pour fonctionner avec le SSL.


sudo nano /etc/nginx/sites-available/nextcloud

server {
    listen                        80;
    listen                        [::]:80;
    server_name                   example.com;
    root                          /var/www/nextcloud/;
}
                    

En changeant bien sûr example.com par votre domaine, ou votre sous-domaine.


Cette configuration est dans le dossier "sites-available", ce qui dit à Nginx qu'elle existe.
Pour la rendre active, on doit créer un lien vers le dossier "sites-enabled".

cd /etc/nginx/sites-enabled/
sudo ln -s ../sites-available/nextcloud .
sudo systemctl restart nginx.service

Voilà, Nginx est prêt à recevoir Certbot. On l'installe.

sudo apt-get install -y software-properties-common certbot

sudo certbot certonly --webroot -w /var/www/nextcloud --agree-tos --no-eff-email --email email@example.com -d example.com --rsa-key-size 4096

En renseignant votre adresse email et votre domaine.



Pour plus de sécurité, on va générer une clé DH de 4096 bits. La commande peut prendre beaucoup de temps en fonction de votre pc.

sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096

Une fois que c'est fait, on lui donne le minimum de droits

sudo chmod 600 /etc/ssl/certs/dhparam.pem


Et voilà ! Nos clés SSL sont prêtes. Il suffit de mettre à jour notre configuration Nginx.

Supprimez toutes les lignes précédemment écrites et remplacer le tout.

sudo nano /etc/nginx/sites-available/nextcloud

upstream php-handler {
    server unix:/var/run/nextcloud.sock;                        
}
                        
map $arg_v $asset_immutable {
    "" "";
    default "immutable";
}
                        
                        
server {
    listen 80;
    listen [::]:80;
    server_name example.com;
                        
    server_tokens off;
                        
    location ~ /.well-known {
        root /var/www/nextcloud/;
        allow all;
    }
                        
    # Enforce HTTPS
    return 301 https://$server_name$request_uri;
}
                        
server {
    listen 443      ssl http2;
    listen [::]:443 ssl http2;
    server_name example.com;
                        
    # Path to the root of your installation
    root /var/www/nextcloud;
                        
    # Use Mozilla's guidelines for SSL/TLS settings
    # https://mozilla.github.io/server-side-tls/ssl-config-generator/
    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
                        
    ssl_session_timeout 1d;
    ssl_session_cache shared:MozSSL:10m;  # about 40000 sessions
    ssl_session_tickets off;
                        
    ssl_dhparam /etc/ssl/certs/dhparam.pem;
                        
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;
                        
    # HSTS (ngx_http_headers_module is required) (63072000 seconds)
    add_header Strict-Transport-Security "max-age=63072000" always;
                        
    # OCSP stapling
    ssl_stapling on;
    ssl_stapling_verify on;
                        
    ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
                        
    resolver 127.0.0.1;
                        
                           
    server_tokens off;
    
    # set max upload size and increase upload timeout:
    client_max_body_size 1G;
    client_body_timeout 300s;
    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/wasm 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;
    
    client_body_buffer_size 512k;
    
    # 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                      "noindex, nofollow" 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;
    
    
    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 rules in this block are an adaptation of the rules
        # in `.htaccess` that concern `/.well-known`.
    
        location = /.well-known/carddav { return 301 /remote.php/dav/; }
        location = /.well-known/caldav  { return 301 /remote.php/dav/; }
    
        location /.well-known/acme-challenge    { try_files $uri $uri/ =404; }
        location /.well-known/pki-validation    { try_files $uri $uri/ =404; }
    
        # Let Nextcloud's API for `/.well-known` URIs handle all other
        # requests by passing them to the front-end controller.
        return 301 /index.php$request_uri;
    }
    
    # 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(?:$|/) {
        # Required for legacy support
        rewrite ^/(?!index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+|.+\/richdocumentscode\/proxy) /index.php$request_uri;
    
        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;
        fastcgi_read_timeout      3600;
    
        fastcgi_max_temp_file_size 0;
    }
    
    location ~ \.(?:css|js|svg|gif|png|jpg|ico|wasm|tflite|map)$ {
        try_files $uri /index.php$request_uri;
        add_header Cache-Control "public, max-age=15778463, $asset_immutable";
        access_log off;     # Optional: Don't log access to assets
    
        location ~ \.wasm$ {
            default_type application/wasm;
        }
    }
    
    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
    }
    
    # Rule borrowed from `.htaccess`
    location /remote {
        return 301 /remote.php$request_uri;
    }
    
    location / {
        try_files $uri $uri/ /index.php$request_uri;
    }
                        
    location ~ /\.(?!file).* { deny all; }
}
                    

Voilà notre véritable configuration pour nextcloud. Pensez à changer example.com par votre domaine ou sous domaine.

sudo systemctl reload nginx.service
sudo certbot renew --dry-run
sudo systemctl restart nginx.service
sudo systemctl restart php8.2-fpm.service

On redémarre tout pour bien prendre les configs.


VI- OPcache et apcu


Il nous reste peu de chose à faire. On va faire quelques optimisations avec le cache.

sudo nano /etc/php/8.2/fpm/php.ini

.....

memory_limit=512M (ligne environ 435)

.....

[opcache] (ligne environ 1787)
opcache.enable=1
opcache.enable_cli=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=10000
opcache.revalidate_freq=60
opcache.save_comments=1
                    

Il faut décommenter les lignes et modifier les valeurs.
Sous Nano, pour rechercher, c'est CTRL+W.


sudo systemctl restart php8.2-fpm.service
sudo apt-get install php-apcu redis-server php-redis -y


On modifie le fichier de configuration d'apcu.

sudo nano /etc/php/8.2/mods-available/apcu.ini

extension=apcu.so
apc.enable_cli=1


VII - On lance !


Enfin, courage, la configuration est casi finie.


Rendez-vous sur votre domaine example.com

Vous devriez avoir la fenêtre de configuration de nextcloud qui s'ouvre.


fenetre de configuration de nextcloud

Les deux premiers champs sont vos identifiants de connexion administrateur pour votre interface nextcloud.
Le répertoire des données est un dossier accessible (nextcloud:www-data).
Par exemple: /var/www/nextcloud/data
En dessous, ce sont les identifiants de la base de données:
L'utilisateur de la base de données est nextcloud
Le mot de passe est celui que vous avez définie lors de la configuration de mariaDB (à la place de motdepasse)
Le nom de la base de données est nextcloud
Et l'hôte est localhost.


VIII - Petites retouches


Pour modifier la configuration de nextcloud, sans altérer les droits, on doit se connecter en tant que nextcloud.

su nextcloud


nano /var/www/nextcloud/config/config.php

Ajoutez les lignes suivantes en dessous de la ligne instanceid, au-dessus de ");"


'memcache.local' => '\\OC\\Memcache\\APCu',
'memcache.locking' => '\\OC\\Memcache\\Redis',
'redis' => array(
    'host' => 'localhost',
    'port' => 6379,
),
'loglevel' => 2,
'logtimezone' => 'Europe/Paris',
'logfile' => '/var/log/nextcloud/nextcloud.log',
'log_rotate_size' => '104857600',
'default_phone_region' => 'FR',

Puis on retourne en root

exit


On va maintenant installer Fail2Ban, un outil qui permet de bannir une partie des bots qui essaieraient d'attaquer votre site.

sudo systemctl restart php8.2-fpm.service
sudo mkdir /var/log/nextcloud
sudo chown nextcloud:www-data /var/log/nextcloud
sudo apt-get -y install fail2ban


Et on modifie sa configuration

sudo nano /etc/fail2ban/filter.d/nextcloud.conf

[Definition]
failregex=^{"reqId":".*","remoteAddr":".*","app":"core","message":"Login failed: '.*' \(Remote IP: ''\)","level":2,"time":".*"}$
      ^{"reqId":".*","level":2,"time":".*","remoteAddr":".*","user,:".*","app":"no app in context".*","method":".*","message":"Login failed: '.*' \(Remote IP: ''\)".*}$
      ^{"reqId":".*","level":2,"time":".*","remoteAddr":".*","user":".*","app":".*","method":".*","url":".*","message":"Login failed: .* \(Remote IP: \).*}$


On crée la jail pour nextcloud

sudo nano /etc/fail2ban/jail.local

[nextcloud]
enabled = true
port = 80,443
protocol = tcp
filter = nextcloud
maxretry = 3
bantime = 3600
logpath = /var/log/nextcloud/nextcloud.log

On redémarre le service

sudo systemctl restart fail2ban.service

Et on l'active

sudo fail2ban-client start


Enfin, on modifie le fichier cron pour lancer les vérifications de Nextcloud automatiquement.

sudo crontab -u nextcloud -e

il se peut qu'il vous demande quel éditeur utilisé. Si vous ne savez pas, mettez 1.


Et on ajoute cette ligne

*/5 * * * * php -f /var/www/nextcloud/cron.php


Et on relance tout pour être sûr.

sudo systemctl restart php8.2-fpm.service
sudo systemctl restart nginx.service


Bonus


Connecté sous l'utilisateur nextcloud, on installe RichDocuments

su nextcloud
cd /var/www/nextcloud
php -d memory_limit=512M occ app:install richdocumentscode


RichDocuments permet d'avoir une sorte de suite office (word powerpoint etc) directement sur son nextcloud.


DEBUG


Si vous ajoutez manuellement des fichiers dans le répertoire /var/www/nextcloud/data/
tout d'abord, il faut faire attention aux droits. Donc soit vous les copiez en étant connecté en tant qu'utilisateur Nextcloud.
Soit après le transfert, il faut changer les droits

su root
sudo chown -R nextcloud:www-data /var/www/nextcloud
sudo chmod -R o-rwx /var/www/nextcloud


Ensuite, il faut indiquer à Nextcloud qu'il doit les prendre en compte !
Pour ça, on fait un scan avec la commande suivante :

su nextcloud
cd /var/www/nextcloud
php occ files:scan --all



Si vous vous retrouvez limité par le système anti-intrusion de Nextcloud (en vous trompant trop de fois de mot de passe),
exécutez ces commandes pour vous débannir.

su nextcloud
cd /var/www/nextcloud
php occ security:bruteforce:reset ip