Como instalar Nextcloud em VPS com Docker e TLS
Veja como rodar Nextcloud em uma VPS com Docker Compose, Postgres, Redis e proxy TLS, incluindo backup restaurável, upgrades e Let's Encrypt.
O que está realmente a criar
Este guia executa o Nextcloud numa VPS com Docker Compose, coloca o TLS do Let's Encrypt à frente do serviço e configura um backup que pode ser efetivamente restaurado. São quatro contentores e um proxy: a imagem oficial nextcloud a escutar na interface de loopback, o Postgres a armazenar todos os metadados dos ficheiros, o Redis a armazenar os bloqueios dos ficheiros, uma segunda cópia da imagem do Nextcloud a executar apenas o ciclo do cron e o nginx no host a terminar o TLS à frente de tudo. A instalação demora vinte minutos, mas não é essa a parte importante. Duas decisões tomadas na primeira hora determinam se ainda terá os seus ficheiros daqui a um ano: usar uma base de dados real em vez do SQLite e ter um backup que capture o diretório de dados, a base de dados e config.php como um conjunto consistente.
Isto pressupõe Ubuntu 24.04 LTS ou Debian 13, Docker Engine com o plugin Compose v2 instalado a partir do repositório oficial do Docker e um registo DNS A (e também AAAA se tiver IPv6) já a apontar cloud.example.com para a VPS. Tudo isto requer um servidor sob o seu controlo. Não é possível terminar o TLS e criar um dump da base de dados num SaaS de terceiros.
Dimensionamento: o que realmente consome a memória
O uso de memória do Nextcloud é dominado por três componentes, e nenhum deles é o próprio "Nextcloud".
Workers PHP. A imagem -apache processa cada pedido simultâneo através de um processo worker que mantém um interpretador PHP. Cada worker pode crescer até PHP_MEMORY_LIMIT antes de o PHP terminar o pedido. A memória residente no pior caso é aproximadamente pedidos simultâneos × limite de memória, e um cliente de sincronização para desktop abre várias ligações paralelas por utilizador. É a simultaneidade, e não o número de utilizadores, que define o limite.
A base de dados. O Postgres cria um processo backend por ligação e mantém buffers partilhados residentes. O conjunto de trabalho aumenta com o número de ficheiros, e não com o número de bytes: oc_filecache mantém uma linha por ficheiro e por utilizador. Cem mil ficheiros pequenos representam uma carga maior para a base de dados do que cem ficheiros grandes.
Geração de pré-visualizações. Gerar uma miniatura descodifica a imagem original na memória com a resolução completa. As pré-visualizações de vídeo executam ffmpeg como processo externo. Executar occ preview:generate-all repete esse pico várias vezes, sem intervalo, e é a forma mais comum de levar um VPS pequeno ao OOM killer.
O Redis é comparativamente económico. Qualquer componente que adicionar mais tarde, como o Collabora, a pesquisa de texto integral ou um antivírus, é um serviço residente separado, com a sua própria utilização de memória, e deve ser incluído no plano de dimensionamento antes de ser ativado.
Se a memória RAM for limitada, ajuste estes parâmetros: reduza PHP_MEMORY_LIMIT, limite preview_max_x / preview_max_y / preview_max_filesize_image, reduza enabledPreviewProviders aos formatos que realmente consulta e defina trashbin_retention_obligation e versions_retention_obligation para que o diretório de dados não cresça silenciosamente até várias vezes o tamanho dos seus ficheiros. Adicione um ficheiro de swap. O swap é lento, mas terminar um processo pelo OOM killer durante uma atualização é pior.
Por que o SQLite falha
O Nextcloud inclui suporte ao SQLite, e a imagem oficial pode utilizá-lo sem problemas aparentes. Não o utilize. O SQLite serializa as escritas com um bloqueio ao nível de toda a base de dados: apenas um processo pode escrever de cada vez em todo o ficheiro. O Nextcloud escreve constantemente: bloqueios de ficheiros, registos de atividade, entradas de cache e estado das tarefas. Além disso, um único cliente de ambiente de trabalho a sincronizar uma árvore de diretórios gera muitos pedidos paralelos. Nesse cenário, ocorre SQLSTATE[HY000]: General error: 5 database is locked e surgem erros HTTP 500. A falha aparece precisamente quando a instância começa a ser útil.
Mais tarde, é possível converter a base de dados com occ db:convert-type, mas trata-se de uma migração longa e indivisível num conjunto de dados ativo. Comece com Postgres ou MariaDB.
O ficheiro Compose
Coloque isto em /srv/nextcloud/compose.yaml, com os segredos num ficheiro .env irmão, com o modo 600.
services:
db:
image: postgres:16-alpine
restart: unless-stopped
volumes:
- db:/var/lib/postgresql/data
environment:
POSTGRES_DB: nextcloud
POSTGRES_USER: nextcloud
POSTGRES_PASSWORD: ${DB_PASSWORD}
redis:
image: redis:7-alpine
restart: unless-stopped
command: redis-server --requirepass ${REDIS_PASSWORD}
app:
image: nextcloud:35-apache
restart: unless-stopped
depends_on: [db, redis]
ports:
- "127.0.0.1:8080:80"
volumes:
- html:/var/www/html
- /srv/nextcloud/data:/var/www/html/data
environment:
POSTGRES_HOST: db
POSTGRES_DB: nextcloud
POSTGRES_USER: nextcloud
POSTGRES_PASSWORD: ${DB_PASSWORD}
REDIS_HOST: redis
REDIS_HOST_PASSWORD: ${REDIS_PASSWORD}
NEXTCLOUD_ADMIN_USER: admin
NEXTCLOUD_ADMIN_PASSWORD: ${ADMIN_PASSWORD}
NEXTCLOUD_TRUSTED_DOMAINS: cloud.example.com
TRUSTED_PROXIES: 172.16.0.0/12
OVERWRITEPROTOCOL: https
OVERWRITECLIURL: https://cloud.example.com
APACHE_DISABLE_REWRITE_IP: "1"
PHP_MEMORY_LIMIT: 512M
PHP_UPLOAD_LIMIT: 10G
cron:
image: nextcloud:35-apache
restart: unless-stopped
entrypoint: /cron.sh
depends_on: [db, redis]
volumes:
- html:/var/www/html
- /srv/nextcloud/data:/var/www/html/data
volumes:
db:
html:Fixe a tag principal e confirme a tag atual no Docker Hub antes de copiar 35 literalmente. Em 21 de outubro de 2026, o Nextcloud mantém as versões 33, 34 e 35. A versão 31 atingiu o fim de vida em fevereiro de 2026 e a versão 32 em setembro de 2026. Por isso, uma tag copiada de um guia antigo instala uma versão que já não recebe correções. latest fará a atualização através de uma fronteira entre versões principais num futuro docker compose pull, e o Nextcloud não suporta esse procedimento.
O diretório de dados é um bind mount, e não um volume nomeado, de propósito: um caminho que pode indicar diretamente a uma ferramenta de backup é mais útil do que uma configuração organizada. Crie-o com o UID www-data da imagem e com as permissões exigidas pelo Nextcloud:
sudo mkdir -p /srv/nextcloud/data
sudo chown -R 33:33 /srv/nextcloud/data
sudo chmod 0770 /srv/nextcloud/dataObserve a publicação da porta: 127.0.0.1:8080:80. O Docker publica portas através de regras DNAT que são avaliadas antes de o pacote chegar à cadeia INPUT do ufw. Um 8080:80 simples coloca um Nextcloud sem encriptação na Internet pública, independentemente do que o ufw indicar. A associação à interface loopback mantém o serviço fora da interface pública. Assim, a firewall só precisa de permitir o proxy. Se preferir não deixar o SSH aberto a toda a Internet, aceder ao VPS através de uma VPN WireGuard autoalojada permite remover completamente a porta 22 das regras públicas:
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enableInicie-o com docker compose up -d e monitorize docker compose logs -f app. No primeiro arranque, a aplicação copia toda a árvore de ficheiros para o volume e executa o instalador. O contentor não responde até esse processo terminar.
TLS e o reverse proxy
Instale nginx e certbot a partir da distribuição, crie um server block simples na porta 80 com o server_name correto e deixe o certbot reescrevê-lo. O funcionamento do desafio HTTP-01, o temporizador de renovação e os modos de falha são explicados detalhadamente em emitir certificados Let's Encrypt com certbot e nginx no Ubuntu 24.04:
sudo apt install nginx certbot python3-certbot-nginx
sudo certbot --nginx -d cloud.example.comO certbot adiciona as linhas ssl_certificate e o redirecionamento :80 → :443. Também instala um temporizador systemd que renova o certificado de 90 dias. Confirme que ele existe com systemctl list-timers | grep certbot. Um temporizador de renovação que nunca foi ativado é um temporizador de 90 dias até à falha.
O bloco de proxy:
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name cloud.example.com;
# certbot manages ssl_certificate / ssl_certificate_key here
add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
client_max_body_size 10G;
client_body_timeout 300s;
location = /.well-known/carddav { return 301 /remote.php/dav; }
location = /.well-known/caldav { return 301 /remote.php/dav; }
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_request_buffering off;
proxy_buffering off;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
}No nginx 1.25.1 e posteriores, adicione http2 on;. Essa diretiva não existe no 1.25.0, e o nginx não arranca se a encontrar nessa versão. O Ubuntu 24.04 inclui uma compilação mais antiga, em que o equivalente é listen 443 ssl http2;. nginx -t mostra qual das duas opções a sua compilação aceita.
Se client_max_body_size for demasiado pequeno, o nginx rejeita imediatamente um upload grande com um erro 413. Se os tempos limite de leitura forem demasiado curtos, o upload falha a meio. Os valores acima evitam ambos os problemas. proxy_request_buffering off transmite o upload em vez de guardar primeiro o ficheiro completo no disco do proxy.
O nginx no host é a solução mais simples para uma única aplicação. Se o Nextcloud for partilhar o VPS com outros contentores, executar o Traefik como reverse proxy Docker Compose para várias aplicações transfere o encaminhamento e a emissão de certificados para labels de contentores. As mesmas preocupações com client_max_body_size e os tempos limite voltam a surgir nas definições de middleware e transporte.
trusted_proxies e overwriteprotocol
É aqui que a maioria das instâncias Nextcloud autoalojadas fica mal configurada. Os sintomas parecem não ter relação com a causa.
X-Forwarded-Proto: https só é aplicado quando o pedido chega de um endereço listado em trusted_proxies. Quando não é aplicado, o Nextcloud considera que o pedido usa HTTP simples e gera URLs http://. O proxy redireciona essas URLs para HTTPS. O navegador segue o redirecionamento. O Nextcloud gera novamente http://. Esse é o ciclo de redirecionamento. OVERWRITEPROTOCOL: https fixa o esquema, independentemente disso.
A armadilha em TRUSTED_PROXIES é que o endereço que o Nextcloud vê não é 127.0.0.1. O nginx é executado no host e liga-se a uma porta publicada. Por isso, o contentor vê o gateway da bridge Docker, que pertence a algo em 172.x. Descubra a sub-rede real:
docker network inspect nextcloud_default \
-f '{{range .IPAM.Config}}{{.Subnet}}{{end}}'Adicione esse CIDR, ou o 172.16.0.0/12 que o abrange, a TRUSTED_PROXIES. Se o intervalo for demasiado amplo, qualquer cliente poderá falsificar X-Forwarded-For. Se estiver incorreto, todos os logins parecerão vir do endereço do gateway, a proteção contra brute force bloqueará toda a instância de uma só vez e a visão geral de administração mostrará "The reverse proxy header configuration is incorrect, or you are accessing Nextcloud from a trusted proxy."
OVERWRITECLIURL é importante para o contentor do cron, que não recebe nenhum pedido de entrada do qual possa inferir um hostname. Sem essa configuração, as tarefas em segundo plano geram links para localhost e as notificações por email enviam URLs inutilizáveis.
Tarefas em segundo plano: cron, não AJAX
O executor de tarefas predefinido do Nextcloud é AJAX: as tarefas são executadas como efeito secundário do carregamento de uma página por alguém. Ninguém navega às 04:00, por isso a expiração do lixo, a limpeza de versões, as pré-visualizações e as novas tentativas federadas ficam bloqueadas. O primeiro sintoma é um diretório de dados que nunca para de crescer. O serviço cron acima executa o ciclo oficial /cron.sh nos mesmos volumes. Configure o Nextcloud para esperar esse executor:
docker compose exec -u www-data app php occ background:cronTodos os comandos occ seguem este formato: docker compose exec -u www-data app php occ <command>. Vale a pena criar um alias.
Backups: three things, or none
Um backup apenas do sistema de ficheiros restaura uma instância avariada. O diretório de dados contém os bytes; o Postgres contém a cache de ficheiros, as partilhas, os utilizadores e o estado da aplicação; config.php contém as credenciais da base de dados, o ID da instância e o salt da palavra-passe. Restaure os ficheiros sem a base de dados e o Nextcloud não consegue vê-los. Restaure a base de dados sem config.php e não consegue abrir a base de dados. Restaure uma base de dados antiga sobre um diretório de dados mais recente e obterá partilhas que apontam para ficheiros que foram movidos.
Faça cópias de segurança dos três componentes, a partir de uma instância colocada em estado quiescente:
#!/usr/bin/env bash
set -euo pipefail
cd /srv/nextcloud
DEST="/var/backups/nextcloud/$(date -u +%Y%m%dT%H%M%SZ)"
mkdir -p "$DEST"
occ() { docker compose exec -T -u www-data app php occ "$@"; }
occ maintenance:mode --on
trap 'occ maintenance:mode --off' EXIT
docker compose exec -T db \
pg_dump -U nextcloud --clean --if-exists nextcloud | gzip > "$DEST/db.sql.gz"
docker compose exec -T app \
tar -C /var/www/html -cf - config custom_apps themes > "$DEST/app.tar"
rsync -a --delete /srv/nextcloud/data/ /var/backups/nextcloud/data/O modo de manutenção faz com que o dump e a cópia dos ficheiros sejam consistentes entre si. Se o ignorar, acabará por capturar uma base de dados que referencia um ficheiro que o rsync ainda não tinha alcançado. Tenha em atenção que o script mantém dumps da base de dados com timestamp, mas apenas um espelho rotativo do diretório de dados. rsync --delete substitui-o em cada execução, pelo que apenas o dump mais recente corresponde à cópia dos ficheiros.
Depois, retire a cópia do servidor. Uma cópia de segurança que permanece no mesmo VPS que os dados protegidos é uma cópia, não uma cópia de segurança. restic para armazenamento de objetos ou para um segundo host é a resposta habitual, e a deduplicação lida muito melhor com o diretório de dados do que um tarball noturno. A configuração completa, desde a inicialização do repositório até ao timer noturno e ao teste de restauração, está em cópias de segurança de VPS fora do servidor com restic.
A restauração não é simplesmente o processo inverso. Uma stack iniciada de novo executa o instalador e grava um config.php completamente novo, um novo ID de instância e um novo salt da palavra-passe. Importar o dump sobre essa nova identidade deixa as sessões e os tokens de partilha avariados. Reponha primeiro a identidade antiga, pela seguinte ordem:
docker compose up -d && docker compose stop app cron # create the volumes, then halt the app
sudo rsync -a --delete /var/backups/nextcloud/data/ /srv/nextcloud/data/
docker compose run --rm -T --entrypoint "" app \
tar -C /var/www/html -xf - < app.tar # the original config.php returns
gunzip -c db.sql.gz | docker compose exec -T db psql -U nextcloud -d nextcloud
docker compose start app cron
docker compose exec -T -u www-data app php occ maintenance:mode --off
docker compose exec -T -u www-data app php occ files:scan --allfiles:scan reconcilia a cache de ficheiros com o que existe efetivamente no disco. Faça este procedimento uma vez, num VPS de reserva, antes de precisar dele. A mesma separação entre os bytes no disco e os metadados no Postgres aplica-se a qualquer outra aplicação deste tipo. É por isso que um backup do Immich que captura a biblioteca, mas não a base de dados, restaura uma linha do tempo vazia.
Atualizações: uma versão principal de cada vez
O Nextcloud suporta a atualização de exatamente uma versão principal de cada vez. Com a imagem oficial do Docker, saltar da 29 para a 31 nunca chega ao atualizador. O entrypoint compara as versões principais antes de executar occ upgrade, apresenta Can't start Nextcloud because upgrading from <installed version> to <image version> is not supported. seguido de It is only possible to upgrade one major version at a time. e termina. O contentor recusa arrancar (com restart: unless-stopped, continua a reiniciar e a apresentar as mesmas linhas), o modo de manutenção nunca é ativado e os dados e a base de dados permanecem inalterados. Defina a tag para a versão principal seguinte e arranque novamente.
O processo de atualização no Docker é: faça uma cópia de segurança, edite a tag para a versão principal seguinte nos serviços app e cron (de 35 para 36 quando a 36 for lançada, algo que o Nextcloud prevê para fevereiro de 2027), depois execute docker compose pull && docker compose up -d e, em seguida, docker compose logs -f app. O entrypoint da imagem deteta o código mais recente face aos dados existentes e executa occ upgrade automaticamente. Não o interrompa. Quando os logs deixarem de apresentar atividade, execute docker compose exec -u www-data app php occ status e confirme versionstring e que as aplicações voltaram a ficar ativadas.
Duas regras evitam problemas: avance uma versão principal, verifique e só depois avance para a seguinte. Nunca edite a tag do serviço app sem editar também cron para corresponder. Duas versões diferentes do Nextcloud a utilizar a mesma base de dados podem causar corrupção.
Os erros que você verá na prática
"Your data directory is readable by other people. Please change the permissions to 0770 so that the directory cannot be listed by other people." O último dígito do modo do diretório, o que corresponde aos outros utilizadores, não é zero. Qualquer bit de leitura, escrita ou execução para outros utilizadores provoca este erro. Os bits do grupo nunca são verificados, porque o próprio 0770 dá ao grupo acesso total. O Nextcloud tenta primeiro chmod 0770 por conta própria e só apresenta um aviso se isso falhar. Numa montagem bind, isso normalmente significa que o diretório não pertence ao UID 33. sudo chown -R 33:33 /srv/nextcloud/data e sudo chmod 0770 /srv/nextcloud/data.
"Your data directory is invalid. Ensure there is a file called ".ncdata" in the root of the data directory." A montagem bind aponta para um local que o Nextcloud nunca inicializou, o caminho contém um erro de escrita ou um diretório vazio foi colocado no lugar da instância funcional. Confirme que o caminho no host corresponde à linha do volume.
"Access through untrusted domain." O nome de host no pedido não está em trusted_domains. NEXTCLOUD_TRUSTED_DOMAINS só se aplica durante a instalação inicial. Depois, defina-o em tempo real: occ config:system:set trusted_domains 1 --value=cloud.example.com.
502 Bad Gateway, com connect() failed (111: Connection refused) while connecting to upstream em /var/log/nginx/error.log. O nginx não encontrou nada em 127.0.0.1:8080. O contentor ainda pode estar a ser inicializado (verifique docker compose logs app), pode ter terminado (docker compose ps) ou a linha de publicação pode não corresponder à porta proxy_pass. Confirme com ss -ltnp | grep 8080.
Um ciclo de redirecionamento ou avisos de ligação "insecure" na vista geral de administração. OVERWRITEPROTOCOL: https está em falta ou TRUSTED_PROXIES não contém a sub-rede do gateway Docker. Consulte a secção anterior sobre o proxy.
LockedException: "files/..." is locked. Com REDIS_HOST definido, a imagem configura o Redis como backend de bloqueios e os bloqueios obsoletos são raros. Sem essa configuração, os bloqueios ficam na tabela da base de dados oc_file_locks e um pedido terminado durante uma escrita deixa linhas para trás. Confirme que o Redis está realmente a ser utilizado. occ config:system:get memcache.locking deve devolver a classe Redis antes de apagar manualmente as linhas de bloqueio.
"The PHP memory limit is below the recommended value of 512 MB." Aumente PHP_MEMORY_LIMIT e recrie o contentor. Tenha em conta o efeito disso no limite máximo do pior caso.
O que falha em escala
O primeiro limite surge quando o diretório de dados ultrapassa o tamanho do volume. Aumentar um volume numa VPS exige redimensioná-lo e aumentar o sistema de ficheiros. É muito menos doloroso fazer isso de forma agendada do que esperar pelos 100% de utilização. Configure já alertas para a utilização do disco.
O segundo limite é oc_filecache. As listagens de ficheiros e as verificações de sincronização ficam mais lentas à medida que aumenta o número de registos. A correção exige trabalho na base de dados: mantenha o Postgres em armazenamento rápido, permita que use memória partilhada suficiente e elimine o lixo e as versões com definições de retenção, em vez de os deixar acumular indefinidamente.
O terceiro limite é a geração de pré-visualizações, que compete com todos os outros processos. Numa máquina pequena, mantenha os fornecedores de pré-visualizações limitados e nunca execute occ preview:generate-all durante o horário de trabalho. Se a maior parte do que armazena for o rolo da câmara de um telemóvel, esse trabalho de criação de miniaturas deve ser feito num servidor de fotografias dedicado. O artigo Comparação entre PhotoPrism e Immich quanto à RAM, aplicações móveis e comandos de backup explica os recursos de cada opção quando usada juntamente com uma máquina Nextcloud.
A partir daí, a resposta honesta é que os componentes adicionais devem ter a sua própria máquina. O Collabora e a pesquisa de texto integral são serviços residentes separados, com os seus próprios perfis de consumo de memória. Colocá-los na máquina que também contém a sua única cópia dos ficheiros aumenta o domínio de falha sem trazer benefícios. Se pretende edição de documentos no navegador, os limites mínimos de RAM e de ligações definidos pelos fornecedores, descritos em os requisitos de RAM e os limites de ligações que distinguem o OnlyOffice do Collabora, determinam qual deles uma VPS de 2 a 4 GB consegue executar. Transfira o armazenamento dos ficheiros para armazenamento primário compatível com S3 quando o volume deixar de ter o formato adequado. Tenha em conta que isto torna os backups mais difíceis, não mais fáceis: a base de dados continua a conter os metadados e tem de ser exportada em conjunto com o bucket.
Quando a instância começar a servir utilizadores reais, coloque o Uptime Kuma à frente dela para ser informado da indisponibilidade antes dos clientes de sincronização. Uma cloud privada combina bem com o seu próprio servidor de correio. Se preferir não ligar os serviços manualmente, Cloudron, CasaOS e Coolify comparam as plataformas que fazem isso por si. Se um motor de pesquisa self-hosted for o próximo componente da lista, espere um tipo de problema diferente dos anteriores: os erros 429 do SearXNG resultam do seu próprio limitador de taxa ou do bloqueio do endereço IP da VPS pelos motores upstream. Só o log permite determinar qual das duas causas ocorreu.
FAQ
Posso executar o Nextcloud com SQLite em vez de Postgres?
Pode. A imagem oficial permite essa configuração, mas um único cliente de sincronização num desktop a emitir pedidos em paralelo irá atingir SQLSTATE[HY000]: General error: 5 database is locked e gerar erros HTTP 500. O SQLite bloqueia a escrita em toda a base de dados, e o Nextcloud escreve constantemente dados como bloqueios de ficheiros, registos de atividade e estado de tarefas. Comece com Postgres ou MariaDB. occ db:convert-type existe, mas é uma migração longa, feita de uma só vez, em dados ativos.
Quanta RAM um VPS com Nextcloud precisa realmente?
Dimensione o sistema para a concorrência, não para o número de utilizadores. No pior caso, a memória residente é aproximadamente o número de pedidos concorrentes multiplicado por PHP_MEMORY_LIMIT, mais os buffers partilhados do Postgres, um backend por ligação e o pico de memória causado pela geração de pré-visualizações. Uma máquina com 2 GB executa uma instância pequena para uma família se limitar as pré-visualizações e adicionar swap. Se adicionar Collabora ou pesquisa de texto integral, terá de dimensionar um segundo conjunto de serviços residentes.
Porque falham os uploads grandes atrás do reverse proxy nginx?
Normalmente, duas definições no proxy explicam o problema. Se client_max_body_size ficar com o valor predefinido de 1 MB, o nginx rejeita imediatamente qualquer pedido maior com um erro 413 (Request Entity Too Large). O erro aparece no log de erros do nginx, e não como um ficheiro parcial. Valores baixos de proxy_read_timeout / proxy_send_timeout interrompem as transferências longas a meio. Defina ambos com valores generosos, ative proxy_request_buffering off para transmitir os dados em vez de os armazenar temporariamente e aumente PHP_UPLOAD_LIMIT no contentor da aplicação para corresponder.
Porque redireciona o Nextcloud num ciclo ou apresenta um aviso sobre o reverse proxy?
O contentor não vê o nginx em 127.0.0.1. Vê o gateway da bridge Docker, algures em 172.x. Quando esse endereço não está incluído em TRUSTED_PROXIES, o cabeçalho X-Forwarded-Proto: https é ignorado, o Nextcloud gera URLs http:// e o proxy encaminha-as novamente. Defina TRUSTED_PROXIES para a sub-rede real da bridge e fixe OVERWRITEPROTOCOL: https.
Posso atualizar o Nextcloud diretamente da versão 29 para a 31?
Não. O Nextcloud suporta uma versão principal por atualização. Na imagem oficial do Docker, o entrypoint verifica as versões principais antes de executar occ upgrade, apresenta It is only possible to upgrade one major version at a time. e termina. Assim, o contentor não inicia e os seus dados e a base de dados permanecem inalterados. Defina a tag como 30. Faça uma cópia de segurança, aumente a tag em uma versão principal nos serviços app e cron, execute docker compose pull && docker compose up -d, confirme com occ status e repita o processo.