Pular para o conteúdo

Instalar com Docker

Um servidor do Cofre Ink só seu traz contas com email e senha, os mesmos dados em todo aparelho que entra nele e espaços compartilhados em que você convida outras pessoas. É um container só, que serve a interface e os dados numa mesma porta. Esta página vai de uma máquina vazia até o primeiro acesso, e depois explica como atualizar, fazer backup e o que pode dar errado.

Se só você vai usar o Cofre Ink, num aparelho só, nada disto é necessário: app.cofre.ink guarda o banco de dados no seu navegador, sem conta. Onde os dados ficam compara as duas formas. Lembre que, com um servidor, todo aparelho precisa alcançar esse servidor para funcionar.

  1. Docker, com o comando docker compose. O repositório não diz uma versão mínima, nem quanto de memória ou de disco.
  2. Git, para baixar o código.
  3. Node, só para gerar o segredo no passo 3, porque o container traz o dele. Qualquer sequência aleatória de pelo menos 32 caracteres também serve.
  4. Internet no primeiro build. Construir a imagem baixa o pnpm e os pacotes que o Cofre Ink usa.
  5. A porta 4321 livre na máquina, ou outra que você escolher com COFRE_PORT.

Todo comando desta página é do próprio repositório ou foi rodado enquanto este guia era escrito, no PowerShell, no Windows 11 com o Docker Desktop. Eles valem igual num terminal de Linux ou de macOS. O Prompt de Comando do Windows (cmd.exe) não entende o ${PWD} dos comandos de backup: use o PowerShell nesse caso.

O repositório traz este arquivo na raiz. Você não mexe nele: o que você define vai no .env, e o Compose preenche as partes ${...} a partir de lá.

compose.yaml
# Cofre on your own machine.
#
# 1. cp .env.example .env
# 2. fill COFRE_SECRET
# 3. docker compose up -d
#
# The data lives in the named volume below, so it survives an update of the image.
# For PostgreSQL instead of SQLite, read the note above the database service further
# down: there are four things to uncomment, and leaving one out stops the whole file.
# The project name comes from here and not from the folder, so the container and the
# volume are called the same thing on every machine.
name: cofre
services:
cofre:
build: .
restart: unless-stopped
ports:
- "${COFRE_PORT:-4321}:4321"
environment:
COFRE_PORT: 4321
COFRE_DATABASE: ${COFRE_DATABASE:-/data/cofre.db}
COFRE_SECRET: ${COFRE_SECRET:?set COFRE_SECRET in .env}
COFRE_WEB_ORIGIN: ${COFRE_WEB_ORIGIN:-http://localhost:4321}
COFRE_PUBLIC_URL: ${COFRE_PUBLIC_URL:-http://localhost:4321}
# The rest of what .env.example offers. Without these lines a person fills the
# file, brings the container up and finds the widget they asked for is not there,
# which is worse than not offering it: they think something is guarding the door.
COFRE_PROOF_BITS: ${COFRE_PROOF_BITS:-18}
COFRE_CLIENT_IP_HEADER: ${COFRE_CLIENT_IP_HEADER:-}
COFRE_TURNSTILE_SITE_KEY: ${COFRE_TURNSTILE_SITE_KEY:-}
COFRE_TURNSTILE_SECRET: ${COFRE_TURNSTILE_SECRET:-}
NODE_ENV: production
volumes:
- cofreData:/data
healthcheck:
test: ["CMD", "node", "-e", "fetch('http://localhost:4321/health').then(r => process.exit(r.ok ? 0 : 1))"]
interval: 30s
timeout: 5s
retries: 3
# Uncomment this with the database service below, and not on its own: Compose
# refuses the whole project when a service depends on one that is not there.
#
# Waiting for the container to exist is not enough, which is why this waits for it
# to be healthy. PostgreSQL starts, writes its own files, restarts itself once and
# only then opens the socket, so a server that connects the moment the container
# appears is refused and dies on the first boot.
# depends_on:
# database:
# condition: service_healthy
# PostgreSQL instead of SQLite. Four things to uncomment, not one: this service, the
# depends_on above, the volume it writes to at the bottom of this file, and
# POSTGRES_PASSWORD in .env. Then point COFRE_DATABASE at it:
# COFRE_DATABASE=postgres://cofre:${POSTGRES_PASSWORD}@database:5432/cofre
# The host is `database`, the name of the service, because that is what the address
# resolves to from inside this network. It is not localhost, which in there is the
# container asking itself.
# database:
# image: postgres:17-alpine
# restart: unless-stopped
# environment:
# POSTGRES_USER: cofre
# POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env}
# POSTGRES_DB: cofre
# volumes:
# - cofrePostgres:/var/lib/postgresql/data
# # What the depends_on above waits for. Asking the database itself, rather than
# # watching a port, because the port is open for a moment during the start before
# # it is ready to answer.
# healthcheck:
# test: ["CMD-SHELL", "pg_isready -U cofre -d cofre"]
# interval: 5s
# timeout: 5s
# retries: 12
volumes:
cofreData:
# The other half of the database service above. Compose refuses the whole project when
# a service mounts a volume nothing declares, so uncommenting one without the other
# brings nothing up at all.
# cofrePostgres:
  1. name: cofre fixa o nome do projeto, seja qual for o nome da pasta. O container e o volume levam esse nome, e é por isso que o volume se chama cofre_cofreData nos comandos de backup mais abaixo.
  2. build: . constrói a imagem na sua máquina, a partir do Dockerfile que fica ao lado deste arquivo. Primeiro ele monta a interface, depois uma imagem sobre node:24-alpine que roda o servidor com o usuário node, e não como root.
  3. restart: unless-stopped sobe o container de novo depois de uma queda ou de um reinício do Docker, a não ser que você mesmo tenha parado.
  4. ports publica o servidor na porta da sua máquina indicada por COFRE_PORT, ou 4321 quando nada a define. Dentro do container o servidor escuta sempre na 4321.
  5. environment entrega as configurações ao servidor. ${NOME:-valor} pega a linha NOME= do .env e só usa o valor depois de :- quando o .env não tem essa linha ou a deixa vazia. Ou seja, uma linha no .env sempre vence o padrão escrito aqui. ${COFRE_SECRET:?...} não tem padrão: sem segredo, o Compose não sobe o container. NODE_ENV fica fixo em production.
  6. volumes monta o volume cofreData em /data, dentro do container. O que é gravado em /data sobrevive quando o container é trocado. O que é gravado em qualquer outro lugar, não.
  7. healthcheck pergunta ao servidor em /health a cada 30 segundos. O docker compose ps mostra a resposta como (healthy).
  8. O depends_on, o serviço database e o volume cofrePostgres comentados são o caminho do PostgreSQL. Eles são descomentados juntos, com uma linha no .env, como dizem os comentários do arquivo. Veja PostgreSQL.
Janela do terminal
git clone https://github.com/AndreiLud/app-cofre-ink
cd app-cofre-ink

Todos os comandos daqui em diante rodam dentro dessa pasta.

Janela do terminal
cp .env.example .env

O .env.example lista todas as configurações, com um comentário em cada uma. O cp funciona no PowerShell também. Ele substitui um .env que já exista sem perguntar, então rode uma vez só: num servidor que já está em uso, você perderia o segredo e os endereços do passo 4.

Janela do terminal
node -e "console.log(require('node:crypto').randomBytes(32).toString('hex'))"

Sai uma sequência de 64 caracteres. Abra o .env num editor de texto e cole logo depois de COFRE_SECRET=, na mesma linha. Sem Node, qualquer sequência aleatória de pelo menos 32 caracteres serve. Uma mais curta impede o servidor de subir.

O segredo assina as sessões de quem está conectado. Ele não é a sua senha. Guarde longe dos olhos dos outros, e não troque: trocar desconecta todo mundo.

4. Deixe o resto comentado, até o endereço mudar

Seção intitulada “4. Deixe o resto comentado, até o endereço mudar”

O COFRE_SECRET é a única linha que precisa ser preenchida para o container. Nas palavras do .env.example, “everything left commented falls through to a default that already suits it”, ou seja, tudo o que fica comentado cai num padrão que já serve. Uma linha comentada continua importando, porque o que o .env define vence o compose.yaml, então não mexa nestas a menos que seja de propósito:

  1. # COFRE_DATABASE= fica comentada. Aí o Compose usa o padrão do compose.yaml, /data/cofre.db, na pasta em que o volume é montado, e o banco sobrevive às atualizações. Um caminho escrito ali que não fique dentro de /data coloca o banco dentro do container, e a próxima atualização apaga. Preencha só para PostgreSQL.
  2. # COFRE_WEB_ORIGIN= e # COFRE_PUBLIC_URL= ficam comentadas enquanto o Cofre Ink for usado só na máquina que roda o Docker. Os dois ficam então em http://localhost:4321, porque o container serve a própria interface e os dois são o mesmo endereço. O COFRE_WEB_ORIGIN é onde a interface é aberta, e todo link de convite é montado com ele. O COFRE_PUBLIC_URL é onde o servidor responde, visto de fora.

No momento em que o servidor for alcançado por algo que não seja localhost (de outro aparelho, por um domínio, em https://), tire o # das duas linhas de endereço e coloque o endereço real nas duas:

.env
COFRE_WEB_ORIGIN=https://cofre.suacasa.com
COFRE_PUBLIC_URL=https://cofre.suacasa.com

Os dois endereços são o que as pessoas digitam no navegador para abrir o Cofre Ink, com http:// ou https:// no começo e sem barra no fim. http://localhost:4321 só funciona na máquina que roda o Docker. Se outros aparelhos vão usar o servidor, um celular na sua casa por exemplo, coloque nas duas linhas o endereço que esses aparelhos usam, e abra o Cofre Ink por esse mesmo endereço em todos eles, inclusive nesta máquina: o servidor só aceita entrar a partir de uma página aberta num desses dois endereços. Para um endereço na internet, leia antes HTTPS e proxy reverso.

Janela do terminal
docker compose up -d

Na primeira vez, o Compose constrói a imagem antes de subir. Isso precisa de internet e leva um tempo: cerca de um minuto na máquina usada neste guia, que já tinha a imagem base do Node. Das próximas vezes, sobe em segundos.

Janela do terminal
docker compose ps

O estado aparece como (health: starting) por uns 30 segundos, depois como (healthy).

Janela do terminal
docker compose logs --tail 50

No meio das linhas, procure estas duas:

Cofre Ink is listening on http://localhost:4321
storing data in /data/cofre.db

A primeira diz sempre localhost, seja qual for o endereço que você definiu. A segunda precisa apontar para um arquivo dentro de /data. Se ela disser storing data in ./data/cofre.db, o .env ainda tem a linha do banco de uma cópia antiga, como descreve o aviso do passo 4: coloque um # na frente dela, rode docker compose up -d de novo e confira outra vez antes que alguém crie uma conta.

Abra http://localhost:4321 num navegador da mesma máquina, ou o endereço que você definiu no passo 4.

A interface abre em português num aparelho com o relógio num fuso horário do Brasil, e em inglês em qualquer outro lugar. O botão PT EN no alto, chamado Idioma, troca o idioma, e aquele navegador guarda a escolha. Os nomes abaixo são os da interface em português.

  1. A primeira tela pergunta Como você quer usar o Cofre Ink?. O container serve a mesma interface de app.cofre.ink, e ela não sabe sozinha que veio do seu servidor, então você diz.
  2. Em Sincronizar entre os meus aparelhos, aperte Ver as duas formas.
  3. Um servidor meu já vem escolhido, e o Endereço do servidor vem preenchido com http://localhost:4321. Na máquina que roda o Docker, deixe assim. Em qualquer outro lugar, digite o endereço do passo 4 com http:// no começo: um endereço digitado sem http:// nem https:// é lido como https://, e este servidor não responde assim.
  4. Aperte Conectar.
  5. A tela diz Crie o seu acesso, com um quadro que avisa Este servidor ainda não tem ninguém. Preencha Como você se chama, Email e Senha, que pede Pelo menos dez caracteres.
  6. Aperte Criar conta e entrar. Leva alguns segundos, porque o navegador primeiro resolve um cálculo que deixa lento quem tenta adivinhar senhas em massa.

Abre o Painel do seu espaço pessoal, Pessoal, vazio. Se Categorias, em Ajustes, estiver sem nenhuma, aperte Usar o conjunto inicial ali. Primeiros passos segue daqui.

O que saber sobre as contas:

  1. Não existe senha padrão, nem senha escrita em lugar nenhum. A que você escolheu é a única.
  2. Não existe recuperação de senha, nem um jeito de trocar a senha pela interface, e o servidor não manda email. Guarde a senha num lugar seguro.
  3. O cadastro fica aberto para qualquer pessoa que chegue ao endereço. A conta nova começa vazia e não vê nada do que é seu. A primeira conta não tem nenhum poder especial sobre o servidor: os papéis existem dentro de cada espaço.
  4. Daqui em diante a tela de entrar deste servidor abre em Entrar. Quem é novo aperta Ainda não tenho conta.
  5. A escolha do servidor fica guardada em cada navegador. Cada um dos outros aparelhos passa pelos passos 1 a 4 acima, com o mesmo endereço.

Convites precisam de um espaço compartilhado, porque o espaço pessoal não aceita membros.

  1. Abra o menu de espaços (o botão com o nome do espaço, no alto), escolha Gerenciar espaços e depois Novo espaço. Dê um nome e aperte Salvar.
  2. Com esse espaço aberto, escolha Membros no mesmo menu e aperte Convidar.
  3. Escolha um Papel, aperte Gerar link e depois Copiar link.

O link começa com o endereço de COFRE_WEB_ORIGIN e Vale por sete dias e serve para uma pessoa só. A outra pessoa abre o link, conecta ao mesmo servidor como em O primeiro acesso, cria uma conta e entra. Membros e convites explica os papéis e o resto.

A janela Convidar sobre a tela Membros do espaço compartilhado Casa num servidor, com o link gerado, o botão Copiar link e o aviso Vale por sete dias e serve para uma pessoa só.(abre a imagem em tamanho real)

O servidor fala HTTP simples na porta 4321 e não tem certificado próprio. Numa máquina só, ou numa rede de casa em que você confia, isso basta. Para alcançar o servidor pela internet, você precisa de um proxy reverso na frente dele, com um certificado de verdade. O repositório não traz configuração de proxy, então use o que você conhece. Depois, no .env:

  1. Tire o # da frente de COFRE_PUBLIC_URL e de COFRE_WEB_ORIGIN e coloque nas duas o endereço público, começando com https://.
  2. Tire o # da frente de COFRE_CLIENT_IP_HEADER e coloque nela o cabeçalho em que o seu proxy escreve o endereço de quem chama, normalmente x-forwarded-for: é dele que o limite de tentativas de entrar lê quem está chamando. Deixe vazio quando nada estiver na frente.
  3. Rode docker compose up -d de novo, para o container subir com os valores novos.

Com https:// em COFRE_PUBLIC_URL, o navegador só guarda a sessão em https, então o proxy precisa responder com um certificado válido, senão ninguém continua conectado.

A interface de app.cofre.ink com o seu servidor. Também dá para conectar a interface de app.cofre.ink ao seu servidor, no lugar da que o próprio servidor serve. Nesse caso COFRE_WEB_ORIGIN precisa ser https://app.cofre.ink e COFRE_PUBLIC_URL o endereço do seu servidor, que é o único caso em que os dois são diferentes, e o seu servidor precisa responder em https com certificado de verdade, senão ninguém continua conectado: para o navegador, são dois sites diferentes. Os testes automáticos do projeto não cobrem essa combinação. Abrir o endereço do seu próprio servidor evita tudo isso.

Esta página monta o SQLite, um arquivo só dentro do volume, que é o padrão. Para PostgreSQL, o compose.yaml traz um serviço database sobre postgres:17-alpine, e quatro coisas são descomentadas juntas. Deixar uma de fora trava o arquivo inteiro, porque o Compose recusa um serviço que monta um volume, ou que depende de um serviço, que ninguém declarou.

  1. O serviço database, no compose.yaml, com o healthcheck dele.
  2. O depends_on do serviço cofre, mais acima no mesmo arquivo.
  3. O volume cofrePostgres, no fim do arquivo. Ele fica longe do serviço, então é o mais fácil de esquecer.
  4. POSTGRES_PASSWORD, no .env, a senha com que o banco é criado.

O segundo impede o servidor de procurar o banco cedo demais: o PostgreSQL reinicia a si mesmo uma vez enquanto sobe, então o Compose espera o healthcheck dele responder antes de subir o servidor.

Depois aponte o servidor para ele, no mesmo .env:

.env
POSTGRES_PASSWORD=alguma coisa longa
COFRE_DATABASE=postgres://cofre:${POSTGRES_PASSWORD}@database:5432/cofre

O Compose expande o ${POSTGRES_PASSWORD}, então a senha é escrita uma vez só. O host é database, o nome do serviço, e não localhost, que dentro do container é o próprio container. Rode docker compose up -d, e o log diz storing data in postgres://cofre:***@database:5432/cofre.

Este caminho foi rodado enquanto este guia era escrito: o docker compose up -d esperou o banco ficar saudável, depois subiu o servidor, que conectou de primeira.

Ele continua sendo o caminho menos provado: os testes automáticos do projeto só rodam o PostgreSQL no PGlite, dentro do processo de teste. A cópia do volume descrita abaixo copia o cofreData, que aqui fica vazio, então faça o backup do PostgreSQL com pg_dump, ou com a cópia pela interface, que funciona igual com qualquer um dos dois bancos.

  1. Faça um backup antes, como explicado abaixo. O repositório não descreve como voltar para uma versão anterior, então essa cópia é o seu caminho de volta.
  2. Leia o changelog: ele diz o que mudou em cada versão, e o que fazer a respeito se você roda um servidor.
  3. Na pasta do clone, rode:
Janela do terminal
git pull
docker compose up -d --build

O git pull traz o código novo e o --build reconstrói a imagem com ele. Quando a imagem mudou, o Compose troca o container. Quando o banco precisa mudar de formato, o servidor faz isso sozinho ao subir. Os seus lançamentos continuam no volume desde que o banco fique dentro de /data, o que acontece enquanto a linha COFRE_DATABASE estiver comentada: depois da atualização, docker compose logs --tail 50 deve dizer de novo storing data in /data/cofre.db. O git pull deixa o .env como estava, então, se o seu veio de uma cópia antiga do repositório, leia o aviso do passo 4 antes de atualizar.

São dois tipos de cópia, e cada um guarda uma coisa:

  1. Uma cópia do volume, feita pela linha de comando, guarda o servidor inteiro: todas as contas, espaços, membros e convites.
  2. Uma cópia pela interface guarda os espaços de quem está conectado, num arquivo que qualquer Cofre Ink traz de volta. Ela não leva contas, nem quem participa de cada espaço.

Rode estes comandos na pasta do clone. O servidor para por alguns segundos, e o arquivo cofre.tar.gz aparece nessa pasta.

Janela do terminal
docker compose stop
docker run --rm -v cofre_cofreData:/data -v ${PWD}:/out alpine tar czf /out/cofre.tar.gz /data
docker compose start

Na primeira vez, o Docker baixa a imagem alpine. A linha tar: removing leading '/' from member names é esperada. O arquivo guarda data/cofre.db, às vezes com cofre.db-wal e cofre.db-shm ao lado, o que não faz mal. Ele não tem senha e guarda todas as contas e lançamentos, então deixe num lugar que só você acessa.

Isto troca tudo o que está no volume pelo conteúdo do arquivo: o que foi escrito depois da cópia se perde. Coloque o cofre.tar.gz na pasta do clone e rode:

Janela do terminal
docker compose stop
docker run --rm -v cofre_cofreData:/data -v ${PWD}:/out alpine sh -c "find /data -mindepth 1 -delete && tar xzf /out/cofre.tar.gz -C /"
docker compose start

O segundo comando esvazia o volume antes de desempacotar, para nenhum arquivo do banco atual se misturar com o restaurado. Numa máquina nova, siga a instalação até o passo 6 primeiro, para o Compose criar o volume, e depois rode os três comandos.

Em Ajustes, Dados, Guardar uma cópia grava um arquivo com tudo do espaço aberto quando você aperta Guardar, e Trazer de volta, com Escolher arquivo, junta um arquivo desses com o que já existe. Com mais de um espaço, Backup de todos os espaços, dentro de Levar os dados para outro programa, guarda num arquivo só todos os espaços em que você é Dono ou Administrador. Essas cópias funcionam igual com SQLite e com PostgreSQL. Backup e restauração tem os detalhes.

O servidor lê estas e nenhuma outra. O Compose passa os valores do .env, e uma linha no .env substitui o valor mostrado depois de “Com o Compose”.

COFRE_SECRETobrigatóriaCom o Compose: nenhum, e sem ela o Compose não sobe

Assina os cookies de sessão e o cálculo que o navegador resolve antes de entrar. Pelo menos 32 caracteres. Trocar desconecta todo mundo.

COFRE_DATABASEopcionalCom o Compose: /data/cofre.db

Onde ficam os dados. Um caminho de arquivo é SQLite, e um valor que começa com postgres é PostgreSQL. O .env.example deixa essa linha comentada. Deixe o arquivo SQLite dentro de /data, para ele ficar no volume.

COFRE_WEB_ORIGINopcionalCom o Compose: http://localhost:4321

O endereço em que a interface é aberta. Os links de convite começam com ele, e o servidor aceita entrar a partir dele. O .env.example deixa essa linha comentada, como a próxima: defina as duas assim que o servidor for alcançado por algo que não seja localhost.

COFRE_PUBLIC_URLopcionalCom o Compose: http://localhost:4321

O endereço em que o servidor responde, visto de fora: atrás de um proxy, o público. O servidor também aceita entrar a partir dele. Com https://, a sessão só fica guardada em https.

COFRE_PORTopcionalCom o Compose: 4321

A porta na sua máquina. Dentro do container o servidor escuta sempre na 4321.

COFRE_CLIENT_IP_HEADERopcionalCom o Compose: vazio

O cabeçalho em que um proxy reverso escreve o endereço de quem chama, normalmente x-forwarded-for. Só com um proxy na frente.

COFRE_PROOF_BITSopcionalCom o Compose: 18

A dificuldade do cálculo antes de entrar, de 0 a 26. Cada ponto dobra o trabalho: 20 é quatro vezes 18, e 16 é um quarto. 0 desliga.

COFRE_TURNSTILE_SITE_KEYopcionalCom o Compose: vazio

A chave pública de um widget Cloudflare Turnstile na tela de entrar. Só junto com o segredo abaixo.

COFRE_TURNSTILE_SECRETopcionalCom o Compose: vazio

O segredo desse widget, que fica no servidor. Com as duas preenchidas, toda entrada e todo cadastro passam pela Cloudflare.

NODE_ENVfixaCom o Compose: production, escrito no compose.yaml

Nada a definir.

COFRE_STATIC_DIRfixaCom o Compose: /app/apps/server/public, definido pela imagem

Onde fica a interface construída, para o mesmo container servir.

Algumas se comportam diferente com o Compose:

  1. NODE_ENV e COFRE_STATIC_DIR não fazem nada quando escritas no .env. O compose.yaml fixa a primeira, e a segunda vem da imagem e não é repassada.
  2. COFRE_PORT só muda a porta na sua máquina. Se você trocar, coloque a porta nova nos dois endereços também.
  3. O Turnstile fica desligado a menos que as duas linhas estejam preenchidas, e o servidor não sobe com uma só. Ligado, ele conta à Cloudflare o endereço de todo mundo que abre a sua tela de entrar, e a entrada é recusada sempre que a Cloudflare não responde. O projeto só testou o Turnstile contra um substituto, nunca contra a própria Cloudflare.
  4. POSTGRES_PASSWORD é lida pelo serviço PostgreSQL e pela linha COFRE_DATABASE que a usa, não pelo servidor em si.

Para ver o que o servidor disse, rode docker compose logs --tail 50 na pasta do clone.

A linha COFRE_SECRET= do .env está vazia. Gere um segredo como no passo 3, cole ali e rode docker compose up -d de novo.

O container para assim que sobe, e o log diz isso, depois onde os valores vão (com Docker, no .env), depois qual configuração e por quê. O mais comum é um COFRE_SECRET com menos de 32 caracteres. Corrija a linha no .env e rode docker compose up -d.

COFRE_TURNSTILE_SECRET is set without COFRE_TURNSTILE_SITE_KEY

Seção intitulada “COFRE_TURNSTILE_SECRET is set without COFRE_TURNSTILE_SITE_KEY”

Ou o contrário. As duas linhas do Turnstile andam juntas: preencha as duas, ou esvazie as duas.

O build baixa o pnpm e os pacotes pela internet, e para, com mensagens como connect ETIMEDOUT, quando não consegue alcançar esses arquivos. Confira a conexão e rode docker compose up -d de novo.

O container sobe e morre porque a imagem está incompleta. Reconstrua do zero e suba de novo:

Janela do terminal
docker compose build --no-cache
docker compose up -d

Isto acontece com um .env feito a partir de uma cópia antiga do repositório. Se o log dizia storing data in ./data/cofre.db, o .env ainda tinha a linha COFRE_DATABASE=./data/cofre.db, e o banco ficava dentro do container que a atualização trocou. O que foi escrito assim não volta pelo servidor. Coloque um # na frente da linha, como diz o aviso do passo 4, e rode docker compose up -d. Daí em diante os dados ficam no volume. Se você guardou cópias pela interface, crie a sua conta de novo e traga as cópias com Trazer de volta.

Se você perceber a linha antes de qualquer atualização, guarde primeiro uma cópia de cada espaço pela interface, como explica Backup e restauração, e não rode nem docker compose down nem docker compose up -d --build antes disso: é recriar o container que apaga o arquivo. Depois comente a linha, rode docker compose up -d, crie a conta de novo e traga as cópias de volta.

O .env veio de uma cópia antiga do repositório e ainda tem COFRE_WEB_ORIGIN=http://localhost:5174. Coloque um # na frente da linha numa máquina só, ou defina os dois endereços com o real como no passo 4, depois rode docker compose up -d e gere um link novo.

Não consegui falar com um endereço que começa com https://

Seção intitulada “Não consegui falar com um endereço que começa com https://”

A linha embaixo do título da tela de entrar, No servidor, mostra o endereço que este navegador está usando. Um endereço digitado sem http:// virou https://, e este servidor não responde assim, então enviar o formulário diz Não consegui falar com esse endereço. A mesma mensagem aparece quando o servidor está desligado, então confira também o docker compose ps.

Este navegador guarda o endereço que recebeu. Para ser perguntado de novo, apague os dados que o navegador guarda para a página, nas configurações do site, abra a página outra vez e digite o endereço com http://. No endereço do seu servidor esses dados guardam essa escolha e preferências como o idioma e o tema, a não ser que você também tenha usado Só neste navegador ali, e nesse caso o banco dele vai junto.

A tela de entrar mostra isso para uma senha errada e para toda outra recusa: tentativas demais, uma página aberta num endereço em que o servidor não confia, ou o Turnstile. Ao criar uma conta, vale o mesmo para Não consegui criar a conta. Talvez esse email já esteja em uso.

  1. Espere um minuto e tente de novo. O servidor aceita cinco tentativas de entrar por minuto e cinco contas novas por hora. Sem nada na frente e sem COFRE_CLIENT_IP_HEADER, ele não consegue separar quem chama e conta todo mundo junto, e é por isso também que o log mostra um aviso que começa com Rate limiting could not determine a client IP, uma vez a cada vez que o servidor sobe.
  2. Confira se o endereço no navegador é exatamente o de COFRE_WEB_ORIGIN ou o de COFRE_PUBLIC_URL.

Entrar funciona, e a tela seguinte pede para entrar de novo.

  1. A interface e o servidor estão em sites diferentes, como app.cofre.ink e um servidor seu. Confira se COFRE_WEB_ORIGIN é o endereço de onde a interface realmente vem, se COFRE_PUBLIC_URL começa com https:// e se o certificado é de verdade, não autoassinado. Servir a interface pelo seu próprio container evita isso.
  2. O COFRE_SECRET mudou, o que desconecta todo mundo. Entre de novo.

O guia de deploy e o guia de solução de problemas do próprio repositório, escritos junto com o código, cobrem mais casos do que esta página. Seja quem for que você procurar para ajudar, nunca mande o seu .env: ele guarda o segredo.

Páginas relacionadas: Onde os dados ficam, Membros e convites, Mudar onde os dados ficam, Backup e restauração.