Servidor próprio
O servidor do Miblo Remote, para subir no seu próprio host. Com ele, o celular e o computador conversam só pelo seu servidor, nunca pelo miblo.ai. É opcional e de graça, para quem sabe hospedar.
Baixar
Versão 1.3.0
- Código-fonte (.tar.gz)https://miblo.ai/dl/relay/miblo-relay-1.3.0.tar.gz
- Assinatura (.sig)https://miblo.ai/dl/relay/miblo-relay-1.3.0.tar.gz.sig
- SHA256SUMS de todas as versõeshttps://miblo.ai/dl/relay/SHA256SUMS
- Assinatura do SHA256SUMShttps://miblo.ai/dl/relay/SHA256SUMS.sig
Distribuído só pelo miblo.ai e assinado com a mesma chave das atualizações do Miblo (Ed25519). Confira a assinatura antes de usar: o comando está logo abaixo, em Baixar e conferir.
Licença AGPL-3.0, no pacote.
Prefere o Git? O código-fonte também está no GitHub: github.com/marcus-campos/miblo-relay
Guia do servidor
O README do pacote desta versão.
O servidor do celular do Miblo, para você subir no seu próprio host: o relay das sessões, a conta em que os seus celulares entram, o registro de celulares e o app do celular (PWA). É o mesmo protocolo que o plugin do Miblo e o miblo.ai usam, então tudo do Miblo+ que passa pelo celular (histórico, respostas, aprovações, tarefas remotas) funciona aqui, de graça e sem licença, para quem subir o próprio servidor.
Privacidade
O Miblo já é cifrado de ponta a ponta: as chaves nascem no seu computador, chegam a cada celular seladas para a chave daquele celular, só depois que você digita no computador o código de 6 dígitos que o celular mostra, e o servidor só repassa dados cifrados. Um servidor malicioso (o miblo.ai ou este) não lê nada, não coloca um celular dele no lugar do seu e não age no seu computador.
O que sobra é o código do app do celular: ele é uma página web, e quem serve a página roda código com as chaves do celular. No miblo.ai, você confia no que o miblo.ai serve. No seu servidor, o app é o que você compilou deste código (ou uma versão cujos hashes você conferiu), servido por você. Isso tira a confiança no JavaScript servido pelo miblo.ai. Detalhes no modelo de ameaças (docs/threat-model.md).
Enquanto o seu servidor estiver configurado, o plugin não manda nada do celular nem da conta para o miblo.ai (ele só continua lendo do miblo.ai o manifesto assinado de atualizações).
Baixar e conferir
O download é pelo miblo.ai, em https://miblo.ai/dl/relay/, ao lado do firmware e dos instaladores (quem prefere o Git encontra o código em https://github.com/marcus-campos/miblo-relay), e vem dos instaladores, e assinado com a mesma chave das releases do Miblo (Ed25519). A versão mais nova está em https://miblo.ai/dl/extras/latest.json; a página miblo.ai/docs/servidor-proprio mostra este guia e o link dela.
V=1.0.0 # a versão mais nova: https://miblo.ai/dl/extras/latest.json
curl -fLO https://miblo.ai/dl/relay/miblo-relay-$V.tar.gz
curl -fLO https://miblo.ai/dl/relay/miblo-relay-$V.tar.gz.sig
node -e 'const c=require("crypto"),fs=require("fs"),f=process.argv[1],k=c.createPublicKey({key:{kty:"OKP",crv:"Ed25519",x:Buffer.from("LGtuUvDA506N8iD1tolbQzWAJBb9hUerW0OH4C2pBek=","base64").toString("base64url")},format:"jwk"});const ok=c.verify(null,fs.readFileSync(f),k,Buffer.from(fs.readFileSync(f+".sig","utf8").trim(),"base64"));console.log(ok?"assinatura OK":"ASSINATURA INVÁLIDA: não use este arquivo");process.exit(ok?0:1)' miblo-relay-$V.tar.gz
tar -xzf miblo-relay-$V.tar.gz && cd miblo-relay-$VA chave pública (LGtuUvDA506N8iD1tolbQzWAJBb9hUerW0OH4C2pBek=) é a mesma que o plugin do Miblo usa para conferir as atualizações. https://miblo.ai/dl/relay/SHA256SUMS (assinado em SHA256SUMS.sig) traz o SHA-256 de cada versão publicada.
Subir em 3 passos (Docker)
Você precisa de uma máquina com Docker, um nome DNS apontando para ela e as portas 80 e 443 abertas (o Caddy pega o certificado TLS sozinho).
1. Configurar, dentro da pasta baixada e conferida acima:
cd deploy/docker
cp .env.example .env # coloque o seu domínio em RELAY_DOMAIN2. Subir
docker compose up -d --build
docker compose logs relay # mostra o código de configuração e a impressão digital do servidor3. Criar a sua conta: abra https://seu-dominio/conta, use o código de configuração, crie a senha e adicione um segundo fator (passkey recomendada, ou app autenticador). Gere os códigos de recuperação.
Depois, no computador: apontar o plugin para o seu servidor. Sem Docker: npm ci && npm run build && PUBLIC_ORIGIN=https://seu-dominio node dist/server.mjs (Node 22.13+ ou 23.4+, que têm node:sqlite) atrás de qualquer proxy com TLS.
Na sua própria conta Cloudflare
Roda como um Worker na sua conta Cloudflare (o plano gratuito basta para uma pessoa), com D1 e Durable Objects:
npm ci
cp deploy/cloudflare/wrangler.jsonc.example deploy/cloudflare/wrangler.jsonc
cd deploy/cloudflare
npx wrangler d1 create miblo-relay # coloque o database_id no wrangler.jsonc
npx wrangler d1 migrations apply miblo-relay --remote
cd ../.. && npm run build:app && npm run cf:secrets # mostra o código de configuração e a impressão digital
cd deploy/cloudflare && npx wrangler deployDepois, o passo 3 acima (https://seu-endereço/conta).
Apontar o seu computador para ele
No seu terminal (nunca por um agente de IA), com o plugin do Miblo na versão que tem miblo server:
miblo server set https://seu-dominioO Miblo lê a chave de identidade do servidor, mostra a impressão digital (compare com a que o seu servidor mostrou no log: docker compose logs relay ou node dist/server.mjs fingerprint) e pede o código que aparece na tela do seu Miblo. No app Miblo do computador: Ajustes › Servidor do celular. Trocar de servidor desvincula este computador e desliga o celular no servidor antigo; depois:
miblo account link # confirme o código em https://seu-dominio/plus/link
miblo phone onNo celular, abra https://seu-dominio/app, entre na sua conta e permita o celular no computador com o código que ele mostra. miblo server mostra para onde aponta; miblo server reset volta para o miblo.ai (também com o código do Miblo).
Configuração
| Variável | Obrigatória | O que é |
|---|---|---|
PUBLIC_ORIGIN | sim | O endereço https do servidor, só a origem (https://relay.exemplo.com). É a origem do app, o relying party das passkeys e o endereço do link de vinculação. Nunca vem da requisição. |
TRUSTED_PROXY | atrás de proxy | Os endereços ou faixas (CIDR) do seu proxy, separados por vírgula (172.30.247.0/24). Só de uma conexão vinda deles o endereço do cliente é a última entrada do X-Forwarded-For (a que o proxy colocou). Só usado como chave de limite de taxa. Não defina sem um proxy na frente. |
RELAY_VAPID_SUBJECT | não | Contato enviado aos serviços de push (mailto:voce@exemplo.com); sem ele, o endereço do servidor. |
SESSION_SECRET, MFA_KEY, SERVER_IDENTITY_KEY, RELAY_VAPID_PUBLIC_KEY, RELAY_VAPID_PRIVATE_KEY, SETUP_TOKEN | não (Node) / sim (Cloudflare) | No Node, os que você não definir são criados uma vez e guardados em secrets.json (0600), na pasta $MIBLO_RELAY_SECRETS_DIR. Na Cloudflare, npm run cf:secrets cria e guarda todos. |
MIBLO_RELAY_DATA | não | Pasta do banco (Docker: /data). |
MIBLO_RELAY_SECRETS_DIR | não | Pasta do secrets.json (padrão: MIBLO_RELAY_DATA; Docker: /secrets, um volume à parte, fora dos backups do banco). |
PORT, HOST | não | Onde o Node escuta (padrão 0.0.0.0:8787). |
Comandos do Node: node dist/server.mjs check (confere a configuração), fingerprint, setup-token (o código de configuração vale para uma configuração só; depois de usado, este comando gera outro, para refazer uma configuração abandonada), reset-account (perdeu todos os fatores: apaga fatores e sessões e gera um novo código de configuração; computadores e celulares continuam). Na Cloudflare, para o mesmo efeito, apague as linhas de mfa_* e sessions com wrangler d1 execute e defina um novo código com npx wrangler secret put SETUP_TOKEN (um valor aleatório longo, como openssl rand -base64 24).
Atualizar
Baixe e confira a versão nova como em Baixar e conferir, copie para ela o seu deploy/docker/.env (na Cloudflare, o seu deploy/cloudflare/wrangler.jsonc) e, na pasta nova:
cd deploy/docker && docker compose up -d --buildOs volumes do Docker (banco e segredos) continuam os mesmos: o projeto do Compose leva o nome da pasta (docker), igual nas duas versões. As migrações do banco rodam sozinhas ao subir (Node). Na Cloudflare: npm ci && npx wrangler d1 migrations apply miblo-relay --remote && npm run build:app && npx wrangler deploy. Acompanhe as versões em https://miblo.ai/dl/extras/latest.json: correções de segurança são avisadas na página miblo.ai/docs/servidor-proprio. Faça backup do volume relay-data (Docker) antes de atualizar.
Segurança
Leia o modelo de ameaças (
docs/threat-model.md): um operador malicioso tem o mesmo poder que um miblo.ai malicioso, que o protocolo já tolera.Uma conta só, segundo fator obrigatório; a senha sozinha nunca entra. Senha com PBKDF2-SHA-256 (600.000 iterações no Node; 100.000 na Cloudflare, o máximo que um Worker permite). Senhas erradas bloqueiam só a rede de onde vieram, por 15 minutos, com a mesma resposta de um nome errado.
O plugin fixa a chave de identidade do servidor na primeira vez (TOFU) e exige uma assinatura nova dela antes de usar o servidor; se a chave mudar, nada é enviado até você aceitar a nova com
miblo server set(e o código do Miblo).Guarde
secrets.json(ou os segredos do Worker) longe de backups que outros leiam.Encontrou uma falha? Escreva para contato@miblo.ai (assunto "Security"), em particular. Não a publique antes da correção.
Builds reproduzíveis
O build é determinístico (imagem base fixada por digest, dependências do package-lock.json). O Docker grava dist/HASHES.txt: o SHA-256 de cada arquivo servido e do servidor, e um hash do conjunto (build …). Para conferir o que roda:
docker compose exec relay tail -1 dist/HASHES.txt # o que está rodando
npm ci && npm run build && npm run hashes | tail -1 # o que este código geraOs dois precisam ser iguais: o que roda é o que este código, conferido pela assinatura, gera.
Licença
AGPL-3.0 (LICENSE): quem oferecer este servidor modificado como serviço precisa publicar o código das modificações. O dono do projeto pode trocar a licença enquanto for o único autor.