Instalar o Nextcloud no seu próprio servidor

Publicado a 15 min de leitura

Do servidor vazio até uma página de resumo sem avisos: servidor web, módulos PHP, base de dados, permissões no diretório de dados, trusted_domains, limites de upload e tarefas em segundo plano por cron.

Descompactar o Nextcloud é rápido. A parte que consome tempo vem depois: numa instalação acabada de fazer, a página de resumo em Definições de administração mostra praticamente sempre uma lista de avisos amarelos e vermelhos, os uploads falham aos 2 MB e o acesso pelo endereço IP termina com "You are accessing the site from an untrusted domain.". Este artigo percorre o caminho completo e detém-se precisamente nos pontos em que a maioria dos guias acaba.

Decidir antes: versão do PHP, base de dados, local dos dados

O Nextcloud depende da versão do PHP mais do que a maior parte do restante software de servidor. As séries atuais 33 e 34 exigem pelo menos PHP 8.2, a série 32 ainda funciona a partir do PHP 8.1. É por isso a distribuição que decide se lhe basta aquilo que o sistema já traz:

SistemaPHP da distribuiçãoBase de dados da distribuiçãoAvaliação
Debian 13 (trixie)8.4MariaDB 11.8serve sem repositórios externos
Debian 12 (bookworm)8.2MariaDB 10.11serve, mas no limite mínimo
Ubuntu 24.04 LTS8.3MariaDB 10.11, MySQL 8.0serve sem repositórios externos
Ubuntu 22.04 LTS8.1MariaDB 10.6, MySQL 8.0demasiado antigo para o Nextcloud 33 e 34
Debian 11 (bullseye)7.4MariaDB 10.5fica excluído

O Debian 11 é o caso mais duro e, ainda assim, costuma dar nas vistas tarde demais, porque a instalação dos pacotes decorre sem qualquer erro. Ali o metapacote php traz consigo o PHP 7.4, e a versão atual do Nextcloud rebenta logo no primeiro acesso pelo navegador, com HTTP 500 e a mensagem "This version of Nextcloud requires at least PHP 8.2". O Debian 11 saiu de qualquer forma do suporte regular, pelo que é a base errada para uma instalação nova. Se for mesmo obrigatório, integre primeiro o repositório Sury e instale explicitamente pacotes com versão, ou seja php8.2-fpm, php8.2-cli, php8.2-mysql e assim por diante, em vez dos metapacotes sem versão.

No Ubuntu 22.04 vai bater igualmente contra uma parede assim que instalar a versão atual do Nextcloud. Ou fica conscientemente na série 32, ou vai buscar o PHP ao conhecido 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

Mais dois pontos que se definem no início e que depois só com muito trabalho se alteram: o Debian não disponibiliza, por princípio, qualquer pacote mysql-server, ali a escolha é o MariaDB. E o diretório de dados não pertence a /var/www/nextcloud/data, mas sim a um local fora da raiz do servidor web, por exemplo /var/nextcloud-data. O caminho predefinido só é perigoso porque uma configuração defeituosa do servidor web passaria a entregar todos os ficheiros dos utilizadores. Nesse caso o Nextcloud avisa com "Your data directory and files are probably accessible from the internet", mas apenas depois de o erro já existir.

Configurar o servidor web, o PHP e a base de dados

Vamos usar o nginx com PHP-FPM. Se preferir o Apache com mod_php, o caminho está descrito em Apache, PHP e MySQL no Debian, e os temas de PHP mais abaixo mantêm-se sem alteração. Uma instalação de base do nginx encontra-a em instalar o 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

Esta lista é propositadamente mais longa do que o mínimo. O Nextcloud precisa de bcmath e gmp para o início de sessão sem palavra-passe, de intl para a ordenação correta de acentos e caracteres especiais, de imagick para as miniaturas e de apcu para a cache local. Se faltar um dos módulos obrigatórios, nem sequer avança no assistente de instalação, e a página indica então, pelo nome, os módulos em falta.

Verifique a seguir o que está realmente carregado:

php -v
php -m

O segundo tropeção frequente: existem duas configurações de PHP separadas, uma para a linha de comandos e outra para o FPM. O php --ini mostra-lhe a da linha de comandos, a do servidor web fica em /etc/php/<version>/fpm/php.ini. Alterações no ficheiro errado não produzem efeito, e é isso que, pela experiência, custa mais tempo.

Agora a base de dados. Comece por proteger o MariaDB, veja proteger o MariaDB e o MySQL, e depois:

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

O utf8mb4 no primeiro comando não é um pormenor. Se criar a base de dados com utf8, o Nextcloud passa mais tarde a indicar "MySQL is used as database but does not support 4-byte characters", e a conversão com o sistema já em produção é bastante mais desagradável do que o CREATE DATABASE correto logo no início. Se a autenticação do utilizador da base de dados falhar, ajuda resolver o Access denied for user.

Descompactar e definir as permissões

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

As permissões são o ponto em que mais vezes se trabalha à pressa. Três sintomas e a respetiva causa:

  • "Cannot write into config directory": /var/www/nextcloud/config não pertence ao utilizador do servidor web. No Debian e no Ubuntu esse utilizador é o www-data, no AlmaLinux e no Rocky é o apache ou o nginx. Um chown www-data copiado às cegas não produz qualquer efeito na família Red Hat.
  • "Can't create or write into the data directory": o caminho não existe, não é um caminho absoluto, ou um diretório acima dele não é acessível ao www-data.
  • "Your data directory is readable by other users": permissões demasiado abertas. Basta um chmod 750 no diretório de dados.

Resista à tentação de resolver o problema à martelada com chmod -R 777. O Nextcloud responde a isso exatamente com o aviso de que se queria livrar e, pelo caminho, tornou cada ficheiro legível para qualquer utilizador local.

A configuração do nginx

O Nextcloud precisa de mais do que um bloco PHP padrão, entre outras coisas de reescritas para a descoberta de serviços em /.well-known/ e de bloqueios para diretórios internos. O que se segue é a versão reduzida do modelo oficial e funciona tal como está:

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

Tem de adaptar o caminho do socket do FPM à sua versão do PHP. No Debian 13 chama-se php8.4-fpm.sock, no Debian 12 php8.2-fpm.sock, no Ubuntu 24.04 php8.3-fpm.sock e no Ubuntu 22.04 php8.1-fpm.sock. Se o nome não estiver certo, recebe um 502 Bad Gateway. O nome real é mostrado por:

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

A primeira linha faz parte do procedimento, porque o ficheiro de socket só nasce com o arranque do serviço. Antes disso, /run/php/ está vazio ou nem sequer existe, e o ls responde com No such file or directory. Num servidor normal, o pacote arranca o serviço logo na instalação, mas depois de uma reinstalação ou dentro de um container isso não está garantido. Ajuste o número de versão no nome do serviço à sua instalação. A seguir, nginx -t e recarregar.

Instalação, HTTPS e trusted_domains

Pode percorrer a instalação a clicar no navegador ou tratar dela logo na linha de comandos. A segunda variante é reproduzível e pode ser escrita num script:

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

Há aqui duas armadilhas. Primeiro, o comando tem de correr a partir do diretório do Nextcloud, caso contrário o PHP aborta com um Fatal Error. Segundo, o occ nunca pode correr como root, senão aparece "Console has to be executed with the user that owns the file config/config.php" e, no pior dos casos, os ficheiros criados a seguir ficam a pertencer ao utilizador errado.

Agora o HTTPS. Sem certificado, as aplicações móveis recusam-se a ligar e o Nextcloud avisa na visão geral:

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

Para vários subdomínios compensa um certificado wildcard. Acrescente depois, no bloco de servidor TLS, o cabeçalho Strict-Transport-Security "max-age=15552000; includeSubDomains" always;, senão o aviso "The Strict-Transport-Security HTTP header is not configured to at least 15552000 seconds" continua lá.

O clássico para terminar: acede à página por um nome diferente daquele que usou na instalação e passa a ver apenas "You are accessing the site from an untrusted domain." O Nextcloud aceita exclusivamente hostnames que constem em trusted_domains. Para acrescentar sem editar o ficheiro à mão:

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

O índice começa em 0, e o 0 costuma já estar ocupado. Se atribuir o mesmo índice duas vezes, sobrescreve a entrada existente e pode acabar por se bloquear a si próprio. Se isso acontecer: config/config.php é um ficheiro PHP perfeitamente normal, e a entrada pode ser corrigida ali no editor. Defina também overwrite.cli.url com o endereço HTTPS definitivo, senão as tarefas em segundo plano geram ligações com o hostname errado.

Tamanho dos uploads e limite de memória

As predefinições do PHP são demasiado apertadas para o Nextcloud. O upload_max_filesize está tipicamente em 2M e o memory_limit em 128M. O Nextcloud recomenda pelo menos 512M de memória e, caso contrário, avisa com "The PHP memory limit is below the recommended value of 512MB".

Há aqui três sítios, e não chega mexer apenas num deles:

  1. A configuração do FPM em /etc/php/<version>/fpm/php.ini: memory_limit = 512M, upload_max_filesize = 10G, post_max_size = 10G, max_execution_time = 3600. Reinicie a seguir o FPM, recarregar o nginx não chega.
  2. O ficheiro .user.ini no diretório do Nextcloud: o Nextcloud traz valores próprios e, como o .user.ini se aplica ao nível do diretório, ganha contra o php.ini global. É precisamente nisto que a procura de erros encalha com regularidade. Ajuste ali também os valores. O PHP guarda este ficheiro em cache, por predefinição durante cinco minutos, pelo que a sua alteração só produz efeito com algum atraso.
  3. A diretiva client_max_body_size do nginx: se faltar ou for demasiado pequena, o upload falha com "413 Request Entity Too Large" antes de o PHP sequer ser consultado.

Para verificar o que fica realmente em vigor, ajuda a página Definições de administração, onde consta o limite máximo efetivo. Na linha de comandos:

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

Consulte explicitamente o ficheiro do FPM e não a linha de comandos. Um php -r "echo ini_get('memory_limit');" lê a SAPI da CLI, e essa devolve -1 em todas as distribuições testadas, ou seja, sem limite. Quem confiar nisso dá o valor por suficiente e mesmo assim vai bater mais tarde em erros de memória, porque no ficheiro do FPM continua a constar memory_limit = 128M. O que chega realmente ao navegador é mostrado por php-fpm8.4 -i ou por um info.php colocado por pouco tempo com phpinfo(), que deve apagar logo a seguir.

Se, ao carregar ficheiros grandes, o processo for terminado pelo kernel, falta simplesmente memória. Nesse caso, configurar swap serve de remendo, mas melhor é mais RAM.

Passar as tarefas em segundo plano para cron

Depois da instalação, o Nextcloud funciona em modo AJAX: as tarefas em segundo plano só são executadas quando alguém tem a interface aberta. É essa a razão pela qual a pesquisa de texto integral, as limpezas e as notificações parecem não acontecer de todo em instâncias pouco usadas. Mude para cron a sério, o Nextcloud espera uma execução a cada cinco minutos. As bases estão em configurar um cronjob no Linux.

sudo crontab -u www-data -e

Introduza ali:

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

A seguir, informe o Nextcloud da mudança de modo:

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

Quem preferir trabalhar sem o daemon do cron usa um serviço systemd com timer. A unit nextcloudcron.service chama /usr/bin/php -f /var/www/nextcloud/cron.php como utilizador www-data, e o timer correspondente define OnBootSec=5min e OnUnitActiveSec=5min.

Se, mesmo assim, o aviso "Last background job execution ran X hours ago. Something seems wrong" continuar lá, verifique por esta ordem: o job corre com o utilizador certo? O caminho existe mesmo? E, muito importante: o cron.php é sequer executável na configuração de PHP da linha de comandos, ou falta ali um módulo que só foi instalado para o FPM? O teste mais honesto é a chamada à mão, porque aí vê cada mensagem de erro em texto claro:

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

Resolver os avisos da visão geral

A lista em Definições de administração e Visão geral não é enfeite, cada linha tem um motivo concreto. Os mais frequentes e a respetiva solução:

  • "No memory cache has been configured": o APCu está instalado, mas não está registado. occ config:system:set memcache.local --value='\OC\Memcache\APCu'. Para que também o occ e as execuções do cron tirem partido disso, defina ainda apc.enable_cli=1 em /etc/php/<version>/mods-available/apcu.ini.
  • "Transactional file locking is disabled": instalar o Redis (apt-get install -y redis-server php-redis) e definir memcache.locking como \OC\Memcache\Redis. Dispensável em instâncias de um só utilizador, deixa de o ser assim que vários utilizadores sincronizam ao mesmo tempo.
  • "Your web server is not properly set up to resolve /.well-known/caldav": faltam as reescritas no bloco location ^~ /.well-known. Pode testar isso diretamente com curl -I https://cloud.example.com/.well-known/caldav, sendo esperado um 301 para /remote.php/dav/.
  • "Your installation has no default phone region set": occ config:system:set default_phone_region --value="AT", para a Alemanha DE. O valor é um código de país segundo a norma ISO 3166-1.
  • "Server has no maintenance window start time configured": occ config:system:set maintenance_window_start --type=integer --value=1. O valor é a hora de início em UTC, e assim os jobs diários pesados correm de noite em vez de a meio do serviço.
  • "The database is missing some indexes": occ db:add-missing-indices e, a par disso, occ db:add-missing-columns e occ db:add-missing-primary-keys. Estes comandos são lentos em instâncias grandes, mas não são perigosos.
  • "PHP does not seem to be setup properly to query system environment variables": no ficheiro de pool do FPM /etc/php/<version>/fpm/pool.d/www.conf, retire o comentário da linha env[PATH] = /usr/local/bin:/usr/bin:/bin e reinicie o FPM.
  • "Module php-imagick in this instance has no SVG support": isto não é um erro do Nextcloud, mas sim uma biblioteca delegate em falta no ImageMagick. Se não precisar de pré-visualizações de SVG, pode deixar o aviso como está.

Como reconhece que está mesmo a funcionar

Quatro verificações que, tomadas em conjunto, são conclusivas:

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

O occ status tem de indicar installed: true e a versão esperada, e o occ check não pode produzir qualquer saída. O terceiro comando devolve um timestamp Unix. Converta-o, porque não pode ter mais de cinco minutos, e só então o seu cron está mesmo a trabalhar.

A partir do exterior:

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

A resposta é um objeto JSON com "installed":true, "maintenance":false e o número da versão. Se vier HTML, uma das suas regras location está a abranger demasiado. Se vier um encaminhamento para a página de início de sessão, está tudo em ordem, apenas apanhou o URL errado.

Por fim, o teste prático que nenhuma página de estado substitui: carregar um ficheiro de vários gigabytes pela interface web e sincronizá-lo depois com o cliente de desktop. Só aí se percebe se client_max_body_size, post_max_size, os tempos limite e o espaço livre em disco encaixam uns nos outros. Se de repente deixar de funcionar, vale a pena olhar para discos cheios, porque o Nextcloud cria pré-visualizações e versões que crescem de forma bem visível.

Quando corre mal

O Nextcloud regista em /var/nextcloud-data/nextcloud.log, ou seja, no seu diretório de dados, e não em /var/log. É esse o primeiro ficheiro que deve consultar, não o log do nginx. Para uma saída legível:

sudo -u www-data php occ log:watch

Se a instância ficar presa em modo de manutenção depois de uma atualização interrompida, o occ maintenance:mode --off traz-na de volta. Se a interface já não estiver de todo acessível, defina 'maintenance' => false diretamente em config/config.php.

Antes de mexer na base de dados ou na configuração, faça backup de ambas. Um backup só do diretório não chega, o Nextcloud não vale nada sem a base de dados correspondente:

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 um conselho de fundo: acabe de montar o servidor antes de o tornar acessível publicamente. Uma firewall, um acesso SSH protegido e os pontos da lista de verificação para novos servidores root vêm antes do primeiro início de sessão, não depois. Uma instância de Nextcloud com palavra-passe predefinida é encontrada em poucas horas.

Perguntas frequentes

De que versão do PHP preciso para o Nextcloud?
O Nextcloud 33 e 34 exigem pelo menos PHP 8.2 e suportam até ao 8.5, o Nextcloud 32 funciona a partir do PHP 8.1. O Debian 13 (PHP 8.4), o Debian 12 (PHP 8.2) e o Ubuntu 24.04 (PHP 8.3) servem sem repositórios externos. O Ubuntu 22.04 só traz PHP 8.1 e é, por isso, demasiado antigo para as séries atuais, ali precisa do PPA ondrej/php. O Debian 11 traz PHP 7.4: a instalação decorre sem erros, mas o Nextcloud rebenta no primeiro acesso com HTTP 500 e "This version of Nextcloud requires at least PHP 8.2".
Porque é que recebo "You are accessing the site from an untrusted domain"?
O Nextcloud só aceita hostnames que constem no array trusted_domains em config/config.php. Acrescente o nome com sudo -u www-data php occ config:system:set trusted_domains 1 --value=cloud.example.com. O índice começa em 0, e um índice já atribuído é sobrescrito.
Porque é que os uploads falham apesar de ter aumentado os valores no php.ini?
Existem três limites. Além de upload_max_filesize e post_max_size no php.ini do FPM, o Nextcloud traz um .user.ini próprio no diretório de instalação, que ganha por se aplicar ao nível do diretório, e o nginx limita ainda através de client_max_body_size. Se este último for demasiado pequeno, aparece 413 Request Entity Too Large antes de o PHP sequer ser consultado.
Porque é que as minhas tarefas em segundo plano não correm?
As instalações novas ficam em AJAX, e nesse modo os jobs só correm com a interface aberta. Introduza */5 * * * * php -f /var/www/nextcloud/cron.php na crontab do www-data e mude com occ background:cron. Pode confirmar com occ config:app:get core lastcron, e o timestamp não pode ter mais de cinco minutos.
De que permissões precisa o diretório de dados?
Pertence ao utilizador do servidor web (www-data no Debian e no Ubuntu, apache ou nginx na família Red Hat) e deve ter chmod 750. Permissões demasiado abertas provocam a mensagem "Your data directory is readable by other users". Crie o diretório fora da raiz do servidor web, por exemplo em /var/nextcloud-data.
Como me livro do aviso sobre a cache de memória em falta?
Instale o php-apcu e defina occ config:system:set memcache.local --value='\OC\Memcache\APCu'. Para que também o occ e as execuções do cron usem a cache, defina ainda apc.enable_cli=1 no apcu.ini da linha de comandos do PHP.
Posso usar o Nextcloud também com PostgreSQL?
Sim, o PostgreSQL é suportado pelo Nextcloud em pé de igualdade e é até referido com preferência na documentação. No Debian isso resolve também a questão do MySQL, que ali de qualquer forma não existe como pacote. Na instalação indica --database "pgsql" em vez de "mysql".

Nextcloud Alojamento próprio PHP nginx MariaDB Debian Ubuntu Cloud Linux