ELK Stack es la combinación de Elasticsearch (almacenamiento y búsqueda), Logstash (procesamiento) y Kibana (visualización), a la que se suma Filebeat como agente ligero que recoge los logs en cada servidor. En este tutorial montarás las cuatro piezas de la versión 9 en un único servidor Ubuntu 24.04, enviarás los logs de acceso de Nginx a través de Logstash, los separarás en campos con grok y los consultarás en Kibana. La seguridad (TLS y autenticación) que Elasticsearch activa por defecto se mantiene en todo momento.
Requisitos previos
Para seguir esta guía necesitas:
- Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath, con al menos 4 GB de RAM (8 GB recomendados), 2 vCPU y 40 GB de disco libres. Elasticsearch y Logstash son procesos Java y no funcionan bien con menos memoria.
- Un usuario no root con privilegios
sudo. - Acceso SSH desde tu equipo local, que usarás para abrir un túnel hacia Kibana.
El flujo que vas a construir es: Nginx escribe /var/log/nginx/access.log, Filebeat lo lee y lo envía a Logstash por el puerto 5044, Logstash lo analiza y lo indexa en Elasticsearch (puerto 9200, solo en localhost) y Kibana (puerto 5601, solo en localhost) lo muestra.
Paso 1: Añadir el repositorio de Elastic
Los cuatro componentes se distribuyen desde el mismo repositorio APT oficial de Elastic. Descarga su clave GPG en /etc/apt/keyrings:
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo gpg --dearmor -o /etc/apt/keyrings/elastic.gpg
Añade el repositorio de la rama 9.x firmado con esa clave:
echo "deb [signed-by=/etc/apt/keyrings/elastic.gpg] https://artifacts.elastic.co/packages/9.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-9.x.list
Actualiza el índice de paquetes y comprueba que APT ve la versión de Elastic:
sudo apt update
apt-cache policy elasticsearch
elasticsearch:
Installed: (none)
Candidate: 9.x.y
Version table:
9.x.y 500
500 https://artifacts.elastic.co/packages/9.x/apt stable/main amd64 Packages
Paso 2: Instalar y arrancar Elasticsearch
Instala Elasticsearch. Durante la instalación se genera la configuración de seguridad: certificados TLS en /etc/elasticsearch/certs/ y una contraseña para el superusuario elastic:
sudo apt install elasticsearch
Busca en la salida el bloque de seguridad y guarda la contraseña en un lugar seguro:
--------------------------- Security autoconfiguration information ------------------------------
Authentication and authorization are enabled.
TLS for the transport and HTTP layers is enabled and configured.
The generated password for the elastic built-in superuser is : xxxxxxxxxxxxxxxxxxxx
...
Notasi la has perdido, genera una nueva con
sudo /usr/share/elasticsearch/bin/elasticsearch-reset-password -u elasticuna vez que el servicio esté arrancado.
Elasticsearch calcula el tamaño del heap de Java según la RAM disponible. En un servidor que comparte memoria con Logstash y Kibana conviene fijarlo. Crea un archivo de opciones:
sudo nano /etc/elasticsearch/jvm.options.d/heap.options
Para un servidor de 8 GB, 2 GB de heap es un punto de partida razonable (usa 1g con 4 GB de RAM):
-Xms2g
-Xmx2g
Por defecto Elasticsearch solo escucha en localhost, que es lo que quieres en una instalación de un solo nodo. Habilita e inicia el servicio:
sudo systemctl enable --now elasticsearch
El arranque tarda unos segundos. Comprueba que responde por HTTPS usando la CA generada y la contraseña de elastic:
sudo curl --cacert /etc/elasticsearch/certs/http_ca.crt -u elastic https://localhost:9200
{
"name" : "your_hostname",
"cluster_name" : "elasticsearch",
"version" : {
"number" : "9.x.y",
...
},
"tagline" : "You Know, for Search"
}
Paso 3: Instalar y enlazar Kibana
Instala Kibana:
sudo apt install kibana
Kibana se conecta a Elasticsearch mediante un token de inscripción, que configura automáticamente la URL, la CA y las credenciales internas. Genera el token:
sudo /usr/share/elasticsearch/bin/elasticsearch-create-enrollment-token -s kibana
Pásalo a Kibana (el token caduca a los 30 minutos):
sudo /usr/share/kibana/bin/kibana-setup --enrollment-token <token>
✔ Kibana configured successfully.
To start Kibana run:
bin/kibana
Habilita e inicia Kibana como servicio:
sudo systemctl enable --now kibana
Kibana escucha en localhost:5601, así que no queda expuesto a internet. Comprueba su estado tras un minuto:
sudo systemctl status kibana --no-pager
● kibana.service - Kibana
Loaded: loaded (/usr/lib/systemd/system/kibana.service; enabled; preset: enabled)
Active: active (running) since ...
Paso 4: Crear un usuario de escritura para Logstash
Logstash no debe usar el superusuario elastic. Crea un rol que solo pueda escribir en los índices nginx-* y un usuario asociado. Primero, el rol:
sudo curl --cacert /etc/elasticsearch/certs/http_ca.crt -u elastic \
-X POST "https://localhost:9200/_security/role/logstash_writer" \
-H "Content-Type: application/json" -d '
{
"cluster": ["monitor", "manage_index_templates", "manage_ilm"],
"indices": [
{
"names": ["nginx-*"],
"privileges": ["write", "create", "create_index", "manage", "manage_ilm"]
}
]
}'
{"role":{"created":true}}
Después el usuario. Sustituye your_strong_password por una contraseña larga y aleatoria:
sudo curl --cacert /etc/elasticsearch/certs/http_ca.crt -u elastic \
-X POST "https://localhost:9200/_security/user/logstash_internal" \
-H "Content-Type: application/json" -d '
{
"password": "your_strong_password",
"roles": ["logstash_writer"],
"full_name": "Logstash internal user"
}'
{"created":true}
Paso 5: Instalar y configurar Logstash
Instala Logstash:
sudo apt install logstash
Logstash necesita la CA de Elasticsearch para validar su certificado. Cópiala a un directorio propio con permisos de lectura para el usuario logstash:
sudo mkdir -p /etc/logstash/certs
sudo cp /etc/elasticsearch/certs/http_ca.crt /etc/logstash/certs/
sudo chown -R root:logstash /etc/logstash/certs
sudo chmod 640 /etc/logstash/certs/http_ca.crt
Si el servidor tiene 4 GB de RAM, reduce el heap de Logstash (1 GB por defecto) editando /etc/logstash/jvm.options y cambiando -Xms1g y -Xmx1g por -Xms512m y -Xmx512m. Con 8 GB puedes dejarlo como está.
Crea el pipeline. Cada archivo de /etc/logstash/conf.d/ terminado en .conf se carga en el pipeline principal:
sudo nano /etc/logstash/conf.d/nginx.conf
La entrada beats recibe los eventos de Filebeat, el filtro grok separa la línea de log de Nginx (formato combined) en campos, date usa la fecha de la petición como @timestamp y la salida escribe un índice diario:
input {
beats {
port => 5044
}
}
filter {
grok {
match => { "message" => "%{COMBINEDAPACHELOG}" }
}
date {
match => ["timestamp", "dd/MMM/yyyy:HH:mm:ss Z"]
remove_field => ["timestamp"]
}
}
output {
elasticsearch {
hosts => ["https://localhost:9200"]
user => "logstash_internal"
password => "your_strong_password"
ssl_certificate_authorities => ["/etc/logstash/certs/http_ca.crt"]
index => "nginx-%{+YYYY.MM.dd}"
}
}
El archivo contiene una contraseña, así que restringe su lectura:
sudo chown root:logstash /etc/logstash/conf.d/nginx.conf
sudo chmod 640 /etc/logstash/conf.d/nginx.conf
Valida la sintaxis antes de arrancar el servicio (tarda unos 30 segundos):
sudo -u logstash /usr/share/logstash/bin/logstash --path.settings /etc/logstash -t
...
Configuration OK
[INFO ][logstash.runner] Using config.test_and_exit mode. Config Validation Result: OK. Exiting Logstash
Habilita e inicia Logstash y comprueba que el puerto 5044 queda a la escucha:
sudo systemctl enable --now logstash
sudo ss -tlnp | grep 5044
LISTEN 0 4096 *:5044 *:* users:(("java",pid=12345,fd=120))
Paso 6: Instalar Nginx y Filebeat
Para tener una fuente de logs real, instala Nginx y genera algunas peticiones:
sudo apt install nginx
for i in $(seq 1 20); do curl -s -o /dev/null http://localhost/; done
curl -s -o /dev/null http://localhost/no-existe
Instala Filebeat desde el mismo repositorio:
sudo apt install filebeat
El filebeat.yml de ejemplo trae una salida hacia Elasticsearch activada. Guarda una copia y sustitúyelo por una configuración mínima:
sudo mv /etc/filebeat/filebeat.yml /etc/filebeat/filebeat.yml.orig
sudo nano /etc/filebeat/filebeat.yml
La entrada filestream necesita un id único y lee el log de acceso de Nginx. La salida apunta a Logstash:
filebeat.inputs:
- type: filestream
id: nginx-access
paths:
- /var/log/nginx/access.log
output.logstash:
hosts: ["localhost:5044"]
Filebeat se niega a arrancar si su configuración es escribible por otros usuarios, así que ajusta los permisos y prueba la configuración y la conexión:
sudo chmod 600 /etc/filebeat/filebeat.yml
sudo filebeat test config
sudo filebeat test output
Config OK
logstash: localhost:5044...
connection...
parse host... OK
dns lookup... OK
addresses: 127.0.0.1
dial up... OK
TLS... WARN secure connection disabled
talk to server... OK
Habilita e inicia Filebeat:
sudo systemctl enable --now filebeat
Paso 7: Comprobar que los datos llegan a Elasticsearch
Tras unos segundos debe existir el índice del día con documentos:
sudo curl --cacert /etc/elasticsearch/certs/http_ca.crt -u elastic "https://localhost:9200/_cat/indices/nginx-*?v"
health status index uuid pri rep docs.count ...
yellow open nginx-2026.09.25 aBcD1234EfGh5678IjKl 1 1 21 ...
El estado yellow es normal en un clúster de un solo nodo: las réplicas no tienen otro nodo donde asignarse. Consulta un documento para ver los campos que ha generado grok:
sudo curl --cacert /etc/elasticsearch/certs/http_ca.crt -u elastic "https://localhost:9200/nginx-*/_search?size=1&pretty&q=http.response.status_code:404"
Deberías ver campos como source.address, http.request.method, url.original, http.response.status_code y user_agent.original. Logstash 9 aplica nombres ECS (Elastic Common Schema) por defecto.
Si el documento tiene la etiqueta _grokparsefailure, la línea no coincide con el formato combined; revisa si has cambiado log_format en Nginx.
Paso 8: Consultar los logs en Kibana
Kibana solo escucha en localhost, así que accede mediante un túnel SSH desde tu equipo local:
ssh -L 5601:localhost:5601 your_user@your_server_ip
Con la sesión abierta, visita http://localhost:5601 en tu navegador e inicia sesión con el usuario elastic y su contraseña.
Crea una vista de datos (data view) para los índices de Nginx:
- Abre el menú principal y ve a Stack Management > Data Views.
- Pulsa Create data view.
- En Index pattern escribe
nginx-*y elige@timestampcomo campo de tiempo. - Pulsa Save data view to Kibana.
Ve a Discover, selecciona la vista nginx-* y verás las peticiones. Puedes filtrar con KQL, por ejemplo:
http.response.status_code >= 400
Desde Visualize Library o Dashboards puedes crear un gráfico de barras de peticiones por código de estado o una tabla de las URL más solicitadas usando esos mismos campos.
Enviar logs desde otros servidores
Para recoger logs de más servidores, instala Filebeat en cada uno (pasos 1 y 6, sin Nginx si no lo necesitas) y cambia la salida a la IP del servidor ELK:
output.logstash:
hosts: ["your_server_ip:5044"]
En el servidor ELK abre el puerto 5044 solo para esas IP:
sudo ufw allow from your_client_ip to any port 5044 proto tcp
Importantela entrada
beatsde este tutorial no cifra el tráfico. Si los servidores se comunican por internet y no por una red privada, configura TLS en la entradabeatsde Logstash y enoutput.logstashde Filebeat antes de enviar logs sensibles.
Solución de problemas
- Elasticsearch no arranca: revisa
sudo journalctl -u elasticsearch -n 50y/var/log/elasticsearch/elasticsearch.log. La causa más habitual es falta de memoria; reduce el heap del paso 2. - Logstash no escribe:
sudo journalctl -u logstash -n 50. Un error401indica credenciales incorrectas del usuariologstash_internal; un error403indica que el índice no encaja connginx-*. - Filebeat no envía nada:
sudo journalctl -u filebeat -n 50. Si el log ya se había leído, Filebeat solo envía líneas nuevas; genera más peticiones a Nginx. - Kibana muestra "Kibana server is not ready yet": espera un par de minutos tras arrancar y revisa
sudo journalctl -u kibana -n 50.
Conclusión
Ya tienes un ELK Stack de un nodo con seguridad activada que recibe los logs de Nginx a través de Filebeat y Logstash, los estructura con grok y los muestra en Kibana. Como siguientes pasos, define una política de ciclo de vida (ILM) en Stack Management > Index Lifecycle Policies para borrar índices antiguos, publica Kibana detrás de Nginx con HTTPS en lugar del túnel SSH y añade más entradas a Filebeat para los logs de tus aplicaciones.
