Fluentd es un recolector de logs de código abierto que lee eventos de muchas fuentes, los transforma y los envía a uno o varios destinos. Todo lo que hace se basa en plugins: de entrada (source), de filtrado (filter) y de salida (match). En este tutorial instalarás Fluentd en Ubuntu 24.04 con el paquete oficial fluent-package, aprenderás a instalar y comprobar plugins, y montarás un pipeline que lee el log de acceso de Nginx, lo enriquece, descarta el ruido y lo envía a Elasticsearch con un buffer en disco.

Requisitos previos

  • Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath, con un usuario no root con privilegios sudo.
  • Al menos 1 GB de RAM.
  • Nginx instalado y sirviendo tráfico, para tener un log de acceso que recoger.
  • Opcional para el paso 6: un clúster de Elasticsearch accesible desde el servidor, un usuario con permiso de escritura en los índices fluentd-* y el certificado de su CA.

Paso 1: Instalar fluent-package

El proyecto Fluentd publica un script por distribución que añade su repositorio APT con la clave de firma e instala el paquete. Descárgalo en lugar de enviarlo directamente a la shell, para poder revisarlo antes:

curl -fsSL -o install-fluent-package.sh https://fluentd.cdn.cncf.io/sh/install-ubuntu-noble-fluent-package6-lts.sh
less install-fluent-package.sh

El script solo añade el repositorio en /etc/apt/sources.list.d/ y ejecuta apt install fluent-package. Si todo es correcto, ejecútalo:

sudo sh install-fluent-package.sh

Comprueba la versión y el estado del servicio:

fluentd --version
sudo systemctl status fluentd --no-pager
fluent-package 6.0.0 fluentd 1.19.0 (...)
● fluentd.service - fluentd: All in one package of Fluentd
     Loaded: loaded (/usr/lib/systemd/system/fluentd.service; enabled; preset: enabled)
     Active: active (running) since ...

El servicio se ejecuta con el usuario de sistema _fluentd, un detalle importante para los permisos de lectura de los logs.

Paso 2: Entender la estructura de la configuración

La configuración está en /etc/fluent/fluentd.conf y se compone de directivas:

DirectivaFunciónEjemplos de plugins
<source>Lee eventos y les asigna una etiqueta (tag)tail, http, syslog, forward
<filter patrón>Modifica o descarta eventos cuya etiqueta coinciderecord_transformer, grep, parser
<match patrón>Envía los eventos cuya etiqueta coincide a un destinoelasticsearch, file, s3, stdout

Los eventos recorren el archivo de arriba abajo: pasan por todos los filter que coinciden con su etiqueta y terminan en el primer match que coincida. Por eso los match genéricos (**) van siempre al final.

Paso 3: Gestionar plugins con fluent-gem

Los plugins de Fluentd son gemas de Ruby. fluent-package incluye su propio Ruby, así que los plugins se instalan con fluent-gem y no con el gem del sistema.

Lista los plugins que trae el paquete:

fluent-gem list | grep fluent-plugin
fluent-plugin-elasticsearch (...)
fluent-plugin-kafka (...)
fluent-plugin-opensearch (...)
fluent-plugin-prometheus (...)
fluent-plugin-record-modifier (...)
fluent-plugin-rewrite-tag-filter (...)
fluent-plugin-s3 (...)
fluent-plugin-systemd (...)
fluent-plugin-td (...)
fluent-plugin-webhdfs (...)

La lista exacta varía entre versiones. Si un plugin que necesitas no aparece, instálalo con sudo, porque las gemas se guardan en el directorio del paquete:

sudo fluent-gem install fluent-plugin-elasticsearch

Busca plugins en la lista oficial de fluentd.org/plugins o con fluent-gem search -r fluent-plugin-<nombre>. Tras instalar o actualizar un plugin, reinicia el servicio para que lo cargue:

sudo systemctl restart fluentd

Los plugins tail, http, record_transformer, grep, file y stdout que se usan a continuación forman parte del núcleo de Fluentd y no requieren instalación.

Paso 4: Dar acceso a los logs de Nginx

En Ubuntu, /var/log/nginx/access.log pertenece a www-data:adm con permisos 640. Añade el usuario _fluentd al grupo adm, que puede leer los logs del sistema:

sudo usermod -aG adm _fluentd

Comprueba que el usuario puede leer el archivo:

sudo -u _fluentd head -n 1 /var/log/nginx/access.log

Si ves una línea del log, el permiso es correcto. El cambio de grupo se aplica al servicio cuando lo reinicies en el siguiente paso.

Paso 5: Crear un pipeline de prueba con salida a stdout

Antes de enviar nada a Elasticsearch, comprueba que el parseo y los filtros hacen lo que esperas. La salida stdout escribe cada evento en el log de Fluentd.

Guarda una copia de la configuración de ejemplo y abre el archivo:

sudo cp /etc/fluent/fluentd.conf /etc/fluent/fluentd.conf.orig
sudo nano /etc/fluent/fluentd.conf

Sustituye su contenido por lo siguiente:

<system>
  log_level info
</system>

<source>
  @type tail
  path /var/log/nginx/access.log
  pos_file /var/log/fluent/nginx-access.pos
  tag nginx.access
  <parse>
    @type nginx
  </parse>
</source>

<filter nginx.access>
  @type grep
  <exclude>
    key path
    pattern /^\/(health|metrics)/
  </exclude>
</filter>

<filter nginx.access>
  @type record_transformer
  <record>
    hostname "#{Socket.gethostname}"
    service nginx
  </record>
</filter>

<match nginx.**>
  @type stdout
</match>

Qué hace cada bloque:

  • tail sigue el archivo como tail -F, y guarda en pos_file hasta dónde ha leído para continuar tras un reinicio. El parser nginx entiende el formato combined por defecto de Nginx y genera campos como remote, method, path, code y agent.
  • El primer filtro grep descarta las peticiones a /health y /metrics, que suelen ser ruido de sondas.
  • record_transformer añade el nombre del servidor y un campo service a cada evento. La expresión #{...} se evalúa una sola vez al cargar la configuración.

Valida la sintaxis sin arrancar el pipeline:

sudo fluentd --dry-run -c /etc/fluent/fluentd.conf

La última línea debe ser finished dry run mode. Reinicia el servicio:

sudo systemctl restart fluentd

Genera una petición normal y otra a /health:

curl -s http://localhost/ > /dev/null
curl -s http://localhost/health > /dev/null

Mira el log de Fluentd:

sudo tail -n 5 /var/log/fluent/fluentd.log
2026-09-25 10:12:03.000000000 +0000 nginx.access: {"remote":"127.0.0.1","host":"-","user":"-","method":"GET","path":"/","code":"200","size":"615","referer":"-","agent":"curl/8.5.0","hostname":"web01","service":"nginx"}

Solo aparece la petición a /: la de /health ha sido descartada por el filtro.

Paso 6: Enviar los eventos a Elasticsearch con buffer en disco

Con el pipeline validado, sustituye la salida stdout por el plugin elasticsearch. Guarda la contraseña del usuario de Elasticsearch en un archivo de entorno que solo root pueda leer, en lugar de escribirla en la configuración:

sudo install -d -m 0755 /etc/systemd/system/fluentd.service.d
sudo nano /etc/fluent/es.env

Añade la contraseña. Sustituye your_strong_password por la real:

ES_PASSWORD=your_strong_password

Protege el archivo y crea un override del servicio que lo cargue:

sudo chmod 600 /etc/fluent/es.env
sudo nano /etc/systemd/system/fluentd.service.d/override.conf
[Service]
EnvironmentFile=/etc/fluent/es.env

Copia el certificado de la CA de Elasticsearch a /etc/fluent/es-ca.crt. Después abre fluentd.conf y sustituye el bloque <match nginx.**> por este, cambiando your_es_host y el nombre de usuario:

<match nginx.**>
  @type elasticsearch
  host your_es_host
  port 9200
  scheme https
  ssl_verify true
  ca_file /etc/fluent/es-ca.crt
  user fluentd_writer
  password "#{ENV['ES_PASSWORD']}"
  logstash_format true
  logstash_prefix fluentd-nginx
  <buffer>
    @type file
    path /var/log/fluent/buffer/nginx
    flush_interval 5s
    chunk_limit_size 8m
    total_limit_size 1g
    overflow_action block
    retry_type exponential_backoff
    retry_max_interval 60s
    retry_forever true
  </buffer>
</match>

Las opciones del buffer son las que dan fiabilidad al pipeline:

  • @type file guarda los eventos pendientes en disco, de modo que no se pierden si Fluentd se reinicia o Elasticsearch deja de responder.
  • total_limit_size 1g limita el espacio en disco del buffer, y overflow_action block hace que, al llenarse, Fluentd deje de leer el archivo en lugar de descartar eventos. Como el tail recuerda su posición, retomará la lectura cuando haya sitio.
  • retry_forever con exponential_backoff reintenta sin fin, esperando cada vez más, hasta un máximo de 60 segundos entre intentos.
  • logstash_format true crea un índice por día: fluentd-nginx-2026.09.25.

Recarga systemd, valida y reinicia:

sudo systemctl daemon-reload
sudo fluentd --dry-run -c /etc/fluent/fluentd.conf
sudo systemctl restart fluentd

Genera tráfico y comprueba que el índice recibe documentos:

curl -s http://localhost/ > /dev/null
curl --cacert /etc/fluent/es-ca.crt -u fluentd_writer "https://your_es_host:9200/fluentd-nginx-*/_count?pretty"
{
  "count" : 17,
  ...
}

Si el usuario no tiene permiso de lectura, haz esta última comprobación con un usuario administrador o desde Kibana.

Paso 7: Recibir eventos de aplicaciones por HTTP

Las aplicaciones también pueden enviar eventos directamente a Fluentd. El plugin de entrada http acepta JSON por POST y usa la ruta de la URL como etiqueta. Añade este bloque al principio de fluentd.conf, escuchando solo en localhost:

<source>
  @type http
  bind 127.0.0.1
  port 9880
</source>

<match app.**>
  @type file
  path /var/log/fluent/app
  <buffer time>
    timekey 1d
    timekey_wait 10m
  </buffer>
</match>

Este match guarda los eventos con etiqueta app.* en archivos diarios. Colócalo antes de cualquier match ** genérico que añadas en el futuro. Reinicia y envía un evento de prueba con -i para ver la respuesta:

sudo systemctl restart fluentd
curl -i -X POST -d 'json={"user":"ana","action":"login"}' http://127.0.0.1:9880/app.auth
HTTP/1.1 200 OK
Content-Type: text/plain
Connection: Keep-Alive
Content-Length: 0

Un 200 OK indica que Fluentd aceptó el evento. Los eventos se acumulan en el buffer y se escriben en un archivo por día, con un nombre como /var/log/fluent/app.20260925_0.log, cuando se cierra el periodo diario más los 10 minutos de timekey_wait.

Solución de problemas

El servicio no arranca tras un cambio. Ejecuta sudo fluentd --dry-run -c /etc/fluent/fluentd.conf y revisa sudo journalctl -u fluentd -n 50 --no-pager. Un error Unknown output plugin 'xxx' significa que falta instalar el plugin con fluent-gem.

Permission denied al leer un log. El usuario _fluentd no tiene acceso al archivo. Comprueba el grupo del archivo con ls -l, añade _fluentd a ese grupo y reinicia el servicio.

Los eventos no llegan a Elasticsearch. Busca en /var/log/fluent/fluentd.log mensajes failed to flush the buffer, que incluyen la causa (credenciales, certificado o conexión). Mientras el problema persista, los chunks se acumulan en /var/log/fluent/buffer/nginx; en cuanto se resuelva se enviarán solos.

El parser nginx no reconoce las líneas. Si cambiaste log_format en Nginx, el parser por defecto ya no sirve. Usa @type regexp con una expresión que coincida con tu formato, o configura Nginx para escribir JSON y usa @type json.

Conclusión

Has instalado Fluentd con el paquete oficial, gestionado sus plugins con fluent-gem y montado un pipeline que lee, filtra y enriquece los logs de Nginx y los envía a Elasticsearch con un buffer en disco resistente a caídas. Como siguientes pasos puedes añadir una segunda salida con el plugin copy para archivar los mismos eventos en S3, recoger el journal de systemd con fluent-plugin-systemd, o exponer métricas del pipeline para Prometheus con fluent-plugin-prometheus.