# PostgreSQL

Bancos PostgreSQL no VPS com usuário próprio de privilégio mínimo, TLS e acesso externo limitado por lista de IP.

Fonte: https://ardumaker.com/pt/docs/postgresql/

- Categoria: Servidores e infraestrutura
- Estado: Disponível
- Requisitos: Um VPS ativo com a função `postgresql` disponível; Ser membro com acesso ao VPS para instalar; admin para revelar a credencial, abrir o acesso ou apagar dados
- Ferramentas MCP (Só leem): `ver_catalogo_apps`, `ver_preflight_app`, `ver_app`, `ver_acceso_app`, `ver_operacion_app`, `listar_motores_db_vps`, `listar_bases_db_vps`
- Ferramentas MCP (Escrevem ou modificam): `instalar_app`, `revelar_credencial_app`, `cambiar_lista_ip_app`, `reintentar_operacion_app`
- Ferramentas MCP (Destrutivas): `revocar_acceso_app`, `desinstalar_app`

## O que permite fazer?

Cada banco PostgreSQL é um app: tem seu nome, seu usuário próprio com senha aleatória e, se pedido, acesso pela internet com TLS e lista de IP. O motor é instalado uma única vez por VPS e é compartilhado por todos os seus bancos.

- Criar vários bancos no mesmo motor, cada um isolado dos outros.
- Ver a credencial (usuário, senha e URI de conexão) quando necessário.
- Abrir, alterar ou fechar o acesso pela internet por IP.
- Explorar tabelas e dados pelo [gerenciador de bancos de dados](https://ardumaker.com/pt/docs/gestor-de-bases-de-datos).
- Pela aba PostgreSQL do VPS: listar e criar bancos, usuários e permissões.

## Quando convém usar?

- Uma aplicação publicada no mesmo VPS que precisa de um banco relacional (conecta por `127.0.0.1:5432`).
- Um serviço externo (BI, outra nuvem, um computador) que precisa ler o banco com TLS a partir de IPs conhecidos.

## Como funciona na ArduMaker?

1. Validar: VPS ativo e função `postgresql` do sistema.
2. Motor: se não estiver instalado, é instalado uma única vez (pacotes `postgresql` e `postgresql-contrib` da distribuição, senha administrativa aleatória guardada criptografada). Se já estava, não é reinstalado nem muda de versão ou senha.
3. Credencial: é gerado um usuário `app<id>_<hex>` com senha aleatória, criptografada na plataforma antes de tocar o VPS.
4. Papel e banco: o papel é criado `LOGIN NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION`; o banco é criado com esse papel como dono, tudo é revogado de `PUBLIC` e uma linha `hostssl <banco> <papel> … scram-sha-256` é adicionada ao `pg_hba.conf`, com uma rejeição abaixo para qualquer outro banco.
5. Verificação: o papel não pode ser superusuário nem criar bancos ou papéis, é dono do seu banco e `PUBLIC` não se conecta. Se algo não bater, falha `permisos_no_verificados`.
6. Acesso externo: só se pedido com IPs. O TLS do motor é ativado e a abertura é pedida como operação separada; se ainda não puder abrir, o banco fica instalado assim mesmo e o motivo é registrado.

O SQL viaja codificado no ambiente e entra por stdin; a senha nunca aparece em uma linha de comando nem em um log.

`config.external_access` decide se o banco sai para a internet: `{"ips": [...]}` abre só para esses IPs; `{"local": true}` (ou `false`) o deixa só dentro do VPS. Se não for informado, pelo painel usa-se o IP de quem instala; via MCP o IP do agente não conta, então sem `ips` o banco fica local em vez de falhar.

## O que muda realmente?

| O quê | Detalhe |
| --- | --- |
| Motor | Serviço `postgresql` habilitado, escutando em `127.0.0.1:5432` |
| Banco | Nome `[A-Za-z_][A-Za-z0-9_]{0,62}`, com maiúsculas como estão (entre aspas) |
| Papel do app | `app<id>_<hex>` |
| `pg_hba.conf` | Seu bloco `hostssl` e um `reject` para os demais bancos |
| TLS (se houver acesso externo) | Certificado próprio em `/etc/ardumaker/tls/`, `ssl=on`, TLS 1.2 no mínimo, recarga sem reinício |

> **INFO:** Não são aceitos como nome `postgres`, `template0`, `template1`, `all`, `sameuser`, `samerole`, `replication` nem nada que comece com `pg_`.

## Acesso pela internet e lista de IP

Por padrão o motor escuta só dentro do VPS (5432 em `127.0.0.1`). Para usar o banco de fora, a ArduMaker publica um endpoint próprio do motor: `db-<id do VPS>` dentro da zona da plataforma (registro DNS direto, sem proxy), em uma porta reservada entre 61000 e 64999. No host, um proxy leva essa porta ao 5432 do VPS e o firewall só deixa entrar os IPs da lista.

O certificado é próprio desse nome (não um curinga) e é instalado no motor: o PostgreSQL ativa `ssl` com TLS 1.2 no mínimo e recarrega a configuração sem reiniciar. O usuário do app só entra por TCP com TLS (`hostssl`) e só no seu banco.

| Regra da lista | Detalhe |
| --- | --- |
| Formato | IPv4 ou IPv6, com ou sem prefixo; um IP solto é /32 ou /128. Nada de nomes, loopback, link-local nem multicast |
| Amplitude | Prefixo mínimo /24 em IPv4 e /48 em IPv6 por padrão; `0.0.0.0/0` e `::/0` são recusados na lista |
| Tamanho | Até 20 entradas; vazia = fechado para todos |
| Nomes de host | Até 5 (`allowed_hosts`), com até 8 IPs públicos cada; são resolvidos de novo a cada 5 minutos e uma falha de DNS mantém o último conhecido |
| Aberto a todos | Só com `allow_any` e `confirm_open` juntos; a resposta informa em `open_to_any` |

A lista é do motor, não de cada banco: alterá-la a partir de qualquer banco PostgreSQL muda o acesso de todos os bancos desse motor nesse VPS (a resposta indica com `shared_with_engine` e `affected_apps`).

1. As regras de firewall que faltam são adicionadas, uma por CIDR (`ufw allow from <cidr> to any port <porta> proto tcp`).
2. Depois as que sobram são removidas e suas conexões abertas são cortadas.
3. Só então o listener é criado e verificado: regras iguais à lista, nenhuma regra aberta a qualquer um, listener presente e handshake TLS com o nome correto.

> **INFO:** Adicionar antes de remover faz com que o estado intermediário seja sempre a união de duas listas válidas: nunca há um instante aberto a todos. Se a verificação falhar, o listener é removido.

> **PRECAUCION:** Outro VPS do mesmo host não chega pelo IP público mesmo estando na lista: a conexão estoura o tempo. A resposta avisa em `warnings` (`mismo_host`); entre dois VPS assim usa-se um túnel SSH (`configurar_tunel_entre_vps`).

## Desinstalar, persistência e cópias

- Sem `delete_data` (o normal): o acesso externo próprio é fechado e o app deixa de aparecer como instalado, mas o banco, seu usuário e seus dados ficam no VPS. A próxima reconciliação o mostra como detectado. Nada se perde.
- Com `delete_data: true` (confirmado duas vezes, só admin): `DROP DATABASE` e, se o usuário foi criado pelo Apps (`app<id>_<hex>`), também o papel e sua senha guardada. Nunca um usuário do cliente nem o administrador do motor.
- O motor nunca é desinstalado pelo Apps: fica instalado mesmo sem bancos.
- Se o VPS ou o motor não responderem, `desinstalar_app` com `forzar=true` tenta cada passo uma vez, remove o app e lista em `not_cleaned` o que ficou no servidor.
- Os dados vivem no disco do VPS e viajam na sua cópia semanal, feita com o VPS ligado. Para uma cópia consistente de um banco específico convém também um dump próprio pelo [gerenciador de bancos de dados](https://ardumaker.com/pt/docs/gestor-de-bases-de-datos) (exportar) ou com as ferramentas do motor.

> **PELIGRO:** Com `delete_data` a desinstalação é irreversível.

## Esquema

**Conexões a um banco PostgreSQL**

```text
App no mesmo VPS (`127.0.0.1:5432`)
  ↓
Cliente externo (`db-<id>:<porta>` com `sslmode=verify-full`)
  ↓
Firewall do host (só os IPs da lista)
  ↓
Proxy do host (porta 61000–64999 → 5432 do VPS)
  ↓
PostgreSQL (`hostssl` + `scram-sha-256`, só o seu banco)
```

## Resultado esperado

O banco aparece em Apps pendurado no seu motor. `ver_acceso_app` mostra estado, host, porta, TLS e a lista aplicada; `revelar_credencial_app` devolve usuário, senha e a URI. A URI só existe quando o acesso externo está pronto:

```text
postgresql://app<id>_<hex>@db-<vps>.<zona>:<puerto>/<base>?sslmode=verify-full
```

## Erros e resolução

| Erro | Causa | Tentar de novo? |
| --- | --- | --- |
| `base_ya_existe` | Já existe um banco com esse nome de outro dono; não é sobrescrito nem adotado | Não |
| `motor_detenido` / `motor_instalandose` / `motor_no_instalado` | O motor está parado, instalando ou não pôde ser instalado | Sim |
| `base_no_creada` / `permisos_no_verificados` | O SQL falhou ou as permissões do papel não verificaram | Sim |
| `lista_ip_invalida` / `lista_ip_demasiado_amplia` | Entrada malformada ou faixa mais ampla que o mínimo; `data.invalid` diz quais | Corrigindo a lista |
| `credencial_legacy` / `cuentas_del_motor_sin_verificar` / `tls_no_disponible` | O motor ainda não cumpre as condições para ser exposto (senhas antigas, contas do cliente não verificadas ou TLS pendente) | Após resolver |
| `acceso_externo_no_habilitado` | O acesso externo não está habilitado para esse tipo na empresa | Não |
| `cierre_no_verificado` | Ao fechar ficou uma regra ou o listener; é informado o que realmente existe | Sim |

Estado e passos de cada operação: `ver_operacion_app` (inclui se pode ser repetida). Uma operação falha que pode ser repetida é retomada do passo que falhou com `reintentar_operacion_app`, sem reinstalar o motor. Pedir a lista que já está aplicada não enfileira nada (`idempotent: true`).

## Relação com MCP

Todo o ciclo do banco é operado via MCP com as permissões da pessoa que autorizou o agente. Referência em [/mcp/docs](https://ardumaker.com/pt/mcp/docs) e [/mcp/bases-de-datos](https://ardumaker.com/pt/mcp/bases-de-datos).

- Leitura: `ver_catalogo_apps`, `ver_preflight_app`, `listar_apps_empresa`, `ver_app`, `ver_acceso_app` (host, porta, TLS e lista de IP, sem segredos), `ver_operacion_app`.
- Modificam: `instalar_app` com `app_type: postgres` (exige `idempotency_key`), `cambiar_lista_ip_app` (só se o dono for admin; os IPs são informados explicitamente: o IP do agente não é o da pessoa), `reintentar_operacion_app`, `refrescar_apps`.
- Sensível: `revelar_credencial_app` (só admin, não aceita `idempotency_key`; a resposta vem marcada `sensible: true` e a auditoria registra que foi revelado, nunca o valor).
- Destrutivas: `revocar_acceso_app` (fecha o acesso externo de todo o motor) e `desinstalar_app` (com `delete_data` apaga os dados; exige `confirm_delete_data`).

Para ler e escrever dados dentro do banco, o agente usa as ferramentas do [gerenciador de bancos de dados](https://ardumaker.com/pt/docs/gestor-de-bases-de-datos). Um agente autorizado como somente leitura não vê as ferramentas que modificam nem pode revelar credenciais.

## Funcionalidades relacionadas

- [Gerenciador de bancos de dados](https://ardumaker.com/pt/docs/gestor-de-bases-de-datos/)
- [MySQL](https://ardumaker.com/pt/docs/mysql/)
- [Redis](https://ardumaker.com/pt/docs/redis/)
- [Firewall e portas](https://ardumaker.com/pt/docs/firewall-y-puertos/)
- [Túneis SSH](https://ardumaker.com/pt/docs/tuneles-ssh/)
- [Cópias de segurança](https://ardumaker.com/pt/docs/backups/)
