MySQL
Bases MySQL 8 o MariaDB en el VPS con cuenta propia que exige TLS, permisos solo sobre su base y acceso externo por IP.
- Categoría: Servidores e infraestructura
- Estado: Disponible
- Requisitos: Un VPS activo con la función
mysqldisponible; Si el motor ya existe: MySQL 8.x o MariaDB 10.4 o superior; Ser miembro con acceso al VPS para instalar; admin para revelar, abrir acceso o borrar datos - Herramientas MCP (Solo leen):
ver_catalogo_apps,ver_preflight_app,ver_app,ver_acceso_app,ver_operacion_app,listar_motores_db_vps,listar_bases_db_vps - Herramientas MCP (Escriben o modifican):
instalar_app,revelar_credencial_app,cambiar_lista_ip_app,reintentar_operacion_app - Herramientas MCP (Destructivas):
revocar_acceso_app,desinstalar_app
¿Qué permite hacer?
Cada base MySQL es una app con su cuenta propia. El motor (MySQL o MariaDB) es uno por VPS y lo comparten sus bases; si no existe, se instala MySQL desde los paquetes de la distribución.
- Crear varias bases
utf8mb4, cada una con su cuenta y sus permisos. - Revelar usuario, contraseña y URI de conexión.
- Abrir el motor a internet solo para ciertas IP, con TLS.
- Desde la pestaña MySQL del VPS: bases, usuarios, permisos y tablas.
¿Cuándo conviene usarlo?
- Aplicaciones que esperan MySQL (PHP, Laravel, muchas herramientas de terceros).
- Un WordPress usa este mismo motor, con una base y una cuenta propias por sitio.
¿Cómo funciona en ArduMaker?
- Motor: si el agente dice que no está instalado, se instala una vez (
mysql-serverymysql-client); si ya existe, nunca se reinstala ni cambia de versión. - Variante: se lee
mysql --version. Solo MySQL 8.x o MariaDB 10.4+; otra cosa fallamotor_no_soportadosin ejecutar SQL. - Credencial
app<id>_<hex>con contraseña aleatoria, guardada cifrada antes de tocar el VPS. - Se entra como administrador por socket, con la contraseña en un archivo de opciones efímero, nunca en la línea de comandos.
- Cuenta
'app<id>_<hex>'@'127.0.0.1'conREQUIRE SSL, yGRANT ALL PRIVILEGESsolo sobre<base>.*, sinGRANT OPTION, antes de crear la base. CREATE DATABASE <base> CHARACTER SET utf8mb4solo si no existía.- Verificación: TLS exigido, sin privilegios globales y permisos sobre una sola base, la suya.
La cuenta es @'127.0.0.1' a propósito: no % (abriría la cuenta a cualquier origen) ni localhost (socket, sin TLS). Cuando el servidor no tiene partial_revokes (o es MariaDB), el _ del nombre se escapa en el GRANT, porque ahí es un comodín.
config.external_access decide si la base sale a internet: {"ips": [...]} abre solo a esas IP; {"local": true} (o false) la deja solo adentro del VPS. Si no se indica, desde el panel se toma la IP de quien instala; por MCP la IP del agente no cuenta, así que sin ips la base queda local en vez de fallar.
¿Qué cambia realmente?
| Qué | Detalle |
|---|---|
| Motor | MySQL o MariaDB escuchando en 127.0.0.1:3306 |
| Base | utf8mb4; un nombre igual con otras mayúsculas cuenta como el mismo |
| Cuenta | 'app<id>_<hex>'@'127.0.0.1' REQUIRE SSL |
| TLS en MySQL 8 | SET PERSIST + ALTER INSTANCE RELOAD TLS, sin reinicio |
| TLS en MariaDB | Archivo 90-ardumaker-tls.cnf; la primera vez requiere reiniciar el motor |
Acceso desde internet y lista de IP
Por defecto el motor escucha solo dentro del VPS (3306 en 127.0.0.1). Para usar la base desde afuera, ArduMaker publica un endpoint propio del motor: db-<id del VPS> dentro de la zona de la plataforma (registro DNS directo, sin proxy), en un puerto reservado entre 61000 y 64999. En el host, un proxy lleva ese puerto al 3306 del VPS y el firewall deja entrar solo las IP de la lista.
El certificado es propio del nombre db-<id> y lo termina mysqld: el proxy del host solo pasa TCP. La cuenta de la app exige SSL venga por donde venga.
| Regla de la lista | Detalle |
|---|---|
| Formato | IPv4 o IPv6, con o sin prefijo; una IP suelta es /32 o /128. Nada de nombres, loopback, link-local ni multicast |
| Amplitud | Prefijo mínimo /24 en IPv4 y /48 en IPv6 por defecto; 0.0.0.0/0 y ::/0 se rechazan en la lista |
| Tamaño | Hasta 20 entradas; vacía = cerrado para todos |
| Nombres de host | Hasta 5 (allowed_hosts), con hasta 8 IP públicas cada uno; se vuelven a resolver cada 5 minutos y una falla de DNS conserva lo último conocido |
| Abierto a todos | Solo con allow_any y confirm_open juntos; la respuesta lo dice en open_to_any |
La lista es del motor, no de cada base: cambiarla desde cualquier base de MySQL cambia el acceso de todas las bases de ese motor en ese VPS (la respuesta lo indica con shared_with_engine y affected_apps).
- Se agregan las reglas de firewall que faltan, una por CIDR (
ufw allow from <cidr> to any port <puerto> proto tcp). - Después se quitan las que sobran y se cortan sus conexiones abiertas.
- Recién entonces se crea el listener y se verifica: reglas iguales a la lista, ninguna regla abierta a cualquiera, listener presente y handshake TLS con el nombre correcto.
Desinstalar, persistencia y copias
- Sin
delete_data(lo normal): se cierra el acceso externo propio y la app deja de figurar como instalada, pero la base, su usuario y sus datos quedan en el VPS. La siguiente reconciliación la muestra como detectada. No se pierde nada. - Con
delete_data: true(confirmado dos veces, solo admin): se borra la base y, si la cuenta la creó Apps, también la cuenta y su contraseña guardada. Nunca una cuenta del cliente niroot. - El motor nunca se desinstala desde Apps: queda instalado aunque no tenga bases.
- Si el VPS o el motor no responden,
desinstalar_appconforzar=trueintenta cada paso una vez, da de baja la app y lista ennot_cleanedlo que quedó en el servidor. - Los datos viven en el disco del VPS y viajan en su copia semanal, que se toma con el VPS andando. Para una copia consistente de una base concreta conviene además un volcado propio desde el gestor de bases de datos (exportar) o con las herramientas del motor.
Esquema
- App en el mismo VPS:
127.0.0.1:3306 - Cliente externo:
db-<id>:<puerto>con verificación de identidad TLS - Firewall y proxy del host: solo IP de la lista → 3306 del VPS
- mysqld: termina TLS; la cuenta exige SSL y ve solo su base
Resultado esperado
La URI (sin contraseña) aparece cuando el acceso externo está listo; la completa se obtiene con 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)Errores y resolución
| Error | Causa | ¿Reintentar? |
|---|---|---|
motor_no_soportado | No es MySQL 8.x ni MariaDB 10.4+; no se toca nada | No |
base_ya_existe | Hay una base con ese nombre (sin distinguir mayúsculas) sobre la que la cuenta no tiene permisos | No |
motor_detenido / base_no_creada / permisos_no_verificados | Motor parado, SQL fallido o permisos que no verificaron | Sí |
requiere_reinicio | MariaDB necesita reiniciar para el primer TLS; el acceso no se abre hasta resolverlo | Tras reiniciar |
| Acceso externo no pedido | El motor tiene cuentas anónimas o sin contraseña que el listener expondría | Tras limpiar esas cuentas |
Las demás causas (lista de IP, TLS, credenciales antiguas, cierre no verificado) son las mismas que en PostgreSQL. El seguimiento es con ver_operacion_app y reintentar_operacion_app.
Relación con MCP
Todo el ciclo de la base se opera por MCP con los permisos de la persona que autorizó al agente. Referencia en /mcp/docs y /mcp/bases-de-datos.
- Lectura:
ver_catalogo_apps,ver_preflight_app,listar_apps_empresa,ver_app,ver_acceso_app(host, puerto, TLS y lista de IP, sin secretos),ver_operacion_app. - Modifican:
instalar_appconapp_type: mysql(exigeidempotency_key),cambiar_lista_ip_app(solo si su dueño es admin; las IP se nombran explícitas: la IP del agente no es la de la persona),reintentar_operacion_app,refrescar_apps. - Sensible:
revelar_credencial_app(solo admin, no aceptaidempotency_key; la respuesta viene marcadasensible: truey la auditoría registra que se reveló, nunca el valor). - Destructivas:
revocar_acceso_app(cierra el acceso externo de todo el motor) ydesinstalar_app(condelete_databorra los datos; requiereconfirm_delete_data).
Para leer y escribir datos dentro de la base, el agente usa las herramientas del gestor de bases de datos. Un agente autorizado solo lectura no ve las herramientas que modifican ni puede revelar credenciales.