Nextcloud op de eigen server installeren

Gepubliceerd op 13 min leestijd

Van een lege server tot een overzichtspagina zonder waarschuwingen: webserver, PHP-modules, database, rechten op de datamap, trusted_domains, uploadlimieten en achtergrondtaken via cron.

Nextcloud is snel uitgepakt. Het deel dat tijd kost komt daarna: de overzichtspagina onder Beheerinstellingen toont bij een verse installatie vrijwel altijd een lijst met gele en rode meldingen, uploads breken bij 2 MB af, en het opvragen via het IP-adres eindigt met "You are accessing the site from an untrusted domain.". Dit artikel loopt de volledige route door en blijft juist stilstaan op de punten waar de meeste handleidingen ophouden.

Vooraf beslissen: PHP-versie, database, opslaglocatie

Nextcloud is sterker afhankelijk van de PHP-versie dan de meeste andere serversoftware. De actuele series 33 en 34 vereisen minimaal PHP 8.2, serie 32 draait nog vanaf PHP 8.1. Daarmee bepaalt de distributie of u met de eigen pakketbronnen uitkomt:

SysteemPHP uit de distributieDatabase uit de distributieOordeel
Debian 13 (trixie)8.4MariaDB 11.8geschikt zonder externe pakketbron
Debian 12 (bookworm)8.2MariaDB 10.11geschikt, maar op de ondergrens
Ubuntu 24.04 LTS8.3MariaDB 10.11, MySQL 8.0geschikt zonder externe pakketbron
Ubuntu 22.04 LTS8.1MariaDB 10.6, MySQL 8.0te oud voor Nextcloud 33 en 34
Debian 11 (bullseye)7.4MariaDB 10.5valt af

Debian 11 is het lastigste geval en valt toch vaak pas laat op, omdat de pakketinstallatie foutloos doorloopt. Het metapakket php haalt daar PHP 7.4 binnen, en de actuele Nextcloud-versie stopt daarmee bij de eerste aanroep in de browser met HTTP 500 en de melding "This version of Nextcloud requires at least PHP 8.2". Debian 11 valt sowieso buiten de reguliere ondersteuning, voor een nieuwe installatie is het de verkeerde basis. Moet het per se, neem dan vooraf de Sury-repository op en installeer uitdrukkelijk pakketten met versienummer, dus php8.2-fpm, php8.2-cli, php8.2-mysql enzovoort, in plaats van de metapakketten zonder versie.

Op Ubuntu 22.04 loopt u net zo onvermijdelijk vast zodra u de actuele Nextcloud-versie installeert. Ofwel u blijft bewust op serie 32, ofwel u haalt PHP uit de bekende 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

Nog twee punten die u aan het begin vastlegt en later maar moeizaam wijzigt: Debian levert principieel geen pakket mysql-server, daar is MariaDB de standaard. En de datamap hoort niet onder /var/www/nextcloud/data, maar buiten de documentroot van de webserver, bijvoorbeeld in /var/nextcloud-data. Het standaardpad is alleen daarom gevaarlijk, omdat een kapotte webserverconfiguratie anders alle gebruikersbestanden uitserveert. Nextcloud waarschuwt in dat geval met "Your data directory and files are probably accessible from the internet", maar pas nadat de fout al bestaat.

Webserver, PHP en database inrichten

Wij nemen nginx met PHP-FPM. Gebruikt u liever Apache met mod_php, dan staat die route beschreven in Apache, PHP en MySQL op Debian, de PHP-onderwerpen verderop gelden ongewijzigd. Een basisinstallatie van nginx vindt u onder nginx installeren.

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

Deze lijst is bewust langer dan het minimum. bcmath en gmp heeft Nextcloud nodig voor het inloggen zonder wachtwoord, intl voor de juiste sortering van accenttekens en speciale tekens, imagick voor voorbeeldweergaven, apcu voor de lokale cache. Ontbreekt een van de verplichte modules, dan komt u in de installatiewizard niet eens verder: de pagina noemt de ontbrekende modules dan bij naam.

Controleer daarna wat er werkelijk geladen is:

php -v
php -m

Het tweede veelvoorkomende struikelblok: er zijn twee gescheiden PHP-configuraties, een voor de commandoregel en een voor FPM. php --ini toont u die van de commandoregel, die van de webserver staat onder /etc/php/<version>/fpm/php.ini. Wijzigingen in het verkeerde bestand hebben geen effect, en dat kost ervaringsgewijs de meeste tijd.

Nu de database. Beveilig MariaDB eerst, zie MariaDB en MySQL beveiligen, daarna:

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

De utf8mb4 in het eerste commando is geen detail. Maakt u de database met utf8 aan, dan meldt Nextcloud later "MySQL is used as database but does not support 4-byte characters", en de omzetting tijdens productie is een stuk vervelender dan meteen het juiste CREATE DATABASE aan het begin. Mislukt het aanmelden van de databasegebruiker, dan helpt Access denied for user oplossen.

Uitpakken en rechten instellen

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

Bij de rechten wordt het vaakst geslordigd. Drie foutbeelden en hun oorzaak:

  • "Cannot write into config directory": /var/www/nextcloud/config is niet van de webservergebruiker. Op Debian en Ubuntu is dat www-data, op AlmaLinux en Rocky juist apache of nginx. Een blind gekopieerde chown www-data haalt op de Red Hat-familie niets uit.
  • "Can't create or write into the data directory": het pad bestaat niet, is geen absoluut pad, of een bovenliggende map is voor www-data niet toegankelijk.
  • "Your data directory is readable by other users": de rechten staan te ruim. chmod 750 op de datamap volstaat.

Weersta de verleiding om het probleem met chmod -R 777 weg te slaan. Nextcloud beantwoordt dat met precies de waarschuwing die u kwijt wilde, en u hebt en passant elk bestand leesbaar gemaakt voor iedere lokale gebruiker.

De nginx-configuratie

Nextcloud heeft meer nodig dan een standaard PHP-blok, onder andere rewrites voor de dienstdetectie onder /.well-known/ en blokkades voor interne mappen. Hieronder staat de ingekorte versie van het officiële sjabloon, en zo draait het:

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;
    }
}

Het pad naar de FPM-socket moet u aanpassen aan uw PHP-versie. Op Debian 13 heet die php8.4-fpm.sock, op Debian 12 php8.2-fpm.sock, op Ubuntu 24.04 php8.3-fpm.sock en op Ubuntu 22.04 php8.1-fpm.sock. Klopt de naam niet, dan krijgt u een 502 Bad Gateway. De werkelijke naam toont:

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

De eerste regel hoort erbij, want het socketbestand ontstaat pas bij het starten van de service. Daarvoor is /run/php/ ofwel leeg, ofwel het bestaat helemaal niet, en ls antwoordt met No such file or directory. Op een normale server start het pakket de service tijdens de installatie zelf, maar na een herinstallatie of in een container is dat niet gegarandeerd. Pas het versienummer in de servicenaam aan uw installatie aan. Daarna nginx -t en opnieuw laden.

Installatie, HTTPS en trusted_domains

U kunt de installatie in de browser doorklikken of meteen op de commandoregel afhandelen. De tweede variant is reproduceerbaar en laat zich in een script vastleggen:

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

Daarbij zitten twee valkuilen. Ten eerste moet het commando vanuit de Nextcloud-map draaien, anders stopt PHP met een fatal error. Ten tweede mag occ nooit als root draaien, anders volgt "Console has to be executed with the user that owns the file config/config.php", en in het ergste geval zijn nieuw aangemaakte bestanden daarna van de verkeerde gebruiker.

Nu HTTPS. Zonder certificaat weigeren de mobiele apps dienst en waarschuwt Nextcloud in het overzicht:

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

Voor meerdere subdomeinen loont een wildcardcertificaat. Vul daarna in het TLS-serverblok de header Strict-Transport-Security "max-age=15552000; includeSubDomains" always; aan, anders blijft de melding "The Strict-Transport-Security HTTP header is not configured to at least 15552000 seconds" staan.

De klassieker tot slot: u opent de site onder een andere naam dan bij de installatie en ziet alleen nog "You are accessing the site from an untrusted domain." Nextcloud accepteert uitsluitend hostnamen die in trusted_domains staan. Toevoegen zonder het bestand met de hand te bewerken:

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

De index begint bij 0, en 0 is meestal al bezet. Gebruikt u dezelfde index twee keer, dan overschrijft u de bestaande vermelding en sluit u zichzelf mogelijk buiten. Gebeurt dat toch: config/config.php is een doodgewoon PHP-bestand, de vermelding valt daar in de editor te corrigeren. Zet daarnaast overwrite.cli.url op het definitieve HTTPS-adres, anders maken de achtergrondtaken links met een verkeerde hostnaam.

Uploadgrootte en geheugenlimiet

De standaardinstellingen van PHP zijn voor Nextcloud te krap. upload_max_filesize staat doorgaans op 2M, memory_limit op 128M. Nextcloud adviseert minimaal 512M geheugen en waarschuwt anders met "The PHP memory limit is below the recommended value of 512MB".

Er zijn hier drie plekken, en het volstaat niet om er één aan te passen:

  1. De FPM-configuratie onder /etc/php/<version>/fpm/php.ini: memory_limit = 512M, upload_max_filesize = 10G, post_max_size = 10G, max_execution_time = 3600. Herstart daarna FPM, opnieuw laden van nginx volstaat niet.
  2. Het bestand .user.ini in de Nextcloud-map: Nextcloud levert eigen waarden mee, en omdat .user.ini per map geldt, wint die het van de globale php.ini. Precies daarop loopt het zoeken naar de fout regelmatig vast. Pas de waarden daar dus ook aan. PHP bewaart dit bestand in de cache, standaard vijf minuten, uw wijziging werkt dus met vertraging.
  3. De nginx-directive client_max_body_size: ontbreekt die of staat die te laag, dan breekt de upload af met "413 Request Entity Too Large", nog voordat PHP er ook maar aan te pas komt.

Om te controleren wat er uiteindelijk aankomt, helpt de pagina Beheerinstellingen, daar staat de werkelijk geldende bovengrens. Op de commandoregel:

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

Bevraag uitdrukkelijk het FPM-bestand en niet de commandoregel. Een php -r "echo ini_get('memory_limit');" leest de CLI-SAPI, en die meldt op alle geteste distributies -1, oftewel onbeperkt. Wie daarop vertrouwt, houdt de waarde voor voldoende en loopt later toch tegen geheugenfouten aan, omdat in het FPM-bestand nog altijd memory_limit = 128M staat. Wat er in de browser echt aankomt, toont php-fpm8.4 -i of een kortstondig neergezette info.php met phpinfo(), die u daarna meteen weer verwijdert.

Wordt het proces bij het uploaden van grote bestanden door de kernel beëindigd, dan ontbreekt er simpelweg werkgeheugen. Dan helpt swap inrichten als noodgreep, meer RAM is beter.

Achtergrondtaken omzetten naar cron

Na de installatie draait Nextcloud in de AJAX-modus: achtergrondtaken worden alleen uitgevoerd zolang er iemand de interface open heeft staan. Dat is de reden dat zoeken in volledige tekst, opruimwerk en meldingen op weinig gebruikte installaties schijnbaar helemaal niet gebeuren. Schakel over op echte cron, Nextcloud verwacht elke vijf minuten een uitvoering. De basis daarvan staat in Cronjob onder Linux instellen.

sudo crontab -u www-data -e

Voer daar in:

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

Meld daarna de moduswissel aan Nextcloud:

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

Wie liever zonder cron-daemon werkt, neemt een systemd-service met timer. De unit nextcloudcron.service roept /usr/bin/php -f /var/www/nextcloud/cron.php aan als gebruiker www-data, de bijbehorende timer zet OnBootSec=5min en OnUnitActiveSec=5min.

Blijft de waarschuwing "Last background job execution ran X hours ago. Something seems wrong" toch staan, controleer dan in deze volgorde: draait de taak onder de juiste gebruiker? Bestaat het pad werkelijk? En heel belangrijk: is cron.php in de PHP-configuratie van de commandoregel wel uitvoerbaar, of ontbreekt daar een module die alleen voor FPM is geïnstalleerd? De eerlijkste test is de aanroep met de hand, daarbij ziet u elke foutmelding voluit:

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

De waarschuwingen in het overzicht afhandelen

De lijst onder Beheerinstellingen en Overzicht is geen versiering, elke regel heeft een concrete reden. De meest voorkomende en hoe u ze verhelpt:

  • "No memory cache has been configured": APCu is geïnstalleerd, maar niet ingesteld. occ config:system:set memcache.local --value='\OC\Memcache\APCu'. Zodat ook occ en de cron-uitvoeringen daarvan profiteren, zet u daarnaast apc.enable_cli=1 in /etc/php/<version>/mods-available/apcu.ini.
  • "Transactional file locking is disabled": Redis installeren (apt-get install -y redis-server php-redis) en memcache.locking op \OC\Memcache\Redis zetten. Op installaties met één gebruiker kunt u dit overslaan, zodra meerdere mensen tegelijk synchroniseren niet meer.
  • "Your web server is not properly set up to resolve /.well-known/caldav": de rewrites in het blok location ^~ /.well-known ontbreken. Testen kunt u dat direct met curl -I https://cloud.example.com/.well-known/caldav, verwacht wordt een 301 naar /remote.php/dav/.
  • "Your installation has no default phone region set": occ config:system:set default_phone_region --value="AT", voor Duitsland DE. De waarde is een landcode volgens ISO 3166-1.
  • "Server has no maintenance window start time configured": occ config:system:set maintenance_window_start --type=integer --value=1. De waarde is het beginuur in UTC, zware dagtaken draaien dan 's nachts in plaats van midden in bedrijfstijd.
  • "The database is missing some indexes": occ db:add-missing-indices, en in dezelfde lijn occ db:add-missing-columns en occ db:add-missing-primary-keys. Deze commando's zijn op grote installaties traag, maar ongevaarlijk.
  • "PHP does not seem to be setup properly to query system environment variables": haal in het FPM-poolbestand /etc/php/<version>/fpm/pool.d/www.conf de regel env[PATH] = /usr/local/bin:/usr/bin:/bin uit commentaar en herstart FPM.
  • "Module php-imagick in this instance has no SVG support": dat is geen fout van Nextcloud, maar een ontbrekende delegate-bibliotheek in ImageMagick. Hebt u geen SVG-voorbeeldweergaven nodig, dan kunt u de melding laten staan.

Waaraan u ziet dat het echt werkt

Vier controles die samen genomen zeggingskracht hebben:

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 moet installed: true en de verwachte versie melden, occ check mag geen uitvoer produceren. Het derde commando geeft een Unix-tijdstempel terug. Reken die om, hij mag niet ouder zijn dan vijf minuten, dan werkt uw cron echt.

Van buitenaf:

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

Het antwoord is een JSON-object met "installed":true, "maintenance":false en het versienummer. Komt hier HTML terug, dan grijpt een van uw location-regels te breed. Komt er een doorverwijzing naar de inlogpagina, dan is alles in orde, maar hebt u de verkeerde URL te pakken.

Tot slot de praktijktest die geen statuspagina vervangt: een bestand van meerdere gigabytes via de webinterface uploaden en het daarna met de desktopclient synchroniseren. Pas daarbij blijkt of client_max_body_size, post_max_size, time-outs en de vrije schijfruimte bij elkaar passen. Loopt daarbij ineens alles vast, dan loont een blik op volle schijven, want Nextcloud legt voorbeeldweergaven en versies aan die merkbaar groeien.

Als het misgaat

Nextcloud logt naar /var/nextcloud-data/nextcloud.log, dus in uw datamap en niet in /var/log. Dat is het eerste bestand waarin u moet kijken, niet het nginx-log. Voor leesbare uitvoer:

sudo -u www-data php occ log:watch

Blijft de installatie na een afgebroken update in de onderhoudsmodus hangen, dan haalt occ maintenance:mode --off haar terug. Is de interface helemaal niet meer bereikbaar, zet dan 'maintenance' => false rechtstreeks in config/config.php.

Voordat u aan database of configuratie sleutelt, maakt u van beide een back-up. Een back-up van alleen de map volstaat niet, Nextcloud is zonder de bijbehorende database waardeloos:

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

En een principieel advies: bouw de server eerst af voordat u hem publiek bereikbaar maakt. Een firewall, een beveiligde SSH-toegang en de punten uit de checklist voor nieuwe rootservers horen vóór het eerste inloggen, niet erna. Een Nextcloud-installatie met een standaardwachtwoord is binnen enkele uren gevonden.

Veelgestelde vragen

Welke PHP-versie heb ik nodig voor Nextcloud?
Nextcloud 33 en 34 vereisen minimaal PHP 8.2 en ondersteunen tot en met 8.5, Nextcloud 32 draait vanaf PHP 8.1. Debian 13 (PHP 8.4), Debian 12 (PHP 8.2) en Ubuntu 24.04 (PHP 8.3) passen zonder externe pakketbron. Ubuntu 22.04 levert alleen PHP 8.1 en is daarmee te oud voor de actuele series, daar hebt u de PPA ondrej/php nodig. Debian 11 levert PHP 7.4: de installatie loopt daar zonder fouten door, maar Nextcloud stopt bij de eerste aanroep met HTTP 500 en "This version of Nextcloud requires at least PHP 8.2".
Waarom krijg ik "You are accessing the site from an untrusted domain"?
Nextcloud accepteert alleen hostnamen die in de array trusted_domains in config/config.php staan. Voeg de naam toe met sudo -u www-data php occ config:system:set trusted_domains 1 --value=cloud.example.com. De index telt vanaf 0, een al gebruikte index wordt overschreven.
Waarom breken uploads af ondanks een verhoogde php.ini?
Er zijn drie limieten. Naast upload_max_filesize en post_max_size in de php.ini van FPM brengt Nextcloud een eigen .user.ini in de installatiemap mee, die per map wint, en nginx begrenst daarbovenop via client_max_body_size. Staat die laatste te laag, dan verschijnt 413 Request Entity Too Large nog voordat PHP er ook maar aan te pas komt.
Waarom draaien mijn achtergrondtaken niet?
Verse installaties staan op AJAX, waarbij taken alleen draaien zolang de interface open staat. Zet */5 * * * * php -f /var/www/nextcloud/cron.php in de crontab van www-data en schakel om met occ background:cron. Controleren kunt u het met occ config:app:get core lastcron, dat tijdstempel mag niet ouder zijn dan vijf minuten.
Welke rechten heeft de datamap nodig?
De map hoort van de webservergebruiker te zijn (www-data op Debian en Ubuntu, apache of nginx op de Red Hat-familie) en zou chmod 750 moeten hebben. Te ruime rechten leiden tot de melding "Your data directory is readable by other users". Maak de map aan buiten de documentroot van de webserver, bijvoorbeeld onder /var/nextcloud-data.
Hoe kom ik van de waarschuwing over de ontbrekende memory cache af?
Installeer php-apcu en zet occ config:system:set memcache.local --value='\OC\Memcache\APCu'. Zodat ook occ en de cron-uitvoeringen de cache gebruiken, zet u daarnaast apc.enable_cli=1 in de apcu.ini van de PHP-commandoregel.
Kan ik Nextcloud ook met PostgreSQL draaien?
Ja, PostgreSQL wordt door Nextcloud gelijkwaardig ondersteund en in de documentatie zelfs met voorkeur genoemd. Op Debian vervalt daarmee ook de vraag naar MySQL, dat daar toch niet als pakket beschikbaar is. Bij de installatie geeft u --database "pgsql" op in plaats van "mysql".

Nextcloud Selfhosting PHP nginx MariaDB Debian Ubuntu Cloud Linux