# 🗄️ Guia de Provisionamento e Tuning de Dados: VPS 3 (newwhats) Este documento centraliza as instruções práticas de configuração, tuning e provisionamento para o banco de dados principal de produção (**PostgreSQL**) e o cache de alta performance (**DragonflyDB**) hospedados na **VPS 3 dedicada** (especificações físicas: **8 GB de RAM e 4 núcleos de CPU**). --- ## 🏛️ Divisão e Partilha Fisiológica de Recursos (Capacidade: 8 GB RAM / 4 CPUs) Para garantir estabilidade absoluta do sistema e impedir que oscilações no tráfego de mensagens do WhatsApp causem o encerramento forçado de serviços pelo OOM (*Out Of Memory Killer*) do Linux, o hardware é segmentado de forma cirúrgica: | Componente | Memória Alocada | Threads / CPUs | Função / Justificativa | | :--- | :--- | :--- | :--- | | **PostgreSQL shared_buffers** | **2.0 GB** (25%) | Automático (Host) | Cache interno nativo de tabelas e índices de negócio do PostgreSQL. | | **PostgreSQL work_mem & OS** | **2.2 GB** (~27%) | Automático (Host) | Ordenações locais de queries, conexões e buffers de escrita do banco. | | **DragonflyDB `--memlimit_gb`** | **3.0 GB** (~38%) | **`--num_threads 2`** | Armazenamento seguro de sessões de WhatsApp, presenças e QR codes ativos. | | **Sistema Operacional (SO) & Redes** | **800 MB** (~10%) | Reservado (2 CPUs) | Processamento da rede VPN WireGuard, kernel e deamon de firewall. | > [!IMPORTANT] > **Tuning de CPU**: O DragonflyDB é multi-threaded por natureza. Definir `--num_threads 2` confina a execução do cache a apenas 2 núcleos, deixando 2 núcleos de processamento físico totalmente livres para as consultas SQL do PostgreSQL e para a criptografia do túnel Wireguard. --- ## 🚪 Escolha Estratégica do Temporal: **Opção B (Temporal Server na VPS 5)** O **Temporal Server** possui uma pegada de RAM ativa que consome entre **400 MB a 800 MB** em produção. Rodá-lo na VPS 3 deixaria a máquina no limite crítico de recursos físicos (apenas ~600 MB livres de folga). Portanto, adota-se a **Opção B: Hospedar o Temporal Server na VPS 5 (Aplicação)**: * **Ganho de Estabilidade**: Preserva a VPS 3 exclusivamente como um *Data Appliance* de alta performance (Postgres + DragonflyDB). * **Latência Zero de API**: Como o **Temporal Worker** roda ao lado do backend Express na VPS 5, colocá-los na mesma máquina permite que a comunicação entre Worker e Server aconteça via `localhost`, eliminando overhead de rede VPN. * **Persistência**: O Temporal Server na VPS 5 continuará salvando seus dados persistentes de workflows (agenda/reputação) de forma segura no database dedicado `temporal` na VPS 3 via túnel privado. --- ## 🗄️ 1. Separação de Databases e Privilégios no PostgreSQL O banco de dados do negócio (`newwhats`) e a infraestrutura interna do orquestrador (`temporal`) são isolados fisicamente em databases independentes para evitar conflito de migrações (Prisma/Knex vs `temporal-sql-tool`), facilitar backups por tabela e prover auditoria de acessos. Acesse o console do PostgreSQL (`sudo -u postgres psql`) e execute o script SQL abaixo: ```sql -- ==================================================== -- 1. CRIAÇÃO DE DATABASES INDEPENDENTES -- ==================================================== CREATE DATABASE newwhats; CREATE DATABASE temporal; -- ==================================================== -- 2. CRIAÇÃO DOS USUÁRIOS/ROLES ESTREITOS -- ==================================================== CREATE USER newwhats_user WITH PASSWORD 'SuaSenhaForteNewwhatsAqui'; CREATE USER temporal_user WITH PASSWORD 'SuaSenhaForteTemporalAqui'; -- ==================================================== -- 3. REVOGAÇÃO DE ACESSOS PÚBLICOS PADRÃO (ZERO-TRUST) -- ==================================================== REVOKE ALL ON DATABASE newwhats FROM PUBLIC; REVOKE ALL ON DATABASE temporal FROM PUBLIC; -- ==================================================== -- 4. ATRIBUIÇÃO DE CONEXÕES EXCLUSIVAS -- ==================================================== GRANT CONNECT ON DATABASE newwhats TO newwhats_user; GRANT CONNECT ON DATABASE temporal TO temporal_user; -- ==================================================== -- 5. CONFIGURAÇÃO DE PRIVILÉGIOS GRANULARES -- ==================================================== -- Conecte no banco 'newwhats' (\c newwhats) e execute: GRANT USAGE ON SCHEMA public TO newwhats_user; GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO newwhats_user; GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO newwhats_user; ALTER DATABASE newwhats OWNER TO newwhats_user; -- Conecte no banco 'temporal' (\c temporal) e execute: -- O temporal-sql-tool precisa de privilégios plenos dentro de seu banco para autogerenciar tabelas GRANT ALL PRIVILEGES ON DATABASE temporal TO temporal_user; ALTER DATABASE temporal OWNER TO temporal_user; ``` --- ## 📊 2. Hardening da Configuração do PostgreSQL (`pg_hba.conf`) Edite o arquivo `/etc/postgresql/18/main/pg_hba.conf` para garantir que o acesso ao banco de dados seja liberado apenas para os papéis designados originados da rede interna da VPN Wireguard: ```text # TYPE DATABASE USER ADDRESS METHOD # 1. Permissões locais do sistema operacional (Apenas Root local) local all postgres peer # 2. Permitir que o backend (VPS 5) conecte apenas no database de negócio host newwhats newwhats_user 10.99.0.5/32 scram-sha-256 # 3. Permitir que o orquestrador Temporal (VPS 5) conecte apenas no database temporal host temporal temporal_user 10.99.0.5/32 scram-sha-256 # 4. Permitir conexões de replicação da VPS 4 (Staging/Replica) host replication replicator 10.99.0.4/32 scram-sha-256 # 5. Bloqueio preventivo total para qualquer outro IP ou usuário host all all 0.0.0.0/0 reject ``` *Para aplicar as alterações:* ```bash sudo systemctl reload postgresql ``` --- ## 🚀 3. Provisionamento do DragonflyDB (Systemd) O **DragonflyDB** roda nativamente como um serviço leve do sistema, configurado com escuta restrita e controle estrito de memória física. ### 🛠️ Configuração do Serviço `/etc/systemd/system/dragonfly.service`: Crie o arquivo de configuração de unidade do Systemd: ```ini [Unit] Description=DragonflyDB Cache Server After=network.target Wants=network-online.target [Service] Type=simple User=dragonfly Group=dragonfly # Inicialização endurecida e otimizada para 8 GB RAM / 4 CPUs ExecStart=/usr/local/bin/dragonfly \ --bind 10.99.0.3 \ --port 6379 \ --memlimit_gb 3 \ --num_threads 2 \ --save_schedule "" \ --logtostdout \ --requirepass SENHA_DRAGONFLY_PRODUCAO Restart=always RestartSec=5 LimitNOFILE=65536 [Install] WantedBy=multi-user.target ``` > [!NOTE] > **Hardening de Escuta**: O parâmetro `--bind 10.99.0.3` substitui o padrão inseguro `0.0.0.0`. Isso força o DragonflyDB a escutar **exclusivamente** as requisições que transitam por dentro do túnel privado do Wireguard, impossibilitando tentativas de conexão direta a partir da internet pública. ### 🏁 Passos de ativação do serviço: 1. Certifique-se de criar o usuário dedicado do sistema: ```bash sudo useradd -r -s /bin/false dragonfly ``` 2. Recarregue os daemons e ative o DragonflyDB: ```bash sudo systemctl daemon-reload sudo systemctl enable dragonfly sudo systemctl start dragonfly ``` --- ## 🏛️ 4. Centralização de Múltiplos Projetos (Database Appliance) Centralizar os bancos de dados de todos os seus projetos (ex: `google.com`, `facebook.com`, `newwhats`) na **VPS 3 dedicada**, mantendo as aplicações e frontends isolados na **VPS 1 (ou outras VPSs de app)**, é uma excelente decisão de design. Isso separa a computação volátil das aplicações (onde acontecem picos de tráfego, deploys, memory leaks e builds pesados) da consistência estável da camada de persistência de dados. ### ⚠️ Regras de Segurança e Isolamento Mandatórias: Para operar esse modelo compartilhado com segurança de nível corporativo e evitar que uma falha em um projeto comprometa ou degrade os outros (efeito *Noisy Neighbor*): #### 1. Isolamento Lógico Absoluto (Databases & Roles Independentes) **Nunca** use o mesmo banco de dados ou o mesmo usuário PostgreSQL para projetos distintos. Cada projeto deve ter seu banco de dados próprio e seu usuário com privilégios restritos ao seu respectivo banco. ```text PostgreSQL (VPS 3) ├── database: google_db ──> OWNER: google_user (Apenas VPS 1 / 10.99.0.1) ├── database: facebook_db ──> OWNER: facebook_user (Apenas VPS 1 / 10.99.0.1) └── database: newwhats ──> OWNER: newwhats_user (Apenas VPS 5 / 10.99.0.5) ``` #### 2. Configuração do `pg_hba.conf` para Múltiplos Projetos: Edite o arquivo `/etc/postgresql/18/main/pg_hba.conf` para mapear de forma cirúrgica as origens permitidas para cada projeto: ```text # TYPE DATABASE USER ADDRESS METHOD # 1. Permissões de Administração local local all postgres peer # 2. Projeto GOOGLE (Frontend/Backend na VPS 1 -> Banco na VPS 3) host google_db google_user 10.99.0.1/32 scram-sha-256 # 3. Projeto FACEBOOK (Frontend/Backend na VPS 1 -> Banco na VPS 3) host facebook_db facebook_user 10.99.0.1/32 scram-sha-256 # 4. Projeto NEWWHATS (Backend na VPS 5 -> Banco na VPS 3) host newwhats newwhats_user 10.99.0.5/32 scram-sha-256 # 5. Permitir conexões de replicação da VPS 4 (Staging/Replica) host replication replicator 10.99.0.4/32 scram-sha-256 # 6. BLOQUEIO PADRÃO TOTAL (Zero-Trust) host all all 0.0.0.0/0 reject ``` #### 3. Gestão de Pools de Conexão no Node.js (Prisma/Knex) Cada aplicação Node.js aberta na VPS 1 tentará criar um pool de conexões persistentes. Se muitos projetos rodarem simultaneamente, as conexões ativas podem saturar a memória RAM da VPS 3 (cada conexão ativa no Postgres é um processo físico consumindo ~10MB-20MB de RAM). * **Solução**: Restrinja o tamanho máximo de pool nas variáveis de ambiente `.env` de cada projeto na VPS 1: ```env # Exemplo de limite de conexões no Prisma DATABASE_URL="postgresql://google_user:SENHA@10.99.0.3:5432/google_db?connection_limit=10" ``` * **PgBouncer (Avançado)**: Se o número de projetos escalonar para dezenas de aplicações na VPS 1, configure o **PgBouncer** na VPS 3 para multiplexar centenas de conexões virtuais em poucas conexões físicas reais do Postgres, reduzindo drasticamente o consumo de RAM. --- ## 🚀 5. Otimização de Performance e Tuning do PostgreSQL 18 Para aproveitar ao máximo os **8 GB de RAM e 4 núcleos de CPU** da VPS 3 (Data Appliance) e garantir o processamento rápido e estável de dados para o `newwhats` e o `giteadb`, aplicamos um tuning avançado nativo. As configurações foram modularizadas no arquivo `/etc/postgresql/18/main/conf.d/tuning.conf` para manter o `postgresql.conf` limpo e facilitar a portabilidade: ```ini # ========================================== # PostgreSQL Performance Tuning Configuration # Optimized for 8 GB RAM / 4 CPU Cores # ========================================== # Memory Configuration shared_buffers = 2GB effective_cache_size = 6GB maintenance_work_mem = 512MB work_mem = 10MB # Write-Ahead Log (WAL) Configuration checkpoint_completion_target = 0.9 wal_buffers = 16MB min_wal_size = 1GB max_wal_size = 4GB # Disk and Query Planner Settings (assuming SSD/NVMe) random_page_cost = 1.1 effective_io_concurrency = 200 default_statistics_target = 100 # Worker Process and Parallelism Settings max_worker_processes = 4 max_parallel_workers_per_gather = 2 max_parallel_workers = 4 max_parallel_maintenance_workers = 2 # Connections Configuration max_connections = 100 ``` ### 🏁 Passos de ativação e validação: ```bash # Reiniciar o serviço do cluster 18-main sudo systemctl restart postgresql@18-main.service # Confirmar os parâmetros carregados sudo -u postgres psql -c "SHOW shared_buffers; SHOW effective_cache_size; SHOW work_mem;" ``` --- ## 🧁 6. Resiliência de Inicialização do Gitea e DragonflyDB (Non-local Bind) ### 🔴 O Problema do Boot Sequencial Como o Gitea (`HTTP_ADDR = 10.99.0.3`) e o DragonflyDB (`--bind 10.99.0.3`) escutam exclusivamente no IP interno da VPN Wireguard, ocorria uma **falha de bind no reboot**: * O systemd inicializava estes serviços alguns milissegundos **antes** que a interface VPN (`wg0`) estivesse totalmente ativa e com o IP associado. * Isso resultava no erro `bind: cannot assign requested address`. * No caso do Gitea, ele falhava silenciosamente mantendo o processo de gerenciamento ativo, o que impedia o systemd de perceber a queda e reiniciar o serviço automaticamente. ### 🛡️ Solução Permanente Implementada #### 1. Configuração de Kernel: Non-local Bind Ativamos uma diretiva de kernel para permitir que os daemons executem o bind em IPs de interfaces que ainda não estejam totalmente ativas no momento do boot: ```bash # Ativar imediatamente sudo sysctl -w net.ipv4.ip_nonlocal_bind=1 # Persistir para reboots futuros echo "net.ipv4.ip_nonlocal_bind=1" | sudo tee -a /etc/sysctl.conf ``` #### 2. Dependência no Systemd do Gitea Atualizamos a unidade `/etc/systemd/system/gitea.service` para exigir que a rede esteja completamente online antes do início do Gitea: ```ini [Unit] Description=Gitea (Git with a cup of tea) After=syslog.target network.target network-online.target postgresql.service Wants=network-online.target ``` *Após atualizar, execute:* `sudo systemctl daemon-reload` #### 3. Dependência no Systemd do DragonflyDB (Override Nativo) Criamos um arquivo de override limpo para o DragonflyDB em `/etc/systemd/system/dragonfly.service.d/override.conf`: ```ini [Unit] After=network-online.target Wants=network-online.target ``` *Após criar, execute:* `sudo systemctl daemon-reload`