Skip to content

Deploy isolado on-prem (Tier Carrier)

Esta página descreve o procedimento de implantação do TELECOM TOWER POWER em ambiente isolado (on-premises ou VPC dedicada do cliente). É o caminho oficial para clientes do Tier Carrier (Tier-1) ou para qualquer cenário onde dados de planejamento não podem trafegar pela SaaS multi-tenant em sa-east-1.

Quando usar este modo

  • Operadora Tier-1 que exige residência de dados em VPC própria ou data center on-prem.
  • Cliente sob mandato regulatório que proíbe processamento em SaaS compartilhado.
  • Cenário air-gapped (sem conectividade com AWS / Internet pública).
  • PoC ou laboratório técnico precisando reproduzir a stack completa localmente.

Para uso em SaaS gerenciado, use o docker-compose.yml padrão (não este).

O que está incluído

O arquivo docker-compose.onprem.yml traz uma stack completa e local, sem dependência de serviços AWS:

Componente Imagem Substitui (SaaS)
postgres + pgbouncer postgres:16-alpine RDS PostgreSQL
redis redis ElastiCache Redis
minio minio/minio AWS S3
ollama ollama/ollama (Llama-3 local) AWS Bedrock
api / worker / rq-worker imagem TTP ECS Fargate
frontend-react imagem TTP React PWA em EC2
prometheus + grafana oficiais CloudWatch + dashboards SaaS

Intencionalmente omitido vs SaaS:

  • stripe-webhook — não há billing comercial on-prem (licença por contrato).
  • blackbox-exporter — não há edge Railway a sondar.
  • jaeger — opcional (--profile tracing).
  • SES/SMTP AWS — use qualquer relay SMTP interno via env vars.
  • KMS — AUDIT_KMS_KEY_ID vazio faz o audit log usar JSON em claro; recomenda-se montar HSM/KMS on-prem do cliente.

Pré-requisitos

  • Docker Engine ≥ 24 + Docker Compose v2.
  • 16 vCPU / 32 GB RAM mínimo para POC; produção Tier-1 segue sizing por contrato (workers GPU separados).
  • GPU NVIDIA (CUDA ≥ 12) para batch_gpu_interference_worker.py em produção; opcional para POC (fallback CPU).
  • 200 GB de disco para Postgres + tiles SRTM/MapBiomas.
  • Sistema host Linux x86_64 (Ubuntu 22.04 LTS ou RHEL 9 testados).

Bootstrap mínimo

# 1. Diretório de secrets file-based (nunca expostos em `docker inspect`).
#    Todos os valores `CHANGE_ME` abaixo DEVEM ser substituídos antes do
#    go-live; não suba para produção com secrets de exemplo.
mkdir -p secrets-onprem

# Postgres: a senha precisa ser idêntica à de POSTGRES_PASSWORD no .env
# (PgBouncer usa a env, a API usa o secret file).
PG_PASS="$(openssl rand -base64 24 | tr -d '/+=' | cut -c1-24)"
echo "$PG_PASS"                            > secrets-onprem/postgres_password
echo "postgresql://telecom:${PG_PASS}@pgbouncer:5432/towers" \
                                          > secrets-onprem/database_url

# MinIO (S3 substitute). O alias aws_secret_access_key no compose
# aponta para o MESMO arquivo, então só precisamos gerar este.
openssl rand -base64 32 | tr -d '/+='     > secrets-onprem/minio_root_password

# Grafana admin
openssl rand -base64 24                   > secrets-onprem/grafana_admin_password

# Audit log target HMAC pepper
openssl rand -hex 32                      > secrets-onprem/audit_target_hmac_pepper

# Admin API keys / TOTP — placeholders. Trocar antes do go-live por
# valores reais (TOTP secret = base32 do enrollment do seu autenticador,
# API key = string opaca de >= 32 bytes).
echo 'admin:CHANGE_ME'                    > secrets-onprem/admin_api_keys
echo 'admin:CHANGE_ME_BASE32_TOTP'        > secrets-onprem/admin_totp_secrets
echo 'CHANGE_ME:CHANGE_ME'                > secrets-onprem/valid_api_keys

chmod 600 secrets-onprem/*

# 2. Variáveis de ambiente
cp .env.onprem.example .env
# Edite .env e garanta que POSTGRES_PASSWORD = $(cat secrets-onprem/postgres_password).
# Configure também SMTP interno, IP allowlist, etc.

# 3. Subir a stack
docker compose -f docker-compose.onprem.yml up -d

# 4. Baixar o modelo Llama-3 local (uma vez; ver seção air-gapped abaixo
#    se o host não tem acesso ao registry público).
docker compose -f docker-compose.onprem.yml exec ollama ollama pull llama3

Antes do go-live: rotacione todos os valores CHANGE_ME, valide que o admin_totp_secrets corresponde ao QR-code escaneado pelo administrador (Google Authenticator / Authy / 1Password), e remova qualquer entrada de exemplo em valid_api_keys.

A API responde em http://<host>:8000. O frontend React em http://<host>:3000. O Grafana em http://<host>:3001 (login admin / senha em secrets-onprem/grafana_admin_password).

Cenário air-gapped (sem acesso a registries públicos)

O docker compose ... up e o ollama pull acima assumem conectividade com Docker Hub / registry da Ollama. Em deploy air-gapped esses downloads precisam ser feitos em uma máquina com Internet (host de staging) e transferidos para o site final:

# Em um host com Internet, pré-baixe todas as imagens referenciadas pelo compose:
docker compose -f docker-compose.onprem.yml pull
docker save \
  postgres:16-alpine \
  redis:7-alpine \
  minio/minio:latest \
  ollama/ollama:latest \
  $(docker compose -f docker-compose.onprem.yml config --images) \
  | gzip > ttp-onprem-images.tar.gz

# E o modelo Llama-3 (~4 GB):
docker run --rm -v ollama_models:/root/.ollama ollama/ollama:latest \
  sh -c 'ollama serve & sleep 3 && ollama pull llama3 && ollama list'
docker run --rm -v ollama_models:/data busybox tar czf - /data > llama3-cache.tar.gz

Transfira ttp-onprem-images.tar.gz + llama3-cache.tar.gz para o site air-gapped (mídia removível, registry interno, etc) e carregue antes do docker compose up:

gunzip -c ttp-onprem-images.tar.gz | docker load
docker volume create ollama_models
tar xzf llama3-cache.tar.gz -C /var/lib/docker/volumes/ollama_models/_data --strip-components=1
docker compose -f docker-compose.onprem.yml up -d   # já roda offline

Alternativa preferida em ambientes corporativos: hospedar um registry interno (Harbor / Artifactory / GitLab Registry), re-taggear as imagens para registry.intranet.cliente/... e ajustar o docker-compose.onprem.yml para apontar para esse registry.

Validação pós-deploy

# Health da API
curl -fsS http://<host>:8000/health

# Smoke do worker batch
curl -fsS -H "X-API-Key: demo-key" \
     -H "Content-Type: application/json" \
     -d '{"receivers":[{"lat":-23.55,"lon":-46.63}]}' \
     http://<host>:8000/coverage/predict

# Métricas Prometheus
curl -fsS http://<host>:9090/-/healthy

Em ambientes Tier Carrier executamos load test prévio via locustfile.py com o volume real previsto em contrato, antes do cutover. Isso valida que o sizing contratado sustenta o SLA acordado.

Operação

  • Observabilidade: Prometheus + Grafana locais; regras em prometheus_alert_rules.yml.
  • Backup: snapshot do volume postgres-data + bucket MinIO (mc mirror).
  • Audit log: gravado em audit_log (Postgres) + opcionalmente em SIEM externo via audit_siem_forwarder.py.
  • Upgrade: docker compose pull && docker compose up -d em janela acordada; migrations Alembic rodam automaticamente no boot da API.
  • Runbook: operations/runbook.md.

SLA, NOC e suporte

O Tier Carrier inclui SLA financeiro e NOC 24/7 sob contrato. Antes do go-live:

  1. Definir RTO / RPO formais por componente.
  2. Acordar janela de manutenção e change window.
  3. Configurar rota de paging do Alertmanager para o NOC contratado.
  4. Validar runbook customizado com o time de operação do cliente.

Detalhes comerciais e técnicos em Enterprise Tier-1. Para iniciar uma avaliação, fale com vendas.


Licença Perpétua On-Prem (SKU C1 — resposta a alegações #9 e #10 do auditor)

A partir de junho/2026, TTP oferece o SKU TTP On-Prem Perpetual Enterprise (one-time purchase) como alternativa à assinatura recorrente.

  • Preço indicativo: 5× MRR Enterprise anual (piso negociável).
  • Entrega: bundle air-gapped assinado + license.ttp + 36 meses de updates incluídos.
  • Validação: local (sem rede), compatível com TTP_OFFLINE=1 e docker-compose.onprem.yml.
  • Suporte & Maintenance: 20%/ano opcional (SLA 4h, updates de segurança 5 anos, source escrow Enterprise).

Aquisição: - Self-serve (quando STRIPE_PRICE_PERPETUAL_ENTERPRISE configurado): Checkout Stripe mode=payment via /signup/checkout?billing_cycle=perpetual&tier=enterprise. - Sales-led / wire: Order Form + entrega manual do tarball + licença.

Evidência de compliance com o plano de auditoria: ver LICENSE-PERPETUAL.md (raiz do repo) e seção C1 do audit-rebuttal-2026.md.

Após instalação, a licença perpétua fecha as 50 contagens ponderadas de "dependência nuvem" e "sem propriedade perpétua" para clientes Enterprise Carrier.

Exemplo de ativação (após receber o bundle):

cp license.ttp secrets-onprem/
echo 'perpetual=true' >> .env.onprem   # ou via volume
docker compose -f docker-compose.onprem.yml up -d
curl http://localhost:8000/health
# (Roadmap) o payload incluirá `"license": {"type": "perpetual", "updates_until": "2029-06-..."}`.
# Hoje `/health` retorna apenas status básico; o marcador perpétuo é persistido em
# `key_store_db` como `billing_cycle == "perpetual"` (ver `stripe_billing.py`).

Clientes com licença perpétua têm prioridade em features offline (ex: drivers de GPU local para Sionna RT sem Batch).