Install an ELK Server on Ubuntu 18.04

ELK Stack

The ELK stack is an amazing open source for logs and metrics.  What you can do with it is almost literally restricted by your imagination.  I use it extensively in my infrastructure for anything from ingesting server logs, setting alerts, statistic gathering and data visualization.  It is an amazing tool and worth the time to learn and add to your toolkit.


The ELK (or Elastic) stack has four main components which are:

  • Elasticsearch: a distributed RESTful search engine which stores all of the collected data.
  • Logstash: the data processing component of the Elastic Stack which sends incoming data to Elasticsearch.
  • Kibana: a web interface for searching and visualizing logs.
  • Beats: lightweight, single-purpose data shippers that can send data from hundreds or thousands of machines to either Logstash or Elasticsearch.

What you need:

  • Ubuntu 18.04 Server (or desktop) installed

First Step:    Install Java

$ sudo apt update
$ sudo apt install default-jre

Second Step:  Add Elasticsearch source and install

$ wget -qO - | sudo apt-key add -
$ echo "deb stable main" | sudo tee -a /etc/apt/sources.list.d/elastic-6.x.list
$ sudo apt update
$ sudo apt install elasticsearch

Third Step:  Configure Elasticsearch to listen only on local host 

Change value and save elasticsearch.yml

$ sudo nano /etc/elasticsearch/elasticsearch.yml

. . . localhost
. . .

Start Elasticsearch:

$ sudo systemctl start elasticsearch

Start Elasticsearch on system boot:

$ sudo systemctl enable elasticsearch

Fourth Step:  Install Kibana

$ sudo apt install kibana

Enable and start Kibana

$ sudo systemctl enable kibana
$ sudo systemctl start kibana

Fifth Step:  Install Logstash

$ sudo apt install logstash

Configure an Beats input:

$ sudo nano /etc/logstash/conf.d/02-beats-input.conf

Add the following text

input {
beats {
port => 5044

Add a syslog input:

$ sudo nano /etc/logstash/conf.d/10-syslog-filter.conf

filter {
if [fileset][module] == "system" {
if [fileset][name] == "auth" {
grok {
match => { "message" => ["%{SYSLOGTIMESTAMP:[system][auth][timestamp]} %{SYSLOGHOST:[system][auth][hostname]} sshd(?:[%{POSINT:[system][auth][pid]}])?: %{DATA:[system][auth][ssh][event]} %{DATA:[system][auth][ssh][method]} for (invalid user )?%{DATA:[system][auth][user]} from %{IPORHOST:[system][auth][ssh][ip]} port %{NUMBER:[system][auth][ssh][port]} ssh2(: %{GREEDYDATA:[system][auth][ssh][signature]})?",
"%{SYSLOGTIMESTAMP:[system][auth][timestamp]} %{SYSLOGHOST:[system][auth][hostname]} sshd(?:[%{POSINT:[system][auth][pid]}])?: %{DATA:[system][auth][ssh][event]} user %{DATA:[system][auth][user]} from %{IPORHOST:[system][auth][ssh][ip]}",
"%{SYSLOGTIMESTAMP:[system][auth][timestamp]} %{SYSLOGHOST:[system][auth][hostname]} sshd(?:[%{POSINT:[system][auth][pid]}])?: Did not receive identification string from %{IPORHOST:[system][auth][ssh][dropped_ip]}",
"%{SYSLOGTIMESTAMP:[system][auth][timestamp]} %{SYSLOGHOST:[system][auth][hostname]} sudo(?:[%{POSINT:[system][auth][pid]}])?: \s%{DATA:[system][auth][user]}  %{DATA:[system][auth][sudo][error]} ;)? TTY=%{DATA:[system][auth][sudo][tty]} ; PWD=%{DATA:[system][auth][sudo][pwd]} ; USER=%{DATA:[system][auth][sudo][user]} ; COMMAND=%{GREEDYDATA:[system][auth][sudo][command]}",                  "%{SYSLOGTIMESTAMP:[system][auth][timestamp]} %{SYSLOGHOST:[system][auth][hostname]} groupadd(?:[%{POSINT:[system][auth][pid]}])?: new group: name=%{}, GID=%{NUMBER:system.auth.groupadd.gid}",                  "%{SYSLOGTIMESTAMP:[system][auth][timestamp]} %{SYSLOGHOST:[system][auth][hostname]} useradd(?:[%{POSINT:[system][auth][pid]}])?: new user: name=%{DATA:[system][auth][user][add][name]}, UID=%{NUMBER:[system][auth][user][add][uid]}, GID=%{NUMBER:[system][auth][user][add][gid]}, home=%{DATA:[system][auth][user][add][home]}, shell=%{DATA:[system][auth][user][add][shell]}$",                  "%{SYSLOGTIMESTAMP:[system][auth][timestamp]} %{SYSLOGHOST:[system][auth][hostname]} %{DATA:[system][auth][program]}(?:[%{POSINT:[system][auth][pid]}])?: %{GREEDYMULTILINE:[system][auth][message]}"] }        pattern_definitions => {          "GREEDYMULTILINE"=> "(.|\n)"
remove_field => "message"
date {
match => [ "[system][auth][timestamp]", "MMM  d HH:mm:ss", "MMM dd HH:mm:ss" ]
geoip {
source => "[system][auth][ssh][ip]"
target => "[system][auth][ssh][geoip]"
else if [fileset][name] == "syslog" {
grok {
match => { "message" => ["%{SYSLOGTIMESTAMP:[system][syslog][timestamp]} %{SYSLOGHOST:[system][syslog][hostname]} %{DATA:[system][syslog][program]}(?:[%{POSINT:[system][syslog][pid]}])?: %{GREEDYMULTILINE:[system][syslog][message]}"] }
pattern_definitions => { "GREEDYMULTILINE" => "(.|\n)*" }
remove_field => "message"
date {
match => [ "[system][syslog][timestamp]", "MMM  d HH:mm:ss", "MMM dd HH:mm:ss" ]

Create Logstash Output

output {
elasticsearch {
hosts => ["localhost:9200"]
manage_template => false
index => "%{[@metadata][beat]}-%{[@metadata][version]}-%{+YYYY.MM.dd}"

Sixth Step:  Install Filebeat

$ sudo apt install filebeat

Configure Filebeat

$ sudo nano /etc/filebeat/filebeat.yml

Change the output.logstash section

# The Logstash hosts
hosts: ["localhost:5044"]

Enable Filebeat

$ sudo filebeat modules enable system


Leave a Reply