Por qué alojar Elasticsearch en su propio VPS
Elasticsearch destaca allí donde una búsqueda simple ya no basta: scoring BM25 configurable, sinónimos, analizadores lingüísticos personalizados (francés, árabe ICU), consultas geográficas y stack ELK completo para centralizar los logs de sus aplicaciones. Los servicios Elastic Cloud y OpenSearch Service se encarecen rápidamente en cuanto los volúmenes indexados superan unos pocos gigabytes, con facturación del egress como añadido. En su VPS, usted decide la versión desplegada, los plugins activados, la duración de retención y la política de snapshots. Es también la única manera de mantener datos sensibles estrictamente dentro de su propia infraestructura, sin depender de un tercero cloud.
En cuanto a la licencia, Elasticsearch volvió a ser open source en agosto de 2024: desde la versión 8.16, Elastic distribuye el código bajo la licencia AGPLv3 (aprobada por la OSI), junto con Elastic License y SSPL. Las versiones actuales en producción son 8.19.x (rama 8 de mantenimiento largo) y 9.x (rama principal desde 2025).
Lo que gana al autoalojar Elasticsearch
- Búsqueda full-text avanzada: scoring BM25, sinónimos, analizadores lingüísticos personalizados (FR, AR ICU)
- Agregaciones y facetas complejas para el e-commerce, la BI o la centralización de logs
- Stack ELK completo (Logstash, Beats, Kibana) sin sobrecoste de software
- Control total de la versión, de los plugins y de las index lifecycle policies (ILM)
- Sin facturación por volumen indexado ni gastos de egress de red
- Snapshots automáticos hacia su propio almacenamiento de objetos compatible con S3 mediante SLM
- Datos sensibles conservados en su propia infraestructura, bajo su única jurisdicción
Requisitos concretos antes de lanzar el primer contenedor
RAM mínima: 4 GB para un entorno de pruebas, 8 GB (2-4 vCPU) para una instancia de producción ligera, 16 GB en cuanto añada Kibana o indexe varios millones de documentos. El parámetro clave es el heap de la JVM: fije -Xms y -Xmx al 50 % de la RAM disponible, sin superar 31 GB (por encima, la JVM pasa a un modo de compresión de punteros menos eficiente; el límite exacto es 31 GB con G1GC, no 32). Fije siempre -Xms igual a -Xmx: un heap infraasignado en el arranque que luego se amplía provoca largas pausas de GC.
En cuanto a la red, Elasticsearch utiliza dos puertos: 9200 (HTTP, API REST) y 9300 (transporte entre nodos). No exponga nunca el puerto 9200 directamente en la interfaz pública. En cuanto al almacenamiento, se recomienda un SSD NVMe. Prevea también Docker y Docker Compose, y un subdominio es.sudominio.com apuntando al VPS.
Despliegue paso a paso
Preparar el kernel de Linux
Antes de lanzar el contenedor, aplique dos ajustes de sistema obligatorios. Primero:
sysctl -w vm.max_map_count=262144(hágalo persistente en/etc/sysctl.conf). Después, desactive el swap (swapoff -a) o configurebootstrap.memory_lock=trueenelasticsearch.yml.Escribir el archivo docker-compose.yml
Cree un directorio de trabajo y un archivo
docker-compose.ymlcon la imagendocker.elastic.co/elasticsearch/elasticsearch:8.19.4, la variableES_JAVA_OPTS=-Xms4g -Xmx4g, un volumen con nombre para/usr/share/elasticsearch/datay el puerto 9200 enlazado únicamente a127.0.0.1. Añadadiscovery.type=single-nodepara un despliegue de un solo nodo.Activar xpack.security y arrancar
En
elasticsearch.yml, compruebe quexpack.security.enabled: trueyxpack.security.http.ssl.enabled: trueestén activos. Lance el clúster:docker compose up -d. En el primer arranque, espere de 2 a 3 minutos. Consulte los logs:docker compose logs -f elasticsearch.Crear los usuarios y recuperar la contraseña de elastic
Una vez arrancado el contenedor, restablezca la contraseña del superusuario
elastic:docker exec -it elasticsearch bin/elasticsearch-reset-password -u elastic. Guárdela en un gestor de secretos. Cree después el usuariokibana_systemsi añade Kibana. No use este cuenta para consultas de aplicación.Verificar el clúster con curl
Pruebe la conexión desde el VPS:
curl -u elastic:<CONTRASEÑA> https://localhost:9200 --cacert /usr/share/elasticsearch/config/certs/http_ca.crt. Una respuesta JSON concluster_nameystatus: greenoyellowconfirma que el clúster está operativo. Un estadoyellowen un clúster de un solo nodo es normal.Exponer mediante reverse proxy HTTPS con Nginx
Instale Nginx y configure un virtual host para
es.sudominio.com. El reverse proxy transmite las peticiones haciahttps://127.0.0.1:9200. Añada una autenticación básica de Nginx si la API debe ser accesible desde el exterior. Reenvíe solo las rutas necesarias para su aplicación.
Seguridad xpack: TLS, roles y aislamiento de red
La seguridad xpack de Elasticsearch cubre tres capas. TLS entre nodos (xpack.security.transport.ssl.enabled: true) cifra el tráfico en el puerto 9300. TLS HTTP (xpack.security.http.ssl.enabled: true) cifra el puerto 9200. Control de roles: asigne a cada aplicación el rol mínimo necesario. Evite usar la cuenta elastic en producción. El valor por defecto de network.host es _local_ (solo loopback) — no lo cambie a 0.0.0.0 sin haber configurado la seguridad xpack.
Endurecer el acceso de red con UFW
Después de verificar que Elasticsearch escucha únicamente en 127.0.0.1, bloquee el cortafuegos: ufw deny 9200/tcp y ufw deny 9300/tcp. Solo el reverse proxy Nginx (puerto 443) debe ser accesible. Si varios nodos se comunican entre sí, autorice explícitamente las IP de los nodos en el puerto 9300. Un ufw status tras la configuración le da la vista exacta de lo que está abierto.
Index Lifecycle Management (ILM): gestionar el ciclo de vida de los datos
ILM automatiza el ciclo de vida de sus índices según la edad o el tamaño, evitando la saturación del disco y manteniendo rápidas las consultas sobre los datos recientes. Una política ILM típica se divide en cuatro fases:
Fase hot: el índice recibe nuevos datos. Configure el rollover automático al alcanzar un tamaño (max_size: 50gb) o una edad (max_age: 7d). Los índices hot viven en sus SSDs NVMe más rápidos.
Fase warm: el índice solo se lee. Elasticsearch reduce las réplicas a 1 y realiza un force-merge de los segmentos de Lucene.
Fase cold: datos consultados raramente. Las réplicas bajan a 0 y el índice puede montarse en modo de solo lectura desde almacenamiento de objetos.
Fase delete: eliminación automática tras el período de retención definido (ejemplo: 90 días para logs).
PUT _ilm/policy/logs-policy
{
"policy": {
"phases": {
"hot": { "actions": { "rollover": { "max_age": "7d", "max_size": "50gb" } } },
"warm": { "min_age": "7d", "actions": { "forcemerge": { "max_num_segments": 1 }, "shrink": { "number_of_shards": 1 } } },
"cold": { "min_age": "30d", "actions": { "freeze": {} } },
"delete": { "min_age": "90d", "actions": { "delete": {} } }
}
}
}En un VPS donde el espacio en disco está contado, es lo que impide que sus logs saturen el SSD y mantiene rápidas las consultas sobre los datos calientes.
Snapshots hacia S3: copias de seguridad y recuperación ante desastres
Los snapshots de Elasticsearch permiten respaldar el estado completo de sus índices en un almacenamiento de objetos compatible con S3. Combínelos con una Snapshot Lifecycle Policy (SLM) para automatizar las copias de seguridad y su retención.
1. Instalar el plugin S3 y configurar el repositorio:
docker exec -it elasticsearch bin/elasticsearch-plugin install repository-s3Declare las claves de acceso en el keystore de Elasticsearch (nunca en texto claro):
docker exec -it elasticsearch bin/elasticsearch-keystore add s3.client.default.access_key
docker exec -it elasticsearch bin/elasticsearch-keystore add s3.client.default.secret_keyRegistre el repositorio:
PUT _snapshot/s3-backup
{
"type": "s3",
"settings": {
"bucket": "my-elasticsearch-bucket",
"region": "eu-west-1",
"base_path": "snapshots/production"
}
}2. Crear la Snapshot Lifecycle Policy:
PUT _slm/policy/daily-snapshots
{
"schedule": "0 30 2 * * ?",
"name": "<daily-snap-{now/d}>",
"repository": "s3-backup",
"config": { "indices": ["*"], "ignore_unavailable": true },
"retention": { "expire_after": "30d", "min_count": 5, "max_count": 50 }
}Esta política lanza un snapshot cada día a las 2:30 y purga los snapshots de más de 30 días conservando al menos 5 versiones. Pruebe la restauración desde un entorno de staging antes de necesitarla.
Monitorización del heap de la JVM: detectar OOM antes de que ocurra
En un VPS, el OOM killer del kernel de Linux puede terminar el proceso de Elasticsearch sin previo aviso. La monitorización proactiva del heap de la JVM evita el 80% de los incidentes en producción.
Métricas a vigilar mediante la API _nodes/stats:
- jvm.mem.heap_used_percent: lance una alerta por encima del 75% de media y una alerta crítica por encima del 85% durante 5 minutos. Una saturación sostenida al 90%+ indica una fuga de memoria o un heap infradimensionado.
- jvm.gc.collectors.old.collection_count y collection_time_in_millis: un aumento rápido en el número de GC old-gen y tiempos > 2 s por colección indican que la JVM dedica más tiempo a recoger que a trabajar.
Reglas operativas:
1. Si heap_used_percent supera el 75% en estado estacionario, aumente el heap (o la RAM del VPS) antes de sufrir el primer OOM.
2. No aumente el heap por encima de 31 GB: más allá de este umbral, el recolector de basura desactiva los punteros comprimidos (compressed oops) y la JVM consume más memoria por objeto.
3. Verifique periódicamente que bootstrap.memory_lock: true está activo con GET _nodes?filter_path=**.mlockall: un valor false indica que el swap sigue activo en el VPS.
Kibana: exploración de índices y cuadros de mando (opcional)
Kibana es la interfaz gráfica oficial de Elasticsearch para explorar índices, construir cuadros de mando y configurar alertas. No es obligatoria para el uso programático, pero simplifica la gestión de ILM, SLM e índices en general.
Añada Kibana al mismo archivo Compose:
kibana:
image: docker.elastic.co/kibana/kibana:8.19.4
environment:
- ELASTICSEARCH_HOSTS=https://elasticsearch:9200
- ELASTICSEARCH_USERNAME=kibana_system
- ELASTICSEARCH_PASSWORD=<CONTRASEÑA_KIBANA_SYSTEM>
- ELASTICSEARCH_SSL_CERTIFICATEAUTHORITIES=/usr/share/kibana/config/certs/http_ca.crt
volumes:
- /ruta/a/http_ca.crt:/usr/share/kibana/config/certs/http_ca.crt:ro
depends_on:
- elasticsearchExponga Kibana detrás de un proxy Nginx en kibana.sudominio.com con autenticación. No exponga Kibana directamente en internet sin autenticación: da acceso completo a la gestión del clúster. Desde Kibana, acceda a Stack Management → Index Lifecycle Policies y Snapshot and Restore para gestionar ILM y SLM visualmente.
Diagnóstico: los 5 errores más habituales al arrancar
1. El OOM Killer mata el proceso de Elasticsearch. Síntoma: el contenedor se detiene sin mensaje de error, dmesg | grep -i killed revela un Killed process. Corrección: reduzca -Xmx al 50% de la RAM libre real (máximo 31 GB) y vigile el consumo con docker stats.
2. max_map_count demasiado bajo. Síntoma: Elasticsearch se niega a arrancar con el error max virtual memory areas vm.max_map_count [65530] is too low. Corrección: sysctl -w vm.max_map_count=262144 y añada vm.max_map_count=262144 en /etc/sysctl.conf.
3. Permission denied en /usr/share/elasticsearch/data. Síntoma: error AccessDeniedException en los logs. Causa: el directorio del host pertenece a root pero el contenedor usa el UID 1000. Corrección: chown -R 1000:1000 <ruta_del_volumen_host>.
4. Conexión rechazada en el puerto 9200. Síntoma: curl localhost:9200 devuelve Connection refused. Causa frecuente: network.host mal configurado. Deje network.host en su valor por defecto (_local_) y acceda mediante 127.0.0.1:9200. Compruebe también: docker ps.
5. Arranque lento: normal en la primera inicialización. Síntoma: el clúster tarda de 2 a 3 minutos en responder. No es una avería. Espere a que los logs muestren Cluster health status changed from [RED] to [GREEN] antes de enviar peticiones.
¿Y si quiere una alternativa open source completa?
OpenSearch es el fork comunitario de Elasticsearch, nacido en 2021 cuando Elastic cambió su licencia a SSPL. OpenSearch conserva una licencia Apache 2.0 e incluye funciones de seguridad avanzadas en su distribución gratuita. Desde que Elastic reintrodujo AGPLv3 en agosto de 2024 con la versión 8.16, ambos proyectos están de nuevo bajo licencias aprobadas por la OSI — la elección depende ahora más del ecosistema (plugins, integraciones, soporte comercial) que de restricciones de licencia. El despliegue con Docker sigue el mismo esquema con la imagen opensearchproject/opensearch.