MySQL
Bancos MySQL 8 ou MariaDB no VPS com conta própria que exige TLS, permissões só no seu banco e acesso externo por IP.
- Categoria: Servidores e infraestrutura
- Estado: Disponível
- Requisitos: Um VPS ativo com a função
mysqldisponível; Se o motor já existir: MySQL 8.x ou MariaDB 10.4 ou superior; Ser membro com acesso ao VPS para instalar; admin para revelar, abrir 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 MySQL é um app com conta própria. O motor (MySQL ou MariaDB) é um por VPS e compartilhado pelos seus bancos; se não existir, o MySQL é instalado a partir dos pacotes da distribuição.
- Criar vários bancos
utf8mb4, cada um com sua conta e suas permissões. - Revelar usuário, senha e URI de conexão.
- Abrir o motor para a internet só para certos IPs, com TLS.
- Pela aba MySQL do VPS: bancos, usuários, permissões e tabelas.
Quando convém usar?
- Aplicações que esperam MySQL (PHP, Laravel, muitas ferramentas de terceiros).
- Um WordPress usa este mesmo motor, com banco e conta próprios por site.
Como funciona na ArduMaker?
- Motor: se o agente disser que não está instalado, é instalado uma vez (
mysql-serveremysql-client); se já existir, nunca é reinstalado nem muda de versão. - Variante: lê-se
mysql --version. Só MySQL 8.x ou MariaDB 10.4+; outra coisa falhamotor_no_soportadosem executar SQL. - Credencial
app<id>_<hex>com senha aleatória, guardada criptografada antes de tocar o VPS. - Entra-se como administrador pelo socket, com a senha em um arquivo de opções efêmero, nunca na linha de comando.
- Conta
'app<id>_<hex>'@'127.0.0.1'comREQUIRE SSL, eGRANT ALL PRIVILEGESsó sobre<banco>.*, semGRANT OPTION, antes de criar o banco. CREATE DATABASE <banco> CHARACTER SET utf8mb4só se não existia.- Verificação: TLS exigido, sem privilégios globais e permissões sobre um único banco, o seu.
A conta é @'127.0.0.1' de propósito: não % (abriria a conta para qualquer origem) nem localhost (socket, sem TLS). Quando o servidor não tem partial_revokes (ou é MariaDB), o _ do nome é escapado no GRANT, porque ali é um curinga.
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 | MySQL ou MariaDB escutando em 127.0.0.1:3306 |
| Banco | utf8mb4; um nome igual com outras maiúsculas conta como o mesmo |
| Conta | 'app<id>_<hex>'@'127.0.0.1' REQUIRE SSL |
| TLS no MySQL 8 | SET PERSIST + ALTER INSTANCE RELOAD TLS, sem reinício |
| TLS no MariaDB | Arquivo 90-ardumaker-tls.cnf; na primeira vez exige reiniciar o motor |
Acesso pela internet e lista de IP
Por padrão o motor escuta só dentro do VPS (3306 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 3306 do VPS e o firewall só deixa entrar os IPs da lista.
O certificado é próprio do nome db-<id> e é terminado pelo mysqld: o proxy do host só passa TCP. A conta do app exige SSL venha de onde vier.
| 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 MySQL muda o acesso de todos os bancos desse motor nesse VPS (a resposta indica com shared_with_engine e affected_apps).
- As regras de firewall que faltam são adicionadas, uma por CIDR (
ufw allow from <cidr> to any port <porta> proto tcp). - Depois as que sobram são removidas e suas conexões abertas são cortadas.
- 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.
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): o banco é apagado e, se a conta foi criada pelo Apps, também a conta e sua senha guardada. Nunca uma conta do cliente nemroot. - O motor nunca é desinstalado pelo Apps: fica instalado mesmo sem bancos.
- Se o VPS ou o motor não responderem,
desinstalar_appcomforzar=truetenta cada passo uma vez, remove o app e lista emnot_cleanedo 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 (exportar) ou com as ferramentas do motor.
Esquema
- App no mesmo VPS:
127.0.0.1:3306 - Cliente externo:
db-<id>:<porta>com verificação de identidade TLS - Firewall e proxy do host: só IPs da lista → 3306 do VPS
- mysqld: termina o TLS; a conta exige SSL e vê só o seu banco
Resultado esperado
A URI (sem senha) aparece quando o acesso externo está pronto; a completa é obtida com revelar_credencial_app.
mysql://app<id>_<hex>@db-<vps>.<zona>:<puerto>/<base>?ssl-mode=VERIFY_IDENTITY
mysql://app<id>_<hex>@db-<vps>.<zona>:<puerto>/<base>?sslMode=verify-full (MariaDB)Erros e resolução
| Erro | Causa | Tentar de novo? |
|---|---|---|
motor_no_soportado | Não é MySQL 8.x nem MariaDB 10.4+; nada é tocado | Não |
base_ya_existe | Existe um banco com esse nome (sem distinguir maiúsculas) sobre o qual a conta não tem permissões | Não |
motor_detenido / base_no_creada / permisos_no_verificados | Motor parado, SQL com falha ou permissões que não verificaram | Sim |
requiere_reinicio | O MariaDB precisa reiniciar para o primeiro TLS; o acesso não abre até resolver | Após reiniciar |
| Acesso externo não pedido | O motor tem contas anônimas ou sem senha que o listener exporia | Após limpar essas contas |
As demais causas (lista de IP, TLS, credenciais antigas, fechamento não verificado) são as mesmas do PostgreSQL. O acompanhamento é com ver_operacion_app e reintentar_operacion_app.
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 e /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_appcomapp_type: mysql(exigeidempotency_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 aceitaidempotency_key; a resposta vem marcadasensible: truee a auditoria registra que foi revelado, nunca o valor). - Destrutivas:
revocar_acceso_app(fecha o acesso externo de todo o motor) edesinstalar_app(comdelete_dataapaga os dados; exigeconfirm_delete_data).
Para ler e escrever dados dentro do banco, o agente usa as ferramentas do gerenciador de bancos de dados. Um agente autorizado como somente leitura não vê as ferramentas que modificam nem pode revelar credenciais.