This is adapted from Elastic's local development quickstart script (start-local), with Logstash and Filebeat added. It runs a single node with HTTP TLS disabled, so it's for development and homelab use, not production.
Secrets: .env¶
Compose reads .env from the project directory automatically. Keep it out of git.
# .env
STACK_VERSION=9.1.5
ELASTIC_PASSWORD=[ elastic_password ]
KIBANA_PASSWORD=[ kibana_system_password ]
KIBANA_ENCRYPTION_KEY=[ encryption_key ]
Generate the encryption key (Kibana needs at least 32 characters, and openssl rand -hex 16 gives exactly 32):
openssl rand -hex 16
compose.yaml¶
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION}
container_name: elasticsearch
ports:
- 127.0.0.1:9200:9200
environment:
- discovery.type=single-node
- cluster.name=elasticsearch
- ELASTIC_PASSWORD=${ELASTIC_PASSWORD}
- xpack.security.enabled=true
- xpack.security.http.ssl.enabled=false
- xpack.license.self_generated.type=trial # 30-day trial; reverts to basic afterwards
- xpack.ml.use_auto_machine_memory_percent=true
- ES_JAVA_OPTS=-Xms512m -Xmx512m
volumes:
- elasticsearch:/usr/share/elasticsearch/data
ulimits:
memlock:
soft: -1
hard: -1
healthcheck:
test: ["CMD-SHELL", "curl -s -o /dev/null --fail -u elastic:${ELASTIC_PASSWORD} http://localhost:9200"]
interval: 10s
timeout: 10s
retries: 30
networks:
- logging-net
# One-shot job: set the kibana_system password so Kibana can log in.
kibana_settings:
image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION}
container_name: kibana-settings
restart: "no"
depends_on:
elasticsearch:
condition: service_healthy
command: >
bash -c '
echo "Setting kibana_system password";
until curl -s -u "elastic:${ELASTIC_PASSWORD}" -X POST
http://elasticsearch:9200/_security/user/kibana_system/_password
-H "Content-Type: application/json"
-d "{\"password\":\"${KIBANA_PASSWORD}\"}" | grep -q "^{}"; do
sleep 2;
done;
echo "Done.";
'
networks:
- logging-net
kibana:
image: docker.elastic.co/kibana/kibana:${STACK_VERSION}
container_name: kibana
depends_on:
kibana_settings:
condition: service_completed_successfully
ports:
- 127.0.0.1:5601:5601
environment:
- ELASTICSEARCH_HOSTS=http://elasticsearch:9200
- ELASTICSEARCH_USERNAME=kibana_system
- ELASTICSEARCH_PASSWORD=${KIBANA_PASSWORD}
- SERVER_PUBLICBASEURL=http://localhost:5601
- XPACK_ENCRYPTEDSAVEDOBJECTS_ENCRYPTIONKEY=${KIBANA_ENCRYPTION_KEY}
- XPACK_REPORTING_ENCRYPTIONKEY=${KIBANA_ENCRYPTION_KEY}
- XPACK_SECURITY_ENCRYPTIONKEY=${KIBANA_ENCRYPTION_KEY}
healthcheck:
test: ["CMD-SHELL", "curl -s -o /dev/null --fail http://localhost:5601/login"]
interval: 10s
timeout: 10s
retries: 60
networks:
- logging-net
logstash:
image: docker.elastic.co/logstash/logstash:${STACK_VERSION}
container_name: logstash
depends_on:
elasticsearch:
condition: service_healthy
volumes:
- ./logstash.conf:/usr/share/logstash/pipeline/logstash.conf:ro
ports:
- "5044:5044" # Beats
- "5514:5514/udp" # Syslog (e.g. OPNsense)
- "5514:5514/tcp" # Syslog over TCP
environment:
- ELASTICSEARCH_HOST=http://elasticsearch:9200 # referenced from logstash.conf
- ELASTIC_PASSWORD=${ELASTIC_PASSWORD}
networks:
- logging-net
filebeat:
image: docker.elastic.co/beats/filebeat:${STACK_VERSION}
container_name: filebeat
user: root # needed to read /var/lib/docker/containers
restart: unless-stopped
command: ["filebeat", "-e", "--strict.perms=false", "-c", "/usr/share/filebeat/filebeat.yml"]
volumes:
- ./filebeat.yml:/usr/share/filebeat/filebeat.yml:ro
- /var/lib/docker/containers:/var/lib/docker/containers:ro
- /var/log:/var/log:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- logging-net
networks:
logging-net:
volumes:
elasticsearch:
Notes:
- Ports are bound to
127.0.0.1. Change them to0.0.0.0only if other hosts need to reach the stack, and put a reverse proxy with TLS in front if you do. - Kibana waits for
kibana_settingsto finish, so it never starts with an unsetkibana_systempassword. -emakes Filebeat log to stderr (visible indocker logs filebeat). Where events go is set infilebeat.yml.
Bring it up¶
docker compose up -d
docker compose ps
curl -u "elastic:$ELASTIC_PASSWORD" http://localhost:9200
Kibana is at http://localhost:5601. Log in as elastic.
Reset a password¶
docker exec -it elasticsearch bin/elasticsearch-reset-password -u kibana_system
If you reset kibana_system, update KIBANA_PASSWORD in .env and run docker compose up -d kibana.