Grafana Loki es un sistema de agregación de logs que indexa solo un pequeño conjunto de etiquetas de cada flujo de logs y guarda las líneas en sí como bloques comprimidos (chunks). Ese diseño mantiene los requisitos de almacenamiento y memoria muy por debajo de los motores de búsqueda de texto completo, a cambio de depender de las etiquetas y de filtrar en el momento de la consulta. En este tutorial instalarás Loki 3 en Ubuntu 24.04 desde el repositorio APT oficial de Grafana, lo configurarás como binario único con almacenamiento local y una retención de 30 días, le enviarás los logs de journald del servidor con Grafana Alloy y los consultarás con LogQL.
Requisitos previos
Para seguir esta guía necesitas:
- Un servidor con Ubuntu 24.04 LTS y al menos 2 GB de RAM, por ejemplo un VPS de CubePath.
- Un usuario no root con privilegios
sudoy UFW activado con SSH permitido. - Espacio en disco suficiente para tu volumen de logs. Como referencia, Loki guarda los logs comprimidos a una décima parte aproximada de su tamaño original.
curlyjqinstalados (sudo apt install -y curl jq).
Esta guía cubre el servidor Loki. Para añadir encima paneles de Grafana, pipelines de procesado de logs y alertas, sigue después la guía de configuración completa de Grafana, Loki y Alloy de esta misma sección.
Paso 1: Añadir el repositorio APT de Grafana
Grafana Labs publica Loki, Alloy y Grafana como paquetes Debian en un repositorio firmado. Instala las herramientas necesarias para descargar la clave de firma:
sudo apt update
sudo apt install -y gpg wget
Descarga la clave en /etc/apt/keyrings y añade el repositorio, limitado a esa clave:
sudo mkdir -p /etc/apt/keyrings
wget -q -O - https://apt.grafana.com/gpg.key | gpg --dearmor | sudo tee /etc/apt/keyrings/grafana.gpg > /dev/null
echo "deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com stable main" | sudo tee /etc/apt/sources.list.d/grafana.list
sudo apt update
Comprueba que apt ve el paquete de Loki en el nuevo repositorio:
apt-cache policy loki
loki:
Installed: (none)
Candidate: 3.x.x
Version table:
3.x.x 500
500 https://apt.grafana.com stable/main amd64 Packages
Paso 2: Instalar Loki
Instala el paquete:
sudo apt install -y loki
El paquete crea un usuario de sistema loki, instala el binario en /usr/bin/loki, una configuración de ejemplo en /etc/loki/config.yml y una unidad de systemd loki que lee ese archivo. La configuración de ejemplo guarda los datos en /tmp, que se vacía al reiniciar, así que la sustituirás en el siguiente paso.
Crea un directorio de datos persistente propiedad del usuario del servicio:
sudo mkdir -p /var/lib/loki
sudo chown loki:loki /var/lib/loki
Paso 3: Configurar el almacenamiento, el esquema y la retención
Haz una copia del archivo de ejemplo y abre la configuración:
sudo cp /etc/loki/config.yml /etc/loki/config.yml.orig
sudo nano /etc/loki/config.yml
Sustituye su contenido por esta configuración para un único nodo:
auth_enabled: false
server:
http_listen_port: 3100
grpc_listen_port: 9096
log_level: info
common:
instance_addr: 127.0.0.1
path_prefix: /var/lib/loki
storage:
filesystem:
chunks_directory: /var/lib/loki/chunks
rules_directory: /var/lib/loki/rules
replication_factor: 1
ring:
kvstore:
store: inmemory
schema_config:
configs:
- from: 2024-04-01
store: tsdb
object_store: filesystem
schema: v13
index:
prefix: index_
period: 24h
limits_config:
retention_period: 720h
compactor:
working_directory: /var/lib/loki/compactor
retention_enabled: true
retention_delete_delay: 2h
delete_request_store: filesystem
analytics:
reporting_enabled: false
Qué hace cada bloque:
auth_enabled: falseejecuta Loki en modo de un solo inquilino. Los clientes no tienen que enviar la cabeceraX-Scope-OrgID.commondefine rutas compartidas por todos los componentes, yinmemorypara el anillo de hash, que es lo correcto con una sola instancia.schema_configusa el índicetsdby el esquemav13, la combinación recomendada actualmente. La fechafromdebe estar en el pasado en una instalación nueva. No edites nunca una entrada de esquema existente; para cambiarlo más adelante se añade una entrada nueva con una fechafromfutura.limits_config.retention_period: 720hconserva los logs 30 días.- El
compactorfusiona los archivos de índice y, conretention_enabled, borra de verdad los chunks más antiguos que el periodo de retención. Sin él,retention_periodno tiene efecto. analytics.reporting_enabled: falsedesactiva el envío anónimo de estadísticas de uso a Grafana Labs.
Comprueba la configuración antes de arrancar el servicio:
sudo -u loki /usr/bin/loki -config.file=/etc/loki/config.yml -verify-config
level=info ... msg="config is valid"
Paso 4: Iniciar Loki
Activa el servicio y reinícialo para que cargue el nuevo archivo:
sudo systemctl enable loki
sudo systemctl restart loki
sudo systemctl status loki
● loki.service - Loki service
Loaded: loaded (/usr/lib/systemd/system/loki.service; enabled; preset: enabled)
Active: active (running)
Loki tarda unos 15 segundos tras arrancar en estar listo. Consulta el endpoint de disponibilidad:
curl -s http://localhost:3100/ready
ready
Si responde Ingester not ready: waiting for 15s after being ready, espera unos segundos y vuelve a probar.
Envía una línea de prueba por la API HTTP. Las marcas de tiempo son época Unix en nanosegundos, que es lo que produce date +%s%N:
curl -s -X POST http://localhost:3100/loki/api/v1/push \
-H "Content-Type: application/json" \
--data-raw "{\"streams\":[{\"stream\":{\"job\":\"test\"},\"values\":[[\"$(date +%s%N)\",\"hola desde curl\"]]}]}"
Un envío correcto devuelve HTTP 204 con el cuerpo vacío. Léela con una consulta LogQL sobre la última hora, que es el rango por defecto de query_range:
curl -s -G http://localhost:3100/loki/api/v1/query_range --data-urlencode 'query={job="test"}' | jq -r '.data.result[].values[][1]'
hola desde curl
Paso 5: Enviar el journal del sistema con Grafana Alloy
Loki solo guarda lo que los clientes le envían. Grafana Alloy es el recolector que recomienda Grafana para Loki; sustituye a Promtail, que llegó al final de su vida útil en 2026 y ya no recibe actualizaciones. Instálalo desde el mismo repositorio:
sudo apt install -y alloy
Alloy se ejecuta con el usuario alloy. Añádelo al grupo systemd-journal para que pueda leer el journal, y a adm para que pueda leer más adelante archivos de /var/log:
sudo usermod -aG systemd-journal,adm alloy
Abre la configuración de Alloy:
sudo nano /etc/alloy/config.alloy
Sustituye su contenido por este pipeline, que lee el journal, convierte el nombre de la unidad de systemd en una etiqueta unit y lo envía todo a Loki:
loki.relabel "journal" {
forward_to = []
rule {
source_labels = ["__journal__systemd_unit"]
target_label = "unit"
}
rule {
source_labels = ["__journal_priority_keyword"]
target_label = "level"
}
}
loki.source.journal "system" {
max_age = "12h"
relabel_rules = loki.relabel.journal.rules
labels = { job = "systemd-journal", host = constants.hostname }
forward_to = [loki.write.local.receiver]
}
loki.write "local" {
endpoint {
url = "http://127.0.0.1:3100/loki/api/v1/push"
}
}
Los campos __journal_* solo existen durante el reetiquetado y se descartan después, así que a Loki solo llegan las etiquetas que copias (unit, level) más las estáticas job y host. Limita las etiquetas a valores de baja cardinalidad como estos; nunca conviertas en etiquetas identificadores de petición, de usuario ni direcciones IP.
Activa Alloy y reinícialo:
sudo systemctl enable alloy
sudo systemctl restart alloy
sudo journalctl -u alloy -n 20 --no-pager
El log debería mostrar los componentes arrancando sin líneas level=error. Pasados unos segundos, lista las etiquetas que ha recibido Loki:
curl -s http://localhost:3100/loki/api/v1/labels | jq
{
"status": "success",
"data": [
"host",
"job",
"level",
"service_name",
"unit"
]
}
Loki añade service_name automáticamente a partir de las demás etiquetas, para usarla en las vistas de exploración de logs de Grafana.
Paso 6: Consultar los logs con LogQL
Una consulta LogQL empieza siempre con un selector de flujos entre llaves, que usa el índice para elegir flujos por etiqueta, seguido de filtros opcionales que se aplican a las líneas. Define una pequeña función para lanzar consultas desde la shell:
logq() { curl -s -G http://localhost:3100/loki/api/v1/query_range --data-urlencode "query=$1" --data-urlencode "limit=${2:-20}" | jq -r '.data.result[].values[][1]'; }
Muestra las últimas líneas de log de SSH:
logq '{job="systemd-journal", unit="ssh.service"}'
Quédate solo con los intentos de acceso fallidos usando un filtro de línea. |= significa "contiene", != "no contiene" y |~ aplica una expresión regular:
logq '{unit="ssh.service"} |= "Failed password"'
logq '{job="systemd-journal"} |~ "(?i)error|fail"' 50
Las consultas de métricas convierten los logs en números. Esta cuenta las líneas de log por unidad en los últimos 5 minutos y usa el endpoint instantáneo query:
curl -s -G http://localhost:3100/loki/api/v1/query \
--data-urlencode 'query=sum by (unit) (count_over_time({job="systemd-journal"}[5m]))' \
| jq -r '.data.result[] | "\(.value[1])\t\(.metric.unit)"' | sort -rn | head
42 cron.service
18 ssh.service
7 alloy.service
Las mismas consultas funcionan sin cambios en la vista Explore de Grafana en cuanto añades Loki como origen de datos.
Paso 7: Recibir logs de otros servidores
Para centralizar los logs, instala Alloy en cada servidor con la misma configuración y cambia la URL de loki.write a http://your_loki_server_ip:3100/loki/api/v1/push.
Con auth_enabled: false, Loki no tiene autenticación, así que no expongas nunca el puerto 3100 a Internet. Permítelo solo desde los servidores que envían logs, con una regla por IP de origen:
sudo ufw allow from client_server_ip to any port 3100 proto tcp
Para clientes fuera de una red privada, coloca Loki detrás de un proxy inverso con TLS y autenticación básica, y añade un bloque basic_auth al endpoint del loki.write de cada cliente.
Solución de problemas
systemctl status loki muestra que se reinicia en bucle. Ejecuta sudo journalctl -u loki -n 50 --no-pager. Las causas habituales son un error de sangrado en el YAML, o permission denied en /var/lib/loki si el directorio no pertenece a loki.
Los envíos se rechazan con entry too far behind o timestamp too old. Por defecto Loki rechaza muestras de más de una semana. Reduce max_age en loki.source.journal si el journal es más antiguo.
Alloy registra permission denied al leer el journal. El cambio de grupo solo se aplica al reiniciar el servicio. Compruébalo con id alloy y reinicia Alloy.
Los logs antiguos no se borran. Confirma que retention_enabled: true y delete_request_store están en el bloque compactor. El borrado ocurre tras el ciclo de compactación más retention_delete_delay, así que cuenta con un retraso de algunas horas.
Las consultas fallan con maximum of series (500) reached. La consulta selecciona demasiados flujos; acota el selector con más etiquetas.
Conclusión
Tienes una instancia de Loki 3 de un solo nodo en Ubuntu 24.04 que guarda los logs en el disco local, los borra a los 30 días y recibe el journal del sistema a través de Grafana Alloy, con LogQL disponible por la API HTTP.
A partir de aquí puedes añadir Grafana para explorar y graficar los logs, procesar logs de aplicaciones como los de acceso de Nginx para extraer campos con las etapas loki.process de Alloy y mover el almacenamiento de chunks a un bucket compatible con S3 cuando el volumen supere lo que cabe en un disco local.
