This guide provides a complete Ansible playbook to install the Elastic Stack (Elasticsearch, Logstash, Kibana) with proper repository configuration, security settings, and Filebeat integration.
Current Elastic Stack version: 9.3.1
Create a file named elk-stack.yml:
---
- name: Install and Configure ELK Stack
hosts: elk
become: true
vars:
elastic_version: "9.3.1"
elasticsearch_port: 9200
elasticsearch_transport_port: 9300
logstash_beats_port: 5044
kibana_port: 5601
kibana_host: "0.0.0.0"
elastic_password: "elastic_secure_password_123" # Change this!
kibana_password: "kibana_system_password_456" # Change this!
logstash_password: "logstash_system_password_789" # Change this!
cluster_name: "elk-cluster"
node_name: "{{ ansible_hostname }}"
tasks:
- name: Install prerequisites (Debian/Ubuntu)
apt:
name:
- apt-transport-https
- software-properties-common
- wget
- gnupg2
- curl
- openjdk-17-jdk
state: present
update_cache: true
when: ansible_os_family == "Debian"
- name: Install prerequisites (RHEL/CentOS)
yum:
name:
- wget
- gnupg2
- curl
- java-17-openjdk
- java-17-openjdk-devel
state: present
when: ansible_os_family == "RedHat"
- name: Set Java home
set_fact:
java_home: "{{ '/usr/lib/jvm/java-17-openjdk-amd64' if ansible_os_family == 'Debian' else '/usr/lib/jvm/java-17-openjdk' }}"
- name: Add Elastic APT key (Debian/Ubuntu)
apt_key:
url: "https://artifacts.elastic.co/GPG-KEY-elasticsearch"
state: present
when: ansible_os_family == "Debian"
- name: Add Elastic APT repository (Debian/Ubuntu)
apt_repository:
repo: "deb https://artifacts.elastic.co/packages/9.x/apt stable main"
state: present
filename: elastic-9.x
when: ansible_os_family == "Debian"
- name: Add Elastic YUM repository (RHEL/CentOS)
yum_repository:
name: elastic-9.x
description: Elastic Repository
baseurl: "https://artifacts.elastic.co/packages/9.x/yum"
gpgcheck: true
gpgkey: "https://artifacts.elastic.co/GPG-KEY-elasticsearch"
enabled: true
when: ansible_os_family == "RedHat"
# =====================
# Elasticsearch Installation
# =====================
- name: Install Elasticsearch
package:
name: "elasticsearch{% if elastic_version %}-{{ elastic_version }}{% endif %}"
state: present
notify: Restart Elasticsearch
- name: Configure Elasticsearch
template:
src: elasticsearch.yml.j2
dest: /etc/elasticsearch/elasticsearch.yml
owner: root
group: elasticsearch
mode: '0660'
vars:
es_cluster_name: "{{ cluster_name }}"
es_node_name: "{{ node_name }}"
es_path_data: "/var/lib/elasticsearch"
es_path_logs: "/var/log/elasticsearch"
es_network_host: "0.0.0.0"
es_http_port: "{{ elasticsearch_port }}"
es_transport_port: "{{ elasticsearch_transport_port }}"
es_discovery_type: "single-node"
es_xpack_security_enabled: false # Enable in production with certificates
notify: Restart Elasticsearch
- name: Configure Elasticsearch JVM options
copy:
dest: /etc/elasticsearch/jvm.options.d/jvm.options
owner: root
group: elasticsearch
mode: '0660'
content: |
-Xms1g
-Xmx1g
-XX:+UseG1GC
-XX:G1ReservePercent=25
-XX:InitiatingHeapOccupancyPercent=30
-Xlog:gc*,gc+age=trace,safepoint:file=/var/log/elasticsearch/gc.log:utctime,pid,tags:filecount=32,filesize=64m
notify: Restart Elasticsearch
- name: Enable and start Elasticsearch
systemd:
name: elasticsearch
enabled: true
state: started
daemon_reload: true
- name: Wait for Elasticsearch to start
wait_for:
port: "{{ elasticsearch_port }}"
delay: 10
timeout: 300
# =====================
# Logstash Installation
# =====================
- name: Install Logstash
package:
name: "logstash{% if elastic_version %}-{{ elastic_version }}{% endif %}"
state: present
notify: Restart Logstash
- name: Create Logstash pipeline configuration
copy:
dest: /etc/logstash/conf.d/main.conf
owner: root
group: logstash
mode: '0644'
content: |
input {
beats {
port => {{ logstash_beats_port }}
}
syslog {
port => 5514
type => "syslog"
}
}
filter {
if [type] == "syslog" {
grok {
match => { "message" => "%{SYSLOGTIMESTAMP:syslog_timestamp} %{SYSLOGHOST:syslog_hostname} %{DATA:syslog_program}(?:\[%{POSINT:syslog_pid}\])?: %{GREEDYDATA:syslog_message}" }
}
date {
match => [ "syslog_timestamp", "MMM d HH:mm:ss", "MMM dd HH:mm:ss" ]
}
}
}
output {
elasticsearch {
hosts => ["localhost:{{ elasticsearch_port }}"]
index => "logs-%{+YYYY.MM.dd}"
}
stdout { codec => rubydebug }
}
- name: Configure Logstash JVM options
copy:
dest: /etc/logstash/jvm.options.d/jvm.options
owner: root
group: logstash
mode: '0644'
content: |
-Xms512m
-Xmx512m
notify: Restart Logstash
- name: Enable and start Logstash
systemd:
name: logstash
enabled: true
state: started
daemon_reload: true
- name: Wait for Logstash to start
wait_for:
port: "{{ logstash_beats_port }}"
delay: 5
timeout: 120
# =====================
# Kibana Installation
# =====================
- name: Install Kibana
package:
name: "kibana{% if elastic_version %}-{{ elastic_version }}{% endif %}"
state: present
notify: Restart Kibana
- name: Configure Kibana
template:
src: kibana.yml.j2
dest: /etc/kibana/kibana.yml
owner: root
group: kibana
mode: '0660'
vars:
kb_server_port: "{{ kibana_port }}"
kb_server_host: "{{ kibana_host }}"
kb_elasticsearch_hosts: "http://localhost:{{ elasticsearch_port }}"
kb_server_name: "{{ node_name }}"
notify: Restart Kibana
- name: Enable and start Kibana
systemd:
name: kibana
enabled: true
state: started
daemon_reload: true
- name: Wait for Kibana to start
wait_for:
port: "{{ kibana_port }}"
delay: 10
timeout: 300
# =====================
# Firewall Configuration
# =====================
- name: Configure firewall (UFW)
ufw:
rule: allow
port: "{{ item }}"
proto: tcp
comment: "ELK Stack"
loop:
- "{{ elasticsearch_port }}"
- "{{ elasticsearch_transport_port }}"
- "{{ logstash_beats_port }}"
- "5514"
- "{{ kibana_port }}"
when: ansible_os_family == "Debian"
failed_when: false
- name: Configure firewall (firewalld)
firewalld:
port: "{{ item }}/tcp"
permanent: true
immediate: true
state: enabled
loop:
- "{{ elasticsearch_port }}"
- "{{ elasticsearch_transport_port }}"
- "{{ logstash_beats_port }}"
- "5514"
- "{{ kibana_port }}"
when: ansible_os_family == "RedHat"
failed_when: false
# =====================
# Verification
# =====================
- name: Verify Elasticsearch health
uri:
url: "http://localhost:{{ elasticsearch_port }}/_cluster/health"
method: GET
return_content: true
register: es_health
retries: 5
delay: 3
until: es_health.status == 200
- name: Display ELK Stack status
debug:
msg: |
ELK Stack {{ elastic_version }} installed successfully!
Elasticsearch: http://{{ ansible_default_ipv4.address | default(ansible_host) }}:{{ elasticsearch_port }}
Kibana: http://{{ ansible_default_ipv4.address | default(ansible_host) }}:{{ kibana_port }}
Logstash Beats Input: {{ ansible_default_ipv4.address | default(ansible_host) }}:{{ logstash_beats_port }}
Cluster Name: {{ cluster_name }}
Node Name: {{ node_name }}
IMPORTANT: Security is disabled for development. Enable X-Pack security for production!
Create templates/elasticsearch.yml.j2:
# ===================== Elasticsearch Configuration =====================
cluster.name: {{ es_cluster_name }}
node.name: {{ es_node_name }}
path.data: {{ es_path_data }}
path.logs: {{ es_path_logs }}
network.host: {{ es_network_host }}
http.port: {{ es_http_port }}
transport.port: {{ es_transport_port }}
discovery.type: {{ es_discovery_type }}
# X-Pack Security (disabled for development)
xpack.security.enabled: {{ es_xpack_security_enabled | default(false) }}
xpack.security.enrollment.enabled: false
# Memory lock
bootstrap.memory_lock: true
# Action auto create index
action.auto_create_index: true
Create templates/kibana.yml.j2:
# ===================== Kibana Configuration =====================
server.port: {{ kb_server_port }}
server.host: "{{ kb_server_host }}"
server.name: "{{ kb_server_name }}"
elasticsearch.hosts: ["{{ kb_elasticsearch_hosts }}"]
# Logging
logging.dest: /var/log/kibana/kibana.log
logging.verbose: true
# Security (disabled for development)
xpack.security.enabled: false
---
elk:
hosts:
elk-server:
ansible_host: 192.168.1.108
ansible_user: ansible
ansible_become: true
# Test connectivity
ansible all -i inventory.yml -m ping
# Run the ELK Stack playbook
ansible-playbook -i inventory.yml elk-stack.yml
# Run with custom passwords
ansible-playbook -i inventory.yml elk-stack.yml \
-e "elastic_password=MyElasticP@ss123" \
-e "kibana_password=MyKibanaP@ss456" \
-e "logstash_password=MyLogstashP@ss789"
# Check Elasticsearch health
curl http://elk-server:9200/_cluster/health?pretty
# Check Kibana status
curl http://elk-server:5601/api/status
# Check Logstash
curl http://elk-server:9600/_node/stats/pipelines?pretty
# Access Kibana UI
# http://elk-server:5601
- name: Install Filebeat on monitored hosts
hosts: monitored_hosts
become: true
vars:
elastic_version: "9.3.1"
elasticsearch_host: "192.168.1.108"
logstash_host: "192.168.1.108"
tasks:
- name: Add Elastic APT key (Debian/Ubuntu)
apt_key:
url: "https://artifacts.elastic.co/GPG-KEY-elasticsearch"
state: present
when: ansible_os_family == "Debian"
- name: Add Elastic APT repository (Debian/Ubuntu)
apt_repository:
repo: "deb https://artifacts.elastic.co/packages/9.x/apt stable main"
state: present
filename: elastic-9.x
when: ansible_os_family == "Debian"
- name: Install Filebeat
package:
name: "filebeat{% if elastic_version %}-{{ elastic_version }}{% endif %}"
state: present
- name: Configure Filebeat
template:
src: filebeat.yml.j2
dest: /etc/filebeat/filebeat.yml
owner: root
group: root
mode: '0640'
vars:
fb_output_logstash_hosts: ["{{ logstash_host }}:5044"]
fb_setup_kibana_host: "{{ elasticsearch_host }}:5601"
notify: Restart Filebeat
- name: Load Filebeat template
command: filebeat setup --template
changed_when: false
- name: Load Filebeat dashboards
command: filebeat setup --dashboards
changed_when: false
- name: Enable and start Filebeat
systemd:
name: filebeat
enabled: true
state: started
handlers:
- name: Restart Filebeat
systemd:
name: filebeat
state: restarted
Create templates/filebeat.yml.j2:
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/syslog
- /var/log/messages
- /var/log/auth.log
fields:
type: syslog
- type: log
enabled: true
paths:
- /var/log/nginx/*.log
fields:
type: nginx
- type: log
enabled: true
paths:
- /var/log/apache2/*.log
fields:
type: apache
filebeat.config.modules:
path: ${path.config}/modules.d/*.yml
reload.enabled: false
setup.template.settings:
index.number_of_shards: 1
output.logstash:
hosts: {{ fb_output_logstash_hosts }}
setup.kibana:
host: {{ fb_setup_kibana_host }}
processors:
- add_host_metadata:
when.not.contains.tags: forwarded
- add_cloud_metadata: ~
- add_docker_metadata: ~
- add_kubernetes_metadata: ~
# Check logs
sudo tail -f /var/log/elasticsearch/elasticsearch.log
# Check JVM settings
sudo cat /etc/elasticsearch/jvm.options.d/jvm.options
# Verify memory lock
ulimit -l
# Check Elasticsearch connectivity
curl http://localhost:9200/_cluster/health?pretty
# Check Kibana logs
sudo tail -f /var/log/kibana/kibana.log
# Verify configuration
sudo cat /etc/kibana/kibana.yml
# Check pipeline status
curl http://localhost:9600/_node/stats/pipelines?pretty
# Check Logstash logs
sudo tail -f /var/log/logstash/logstash-plain.log
# Test configuration
sudo /usr/share/logstash/bin/logstash --path.settings /etc/logstash --config.test_and_exit
We develop tailored automation solutions for:
Let’s discuss your requirements: office@linux-server-admin.com | Contact