Nextcloud com Docker Compose: nuvem privada passo a passo
|

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 version deve 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:35 fixa a versão maior em vez de usar :latest. Sem isso, um docker compose pull de 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_PROXIES precisa 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.

Gostou? Compartilhe.

Posts Similares

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *