diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..007538e9dc735b15f93802b944c338b938ab28c1
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,50 @@
+*.log
+~*
+*~
+*.sw[op]
+*.py[cod]
+.DS_Store
+__pycache__/
+.vagrant/
+vendor/
+Thumbs.db
+*.retry
+.svn/
+.sass-cache/
+*.log
+*.out
+*.so
+node_modules/
+.npm/
+nbproject/
+*.ipynb
+.idea/
+*.egg-info/
+*.[ao]
+.classpath
+.cache/
+bower_components/
+*.class
+*.[ewj]ar
+secring.*
+.*.kate-swp
+.swp.*
+.directory
+.Trash-*
+build/
+_build/
+dist/
+.tox/
+*.pdf
+*.exe
+*.dll
+*.gz
+*.tgz
+*.tar
+*.rar
+*.zip
+*.pid
+*.lock
+*.env
+.bundle/
+data/
diff --git a/curator/actions.yml b/curator/actions.yml
new file mode 100644
index 0000000000000000000000000000000000000000..1bd95c1864651a4bedd1b83e99d54cdadfc0a7df
--- /dev/null
+++ b/curator/actions.yml
@@ -0,0 +1,16 @@
+---
+actions:
+    1:
+        action: delete_indices
+        description: Delete old Logstash indices
+        ignore_empty_list: True
+        filters:
+            - filtertype: pattern
+              kind: timestring
+              value: '%Y.%m.%d'
+            - filtertype: age
+              source: name
+              direction: older
+              timestring: '%Y.%m.%d'
+              unit: days
+              unit_count: 30
diff --git a/curator/crontab b/curator/crontab
new file mode 100644
index 0000000000000000000000000000000000000000..4aac46f5acc921c12bbda4d0ff05bb7c5eefd148
--- /dev/null
+++ b/curator/crontab
@@ -0,0 +1,2 @@
+0 1 * * * /usr/local/bin/curator --config /etc/curator.yml /actions.yml
+30 * * * * /usr/local/bin/curator-disk-space
diff --git a/curator/curator-disk-space b/curator/curator-disk-space
new file mode 100755
index 0000000000000000000000000000000000000000..eaaea12ecea53eabfbff17bd7fe6d44f45b30a5a
--- /dev/null
+++ b/curator/curator-disk-space
@@ -0,0 +1,22 @@
+#!/bin/sh
+set -eu
+
+[ -n "${CURATOR_DISK_SPACE_PERCENT:-}" ] || { echo "Free disk space percent wasn't set, exiting." > /dev/stderr; exit 1; }
+
+disk_size="$( df -Pk /usr/share/elasticsearch/data | awk 'NR==2 {print $2}' )"
+disk_avail="$( df -Pk /usr/share/elasticsearch/data | awk 'NR==2 {print $4}' )"
+threshold="$((  disk_size * CURATOR_DISK_SPACE_PERCENT ))"
+
+[ "$threshold" -lt "$disk_avail" ] || { echo "Enough disk space, skipping curator run." > /dev/stderr; exit; }
+
+# Assuming the usage is mainly (all) by Elasticsearch.
+export CURATROR_DISK_SPACE="$(( (threshold - disk_avail) / (1024*1024) ))"
+exec curator_cli --config /etc/curator.yml \
+                 delete_indices \
+                 --ignore_empty_list \
+                 --filter_list "[{\"filtertype\": \"pattern\",
+                                  \"kind\": \"timestring\",
+                                  \"value\": \"%Y.%m.%d\"},
+                                 {\"filtertype\": \"space\",
+                                  \"use_age\": true,
+                                  \"disk_space\": $CURATROR_DISK_SPACE}]"
diff --git a/curator/curator.yml b/curator/curator.yml
new file mode 100644
index 0000000000000000000000000000000000000000..7b7e403391cc38db98a9a2e6db4482d37a41bce0
--- /dev/null
+++ b/curator/curator.yml
@@ -0,0 +1,4 @@
+---
+client:
+    hosts:
+        - ${ELASTICSEARCH_HOST:localhost}
diff --git a/data/.gitkeep b/data/.gitkeep
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000000000000000000000000000000000000..c95ffaec6d2f3a6c05d79bafe2c3d42c6898ee41
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,181 @@
+---
+version: '3'
+services:
+    metricbeat:
+        image: docker.elastic.co/beats/metricbeat:${VERSION}
+        volumes: &metricbeat_volumes
+            - /:/hostfs:ro
+            - /proc:/hostfs/proc:ro
+            - /sys/fs/cgroup:/hostfs/sys/fs/cgroup:ro
+            - /var/run/docker.sock:/hostfs/var/run/docker.sock
+            - ./metricbeat.yml:/usr/share/metricbeat/metricbeat.yml:ro
+            - ./metricbeat-entrypoint:/usr/local/bin/metricbeat-entrypoint:ro
+        depends_on:
+            - elasticsearch
+            - kibana
+            - metricbeat_setup
+            - logstash
+        healthcheck:
+            test: ["CMD", "pgrep", "metricbeat"]
+            interval: 10s
+            timeout: 3s
+            retries: 10
+        environment:
+            KIBANA_HOST: localhost
+            ELASTICSEARCH_HOST: localhost
+            LOGSTASH_HOST: localhost
+        network_mode: host
+        pid: host
+        restart: always
+        user: root
+        entrypoint:
+            - /usr/local/bin/metricbeat-entrypoint
+        command:
+            - -e
+        logging: &logging
+            driver: gelf
+            options:
+                gelf-address: "udp://localhost:12201"
+    metricbeat_setup:
+        image: docker.elastic.co/beats/metricbeat:${VERSION}
+        environment: &environment
+            KIBANA_HOST: kibana
+            ELASTICSEARCH_HOST: elasticsearch
+            LOGSTASH_HOST: logstash
+        links:
+            - elasticsearch
+            - kibana
+            - logstash
+        volumes: *metricbeat_volumes
+        command: metricbeat setup -e
+        restart: on-failure
+        logging: *logging
+    heartbeat:
+        image: docker.elastic.co/beats/heartbeat:${VERSION}
+        environment: *environment
+        links:
+            - elasticsearch
+            - kibana
+            - logstash
+        depends_on:
+            - heartbeat_setup
+        volumes:
+            - ./heartbeat.yml:/usr/share/heartbeat/heartbeat.yml:ro
+        healthcheck:
+            test: ["CMD", "pgrep", "heartbeat"]
+            interval: 10s
+            timeout: 3s
+            retries: 10
+        restart: always
+        logging: *logging
+    heartbeat_setup:
+        image: docker.elastic.co/beats/heartbeat:${VERSION}
+        environment: *environment
+        links:
+            - elasticsearch
+            - kibana
+        volumes:
+            - ./heartbeat.yml:/usr/share/heartbeat/heartbeat.yml:ro
+        command: heartbeat setup -e
+        restart: on-failure
+        logging: *logging
+    elasticsearch:
+        image: docker.elastic.co/elasticsearch/elasticsearch-oss:${VERSION}
+        environment:
+            <<: *environment
+            'cluster.name': mobile
+            'discovery.type': 'single-node'
+            'ES_JAVA_OPTS': '-Xms2g -Xmx2g'
+        healthcheck:
+            test: ["CMD", "curl", "--fail", "http://localhost:9200/_cat/health"]
+            interval: 10s
+            timeout: 3s
+            retries: 10
+        volumes:
+            - ./data:/usr/share/elasticsearch/data
+        ulimits:
+            nproc: 4096
+            nofile:
+                soft: 65536
+                hard: 65536
+        #sysctls:
+        #    vm.max_map_count: 262144
+        restart: always
+        logging: *logging
+        ports:
+            - '9200:9200'
+    logstash:
+        image: docker.elastic.co/logstash/logstash-oss:${VERSION}
+        command: logstash -e "input { http { add_field => { 'input' => 'http' } } beats { port => 5044 add_field => { 'input' => 'beats' } } gelf { add_field => { 'input' => 'gelf' } } } output { elasticsearch { hosts => [ 'elasticsearch' ] index => 'logstash-%{[input]}-%{+YYYY.MM.dd}' }}" --path.settings="" --http.host="0.0.0.0"
+        links:
+            - elasticsearch
+        ports:
+            - 8080:8080
+            - 5044:5044
+            - 12201:12201/udp
+        healthcheck:
+            test: ["CMD", "curl", "--fail", "http://localhost:9600/_node"]
+            interval: 10s
+            timeout: 3s
+            retries: 10
+        restart: always
+        logging: *logging
+        expose:
+            - "8080"
+            - "5044"
+            - "9600"
+            - "12201"
+    kibana:
+        build:
+            context: ./kibana
+            args:
+                KIBANA_VERSION: "${VERSION}"
+                LOGTRAIL_VERSION: "0.1.24"
+        links:
+            - elasticsearch
+        ports:
+            - 5601:5601
+        healthcheck:
+            test: ["CMD", "curl", "--fail", "http://localhost:5601/"]
+            interval: 10s
+            timeout: 3s
+            retries: 10
+        restart: always
+        logging: *logging
+        environment:
+            <<: *environment
+            ELASTICSEARCH_URL: http://elasticsearch:9200
+            STATUS_ALLOWANONYMOUS: 'True'
+            SERVER_HOST: 0.0.0.0
+    kibana_setup:
+        image: centos:7
+        links:
+            - kibana
+        restart: on-failure
+        logging: *logging
+        volumes:
+            - ./kibana-setup:/usr/local/bin/kibana-setup:ro
+        command: /usr/local/bin/kibana-setup
+        environment: *environment
+    curator:
+        image: adarnimrod/curator
+        #build:
+        #    context: ./curator
+        links:
+            - elasticsearch
+        healthcheck:
+            test: ["CMD", "pgrep", "crond"]
+            interval: 10s
+            timeout: 3s
+            retries: 10
+        restart: always
+        logging: *logging
+        environment:
+            <<: *environment
+            CURATOR_DISK_SPACE_PERCENT: 20
+        volumes:
+            - ./data:/usr/share/elasticsearch/data:ro
+            - ./curator/actions.yml:/actions.yml:ro
+            - ./curator/curator.yml:/etc/curator.yml:ro
+            - ./curator/crontab:/var/spool/cron/crontabs/nobody:ro
+            - ./curator/curator-disk-space:/usr/local/bin/curator-disk-space:ro
diff --git a/heartbeat.yml b/heartbeat.yml
new file mode 100644
index 0000000000000000000000000000000000000000..24ef0f6eced78c78743b86bd75e3ae4b787e92cb
--- /dev/null
+++ b/heartbeat.yml
@@ -0,0 +1,40 @@
+---
+heartbeat:
+    monitors:
+        - name: Elasticsearch
+          type: http
+          schedule: "@every 1m"
+          urls:
+              - "http://${ELASTICSEARCH_HOST}:9200/_cat/health"
+        - name: Kibana
+          type: http
+          schedule: '@every 1m'
+          urls:
+              - "http://${KIBANA_HOST}:5601/"
+        - name: Logstash HTTP
+          type: http
+          schedule: '@every 1m'
+          urls:
+              - "http://${LOGSTASH_HOST}:9600/?pretty"
+              - "http://${LOGSTASH_HOST}:9600/_node/"
+        - name: Logstash TCP
+          type: tcp
+          schedule: '@every 1m'
+          hosts:
+              - "${LOGSTASH_HOST}"
+          ports:
+              - 5044
+              - 8080
+output:
+    elasticsearch:
+        hosts:
+            - "${ELASTICSEARCH_HOST}:9200"
+system:
+    hostfs: /hostfs
+setup:
+    kibana:
+        host: "${KIBANA_HOST}"
+    dashboards:
+        enabled: True
+    template:
+        overwrite: true
diff --git a/kibana-setup b/kibana-setup
new file mode 100755
index 0000000000000000000000000000000000000000..d55e89ae91a720cc6fbdabcce9f4f24e5def0080
--- /dev/null
+++ b/kibana-setup
@@ -0,0 +1,56 @@
+#!/bin/sh
+set -eu
+
+command -v curl>/dev/null || { echo "Can't find curl, exiting."; exit 1; }
+[ -n "${KIBANA_HOST:-}" ] || { echo "KIBANA_HOST is not specified, exiting."; exit 1; }
+
+alias curl="curl --verbose \
+                 --fail \
+                 -H 'Accept: application/json, text/plain, */*' \
+                 --compressed \
+                 --retry-delay 2 \
+                 --retry 99 \
+                 -H 'Content-Type: application/json;charset=utf-8' \
+                 -H 'kbn-xsrf: something'"
+
+
+echo 'Create the logstash-* index pattern.'
+while ! curl \
+    "http://$KIBANA_HOST:5601/api/saved_objects/index-pattern/logstash?overwrite=true" \
+    --data '{"attributes":{"title":"logstash-*","timeFieldName":"@timestamp"}}'
+do
+    sleep 2
+done
+
+echo 'Create the logstash-gelf-* index pattern.'
+while ! curl \
+    "http://$KIBANA_HOST:5601/api/saved_objects/index-pattern/logstash-gelf?overwrite=true" \
+    --data '{"attributes":{"title":"logstash-gelf-*","timeFieldName":"@timestamp"}}'
+do
+    sleep 2
+done
+
+echo 'Create the logstash-http-* index pattern.'
+while ! curl \
+    "http://$KIBANA_HOST:5601/api/saved_objects/index-pattern/logstash-http?overwrite=true" \
+    --data '{"attributes":{"title":"logstash-http-*","timeFieldName":"@timestamp"}}'
+do
+    sleep 2
+done
+
+echo 'Create the logstash-beats-* index pattern.'
+while ! curl \
+    "http://$KIBANA_HOST:5601/api/saved_objects/index-pattern/logstash-beats?overwrite=true" \
+    --data '{"attributes":{"title":"logstash-beats-*","timeFieldName":"@timestamp"}}'
+do
+    sleep 2
+done
+
+echo 'Set the logstash-* index pattern as default.'
+while ! curl \
+    "http://$KIBANA_HOST:5601/api/kibana/settings/defaultIndex?overwrite=true" \
+    --data '{"value":"logstash"}'
+do
+    sleep 2
+done
+echo
diff --git a/kibana/.dockerignore b/kibana/.dockerignore
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/kibana/Dockerfile b/kibana/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..0cba11e5e79d859a137e4c0f4679c2d5f7a9d9fd
--- /dev/null
+++ b/kibana/Dockerfile
@@ -0,0 +1,8 @@
+ARG KIBANA_VERSION
+FROM docker.elastic.co/kibana/kibana-oss:${KIBANA_VERSION}
+ARG KIBANA_VERSION
+ARG LOGTRAIL_VERSION
+ENV KIBANA_VERSION ${KIBANA_VERSION}
+ENV LOGTRAIL_VERSION ${LOGTRAIL_VERSION}
+RUN ./bin/kibana-plugin install "https://github.com/sivasamyk/logtrail/releases/download/v${LOGTRAIL_VERSION}/logtrail-${KIBANA_VERSION}-${LOGTRAIL_VERSION}.zip"
+COPY logtrail.json ./plugins/logtrail/logtrail.json
diff --git a/kibana/logtrail.json b/kibana/logtrail.json
new file mode 100644
index 0000000000000000000000000000000000000000..59d3c399efa4904b831ab4a90c913f51406c2e4a
--- /dev/null
+++ b/kibana/logtrail.json
@@ -0,0 +1,77 @@
+{
+  "version" : 1,
+  "index_patterns" : [
+    {
+      "es": {
+        "default_index": "logstash-gelf-*"
+      },
+      "tail_interval_in_seconds": 10,
+      "es_index_time_offset_in_seconds": 0,
+      "display_timezone": "local",
+      "display_timestamp_format": "MMM DD HH:mm:ss",
+      "max_buckets": 500,
+      "default_time_range_in_days" : 0,
+      "max_hosts": 100,
+      "max_events_to_keep_in_viewer": 5000,
+      "fields" : {
+        "mapping" : {
+            "timestamp" : "@timestamp",
+            "hostname" : "host",
+            "program": "container_name",
+            "message": "message"
+        },
+        "message_format": "{{{message}}}"
+      },
+      "color_mapping" : {
+      }
+    },
+    {
+      "es": {
+        "default_index": "logstash-http-*"
+      },
+      "tail_interval_in_seconds": 10,
+      "es_index_time_offset_in_seconds": 0,
+      "display_timezone": "local",
+      "display_timestamp_format": "MMM DD HH:mm:ss",
+      "max_buckets": 500,
+      "default_time_range_in_days" : 0,
+      "max_hosts": 100,
+      "max_events_to_keep_in_viewer": 5000,
+      "fields" : {
+        "mapping" : {
+            "timestamp" : "@timestamp",
+            "hostname" : "headers.http_host",
+            "program": "headers.request_uri",
+            "message": "message"
+        },
+        "message_format": "{{{message}}}"
+      },
+      "color_mapping" : {
+      }
+    },
+    {
+      "es": {
+        "default_index": "logstash-beats-*"
+      },
+      "tail_interval_in_seconds": 10,
+      "es_index_time_offset_in_seconds": 0,
+      "display_timezone": "local",
+      "display_timestamp_format": "MMM DD HH:mm:ss",
+      "max_buckets": 500,
+      "default_time_range_in_days" : 0,
+      "max_hosts": 100,
+      "max_events_to_keep_in_viewer": 5000,
+      "fields" : {
+        "mapping" : {
+            "timestamp" : "@timestamp",
+            "hostname" : "beat.hostname",
+            "program": "source",
+            "message": "message"
+        },
+        "message_format": "{{{message}}}"
+      },
+      "color_mapping" : {
+      }
+    }
+  ]
+}
diff --git a/metricbeat-entrypoint b/metricbeat-entrypoint
new file mode 100755
index 0000000000000000000000000000000000000000..a0604a3bd62fc3fc1c8ed74727f20afb3b16be35
--- /dev/null
+++ b/metricbeat-entrypoint
@@ -0,0 +1,9 @@
+#!/bin/sh
+set -eu
+
+[ "$(whoami)" = "root" ] || { echo "Not running as root, exiting." >> /dev/stderr; exit 1; }
+
+gid="$(stat --format='%g' /hostfs/var/run/docker.sock)"
+groupadd --force --non-unique --gid "$gid" docker
+usermod --append --groups docker metricbeat
+eval "exec su -pc '/usr/local/bin/docker-entrypoint $@' metricbeat"
diff --git a/metricbeat.yml b/metricbeat.yml
new file mode 100644
index 0000000000000000000000000000000000000000..8bc28999499545bd0fa6a2e2a4a13221e37dda60
--- /dev/null
+++ b/metricbeat.yml
@@ -0,0 +1,58 @@
+---
+metricbeat:
+    modules:
+        - module: docker
+          metricsets:
+              - container
+              - cpu
+              - diskio
+              - healthcheck
+              - info
+              - memory
+              - network
+          hosts:
+              - unix:///hostfs/var/run/docker.sock
+        - module: system
+          metricsets:
+              - core
+              - cpu
+              - diskio
+              - filesystem
+              - fsstat
+              - load
+              - memory
+              - network
+              - process
+              - process_summary
+              - socket
+              - uptime
+        - module: elasticsearch
+          metricsets:
+              - node
+              - node_stats
+          hosts:
+              - "${ELASTICSEARCH_HOST}:9200"
+        - module: kibana
+          metricsets:
+              - status
+          hosts:
+              - "${KIBANA_HOST}:5601"
+        - module: logstash
+          metricsets:
+              - node
+              - node_stats
+          hosts:
+              - "${LOGSTASH_HOST}"
+output:
+    elasticsearch:
+        hosts:
+            - "${ELASTICSEARCH_HOST}:9200"
+system:
+    hostfs: /hostfs
+setup:
+    kibana:
+        host: "${KIBANA_HOST}"
+    dashboards:
+        enabled: True
+    template:
+        overwrite: true