Installare Nextcloud sul proprio server

Pubblicato il 14 min di lettura

Dal server vuoto alla panoramica senza avvisi: web server, moduli PHP, database, permessi sulla directory dei dati, trusted_domains, limiti di upload e job in background via cron.

Scompattare Nextcloud richiede pochi secondi. La parte che costa tempo viene dopo: su un'installazione appena creata la pagina di panoramica sotto Impostazioni di amministrazione mostra quasi sempre un elenco di avvisi gialli e rossi, gli upload si interrompono a 2 MB e la chiamata tramite indirizzo IP finisce con "You are accessing the site from an untrusted domain.". Questo articolo percorre l'intero tragitto e si ferma proprio nei punti in cui la maggior parte delle guide smette.

Da decidere prima: versione di PHP, database, posizione dei dati

Nextcloud dipende dalla versione di PHP molto più della maggior parte degli altri software server. Le serie attuali 33 e 34 richiedono almeno PHP 8.2, la serie 32 gira ancora a partire da PHP 8.1. È quindi la distribuzione a decidere se ti bastano gli strumenti di bordo:

SistemaPHP della distribuzioneDatabase della distribuzioneValutazione
Debian 13 (trixie)8.4MariaDB 11.8va bene senza repository esterni
Debian 12 (bookworm)8.2MariaDB 10.11va bene, ma è al limite inferiore
Ubuntu 24.04 LTS8.3MariaDB 10.11, MySQL 8.0va bene senza repository esterni
Ubuntu 22.04 LTS8.1MariaDB 10.6, MySQL 8.0troppo vecchio per Nextcloud 33 e 34
Debian 11 (bullseye)7.4MariaDB 10.5da escludere

Debian 11 è il caso più duro e tende comunque a farsi notare tardi, perché l'installazione dei pacchetti va a buon fine senza errori. Lì il metapacchetto php tira dietro PHP 7.4, e la versione attuale di Nextcloud si interrompe alla prima chiamata nel browser con HTTP 500 e il messaggio "This version of Nextcloud requires at least PHP 8.2". Debian 11 è comunque uscito dal supporto regolare e come base per una nuova installazione è la scelta sbagliata. Se proprio non puoi farne a meno, aggiungi prima il repository Sury e installa esplicitamente i pacchetti con numero di versione, quindi php8.2-fpm, php8.2-cli, php8.2-mysql e così via, invece dei metapacchetti senza versione.

Anche su Ubuntu 22.04 finisci inevitabilmente contro un muro non appena installi la versione attuale di Nextcloud. O resti consapevolmente sulla serie 32, oppure prendi PHP dal noto PPA:

sudo apt-get install -y software-properties-common
sudo add-apt-repository -y ppa:ondrej/php
sudo apt-get update
sudo apt-get install -y php8.3-fpm php8.3-cli php8.3-mysql

Altri due punti che si fissano all'inizio e che dopo si cambiano solo a fatica: Debian non fornisce in nessun caso un pacchetto mysql-server, lì la scelta obbligata è MariaDB. E la directory dei dati non va sotto /var/www/nextcloud/data, ma fuori dalla radice del web server, per esempio in /var/nextcloud-data. Il percorso predefinito è pericoloso per un motivo preciso: con una configurazione del web server rotta, tutti i file degli utenti finirebbero serviti in chiaro. In quel caso Nextcloud avverte con "Your data directory and files are probably accessible from the internet", ma solo dopo che l'errore esiste già.

Configurare web server, PHP e database

Qui usiamo nginx con PHP-FPM. Se preferisci Apache con mod_php, il percorso è descritto in Apache, PHP e MySQL su Debian, mentre gli argomenti su PHP più avanti restano validi senza modifiche. Un'installazione di base di nginx la trovi in installare nginx.

sudo apt-get update
sudo apt-get install -y nginx mariadb-server
sudo apt-get install -y php-fpm php-cli php-mysql php-gd php-curl php-mbstring php-intl php-gmp php-bcmath php-xml php-zip php-imagick php-apcu

Questo elenco è volutamente più lungo del minimo indispensabile. Nextcloud usa bcmath e gmp per l'accesso senza password, intl per l'ordinamento corretto di lettere accentate e caratteri speciali, imagick per le anteprime, apcu per la cache locale. Se manca uno dei moduli obbligatori non superi nemmeno la procedura guidata di installazione: la pagina elenca allora per nome i moduli mancanti.

Verifica poi che cosa viene effettivamente caricato:

php -v
php -m

Il secondo inciampo frequente: esistono due configurazioni PHP separate, una per la riga di comando e una per FPM. php --ini ti mostra quella della riga di comando, quella del web server si trova sotto /etc/php/<version>/fpm/php.ini. Le modifiche al file sbagliato non hanno alcun effetto, ed è proprio questo a rubare in genere più tempo di tutto il resto.

Ora il database. Metti prima in sicurezza MariaDB, vedi mettere in sicurezza MariaDB e MySQL, poi:

sudo mariadb -e "CREATE DATABASE nextcloud CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;"
sudo mariadb -e "CREATE USER 'nextcloud'@'localhost' IDENTIFIED BY 'QuiUnaPasswordLunga';"
sudo mariadb -e "GRANT ALL PRIVILEGES ON nextcloud.* TO 'nextcloud'@'localhost';"
sudo mariadb -e "FLUSH PRIVILEGES;"

Il utf8mb4 nel primo comando non è un dettaglio. Se crei il database con utf8, più avanti Nextcloud segnala "MySQL is used as database but does not support 4-byte characters", e la conversione a sistema in esercizio è molto più fastidiosa del CREATE DATABASE giusto fin dall'inizio. Se l'accesso dell'utente del database fallisce, ti aiuta risolvere Access denied for user.

Scompattare e impostare i permessi

sudo apt-get install -y wget unzip
wget https://download.nextcloud.com/server/releases/latest.zip
sudo unzip -q latest.zip -d /var/www
sudo mkdir -p /var/nextcloud-data
sudo chown -R www-data:www-data /var/www/nextcloud
sudo chown -R www-data:www-data /var/nextcloud-data
sudo chmod 750 /var/nextcloud-data

I permessi sono il punto in cui si lavora più spesso in modo approssimativo. Tre quadri d'errore e la loro causa:

  • "Cannot write into config directory": /var/www/nextcloud/config non appartiene all'utente del web server. Su Debian e Ubuntu è www-data, su AlmaLinux e Rocky invece apache oppure nginx. Un chown www-data copiato alla cieca non produce nulla sulla famiglia Red Hat.
  • "Can't create or write into the data directory": il percorso non esiste, non è un percorso assoluto, oppure una directory superiore non è attraversabile da www-data.
  • "Your data directory is readable by other users": permessi troppo larghi. Basta chmod 750 sulla directory dei dati.

Resisti alla tentazione di risolvere il problema a martellate con chmod -R 777. Nextcloud risponde con esattamente l'avviso che volevi togliere di mezzo e, per giunta, hai reso ogni file leggibile a qualunque utente locale.

La configurazione di nginx

Nextcloud ha bisogno di più di un normale blocco PHP, tra le altre cose di riscritture per il rilevamento dei servizi sotto /.well-known/ e di blocchi per le directory interne. Quella che segue è la versione ridotta del modello ufficiale e funziona così com'è:

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

server {
    listen 80;
    server_name cloud.example.com;
    root /var/www/nextcloud;

    client_max_body_size 10G;
    client_body_timeout 300s;
    fastcgi_buffers 64 4K;

    add_header Referrer-Policy "no-referrer" always;
    add_header X-Content-Type-Options "nosniff" 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;

    index index.php index.html /index.php$request_uri;

    location ^~ /.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; }
        return 301 /index.php$request_uri;
    }

    location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/) { return 404; }
    location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console)              { return 404; }

    location ~ \.php(?:$|/) {
        rewrite ^/(?!index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+) /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 front_controller_active true;
        fastcgi_pass php-handler;
        fastcgi_request_buffering off;
        fastcgi_max_temp_file_size 0;
    }

    location ~ \.(?:css|js|mjs|svg|gif|ico|jpg|png|webp|wasm|map|woff2)$ {
        try_files $uri /index.php$request_uri;
        expires 6M;
        access_log off;
    }

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

Il percorso del socket FPM va adattato alla tua versione di PHP. Su Debian 13 si chiama php8.4-fpm.sock, su Debian 12 php8.2-fpm.sock, su Ubuntu 24.04 php8.3-fpm.sock e su Ubuntu 22.04 php8.1-fpm.sock. Se il nome non corrisponde ottieni un 502 Bad Gateway. Il nome reale lo mostra:

systemctl enable --now php8.4-fpm
ls /run/php/

La prima riga fa parte del gioco, perché il file socket nasce solo all'avvio del servizio. Prima /run/php/ è vuota oppure non esiste affatto, e ls risponde con No such file or directory. Su un server normale è il pacchetto stesso ad avviare il servizio durante l'installazione, ma dopo una reinstallazione o dentro un container questo non è garantito. Adatta il numero di versione nel nome del servizio alla tua installazione. Poi nginx -t e ricarica.

Installazione, HTTPS e trusted_domains

Puoi completare l'installazione cliccando nel browser oppure sbrigarla subito dalla riga di comando. La seconda variante è riproducibile e si può mettere in uno script:

cd /var/www/nextcloud
sudo -u www-data php occ maintenance:install --database "mysql" --database-name "nextcloud" --database-user "nextcloud" --database-pass "QuiUnaPasswordLunga" --admin-user "admin" --admin-pass "UnAltraPasswordLunga" --data-dir "/var/nextcloud-data"

Qui ci sono due trappole. Primo: il comando deve girare dalla directory di Nextcloud, altrimenti PHP si interrompe con un fatal error. Secondo: occ non deve mai girare come root, altrimenti arriva "Console has to be executed with the user that owns the file config/config.php" e, nel caso peggiore, i file appena creati appartengono poi all'utente sbagliato.

Ora HTTPS. Senza certificato le app mobili si rifiutano di collegarsi e Nextcloud avvisa nella panoramica:

sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d cloud.example.com

Per più sottodomini conviene un certificato wildcard. Aggiungi poi nel blocco server TLS l'header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;, altrimenti resta l'avviso "The Strict-Transport-Security HTTP header is not configured to at least 15552000 seconds".

Il classico per finire: apri il sito con un nome diverso da quello usato durante l'installazione e vedi soltanto "You are accessing the site from an untrusted domain." Nextcloud accetta esclusivamente i nomi host presenti in trusted_domains. Per aggiungerne uno senza modificare il file a mano:

sudo -u www-data php occ config:system:set trusted_domains 1 --value=cloud.example.com
sudo -u www-data php occ config:system:get trusted_domains

L'indice parte da 0, e lo 0 di solito è già occupato. Se assegni due volte lo stesso indice sovrascrivi la voce esistente e in certi casi ti chiudi fuori da solo. Se succede: config/config.php è un normalissimo file PHP e la voce si corregge lì con un editor. Imposta inoltre overwrite.cli.url sull'indirizzo HTTPS definitivo, altrimenti i job in background generano link con il nome host sbagliato.

Dimensione degli upload e limite di memoria

Le impostazioni predefinite di PHP sono troppo strette per Nextcloud. upload_max_filesize di norma è su 2M, memory_limit su 128M. Nextcloud consiglia almeno 512M di memoria e altrimenti avvisa con "The PHP memory limit is below the recommended value of 512MB".

Qui i punti in gioco sono tre, e toccarne uno solo non basta:

  1. La configurazione di FPM sotto /etc/php/<version>/fpm/php.ini: memory_limit = 512M, upload_max_filesize = 10G, post_max_size = 10G, max_execution_time = 3600. Poi riavvia FPM, un semplice ricaricamento di nginx non basta.
  2. Il file .user.ini nella directory di Nextcloud: Nextcloud porta con sé valori propri e, poiché .user.ini vale a livello di directory, vince sulla php.ini globale. È proprio qui che la ricerca dell'errore si arena di continuo. Adatta i valori anche lì. PHP tiene questo file in cache, per impostazione predefinita cinque minuti, quindi la tua modifica ha effetto in ritardo.
  3. La direttiva nginx client_max_body_size: se manca o è troppo piccola, l'upload si interrompe con "413 Request Entity Too Large" prima ancora che PHP venga interpellato.

Per verificare che cosa arriva davvero in fondo aiuta la pagina Impostazioni di amministrazione, dove è indicato il limite superiore realmente attivo. Dalla riga di comando:

grep -E '^(memory_limit|upload_max_filesize|post_max_size)' /etc/php/8.4/fpm/php.ini

Interroga esplicitamente il file di FPM e non la riga di comando. Un php -r "echo ini_get('memory_limit');" legge la SAPI CLI, e su tutte le distribuzioni verificate quella riporta -1, cioè illimitato. Chi si fida di quel valore lo considera sufficiente e più avanti finisce lo stesso in errori di memoria, perché nel file di FPM continua a esserci memory_limit = 128M. Quello che arriva davvero nel browser lo mostra php-fpm8.4 -i oppure un info.php depositato per poco tempo con phpinfo(), che poi cancelli subito.

Se durante il caricamento di file grandi il processo viene terminato dal kernel, semplicemente manca RAM. In quel caso configurare lo swap serve da ripiego, ma la soluzione migliore è più RAM.

Passare i job in background a cron

Dopo l'installazione Nextcloud gira in modalità AJAX: i job in background vengono eseguiti solo se in quel momento qualcuno ha l'interfaccia aperta. È questo il motivo per cui su istanze poco usate ricerca full text, pulizie e notifiche sembrano non avvenire affatto. Passa a un cron vero, Nextcloud si aspetta un'esecuzione ogni cinque minuti. Le basi sono in configurare un cronjob su Linux.

sudo crontab -u www-data -e

Lì inserisci:

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

Poi comunica a Nextcloud il cambio di modalità:

cd /var/www/nextcloud
sudo -u www-data php occ background:cron

Chi preferisce lavorare senza demone cron usa un servizio systemd con timer. La unit nextcloudcron.service richiama /usr/bin/php -f /var/www/nextcloud/cron.php come utente www-data, il timer corrispondente imposta OnBootSec=5min e OnUnitActiveSec=5min.

Se l'avviso "Last background job execution ran X hours ago. Something seems wrong" resta comunque, controlla in quest'ordine: il job gira con l'utente giusto? Il percorso esiste davvero? E un punto molto importante: cron.php è eseguibile con la configurazione PHP della riga di comando, oppure lì manca un modulo installato solo per FPM? Il test più onesto è la chiamata a mano, così vedi ogni messaggio d'errore in chiaro:

sudo -u www-data php -f /var/www/nextcloud/cron.php

Smaltire gli avvisi della panoramica

L'elenco sotto Impostazioni di amministrazione e Panoramica non è un ornamento, ogni riga ha un motivo concreto. I casi più frequenti e la loro soluzione:

  • "No memory cache has been configured": APCu è installato, ma non registrato. occ config:system:set memcache.local --value='\OC\Memcache\APCu'. Perché ne traggano vantaggio anche occ e le esecuzioni di cron, imposta inoltre apc.enable_cli=1 in /etc/php/<version>/mods-available/apcu.ini.
  • "Transactional file locking is disabled": installa Redis (apt-get install -y redis-server php-redis) e imposta memcache.locking su \OC\Memcache\Redis. Su istanze a utente singolo se ne può fare a meno, ma non appena più utenti sincronizzano contemporaneamente diventa necessario.
  • "Your web server is not properly set up to resolve /.well-known/caldav": mancano le riscritture nel blocco location ^~ /.well-known. Lo verifichi direttamente con curl -I https://cloud.example.com/.well-known/caldav, ci si aspetta un 301 verso /remote.php/dav/.
  • "Your installation has no default phone region set": occ config:system:set default_phone_region --value="AT", per l'Italia IT. Il valore è un codice paese secondo ISO 3166-1.
  • "Server has no maintenance window start time configured": occ config:system:set maintenance_window_start --type=integer --value=1. Il valore è l'ora di inizio in UTC, così i job giornalieri pesanti girano di notte invece che in pieno esercizio.
  • "The database is missing some indexes": occ db:add-missing-indices, insieme a occ db:add-missing-columns e occ db:add-missing-primary-keys. Su istanze grandi questi comandi sono lenti, ma non pericolosi.
  • "PHP does not seem to be setup properly to query system environment variables": nel file di pool di FPM /etc/php/<version>/fpm/pool.d/www.conf togli il commento alla riga env[PATH] = /usr/local/bin:/usr/bin:/bin e riavvia FPM.
  • "Module php-imagick in this instance has no SVG support": non è un errore di Nextcloud, ma una libreria delegate mancante in ImageMagick. Se non ti servono le anteprime SVG, puoi lasciare l'avviso dov'è.

Come capire che funziona davvero

Quattro verifiche che, prese insieme, dicono qualcosa di concreto:

cd /var/www/nextcloud
sudo -u www-data php occ status
sudo -u www-data php occ check
sudo -u www-data php occ config:app:get core lastcron

occ status deve riportare installed: true e la versione attesa, occ check non deve produrre alcun output. Il terzo comando restituisce un timestamp Unix. Convertilo: non deve essere più vecchio di cinque minuti, solo allora il tuo cron sta davvero lavorando.

Dall'esterno:

curl -s https://cloud.example.com/status.php

La risposta è un oggetto JSON con "installed":true, "maintenance":false e il numero di versione. Se qui torna dell'HTML, una delle tue regole location agisce in modo troppo ampio. Se arriva un reindirizzamento alla pagina di accesso va tutto bene, hai solo preso l'URL sbagliato.

Per ultimo il test sul campo, che nessuna pagina di stato può sostituire: carica un file di diversi gigabyte tramite l'interfaccia web e sincronizzalo poi con il client desktop. Solo così si vede se client_max_body_size, post_max_size, i timeout e lo spazio su disco libero vanno d'accordo. Se all'improvviso si blocca tutto, vale la pena dare un'occhiata ai dischi pieni, perché Nextcloud crea anteprime e versioni che crescono in modo percepibile.

Quando qualcosa va storto

Nextcloud scrive il log in /var/nextcloud-data/nextcloud.log, quindi nella tua directory dei dati e non in /var/log. È questo il primo file da guardare, non il log di nginx. Per un output leggibile:

sudo -u www-data php occ log:watch

Se dopo un aggiornamento interrotto l'istanza resta bloccata in modalità di manutenzione, occ maintenance:mode --off la riporta indietro. Se l'interfaccia non è più raggiungibile del tutto, imposta 'maintenance' => false direttamente in config/config.php.

Prima di mettere mano al database o alla configurazione, fai il backup di entrambi. Un backup della sola directory non basta, senza il database corrispondente Nextcloud non vale nulla:

sudo -u www-data php occ maintenance:mode --on
sudo mariadb-dump --single-transaction nextcloud > /root/nextcloud-db.sql
sudo -u www-data php occ maintenance:mode --off

E un consiglio di fondo: finisci di costruire il server prima di renderlo raggiungibile pubblicamente. Un firewall, un accesso SSH messo in sicurezza e i punti della checklist per i nuovi server root vanno prima del primo accesso, non dopo. Un'istanza Nextcloud con password predefinita viene trovata nel giro di poche ore.

Domande frequenti

Quale versione di PHP serve per Nextcloud?
Nextcloud 33 e 34 richiedono almeno PHP 8.2 e arrivano a supportare la 8.5, Nextcloud 32 gira a partire da PHP 8.1. Debian 13 (PHP 8.4), Debian 12 (PHP 8.2) e Ubuntu 24.04 (PHP 8.3) vanno bene senza repository esterni. Ubuntu 22.04 fornisce solo PHP 8.1 ed è quindi troppo vecchio per le serie attuali, lì ti serve il PPA ondrej/php. Debian 11 fornisce PHP 7.4: l'installazione va a buon fine senza errori, ma alla prima chiamata Nextcloud si interrompe con HTTP 500 e "This version of Nextcloud requires at least PHP 8.2".
Perché ricevo "You are accessing the site from an untrusted domain"?
Nextcloud accetta solo i nomi host presenti nell'array trusted_domains in config/config.php. Aggiungi il nome con sudo -u www-data php occ config:system:set trusted_domains 1 --value=cloud.example.com. L'indice parte da 0 e un indice già assegnato viene sovrascritto.
Perché gli upload si interrompono nonostante la php.ini aumentata?
I limiti sono tre. Oltre a upload_max_filesize e post_max_size nella php.ini di FPM, Nextcloud porta con sé un proprio .user.ini nella directory di installazione, che vince perché vale a livello di directory, e nginx limita in più tramite client_max_body_size. Se quest'ultimo è troppo piccolo compare 413 Request Entity Too Large prima ancora che PHP venga interpellato.
Perché i miei job in background non girano?
Le installazioni nuove sono impostate su AJAX, e in quel caso i job partono solo con l'interfaccia aperta. Inserisci */5 * * * * php -f /var/www/nextcloud/cron.php nella crontab di www-data e passa alla nuova modalità con occ background:cron. Puoi controllare con occ config:app:get core lastcron, il timestamp non deve essere più vecchio di cinque minuti.
Quali permessi servono per la directory dei dati?
Appartiene all'utente del web server (www-data su Debian e Ubuntu, apache oppure nginx sulla famiglia Red Hat) e dovrebbe avere chmod 750. Permessi troppo larghi fanno comparire il messaggio "Your data directory is readable by other users". Crea la directory fuori dalla radice del web server, per esempio sotto /var/nextcloud-data.
Come mi tolgo l'avviso sulla memory cache mancante?
Installa php-apcu e imposta occ config:system:set memcache.local --value='\OC\Memcache\APCu'. Perché anche occ e le esecuzioni di cron usino la cache, imposta inoltre apc.enable_cli=1 nell'apcu.ini della riga di comando PHP.
Posso usare Nextcloud anche con PostgreSQL?
Sì, PostgreSQL è supportato da Nextcloud allo stesso livello e nella documentazione viene addirittura citato per primo. Su Debian cade così anche la questione di MySQL, che lì comunque non è disponibile come pacchetto. Durante l'installazione indichi --database "pgsql" invece di "mysql".

Nextcloud Self-hosting PHP nginx MariaDB Debian Ubuntu Cloud Linux