Nextcloud com Docker Compose: nuvem privada passo a passo
Dar aos usuários um “Google Drive” próprio, dentro da própria rede ou numa VPS, resolve dois problemas de uma vez: tira a empresa da dependência de armazenamento de terceiros e mantém os dados sob a jurisdição e a política de backup que você já controla. O Nextcloud é a opção mais madura para isso — sincronização de arquivos, calendário, contatos e edição colaborativa de documentos, tudo auto-hospedado. Rodando em Docker Compose, a instalação inteira fica reproduzível em um único arquivo de texto.
Este guia sobe uma stack completa — aplicação, banco MariaDB, cache Redis e cron em container próprio — e termina com HTTPS funcionando atrás de um proxy reverso, do jeito que uma instância de produção precisa rodar.
Por que não só “docker run nextcloud” e pronto
A imagem oficial funciona sozinha com SQLite, mas isso não escala além de um usuário de teste: SQLite trava em acesso concorrente e não tem caminho de upgrade confortável. Três peças resolvem isso:
- MariaDB como banco — suporta múltiplos usuários escrevendo ao mesmo tempo sem bloqueio de arquivo.
- Redis como cache de file locking e cache de transação — sem ele, dois clientes sincronizando a mesma pasta em paralelo podem gerar conflito de bloqueio e arquivo corrompido.
- Cron em container dedicado — o Nextcloud depende de tarefas em segundo plano (limpeza de versões antigas, notificações, indexação) que não rodam sozinhas sem um agendador.
Pré-requisitos
- Ubuntu Server 22.04 ou 24.04 com Docker Engine e o plugin Docker Compose instalados (
docker compose versiondeve responder). - Um domínio ou subdomínio apontando para o servidor (ex.:
nuvem.seudominio.com.br), necessário para o HTTPS no passo final. - Portas 80 e 443 liberadas no firewall perimetral, se o proxy reverso rodar na mesma máquina.
Passo a passo
1. Criar o diretório do projeto
mkdir -p ~/nextcloud && cd ~/nextcloud
2. Escrever o docker-compose.yml
Troque as três senhas marcadas antes de salvar. Use openssl rand -base64 24 para gerar cada uma.
services:
db:
image: mariadb:11.4
restart: unless-stopped
command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW
volumes:
- db_data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=TROQUE_A_SENHA_ROOT
- MYSQL_DATABASE=nextcloud
- MYSQL_USER=nextcloud
- MYSQL_PASSWORD=TROQUE_A_SENHA_DB
redis:
image: redis:7-alpine
restart: unless-stopped
command: redis-server --requirepass TROQUE_A_SENHA_REDIS
app:
image: nextcloud:35
restart: unless-stopped
ports:
- "8080:80"
depends_on:
- db
- redis
volumes:
- nextcloud_data:/var/www/html
environment:
- MYSQL_HOST=db
- MYSQL_DATABASE=nextcloud
- MYSQL_USER=nextcloud
- MYSQL_PASSWORD=TROQUE_A_SENHA_DB
- REDIS_HOST=redis
- REDIS_HOST_PASSWORD=TROQUE_A_SENHA_REDIS
- NEXTCLOUD_ADMIN_USER=admin
- NEXTCLOUD_ADMIN_PASSWORD=TROQUE_A_SENHA_ADMIN
- NEXTCLOUD_TRUSTED_DOMAINS=nuvem.seudominio.com.br
- OVERWRITEPROTOCOL=https
- TRUSTED_PROXIES=172.16.0.0/12
cron:
image: nextcloud:35
restart: unless-stopped
volumes:
- nextcloud_data:/var/www/html
entrypoint: /cron.sh
depends_on:
- db
- redis
volumes:
db_data:
nextcloud_data:
Dois pontos que custam retrabalho se pulados:
image: nextcloud:35fixa a versão maior em vez de usar:latest. Sem isso, umdocker compose pullde rotina pode saltar direto para a próxima versão maior e travar o upgrade do banco no meio do caminho — atualize de versão maior em versão maior, lendo o changelog antes.TRUSTED_PROXIESprecisa da faixa de IP do proxy reverso (ou da rede Docker dele). Sem essa variável, todo acesso aparece nos logs do Nextcloud com o IP interno do proxy, e a proteção contra força bruta de login passa a bloquear o proxy, não o atacante.
3. Subir os containers
docker compose up -d docker compose ps
O container cron aparece na listagem com status “Up” — é esse status, visível em docker compose ps, que avisa se o agendador caiu, algo que uma entrada de crontab no host não mostra.
4. Ativar o cron dentro do Nextcloud
O container cron já executa cron.php a cada 5 minutos sozinho, mas o Nextcloud só passa a confiar nesse agendamento depois da primeira execução. Force uma rodada manual e confirme o modo:
docker compose exec -u www-data app php cron.php docker compose exec -u www-data app php occ background:cron
Depois, em Administração > Configurações básicas > Tarefas em segundo plano, confirme que o modo selecionado é Cron, não AJAX — no modo AJAX as tarefas só rodam quando alguém está com o navegador aberto na instância, o que deixa tarefas de manutenção paradas em servidores sem acesso web constante.
5. Primeiro acesso e ajuste do limite de upload
Acesse http://IP-DO-SERVIDOR:8080 e entre com o usuário e senha definidos em NEXTCLOUD_ADMIN_USER/NEXTCLOUD_ADMIN_PASSWORD. O limite padrão de upload da imagem (512 MB) é baixo para quem sincroniza vídeos ou backups de VM; para subir, crie um arquivo de override:
mkdir -p ./php-overrides cat > ./php-overrides/uploads.ini << 'EOF' upload_max_filesize=16G post_max_size=16G EOF
Monte o arquivo no serviço app adicionando esta linha em volumes:
- ./php-overrides/uploads.ini:/usr/local/etc/php/conf.d/uploads.ini:ro
Depois recrie o container: docker compose up -d app.
Reverse proxy e HTTPS
A stack acima expõe apenas a porta 8080 em HTTP — de propósito, para não lidar com certificado dentro do mesmo container da aplicação. Aponte um proxy reverso para 127.0.0.1:8080 e deixe o certificado com ele. Se você já tem o Nginx Proxy Manager rodando, é só criar um novo "Proxy Host" apontando para o domínio escolhido, com Force SSL e HTTP/2 ativados e o certificado Let's Encrypt gerado na mesma tela.
Para expor a instância sem abrir nenhuma porta no firewall perimetral — útil quando o servidor está detrás de CGNAT ou numa rede sem IP público —, o caminho é o Cloudflare Tunnel, que já foi coberto aqui.
Backup: o passo que ninguém pode pular
Backup de Nextcloud tem duas partes que precisam estar no mesmo ponto no tempo: o volume nextcloud_data (arquivos e configuração) e o banco MariaDB. Restaurar um sem o outro corrompe a instância.
mkdir -p ~/backup-nextcloud docker compose exec app php occ maintenance:mode --on docker compose exec db sh -c 'exec mariadb-dump -u nextcloud -pTROQUE_A_SENHA_DB nextcloud' > ~/backup-nextcloud/db-$(date +%F).sql docker run --rm -v nextcloud_nextcloud_data:/data -v ~/backup-nextcloud:/backup alpine tar czf /backup/files-$(date +%F).tar.gz -C /data . docker compose exec app php occ maintenance:mode --off
O maintenance:mode --on bloqueia escrita durante o dump — sem isso, um arquivo pode ser alterado entre o backup do banco e o backup dos arquivos, e os dois saem dessincronizados. Para levar esse backup para fora do servidor, os guias de Restic e de rclone com armazenamento S3 publicados aqui se encaixam direto na pasta ~/backup-nextcloud.
Perguntas frequentes
Preciso de Redis ou dá para rodar sem ele?
Dá, mas não deveria em produção: sem Redis o Nextcloud usa bloqueio de arquivo em disco, que é mais lento e, com vários clientes sincronizando ao mesmo tempo, mais sujeito a erro de "arquivo bloqueado" que trava a sincronização do usuário.
Por que o container de cron e não só uma linha no crontab do host?
Uma entrada de crontab chamando docker exec depende do nome do container, que muda se a pasta do projeto for renomeada — e nada avisa quando isso quebra. O container de cron sobe com o resto da stack, aparece em docker compose ps e falha de forma visível.
Posso trocar MariaDB por PostgreSQL?
Sim, a imagem oficial aceita POSTGRES_HOST e variáveis equivalentes no lugar das de MySQL. A troca só vale a pena antes da instalação — migrar de banco depois exige exportar e reimportar todos os dados.
O Nextcloud substitui backup na nuvem?
Não. Ele centraliza e sincroniza os arquivos, mas se o servidor onde ele roda falhar, os dados vão junto. Trate o Nextcloud como a camada de acesso e mantenha uma rotina de backup externa como as citadas acima.
Dá para rodar isso numa VPS pequena?
Sim — 2 vCPUs e 4 GB de RAM sustentam MariaDB, Redis e a aplicação para uso de uma equipe pequena. Abaixo disso, o Redis e o PHP-FPM da aplicação competem por memória e a interface fica perceptivelmente lenta.
Conclusão
Com os quatro serviços no ar, o próximo passo é criar os usuários em Administração > Usuários, instalar o cliente de sincronização nas estações e, se o backup automatizado ainda não existir, montar o cron job que roda o script da seção acima todas as madrugadas. A partir daqui, qualquer upgrade de versão maior do Nextcloud é só trocar a tag da imagem em docker-compose.yml e rodar docker compose up -d de novo — o container cuida da migração do banco sozinho.