Por qué centralizar sus logs en un VPS en lugar de seguir con SSH
Cuando un error afecta a varios servicios de forma simultánea — un timeout del lado de la aplicación, un 502 del lado de nginx, una excepción en un worker — ninguna herramienta SSH permite correlacionar esos eventos sin leerlos uno por uno. docker compose logs -f app, luego docker compose logs -f nginx, luego docker compose logs -f worker: es el diagnóstico en serie, sobre un solo servidor. Con dos VPS, la duración se duplica. Con tres, se triplica.
Loki es un sistema de agregación de logs de código abierto desarrollado por Grafana Labs y listado en el catálogo de la CNCF. A diferencia de Elasticsearch, que indexa la totalidad del contenido de cada línea, Loki solo indexa los labels — metadatos ligeros como el nombre del contenedor, el nombre del servicio o el entorno. Los logs en sí se comprimen y se almacenan tal cual. Esta decisión de diseño tiene una consecuencia directa: Loki funciona con holgura en un VPS de 2 GB de RAM, allí donde una stack ELK básica exige al menos entre 8 y 16 GB para mantenerse estable. Para un desarrollador o un sysadmin que gestiona varias aplicaciones autoalojadas sin presupuesto de APM enterprise, esa es la diferencia entre una solución viable y una solución poco realista.
Lo que esta stack aporta en concreto
- Búsqueda unificada en todos los contenedores — una sola consulta LogQL cubre el conjunto de los servicios en todos sus VPS, sin SSH ni
grepdistribuido. - Correlación temporal — Grafana muestra Loki (logs) y Prometheus (métricas) en el mismo eje de tiempo: usted ve el error 502 y el pico de CPU que lo precedió en una sola vista.
- Sin cuota de ingesta — almacena tantos logs como se lo permita su disco, sin suscripción ni límite mensual impuesto por un tercero.
- Huella de memoria contenida — Loki consume claramente menos RAM que Elasticsearch con un volumen de logs equivalente, gracias a la indexación únicamente por labels.
- Retención configurable — defina la duración de conservación por label (
chunk_retain_period,retention_period) según sus limitaciones de disco y de cumplimiento. - Integración nativa con Grafana — Loki es una fuente de datos de primera clase en Grafana: sin plugin de terceros, sin API intermedia.
- Alertas sobre el contenido de los logs — Grafana puede lanzar una alerta cuando una expresión regular coincide en un flujo Loki, sin pasar por un servicio externo.
- Datos alojados en su infraestructura — los logs permanecen en su VPS, sin transitar por un servicio en la nube.
Requisitos previos antes de desplegar
La stack Loki + Promtail + Grafana es ligera, pero tiene sus propias exigencias. Esto es lo que necesita antes de empezar.
Recursos VPS recomendados: 2 vCPU y 2 GB de RAM son el mínimo razonable para un uso en un solo servidor con algunas decenas de contenedores activos. Si recopila los logs de varios VPS o de un gran número de servicios, apunte a 4 GB de RAM. Loki no mantiene los logs en memoria: los comprime y los escribe en disco, lo que mantiene la huella de memoria estable en el tiempo. Prevea entre 20 y 50 GB de almacenamiento SSD según su volumen de logs y su duración de retención.
Software necesario: Docker y Docker Compose v2 instalados en el VPS, un subdominio dedicado (logs.su-dominio.com) apuntando a la IP del VPS, y los puertos 3100 (Loki) y 3000 (Grafana) accesibles internamente. El puerto 3100 no debe exponerse públicamente — Loki no tiene capa de autenticación nativa, solo Grafana se expone mediante reverse proxy.
Despliegue paso a paso
Crear la estructura de directorios
Conéctese a su VPS y cree un directorio dedicado:
mkdir -p /opt/loki-stack/{loki,promtail} && cd /opt/loki-stack. Esta carpeta alojará los archivos de configuración de Loki y de Promtail, así como eldocker-compose.yml.Escribir la configuración de Loki
Cree
/opt/loki-stack/loki/loki-config.yamlcon el contenido siguiente:auth_enabled: false— desactiva la autenticación multi-tenant, suficiente para un uso en un solo VPS.server: { http_listen_port: 3100 }ingester: { lifecycler: { address: 127.0.0.1, ring: { kvstore: { store: inmemory }, replication_factor: 1 } }, chunk_idle_period: 5m, chunk_retain_period: 30s }schema_config: { configs: [ { from: 2020-10-24, store: boltdb-shipper, object_store: filesystem, schema: v11, index: { prefix: index_, period: 24h } } ] }storage_config: { boltdb_shipper: { active_index_directory: /loki/boltdb-shipper-active, cache_location: /loki/boltdb-shipper-cache, shared_store: filesystem }, filesystem: { directory: /loki/chunks } }limits_config: { retention_period: 720h }Escribir la configuración de Promtail
Cree
/opt/loki-stack/promtail/promtail-config.yaml. Promtail es el agente que recopila los logs de los contenedores Docker y los envía a Loki:server: { http_listen_port: 9080, grpc_listen_port: 0 }positions: { filename: /tmp/positions.yaml }clients: [ { url: http://loki:3100/loki/api/v1/push } ]scrape_configs: [ { job_name: docker, docker_sd_configs: [ { host: unix:///var/run/docker.sock, refresh_interval: 5s } ], relabel_configs: [ { source_labels: ['__meta_docker_container_name'], regex: '/(.*)', target_label: container }, { source_labels: ['__meta_docker_container_log_stream'], target_label: stream } ] } ]Esta configuración utiliza el descubrimiento automático de Docker (
docker_sd_configs), que detecta cada contenedor arrancado sin intervención manual.Escribir el archivo docker-compose.yml
Cree
/opt/loki-stack/docker-compose.yml:version: '3.8'services:
loki:image: grafana/loki:3.0.0ports: ['127.0.0.1:3100:3100']volumes: [loki-data:/loki, ./loki/loki-config.yaml:/etc/loki/local-config.yaml]command: -config.file=/etc/loki/local-config.yamlrestart: unless-stoppedpromtail:image: grafana/promtail:3.0.0volumes: [/var/run/docker.sock:/var/run/docker.sock:ro, ./promtail/promtail-config.yaml:/etc/promtail/config.yml, /var/log:/var/log:ro]command: -config.file=/etc/promtail/config.ymlrestart: unless-stoppeddepends_on: [loki]grafana:image: grafana/grafana:latestports: ['127.0.0.1:3000:3000']volumes: [grafana-data:/var/lib/grafana]environment: [GF_SECURITY_ADMIN_PASSWORD=cambie-esto]restart: unless-stoppeddepends_on: [loki]volumes:loki-data:grafana-data:Observe que Loki (
3100) y Grafana (3000) están enlazados únicamente en127.0.0.1— no son directamente accesibles desde el exterior.Arrancar la stack
Desde
/opt/loki-stack, ejecute:docker compose up -d. Espere entre 20 y 30 segundos y compruebe que los tres contenedores están en ejecución:docker compose ps. Revise después los logs de Loki para confirmar que ha arrancado sin errores:docker compose logs -f loki. Debe ver una líneamsg="Loki started"en la salida.Configurar el reverse proxy para Grafana
Exponga Grafana mediante nginx con un subdominio y un certificado TLS. Cree
/etc/nginx/sites-available/grafana.conf:server { listen 443 ssl; server_name logs.su-dominio.com; ssl_certificate /etc/letsencrypt/live/logs.su-dominio.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/logs.su-dominio.com/privkey.pem; location / { proxy_pass http://127.0.0.1:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }Obtenga el certificado con:
certbot certonly --nginx -d logs.su-dominio.com, y active después el sitio:ln -s /etc/nginx/sites-available/grafana.conf /etc/nginx/sites-enabled/ && nginx -t && systemctl reload nginx.Añadir Loki como fuente de datos en Grafana
Abra
https://logs.su-dominio.comen su navegador. Inicie sesión con el usuarioadminy la contraseña que definió enGF_SECURITY_ADMIN_PASSWORD. Vaya a Connections → Data sources → Add data source, elija Loki e indique la URL:http://loki:3100. Haga clic en Save & test — debe ver el mensajeData source connected and labels found.Consultar sus primeros logs
En Grafana, abra la pestaña Explore y seleccione la fuente Loki. Use el Log Browser para elegir un label
containery filtrar por nombre de contenedor. Por ejemplo, para ver todos los logs del contenedornginx:{container="nginx"}. Para filtrar por una cadena:{container="nginx"} |= "error". Para contar los errores por contenedor durante la última hora:sum by (container) (count_over_time({container=~".+"} |= "error" [1h])).Recopilar los logs de un segundo VPS
Para centralizar los logs de un segundo VPS en la misma instancia de Loki, despliegue únicamente Promtail en ese VPS secundario. En su configuración, sustituya la URL del cliente por la dirección interna de su primer VPS:
url: http://<IP-del-VPS-Loki>:3100/loki/api/v1/push. Abra el puerto 3100 únicamente entre los dos VPS (firewall o red privada), nunca públicamente. Añada un label estático para distinguir los logs por servidor:static_configs: [ { labels: { host: vps2 } } ].
Configuración posterior a la instalación: retención, copia de seguridad y alertas
Una vez arrancada la stack, hay tres ajustes importantes antes de dar el despliegue por completo.
Retención. El valor retention_period: 720h de loki-config.yaml corresponde a 30 días. Ajuste este parámetro según el disco disponible (docker system df para conocer la ocupación de los volúmenes). Loki aplica la retención en segundo plano, sin impacto apreciable en el rendimiento.
Copia de seguridad. El volumen loki-data contiene los índices BoltDB y los chunks comprimidos — es el único elemento que hay que respaldar. Una instantánea diaria del volumen Docker (docker run --rm -v loki-data:/data -v /backup:/backup alpine tar czf /backup/loki-$(date +%F).tar.gz /data) basta para un uso estándar. No respalde Grafana sin su volumen grafana-data (contiene sus dashboards y sus alertas).
Alertas sobre el contenido de los logs. En Grafana, cree una alerta de tipo Grafana managed alert sobre una consulta Loki: por ejemplo, lanzar una notificación cuando el número de líneas que contienen FATAL supere 0 en los últimos 5 minutos. Configure un canal de notificación (correo electrónico, Slack, webhook) en Alerting → Contact points antes de crear la regla.
Loki no expone ningún mecanismo de autenticación nativo en el puerto 3100. Si necesita exponer la API de Loki a una red que no controla (para Promtail remotos, por ejemplo), coloque delante un reverse proxy nginx con autenticación por certificado de cliente o basic auth. Nunca deje el puerto 3100 abierto en 0.0.0.0 en un VPS en producción. Del lado de Grafana, active la autenticación estricta: GF_AUTH_ANONYMOUS_ENABLED=false y GF_USERS_ALLOW_SIGN_UP=false en las variables de entorno del contenedor.
Solución de problemas: errores frecuentes y su resolución
Estos son los problemas más habituales durante el despliegue de la stack Loki + Promtail + Grafana.
Errores frecuentes
msg="error creating ingester" err="context deadline exceeded"al arrancar Loki — el contenedor Loki no tiene acceso de escritura al volumen montado. Compruebe los permisos del directorio correspondiente al volumen Docker (docker inspect loki-datapara encontrar la ruta real) y asegúrese de que el usuario del contenedor (UID 10001 en las imágenes Grafana recientes) puede escribir en él:chown -R 10001:10001 /ruta/al/volumen.Data source connected and labels foundno aparece en Grafana y se sustituye porconnection refused— Grafana no consigue alcanzar Loki. Compruebe que la URL indicada en la fuente de datos seahttp://loki:3100(nombre del servicio Docker, nolocalhost) y que ambos contenedores estén en la misma red Docker (docker inspect loki-grafana-stack_default).- Promtail no recopila ningún log y
docker compose logs -f promtailmuestracomponent=discovery.docker msg="refreshing targets"en bucle sin avanzar — Promtail no tiene acceso al socket de Docker. Compruebe que el volumen/var/run/docker.sock:/var/run/docker.sock:roesté declarado en el servicio Promtail y que el socket exista en el host:ls -la /var/run/docker.sock. err="entry out of order for stream"en los logs de Loki — llegan logs con marcas de tiempo desordenadas (un contenedor reiniciado que reenvía logs antiguos, por ejemplo). Añadamax_stream_label_count: 0enlimits_configyunordered_writes: trueeningesterdeloki-config.yamlpara aceptar las entradas fuera de secuencia.- Grafana muestra
no dataen una consulta LogQL que sin embargo es válida — compruebe primero el rango de tiempo seleccionado en la parte superior derecha (la trampa más habitual: rango fijado enlast 5 minutescuando Promtail todavía no ha recopilado logs recientes). Compruebe después que el label usado en su consulta existe realmente:{container="nginx"}falla si el contenedor se llamanginx-1— use el Log Browser para explorar los labels disponibles.
Un panel para correlacionar logs y métricas
El principal interés de Loki en un entorno Grafana ya existente es la correlación con las métricas de Prometheus. Si ya dispone de una fuente Prometheus (véase el artículo sobre la monitorización de un VPS con Grafana y Prometheus), puede crear un dashboard mixto: una fila de paneles de métricas (CPU, memoria, tasa de peticiones HTTP) arriba, y un panel de logs Loki filtrado por el mismo servicio abajo. Cuando aparece un pico de CPU a las 14:37, usted ve de inmediato qué logs se emitieron en ese instante preciso, sin cambiar de herramienta ni volver a lanzar un comando SSH. Este tipo de correlación es el caso de uso que justifica desplegar ambas stacks en lugar de una u otra: Prometheus para «lo que se mide», Loki para «lo que se cuenta».
Loki frente a ELK y a los logs por SSH: qué enfoque para cada caso
Desplace la tabla
| Criterio | SSH + docker logs | Stack ELK (Elastic) | Loki + Grafana |
|---|---|---|---|
| RAM necesaria | Ninguna (sin servicio) | 8–16 GB mínimo por nodo | 2–4 GB para un VPS estándar |
| Indexación | Ninguna | Indexación full-text (Elasticsearch) | Indexación solo por labels |
| Búsqueda multiservidor | Imposible sin script | Sí, de forma nativa | Sí, con Promtail en varios hosts |
| Correlación con métricas | Manual | Con Kibana + APM (complejo) | Nativa en Grafana |
| Coste de software | Nulo | Licencia Basic gratuita, funcionalidades limitadas | Totalmente open source, sin cuota |
Lo que acaba de poner en órbita
Ahora dispone de una stack de agregación de logs operativa: Loki almacena e indexa por labels, Promtail recopila automáticamente los flujos de todos sus contenedores Docker, y Grafana ofrece una interfaz de búsqueda y de alerta. La stack funciona íntegramente en su VPS, sin servicio de terceros, sin cuota de ingesta y sin coste de software adicional.
Los siguientes pasos naturales: conectar esta stack a su monitorización Prometheus existente para la correlación métricas/logs, activar el trazado distribuido con Tempo si sus aplicaciones emiten trazas OpenTelemetry, y explorar las alertas de Grafana sobre el contenido de los logs para recibir un aviso antes de que sus usuarios señalen un problema.