Hay una pregunta que parece pequeña cuando despliegas un servicio self-hosted y luego decide el tono de tus próximas mudanzas: ¿qué hago con la base de datos?
La mayoría de guías pasan por encima. Te dan un docker compose, levantan PostgreSQL o MariaDB al lado de la aplicación y listo. Funciona. La pantalla carga. Te vienes arriba. Dos meses después tienes doce servicios, doce bases de datos, doce volúmenes con nombres parecidos y una sensación preciosa de que tu homelab ya tiene vida propia y te desprecia un poco.
En casa intento pelearme menos con esto. No porque tenga una teoría perfecta sobre bases de datos, sino porque ya he vivido suficientes despliegues donde el problema no era instalar la app. El problema era actualizarla, migrarla, restaurarla y entender qué demonios guardaba cada contenedor.
Mi criterio actual es bastante simple: uso SQLite cuando el servicio lo permite y el riesgo es bajo, PostgreSQL cuando los datos importan o la app lo espera de verdad, y MariaDB solo cuando el proyecto lo pide claramente o viene de un ecosistema que lo usa mejor. Lo demás suele ser ceremonia.
La base de datos también es parte del servicio#
Durante mucho tiempo traté la base de datos como un detalle de despliegue. La aplicación era “el servicio”. La base de datos era una carpeta más en el volumen. Mala idea.
En la práctica, la base de datos es donde vive lo importante: usuarios, sesiones, documentos, metadatos, índices, tareas, historial, etiquetas, configuraciones y estados internos. Si pierdes el contenedor, reinstalas. Si pierdes la base de datos, igual has perdido el servicio entero.
Por eso ya no miro solo si una aplicación arranca. Antes de meterla en casa me hago estas preguntas:
- ¿Qué datos va a guardar?
- ¿Me importaría perderlos?
- ¿La app permite exportar de forma limpia?
- ¿La base de datos se puede respaldar sin parar todo?
- ¿Voy a querer mover este servicio a otro servidor?
- ¿La aplicación tiene migraciones frecuentes?
Si la respuesta es “me da igual perderlo”, puedo ser más flexible. Un panel de enlaces, una app de pruebas o una herramienta interna que puedo recrear en diez minutos no necesita una arquitectura de banco. Si hablamos de documentos, fotos, contraseñas, automatizaciones o histórico familiar, cambio el chip.
Esto conecta mucho con el artículo de qué servicios self-hosted merece la pena mantener. No todos los servicios merecen el mismo nivel de cariño. Pero los que lo merecen, lo merecen también en la base de datos.
SQLite: la opción aburrida que cada vez respeto más#
SQLite tiene una ventaja enorme para homelab: suele ser un archivo. Un archivo que puedes copiar, respaldar, mover y entender sin montar una novela rusa.
Para servicios pequeños, SQLite me parece fantástico. Menos contenedores, menos credenciales, menos dependencias, menos puntos de fallo. Si una aplicación guarda su estado en un archivo SQLite y no tiene mucha concurrencia, muchas veces prefiero eso antes que levantar PostgreSQL solo porque queda más serio.
Casos donde SQLite me encaja bien:
- Herramientas personales con uno o pocos usuarios.
- Dashboards internos.
- Lectores RSS pequeños.
- Gestores de enlaces.
- Aplicaciones donde puedo exportar los datos fácilmente.
- Servicios que no son críticos para la casa.
La restauración también suele ser más limpia. Paras el servicio, restauras el archivo, levantas y compruebas. No hay roles, schemas, permisos, extensiones ni versiones del motor dando la lata.
Pero SQLite no es magia. Tiene límites. No me gusta para servicios con mucha escritura concurrente, colas intensas, varios usuarios activos a la vez o datos que crecen sin parar. Tampoco me gusta cuando la propia aplicación trata SQLite como opción de desarrollo y recomienda PostgreSQL para producción. Ahí no me hago el listo.
El error habitual es pensar que SQLite es “poco profesional”. No lo es. Lo poco profesional es usar una base de datos más compleja para una app que no la necesita y luego no tener ni idea de cómo restaurarla.
PostgreSQL: mi opción por defecto cuando los datos importan#
PostgreSQL es la base de datos que más uso cuando un servicio va en serio. No porque sea moderna, ni porque quede bien en el compose, sino porque es predecible, está muy soportada y tiene herramientas decentes para backup y restauración.
Si una app soporta PostgreSQL de primera clase y va a guardar datos que me importan, normalmente no le doy muchas vueltas. Paperless-ngx, servicios con usuarios, automatizaciones, apps con búsquedas, colas, históricos o metadatos delicados suelen encajar mejor aquí.
Lo que me gusta de PostgreSQL en homelab:
- Las copias con
pg_dumpson fáciles de automatizar. - La restauración es entendible incluso meses después.
- Hay buen soporte en la mayoría de servicios modernos.
- Es estable con migraciones frecuentes.
- Permite separar bases por servicio sin montar un motor por cada app.
La última parte es importante. No siempre levanto un PostgreSQL por servicio. En servicios pequeños puedo tener una instancia compartida con una base y usuario por aplicación. Eso reduce contenedores y consumo, aunque exige más disciplina. Si ese PostgreSQL compartido cae, caen varias apps. Si lo actualizo mal, también. Nada es gratis, señor Wayne.
Para servicios críticos prefiero una instancia dedicada o, como mínimo, backups muy claros por base. No quiero que una restauración de una app secundaria me obligue a tocar la base de datos de algo importante.
Mi regla práctica:
- Servicio crítico o con datos difíciles de recrear: PostgreSQL dedicado o backup separado muy probado.
- Servicio medio: PostgreSQL compartido con usuario y base separados.
- Servicio prescindible: SQLite si está soportado bien.
Esto no es dogma. Es una forma de reducir sorpresas.
MariaDB: útil, pero no lo elijo por inercia#
MariaDB y MySQL siguen apareciendo en muchas guías. Hay aplicaciones que los usan bien y no tiene sentido pelearse con el proyecto. Si una app está pensada para MariaDB, la uso. Punto.
Lo que intento evitar es levantar MariaDB por costumbre cuando PostgreSQL o SQLite encajan mejor. En mi experiencia, muchas instalaciones antiguas de homelab arrastran MySQL o MariaDB porque era lo que usaba Nextcloud, WordPress o media internet hace años. No pasa nada. Funciona. Pero si empiezo un servicio nuevo, no lo elijo automáticamente.
MariaDB me encaja cuando:
- La documentación oficial lo recomienda.
- El proyecto tiene más trayectoria con MySQL que con PostgreSQL.
- Ya tengo un stack de esa familia y quiero mantenerlo junto.
- Migrar a otra base de datos aportaría cero.
Lo que no hago es mezclar motores sin pensar. Si tengo cinco servicios nuevos y tres pueden usar PostgreSQL, uno SQLite y otro MariaDB, no intento forzarlos todos al mismo molde. Pero tampoco quiero acabar con una colección absurda de motores porque cada tutorial pegó un bloque distinto.
En un homelab pequeño, cada motor adicional es una cosa más que actualizar, respaldar, monitorizar y recordar.
Base compartida o base por servicio#
Aquí hay dos escuelas. Una dice que cada servicio debe tener su propio motor de base de datos en su docker compose. La otra dice que deberías tener un PostgreSQL central y crear bases por aplicación.
Las dos tienen razón en contextos distintos.
Un motor por servicio da aislamiento. Si actualizas una app, su base va con ella. Si rompes algo, el daño queda más contenido. El compose es portátil y fácil de entender. Para servicios serios o raros, me gusta.
Un motor compartido reduce duplicación. Menos RAM, menos contenedores, menos jobs de backup, menos versiones distintas. Para servicios pequeños que usan PostgreSQL de forma estándar, también me gusta.
El problema del motor compartido es que se convierte en infraestructura crítica aunque al principio no lo parezca. Un día ese PostgreSQL tiene cinco bases. Luego diez. Luego no sabes qué puedes reiniciar sin tirar media casa. Si vas por esa ruta, hay que documentarlo.
Mi punto intermedio:
- Un PostgreSQL compartido para servicios secundarios y homogéneos.
- Bases, usuarios y permisos separados por servicio.
- Backups por base, no solo del volumen entero.
- Una nota con qué servicio usa qué base.
- Motores dedicados para servicios grandes o delicados.
No es perfecto. Es manejable.
Backups: copiar el volumen no siempre basta#
Este es el punto donde muchas guías hacen daño. Copiar el volumen de una base de datos en caliente puede funcionar. También puede dejarte una copia inconsistente. Depende del motor, del estado de escritura y de la suerte, que no es una estrategia.
Para SQLite, muchas veces basta con parar la app o usar el mecanismo de backup correcto si la aplicación lo permite. Para PostgreSQL, prefiero pg_dump por base cuando quiero una copia lógica restaurable. Para MariaDB, lo mismo con mysqldump o herramientas más específicas si el tamaño lo justifica.
Además de la copia, quiero una prueba de restauración. No todos los días. Pero sí alguna vez antes de confiar en el sistema. Un backup que nunca has restaurado es una promesa de político.
Mi checklist mínimo para una base de datos self-hosted:
- Backup lógico programado.
- Retención clara.
- Copia fuera del servidor principal.
- Prueba de restauración en una carpeta o instancia temporal.
- Nota corta con el comando de restauración.
Si el servicio guarda datos familiares o documentos, subo el nivel. Ahí quiero más de una copia y prefiero que la restauración esté documentada en un runbook. Ya conté esa filosofía en runbooks caseros para homelab, y con bases de datos se nota mucho.
Migraciones y actualizaciones#
Las bases de datos suelen doler durante actualizaciones. No siempre por el motor. Muchas veces por la aplicación.
Un contenedor nuevo arranca, detecta una versión antigua, aplica migraciones y cambia tablas. Si todo va bien, ni te enteras. Si algo falla, puedes quedarte con la app a medias y la base en un estado que la versión anterior ya no entiende.
Por eso hago tres cosas antes de actualizar servicios con base de datos:
- Backup lógico reciente.
- Snapshot o copia del volumen si el servicio lo permite.
- Lectura rápida de notas de versión cuando hay salto grande.
No necesito convertir cada actualización en una auditoría. Pero si el servicio guarda datos que no quiero perder, no actualizo a ciegas.
También intento evitar versiones latest en servicios serios. Es cómodo hasta que deja de serlo. Prefiero fijar versiones, actualizar con intención y saber qué cambió. En herramientas de laboratorio puedo ser más relajado. En algo que usa la casa, no.
Cómo lo aplicaría en un homelab pequeño#
Si empezara un homelab doméstico hoy, mi regla sería esta:
Primero, SQLite siempre que la aplicación lo soporte bien y los datos sean simples. Menos piezas. Menos ruido.
Segundo, PostgreSQL para servicios con datos importantes, usuarios, búsquedas o crecimiento. Una instancia compartida al principio puede estar bien, pero con bases y usuarios separados desde el primer día.
Tercero, MariaDB cuando el proyecto lo pida de forma natural. No por herencia, no porque una guía antigua lo use, no porque sí.
Cuarto, backups lógicos desde el principio. No “ya lo haré cuando tenga datos”. Cuando tiene datos suele ser tarde y da pereza tocar lo que funciona.
Quinto, documentación mínima. Una tabla sencilla:
| Servicio | Motor | Base | Backup | Restauración probada |
|---|---|---|---|---|
| Documentos | PostgreSQL | documentos | diario | sí |
| Enlaces | SQLite | archivo local | diario | sí |
| Recetas | SQLite o PostgreSQL | recetas | semanal | pendiente |
| Automatización | PostgreSQL | automatizacion | diario | sí |
No hace falta montar una consultora. Hace falta que dentro de tres meses sepas qué tienes.
Mi conclusión#
En self-hosting, elegir base de datos no va de demostrar nivel técnico. Va de dormir mejor.
SQLite es una maravilla cuando quieres simplicidad real. PostgreSQL es mi elección cuando los datos importan y necesito una ruta clara de backup, migración y restauración. MariaDB sigue teniendo su sitio, pero no lo uso por inercia.
La peor decisión suele ser no decidir. Copiar compose tras compose, dejar que cada servicio traiga su base, no apuntar nada y esperar que el día de restaurar te acuerdes. Spoiler: no te acuerdas.
Un homelab bueno no es el que tiene la base de datos más impresionante. Es el que puedes mover, respaldar y reparar sin sentir que estás desactivando una bomba con sueño.