Skip to content

nextcoreti/nchub

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

58 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

nchub

Versão: v2.0.0 · 2026-07-03 Status: Backup (full+incremental+individual+S3 off-site) + Delegated + Sharing + Monitor funcionais.

Painel admin leve (Go binary, ~30MB) pra Carbonio CE — escrito pra rodar junto com o Carbonio no mesmo host (precisa chamar zmmailbox/zmprov que vivem em /opt/zextras/bin/).

Módulos

Módulo URL Status
Dashboard /dashboard.html ✅ funcional
Monitor /monitor.html ✅ funcional (Prometheus + JSON)
Sharing /sharing.html ✅ funcional
Delegated /delegated.html ✅ funcional (full-setup one-shot)
Backup /backup.html ✅ funcional — 5 abas: Executar / Individual / Sessões / Restaurar / Logs

Modelo de execução — por que precisa rodar como zextras

O nchub chama binários do Carbonio (zmmailbox, zmprov, ldapsearch) que vivem em /opt/zextras/bin/. Esses binários precisam rodar como o user zextras (uid 996) porque:

  • Os mailbox stores ficam em /opt/zextras/store/0/<user>/ com ownership zextras:zextras
  • O zmmailbox precisa abrir esses arquivos com permissão de escrita
  • O zmprov precisa de permissão pra escrever no LDAP

3 modos de rodar

Modo Como o daemon roda Como chama zmmailbox Quando usar
Bare-metal (recomendado) root no host su - zextras -c "..." interno Servidor dedicado Carbonio
Docker (alternativo) uid 996 (zextras) no container direto (já é zextras) Ambiente isolado / reproduzível
Bare-metal setuid zextras direto direto Mais raro, evita o su

O nchub usa o modo bare-metal com su - zextras -c "..." — mesmo padrão de qualquer software Carbonio nativo (Zextras Suite, etc).


Install — Bare-metal (recomendado)

1 comando (mais simples, pro leigo)

curl -L https://raw.githubusercontent.com/nextcoreti/nchub/main/scripts/install.sh | sudo bash

O script:

  1. Detecta o Carbonio automaticamente
  2. Detecta o admin (zextras@<hostname> por padrão)
  3. Pede a senha do admin (input oculto)
  4. Baixa o binary (da release do GitHub, ou compila do source se não tiver release)
  5. Instala em /opt/nchub/
  6. Sobe o daemon
  7. Valida que tá respondendo
  8. Oferece instalar systemd unit pra boot automático

Pré-requisitos no servidor Carbonio:

  • Carbonio CE já instalado e funcional
  • Go instalado (só se não tiver release no GitHub) — apt install golang ou yum install golang
  • Conexão com a internet (pra baixar do GitHub)

Install manual (controle total)

Pra rodar diretamente no servidor Carbonio, sem Docker:

# Pré-requisito: Carbonio CE já instalado e funcional
# (zmmailbox, zmprov, LDAP em :389, admin user criado)

# 1. Build (no seu Mac ou CI)
cd nchub
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build \
    -ldflags="-s -w" -o dist/nchubd-v2.0.0 ./cmd/nchubd/

# 2. Copia pro servidor
scp dist/nchubd-v2.0.0 root@CARBONIO:/tmp/

# 3. No servidor, instala
ssh root@CARBONIO
VERSION=v2.0.0
mkdir -p /opt/nchub/versions/$VERSION
mv /tmp/nchubd-v2.0.0 /opt/nchub/versions/$VERSION/nchubd
chmod 755 /opt/nchub/versions/$VERSION/nchubd
ln -sf /opt/nchub/versions/$VERSION/nchubd /opt/nchubd
mkdir -p /opt/nchub/backup

# 4. Detecta o admin Carbonio (ajusta pro SEU servidor)
#    Tipicamente: zextras@<hostname> com a senha que você definiu no install
HOSTNAME=$(hostname -f)
ADMIN_USER="zextras@${HOSTNAME%%.*}.com"  # ajuste aqui

# 5. Sobe o daemon
nohup /opt/nchubd \
    -addr=:1955 \
    -interval=120s \
    -db=/var/lib/nchub/history.db \
    -carbonio-url=https://127.0.0.1:7071 \
    -carbonio-mailbox-url=https://127.0.0.1:8443 \
    -carbonio-user="$ADMIN_USER" \
    -carbonio-pass='SENHA_ADMIN_CARBONIO' \
    </dev/null >/var/log/nchubd.log 2>&1 &

# 6. Valida
sleep 3
curl -s http://localhost:1955/healthz
# Saída esperada: ok
tail /var/log/nchubd.log

NÃO commita a senha no git nem em dotfiles! Use:

  • Variável de ambiente NCHUB_CARBONIO_PASS=...
  • Ou arquivo ~/.config/nchub/passwd com perm 600
  • Ou Vault / 1Password CLI

Update de versão

Pro usuário final (no servidor Carbonio):

sudo nchubd-update            # atualiza pra última versão do GitHub
sudo nchubd-update v2.3.0    # atualiza pra uma versão específica
sudo nchubd-update --rollback # volta pra versão anterior se der ruim

O comando nchubd-update é instalado em /usr/local/bin/ durante o install.sh. Ele:

  1. Detecta versão atual e versão alvo
  2. Baixa o binary (da release do GitHub, ou compila do source se não tiver release)
  3. Para o daemon, swap do symlink, restart
  4. Valida /healthz — se não responder, faz rollback automático
  5. Mantém a versão anterior em versions/<v>/nchubd (pra rollback manual)

Pro dev (no seu Mac/CI):

cd nchub
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build \
  -ldflags="-s -w" -o dist/nchubd-v2.3.0 ./cmd/nchubd/

sshpass -p 'SENHA' scp dist/nchubd-v2.3.0 root@CARBONIO:/opt/nchub/versions/v2.3.0/nchubd
ssh root@CARBONIO "
  pkill -9 nchubd; sleep 1
  ln -sf /opt/nchub/versions/v2.3.0/nchubd /opt/nchubd
  systemctl restart nchubd || nohup /opt/nchubd [flags] &
"

Crie uma release no GitHub (gh release create v2.3.0 dist/nchubd-v2.3.0) pra que o nchubd-update consiga baixar o binary direto (sem precisar compilar).


Install — Docker (alternativo, só pra casos especiais)

Não use Docker se você tem um servidor Carbonio dedicado. O modo bare-metal é mais simples e mais debugável. Docker só vale a pena em cenários específicos listados abaixo.

Quando considerar Docker:

  • Você roda múltiplas instâncias do nchub num mesmo host (multi-tenant SaaS)
  • Você quer CI/CD reproduzível com imagem versionada no registry
  • O host NÃO é o servidor Carbonio (cenário raro, exige NFS/SMB pros mailbox stores)

Pré-requisito: o container precisa do bind mount do Carbonio porque chama zmmailbox/zmprov do host. Não é Docker "puro" — é container com acesso controlado ao host.

# 1. Clone o repo
git clone git@github.com:nextcoreti/nchub.git
cd nchub

# 2. Descobre o uid do zextras no host (default 996, mas confirme)
id -u zextras
# Saída: 996 (ou outro — use esse número)

# 3. Cria o diretório de backup persistente
sudo mkdir -p /opt/nchub/backup
sudo chown 996:996 /opt/nchub/backup

# 4. Edita docker-compose.yml e ajusta:
#    - user: "996:996"  (se uid do zextras for diferente)
#    - NCHUB_CARBONIO_USER=seu_admin@seudominio.com
#    - NCHUB_CARBONIO_PASS='sua_senha'
#    - ports: 1955:1955 (ou outra se 1955 já tá em uso)

# 5. Sobe
docker compose up -d

# 6. Valida
docker compose ps
curl -s http://localhost:1955/healthz
docker compose logs nchubd | tail -20

O que o docker-compose.yml faz

services:
  nchubd:
    user: "996:996"           # roda como zextras (dono dos mailbox stores)
    read_only: true           # filesystem read-only
    cap_drop: [ALL]           # sem capabilities desnecessárias
    cap_add: [NET_BIND_SERVICE]  # só bind de porta
    volumes:
      - /opt/zextras:/opt/zextras:ro   # binários Carbonio (read-only)
      - /opt/nchub/backup:/opt/nchub/backup  # backup persistente
      - /etc/passwd:/etc/passwd:ro     # user zextras precisa existir
      - /etc/group:/etc/group:ro
      - /proc:/proc:ro                 # métricas CPU/mem do host

Por que user: "996:996"? Pra o processo dentro do container ser o mesmo uid do zextras no host. Como o /opt/zextras é bind mount (mesmo filesystem), os arquivos aparecem com o uid 996 → o zmmailbox consegue abrir.

Segurança do container:

  • ✅ Read-only filesystem (impossível escrever fora dos volumes)
  • ✅ Sem capabilities extras (não pode mount/iptables/etc)
  • no-new-privileges (não pode escalar privilégio)
  • apparmor=nchubd (perfil AppArmor restritivo)

Diferença entre Bare-metal e Docker

Aspecto Bare-metal Docker
Onde roda o daemon /opt/nchubd (symlink) container nchubd
Como chama zmmailbox su - zextras -c "..." (root → zextras) direto (já é zextras)
Permissões root no host zextras (uid 996) no container
Bind mount necessário não sim (/opt/zextras ro)
Backup persistente /opt/nchub/backup no host /opt/nchub/backup (volume)
Rollback troca symlink + restart docker compose down && up com tag anterior
Mais seguro não (root total no host) sim (read-only, no caps)

Endpoints principais

Endpoint Descrição
GET /healthz Health check
GET /metrics Prometheus metrics
GET /dashboard.html Dashboard
GET /backup.html Painel backup (5 abas)
GET /api/v1/backup/sessions Lista sessões (full+incremental+individual)
POST /api/v1/backup/start Inicia backup full/incremental {type, domain?}
POST /api/v1/backup/single Backup individual {email}
GET /api/v1/backup/single/list Lista backups individuais
GET /api/v1/backup/single/download?id=X Baixa TGZ de 1 backup individual
GET /api/v1/backup/single/zip?id=X Baixa TGZ+LDIF juntos (ZIP)
POST /api/v1/backup/single/restore Restaura 1 backup pra conta destino {sessionID, sourceEmail, targetEmail, type}
GET /api/v1/backup/session?id=X Detalhes de uma sessão
POST /api/v1/backup/restore Restaura sessão (separate/over)
GET/PUT /api/v1/backup/config Config agendamento (cron + keep_days)
GET /api/v1/logs?n=50 Tail do log
GET /api/v1/delegated/full-setup Aplica grants + cartBlanche

Arquitetura

nchubd (Go binary, ~30MB)
├── cmd/nchubd/
│   ├── main.go               # daemon + HTTP + embed.FS
│   ├── backup.html           # 5 abas: Executar / Individual / Sessões / Restaurar / Logs
│   ├── delegated.html        # painel delegated
│   ├── sharing.html
│   ├── dashboard.html / monitor.html
│   ├── sidebar.html
│   └── nchub.css
├── internal/
│   ├── carbonio/             # SOAP + zmprov fallback
│   ├── delegated/            # SetDelegated, GetRights, cartBlanche
│   ├── sharing/              # COS / grants de domínios
│   ├── monitor/              # collector Prometheus
│   ├── backup/               # full+incremental+individual, scheduler, rotation, restore
│   ├── s3storage/            # aws-sdk-go-v2 (S3 / iDrive E2 / Backblaze / R2 / Wasabi)
│   └── storage/              # SQLite (history.db + sessions.sqlite3)
├── Dockerfile                # multi-stage Go → Alpine
├── docker-compose.yml        # bind mount Carbonio + volume backup
└── docs/                     # 2FA-IMPLEMENTATION-PLAN.md, etc

Backup — features

  • Full: mailbox TGZ (zmmailbox getRestURL) + LDAP LDIF por conta
  • Incremental: query=after:"YYYY-MM-DD HH:MM:SS" no mesmo getRestURL
  • Scheduler: roda 1x/min, decide full/incremental via cron parser (crones separados: full + incremental)
  • Individual (sob demanda): aba "👤 Individual" — escolhe 1 conta, faz backup full, lista de backups anteriores com download TGZ/ZIP
  • Restore: 2 modos — over (sobrescreve conta destino) e separate (cria conta nova no LDAP se não existir)
  • Rotação: deleta fulls > full_keep_days (mantém 1) + incrementais > incremental_keep_days
  • Cleanup: ao subir, marca FAILED sessões IN PROGRESS órfãs
  • Config: cron + keep_days + ativo/pausado via PUT /api/v1/backup/config

Backup — S3 (off-site)

Storage remoto S3-compatible pra disaster recovery (servidor queimou, ransomware, etc). Não use storage local (mesmo HD) — é o mesmo que fazer backup na própria pasta. S3 é pra OFF-SITE.

Providers suportados (via aws-sdk-go-v2):

  • AWS S3
  • Backblaze B2 (S3-compatible API, ~$0.006/GB/mês — 4x mais barato que AWS)
  • Cloudflare R2 (egress grátis)
  • Wasabi (sem cobrança de egress)
  • DigitalOcean Spaces
  • iDrive E2 (validado em produção — endpoint s3j2.da.idrivee2-20.com)
  • Qualquer S3-compatible (MinIO, etc)

Endpoints (7):

  • GET/PUT /api/v1/backup/s3/config
  • POST /api/v1/backup/s3/test — testa credenciais, lista buckets
  • POST /api/v1/backup/s3/sync?session=X — upload de 1 sessão
  • GET /api/v1/backup/s3/list — lista objetos no bucket
  • POST /api/v1/backup/s3/restore?session=X — download pro local
  • POST /api/v1/backup/s3/delete?session=X — apaga sessão

Hook auto-sync: se auto_sync=true na config, todo backup que termina com sucesso sobe pro S3 em background (goroutine separada, não bloqueia).

Configuração típica (Backblaze B2 — mais barato):

  • Endpoint: https://s3.us-west-001.backblazeb2.com
  • Region: us-west-001
  • Bucket: nchub-acme-backups
  • Access Key: Application Key (criar no painel B2 com scope restrito)
  • Storage Class: STANDARD (hot) ou Standard-IA (após 30+ dias)
  • Auto-sync: ON

Storage classes AWS S3 (tier automático):

  • STANDARD — $0.023/GB/mês, acesso imediato
  • STANDARD_IA — $0.0125/GB/mês, mínimo 30 dias
  • GLACIER — $0.004/GB/mês, restore em minutos
  • DEEP_ARCHIVE — $0.00099/GB/mês, restore 12h

Métricas Prometheus

Nome Tipo Descrição
nchub_up gauge Collector respondendo
nchub_cpu_percent gauge CPU% atual
nchub_memory_bytes{type="used|total"} gauge Memória
nchub_disk_bytes{type="used|total",mount="/"} gauge Disco
nchub_load_avg gauge Load 1min
nchub_mail_queue gauge Mensagens na fila
nchub_services_total{status="running|down"} gauge Serviços Carbonio
nchub_accounts_total gauge Contas detectadas
nchub_mail_sent_24h gauge Emails enviados 24h
nchub_mail_received_24h gauge Emails recebidos 24h
nchub_mail_rejected_24h gauge Emails rejeitados 24h
nchub_last_collect_timestamp gauge Última coleta

Hardening aplicado

  • ✅ Container read-only (read_only: true)
  • cap_drop: [ALL] + cap_add: [NET_BIND_SERVICE]
  • no-new-privileges
  • ✅ Binário com chattr +i (imutável, bare-metal)
  • ✅ Build com -ldflags="-s -w" (strip symbols)
  • -trimpath (path limpo)
  • ✅ CGO_ENABLED=0 (static binary)
  • ✅ Bind mount /opt/zextras read-only (Docker)
  • ✅ Roda como zextras (uid 996) no Docker (sem root)

Próximos passos

  • Módulo Backup (full + incremental + individual)
  • Scheduler + rotation
  • Restore Separate/Over
  • Restore individual com escolha de destino
  • Storage S3 / Backblaze / R2 / Wasabi / iDrive E2
  • Módulo Fail2ban policies
  • WebAuthn / 2FA no login
  • API REST autenticada
  • License server + HW fingerprint

About

nchub — admin panel for Carbonio CE (backup, S3 off-site, sharing, monitoring, delegated)

Resources

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors