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.
Notael antiguo paquete
td-agentllegó al final de su vida útil en 2023. Su sustituto esfluent-package, que usa rutas y nombres distintos: serviciofluentd, configuración en/etc/fluent/fluentd.conf, log propio en/var/log/fluent/fluentd.logy el comandofluent-gempara los plugins. Si sigues guías antiguas, traducetd-agenta estos nombres.
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
Notael nombre del script incluye la serie LTS (
fluent-package6-lts). Si la URL devuelve un error 404, consulta la página de instalación de docs.fluentd.org, que siempre enlaza el script de la versión LTS vigente.
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:
| Directiva | Función | Ejemplos de plugins |
|---|---|---|
<source> | Lee eventos y les asigna una etiqueta (tag) | tail, http, syslog, forward |
<filter patrón> | Modifica o descarta eventos cuya etiqueta coincide | record_transformer, grep, parser |
<match patrón> | Envía los eventos cuya etiqueta coincide a un destino | elasticsearch, 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:
tailsigue el archivo comotail -F, y guarda enpos_filehasta dónde ha leído para continuar tras un reinicio. El parsernginxentiende el formatocombinedpor defecto de Nginx y genera campos comoremote,method,path,codeyagent.- El primer filtro
grepdescarta las peticiones a/healthy/metrics, que suelen ser ruido de sondas. record_transformerañade el nombre del servidor y un camposervicea 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 fileguarda los eventos pendientes en disco, de modo que no se pierden si Fluentd se reinicia o Elasticsearch deja de responder.total_limit_size 1glimita el espacio en disco del buffer, yoverflow_action blockhace que, al llenarse, Fluentd deje de leer el archivo en lugar de descartar eventos. Como eltailrecuerda su posición, retomará la lectura cuando haya sitio.retry_foreverconexponential_backoffreintenta sin fin, esperando cada vez más, hasta un máximo de 60 segundos entre intentos.logstash_format truecrea 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.
Importanteno expongas el puerto 9880 a Internet. El input
httpno tiene autenticación. Si otros servidores deben enviar eventos, usa el inputforwardcon TLS y clave compartida, y abre el puerto solo a sus IP con UFW.
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.
