How to Deploy Elasticsearch – Search & Analytics Engine

Elasticsearch is a distributed search and analytics engine built on Apache Lucene. It provides near real-time search capabilities for structured and unstructured data, making it ideal for log aggregation, full-text search, and business analytics. Elasticsearch scales horizontally across multiple nodes and supports complex queries through its RESTful API.
In this article, you will deploy Elasticsearch using Docker Compose, configure persistent storage for indexed data, and set up Traefik as a reverse proxy to securely access your Elasticsearch instance.
Prerequisites
Before you begin, you need to:
- Have access to an Ubuntu 24.04-based server as a non-root user with
sudoprivileges. - Install Docker and Docker Compose.
- Configure a domain A record pointing to your server's IP address (for example,
elasticsearch.example.com).
Set Up the Directory Structure and Environment Variables
In this section, you prepare the required directory structure for Elasticsearch and define environment variables in a .env file.
Create the directory structure for Elasticsearch.
console$ mkdir -p ~/elasticsearch-logging/{elasticsearch-data,elasticsearch-config}
These directories serve different purposes:
- elasticsearch-data: Stores indexed data, including shards and segments.
- elasticsearch-config: Contains YAML configuration files.
Navigate into the
elasticsearch-loggingdirectory.console$ cd ~/elasticsearch-logging
Set proper ownership for the Elasticsearch data directory. Elasticsearch runs as the
elasticsearchuser (UID1000) inside the container.console$ sudo chown -R 1000:1000 elasticsearch-data
You can verify this UID by running
docker run --rm elasticsearch:8.17.0 id.Create a
.envfile.console$ nano .env
Add the following variables:
iniDOMAIN=elasticsearch.example.com LETSENCRYPT_EMAIL=admin@example.com
Replace:
elasticsearch.example.comwith your domain.admin@example.comwith your email.
Save and close the file.
Create an Elasticsearch configuration file.
console$ nano elasticsearch-config/elasticsearch.yml
Add the following content.
yamlcluster.name: logging-cluster node.name: node-1 network.host: 0.0.0.0 http.port: 9200 discovery.type: single-node xpack.security.enabled: false
Save and close the file.
The configuration includes:
- cluster.name: Identifies this Elasticsearch cluster for node discovery.
- node.name: Assigns a unique identifier to this node.
- network.host: Configures Elasticsearch to listen on all network interfaces, allowing Traefik to connect from the Docker network.
- discovery.type: Configures single-node mode, disabling cluster formation requirements.
- xpack.security.enabled: Disables authentication for simplified initial deployment.
Deploy with Docker Compose
In this section, you create and deploy the Docker Compose stack that runs Elasticsearch behind Traefik. Docker Compose manages both containers, applies the environment variables from your .env file, and automatically configures HTTPS routing through Traefik.
Create a new Docker Compose manifest.
console$ nano docker-compose.yaml
Add the following content.
yamlservices: traefik: image: traefik:v3.6 container_name: traefik command: - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--entrypoints.web.address=:80" - "--entrypoints.websecure.address=:443" - "--entrypoints.web.http.redirections.entrypoint.to=websecure" - "--entrypoints.web.http.redirections.entrypoint.scheme=https" - "--certificatesresolvers.letsencrypt.acme.httpchallenge=true" - "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web" - "--certificatesresolvers.letsencrypt.acme.email=${LETSENCRYPT_EMAIL}" - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json" ports: - "80:80" - "443:443" volumes: - "letsencrypt:/letsencrypt" - "/var/run/docker.sock:/var/run/docker.sock:ro" restart: unless-stopped elasticsearch: image: docker.elastic.co/elasticsearch/elasticsearch:9.2.0 container_name: elasticsearch hostname: elasticsearch expose: - "9200" volumes: - "./elasticsearch-config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml" - "./elasticsearch-data:/usr/share/elasticsearch/data" environment: - "ES_JAVA_OPTS=-Xms512m -Xmx512m" labels: - "traefik.enable=true" - "traefik.http.routers.elasticsearch.rule=Host(`${DOMAIN}`)" - "traefik.http.routers.elasticsearch.entrypoints=websecure" - "traefik.http.routers.elasticsearch.tls.certresolver=letsencrypt" restart: unless-stopped volumes: letsencrypt:
Save and close the file.
This manifest specifies:
- services: Defines two containers working together:
- traefik: Accepts external connections, provisions SSL/TLS certificates automatically, and routes requests to backend services.
- elasticsearch: Runs the core search engine, indexes documents, and responds to queries.
- image: Specifies container images from Docker Hub and the official Elastic registry.
- container_name: Assigns fixed names for easier log inspection and container management.
- command (Traefik): Configures Docker provider integration, HTTP/HTTPS entry points on ports 80 and 443, forced HTTPS redirects, and automated Let's Encrypt certificate generation using HTTP challenge validation.
- ports (Traefik): Binds ports 80 (HTTP) and 443 (HTTPS) on the host to receive incoming traffic.
- expose (Elasticsearch): Makes port 9200 accessible only within the Docker network, preventing direct public access.
- volumes:
- Local directories (
./elasticsearch-config,./elasticsearch-data) mount into containers to persist configuration and search indexes. - The
letsencryptnamed volume stores certificate data permanently. - Mounting
/var/run/docker.sockgrants Traefik read-only access for automatic service discovery.
- Local directories (
- environment (Elasticsearch): Sets JVM memory limits to 512MB minimum and maximum for stable resource usage.
- labels (Elasticsearch): Traefik routing rules that activate the reverse proxy, match requests by hostname, and apply Let's Encrypt TLS certificates.
- restart: unless-stopped: Automatically restarts containers after crashes or server reboots, except when manually stopped.
- services: Defines two containers working together:
Create and start the services.
console$ docker compose up -d
Verify that the services are running.
console$ docker compose ps
Output:
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS elasticsearch docker.elastic.co/elasticsearch/elasticsearch:9.2.0 "/bin/tini -- /usr/l…" elasticsearch 22 seconds ago Up 21 seconds 9200/tcp traefik traefik:v3.6 "/entrypoint.sh --pr…" traefik 22 seconds ago Up 21 seconds 0.0.0.0:80->80/tcp, [::]:80->80/tcp, 0.0.0.0:443->443/tcp, [::]:443->443/tcpBoth containers are running. Elasticsearch processes search requests while Traefik handles incoming connections on ports
80and443.View the logs of the services.
console$ docker compose logs
For more information on managing a Docker Compose stack, see the How To Use Docker Compose article.
Access Elasticsearch
This section demonstrates verification of your Elasticsearch installation through cluster health checks and test index creation to validate search and storage functionality.
Access the Elasticsearch API in your browser.
https://elasticsearch.example.comYou should see a JSON response with cluster information including the version number and cluster UUID.
Check cluster health using the command line.
console$ curl https://elasticsearch.example.com/_cluster/health?pretty
Output:
{ "cluster_name" : "logging-cluster", "status" : "green", "number_of_nodes" : 1, "number_of_data_nodes" : 1 }A
greenstatus indicates the cluster is healthy and operational.Create a test index to verify data storage.
console$ curl -X PUT "https://elasticsearch.example.com/test-index" -H 'Content-Type: application/json' -d' { "settings": { "number_of_shards": 1, "number_of_replicas": 0 } }'
Output:
{"acknowledged":true,"shards_acknowledged":true,"index":"test-index"}Index a sample document.
console$ curl -X POST "https://elasticsearch.example.com/test-index/_doc" -H 'Content-Type: application/json' -d' { "message": "Hello Elasticsearch", "timestamp": "2025-12-01T19:32:43Z" }'
Search for the document.
console$ curl "https://elasticsearch.example.com/test-index/_search?pretty"
The output displays your indexed document, confirming that Elasticsearch can store and retrieve data successfully.
Conclusion
You have successfully deployed Elasticsearch for log management with HTTPS encryption. This Docker Compose implementation combines the search engine with an automatic SSL reverse proxy, while volume mounts preserve indexed data through container updates and restarts. Let's Encrypt integration maintains valid certificates automatically as Traefik routes incoming requests securely. Your Elasticsearch instance now stands ready to ingest application logs, perform full-text searches across massive datasets, and deliver real-time analytics through its RESTful API.