Setting up (B)ELK stack on your server

Last updated on

I’m a developer by day, but as evening falls I sometimes like to dabble as an amateur sysops. I’ve recently helped out setting up a server as part of a hobby project that I participate in. While I’m no sysops expert I like testing out technologies helpful in server administration. As a side effect it makes me appreciate just how much detail and work sysops people put into managing servers. One of these sysops technologies is the much known ELK stack (ElasticSearch, Logstash, and Kibana) recently joined by the different Beat log ingestion system services. ELK are usually used as a general tool to gather, filter, index, and analyze logs from different sources. In this post I will describe how a BELK stack can be set up, partially in docker and partially on the host, to provide an insight into your systems network traffic, system activity (from system logs), and process and performance activity.


The first piece of the puzzle is ElasticSearch a distributed search and analysis technology based on the Lucene library. It can be used to index documents and then search in them. It will index our log and event entries in our BELK stack. We can use the ElasticSearch docker image. If you are not familiar with Docker you might want to read up on both Docker and Docker Compose.

Create an elk and elasticsearch folder somewhere appropriate. When using docker /srv is commonly used.

mkdir -p /srv/elk/elasticsearch

Now create a new docker-compose.yml file either in the /srv/elk folder, or better yet on your own computer. It all depends on whether you have tcp access to the docker-engine on the host where you are setting up the BELK stack. Add the following contents to it:

  image: elasticsearch:latest
  restart: always
    - /srv/elk/elasticsearch/plugins:/usr/share/elasticsearch/plugins
    - /srv/elk/elasticsearch/data:/usr/share/elasticsearch/data
    - ""
    - ""

We call the service elasticsearch, use the latest elasticsearch image, and map in ports and volumes from the host into the container. The elasticsearch api should now be available from the host server’s port 9200 on localhost only.

You may start the elasticsearch container to check that everything works by running docker-compose up -d. Run docker-compose stop to stop elasticsearch.


Kibana is our second piece of the puzzle. It is simply put a web based data exploration and visualization tool built on top of elasticsearch to make it simple to explore and visualise/graph your elasticsearch data. It is commonly used to visualise logs or just data.

For Kibana we’ll use the official Kibana image to run Kibana in a docker container. We can simply add Kibana as a service in our docker-compose.yml file (the same one as before) by appending the following yaml config:

  image: kibana:latest
  restart: always
    - /srv/elk/kibana/config:/opt/kibana/config
    - ""
    - elasticsearch

and create a kibana folder under our elk folder:

mkdir -p /srv/elk/kibana/config

Kibana relies on a config file kibana.yml to function so you will need to add this under the kibana config folder.

touch /srv/elk/kibana/config/kibana.yml

See Setting Kibana server properties in the Kibana docs for which properties you may configure. For this setup you probably don’t need to change anything and can rely on the default values.

If you want to test that your Kibana instance works you can again start the docker containers as instructed before with docker-compose up -d. You Kibana instance should be accessible from localhost:5601 on your server. Run docker-compose stop to stop the services again.


While it is entirely possible to make TopBeat, PacketBeat, and FileBeat send their log and event data straight to ElasticSearch you might want to pass them through Logstash as this affords you Logstash’s filter feature with which you may extract more detailed information from your logs. We will therefore set up Logstash as well, all though this post won’t touch upon using the filter feature.

An official Logstash Docker image is available so again we use Docker to run the service. Create a folder for logstash configs:

mkdir -p /srv/elk/logstash/config

and add the following Logstash service configuration to the existing docker-compose.yml file:

  image: logstash:latest
  restart: always
  command: logstash -f /etc/logstash/conf.d/logstash.conf
    - /srv/elk/logstash/config:/etc/logstash/conf.d
    - ""
    - elasticsearch

As you can see we link in the elasticsearch service (so logstash can gain access to it from elasticsearch:9200, and map in a configuration directory from our host to the logstash container. We’ve also exposed the Logstash container’s port 5000 on the server’s localhost:5000.

You need to provide logstash with a configuration file in order to make it listen to port 5000 and send documents to elasticsearch:

vim /srv/elk/logstash/config/logstash.conf

which should contain an input section for the Beats and an ouput section for the ElasticSearch server:

input {
  beats {
    port => 5000

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

The Beats will now be able to send their data to Logstash at localhost:5000 from the host. We are now done with the Docker based services so you may start them with: docker-compose up -d from the directory where you keep your docker-compose.yml file. We need Logstash and Elasticsearch to be running for the upcoming steps.


Finally we need a way to collect our log data. While Logstash can read log files from our host the FileBeat package is special made to perform this task. Unlike Elasticsearch, Logstash, and Kibana we will install FileBeat, TopBeat, and PacketBeat on our host.

First add the Beat repository as described here (for the distro of your choice). Then install the beats. On Ubuntu you can use apt:

apt install filebeat packetbeat topbeat

Now we need to configure each Beat to use our Logstash instance, and provide our Elasticsearch server with the relevant Beat templates.

First edit the filebeat config with vim /etc/filebeat/filebeat.yml and make sure that the elasticsearch ouput is commented out:

# elasticsearch:
    # hosts: ["localhost:9200"]

Then comment in the logstash ouput config:

### Logstash as output
    # The Logstash hosts
    hosts: ["localhost:5000"]

Remember that we configured our Logstash server to listen to port 5000, and mapped port 5000 out to localhost:5000 on our host. This enables Filebeat to log its event to that port.

Then we need to insert the Filebeat template into our Elasticsearch index. The documentation tells us that we can use Curl for this:

curl -XPUT 'http://localhost:9200/_template/filebeat' -d@/etc/filebeat/filebeat.template.json

Finally we can start Filebeat. On Ubuntu you may use service filebeat start.

You can now repeat these steps for PacketBeat and TopBeat. Note that you may want to set the interval of data collection in the Topbeat configuration to avoid generating too much data. What interval is right for you might depend on your disk space, but 5 minutes works for me.

Add Beat indexes to Kibana.

If everything worked out okay you should now be able to go to Kibana and add your indices. Go to localhost:5601 and click the Settings tab. You should be presented with a screen where you can configure an index pattern. Thanks to our Logstash configuration an new index will be created each day for each of our Beat loggers. Our pattern should thus match the configuration "%{[@metadata][beat]}-%{+YYYY.MM.dd}" (from the Logstash config). So to get each of the three index types into Kibana we simply add them as filebeat-*, etc. If your index pattern is matched Kibana should show a green Create button as in the screenshot below.


After adding the index pattern you should be able to go to the Discover tab and view and search your logs.


You can now create your own visualizations over the indexed logs or you can download some of the visualizations and dashboards already created by the Kibana team. You can read more about that here and here.

Hope this guide helped you get started. Currently I’ve not yet tried setting up custom filters for things such as fail2ban and ufw in order to better visualize malicious traffic. You can also use a geoip plugin to map log and network traffic events on a world map to see where traffic is coming from. A future blog post might cover these subjects.


Image post header:

By Bureau of Land Management (Dean Creek Elk 4 Uploaded by Albert Herring) [CC BY-SA 2.0 (], via Wikimedia Commons.