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_IDvazio 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.pyem 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 oadmin_totp_secretscorresponde ao QR-code escaneado pelo administrador (Google Authenticator / Authy / 1Password), e remova qualquer entrada de exemplo emvalid_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 viaaudit_siem_forwarder.py. - Upgrade:
docker compose pull && docker compose up -dem 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:
- Definir RTO / RPO formais por componente.
- Acordar janela de manutenção e change window.
- Configurar rota de paging do Alertmanager para o NOC contratado.
- 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=1edocker-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).