ELK Stack ile Apache Log Analizi: Adım Adım Kurulum ve Kullanım

Geçen ay bir e-ticaret müşterisinde ciddi bir performans sorunu yaşadık. Apache logları her gün 2-3 GB büyüyordu, sunucu yavaşlıyordu ve kimse neyin nereye gittiğini bilmiyordu. “tail -f access.log” ile oturup bakmak artık işe yaramıyordu. ELK Stack kurarak sorunu çözdük, ama bu süreçte öğrendiğimiz bazı ince noktalar var ki belgelemeye değer.

ELK Stack Nedir, Neden Apache Logları için Kullanılır

ELK; Elasticsearch, Logstash ve Kibana’nın kısaltmasıdır. Beats bileşeniyle birlikte artık Elastic Stack olarak da adlandırılıyor ama sektörde ELK adı yapışıp kaldı. Temel mantık şu: Logstash logları toplayıp işliyor, Elasticsearch bu verileri indeksleyip saklıyor, Kibana ise görselleştirme katmanı olarak çalışıyor.

Apache için bu mimari özellikle değerli çünkü:

  • Saniyede binlerce istek logunu gerçek zamanlı analiz edebilirsiniz
  • Belirli IP adreslerini, URL pattern’lerini veya hata kodlarını anında filtreleyebilirsiniz
  • 4xx/5xx hatalarını trend olarak takip edebilirsiniz
  • DDoS veya brute-force girişimlerini erken fark edebilirsiniz

Şimdi sıfırdan kuruluma geçelim.

Ortam Hazırlığı ve Kurulum

Ben bu kurulumu Ubuntu 22.04 LTS üzerinde yaptım. CentOS/RHEL kullananlar için paket yöneticisi komutları farklı olacak ama yapı aynı.

Öncelikle Java gerekiyor. Elasticsearch kendi JDK’sını getiriyor artık ama yine de sisteme bakalım:

# Java kontrolü
java -version

# Elastic'in GPG anahtarını ve repo'yu ekleyelim
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo gpg --dearmor -o /usr/share/keyrings/elasticsearch-keyring.gpg

echo "deb [signed-by=/usr/share/keyrings/elasticsearch-keyring.gpg] https://artifacts.elastic.co/packages/8.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-8.x.list

sudo apt-get update

# Üç bileşeni kuruyoruz
sudo apt-get install elasticsearch logstash kibana -y

Kurulum bittikten sonra Elasticsearch’ü başlatıp durumuna bakalım:

sudo systemctl daemon-reload
sudo systemctl enable elasticsearch
sudo systemctl start elasticsearch

# Servis durumu
sudo systemctl status elasticsearch

# Elasticsearch çalışıyor mu?
curl -X GET "localhost:9200"

Eğer güvenlik ayarları açıksa (8.x sürümlerinde varsayılan olarak açık geliyor) şifre gerekecek. İlk kurulumda terminale yazdırılan şifreyi bir yere not edin. Kaçırdıysanız:

sudo /usr/share/elasticsearch/bin/elasticsearch-reset-password -u elastic

Logstash Yapılandırması: Apache Loglarını Çekmek

Bu kısım işin kalbi. Logstash’ın Apache’nin combined log format’ını anlaması için doğru parser’ı kurmanız gerekiyor.

/etc/logstash/conf.d/apache.conf dosyasını oluşturun:

input {
  file {
    path => "/var/log/apache2/access.log"
    start_position => "beginning"
    sincedb_path => "/var/lib/logstash/sincedb_apache"
    type => "apache_access"
    tags => ["apache", "access"]
  }
  file {
    path => "/var/log/apache2/error.log"
    start_position => "beginning"
    sincedb_path => "/var/lib/logstash/sincedb_apache_error"
    type => "apache_error"
    tags => ["apache", "error"]
  }
}

filter {
  if [type] == "apache_access" {
    grok {
      match => { "message" => "%{COMBINEDAPACHELOG}" }
    }
    date {
      match => [ "timestamp", "dd/MMM/yyyy:HH:mm:ss Z" ]
      target => "@timestamp"
    }
    geoip {
      source => "clientip"
      target => "geoip"
    }
    useragent {
      source => "agent"
      target => "useragent"
    }
    mutate {
      convert => {
        "bytes" => "integer"
        "response" => "integer"
      }
    }
  }
}

output {
  if [type] == "apache_access" {
    elasticsearch {
      hosts => ["localhost:9200"]
      index => "apache-access-%{+YYYY.MM.dd}"
      user => "elastic"
      password => "SIFRENIZ"
    }
  }
  if [type] == "apache_error" {
    elasticsearch {
      hosts => ["localhost:9200"]
      index => "apache-error-%{+YYYY.MM.dd}"
      user => "elastic"
      password => "SIFRENIZ"
    }
  }
}

Birkaç önemli nokta: sincedb_path dosyası Logstash’ın hangi satıra kadar okuduğunu hatırlamasını sağlar. Bu dosyayı silmek logları baştan okutmak anlamına gelir; test süreçlerinde işinize yarar. geoip filtresi IP adreslerini coğrafi konuma çeviriyor, Kibana haritalarında kullanacağız.

Yapılandırmayı test etmek için:

sudo -u logstash /usr/share/logstash/bin/logstash --path.settings /etc/logstash -t
# "Configuration OK" mesajını görmelisiniz

sudo systemctl start logstash
sudo systemctl enable logstash

# Logstash loglarını takip edin
tail -f /var/log/logstash/logstash-plain.log

Filebeat ile Hafif Log Toplama

Logstash’ı doğrudan log sunucusuna kurmak her zaman ideal değildir. Özellikle yüzlerce web sunucunuz varsa her birine Logstash kurmak hem kaynak israfı hem de yönetim kabusu olur. Filebeat bu noktada devreye giriyor.

Gerçek dünya senaryosunda şu mimariyi kullanıyoruz: Web sunucularında Filebeat, merkezi bir log sunucusunda Logstash + Elasticsearch + Kibana.

Web sunucusunda Filebeat kurulumu:

sudo apt-get install filebeat -y

# Filebeat yapılandırması
sudo nano /etc/filebeat/filebeat.yml
filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /var/log/apache2/access.log
  fields:
    log_type: apache_access
    server_name: web01-production
  fields_under_root: true
  multiline.pattern: '^d{1,3}.d{1,3}'
  multiline.negate: true
  multiline.match: after

- type: log
  enabled: true
  paths:
    - /var/log/apache2/error.log
  fields:
    log_type: apache_error
    server_name: web01-production
  fields_under_root: true

output.logstash:
  hosts: ["LOGSTASH_SUNUCU_IP:5044"]

processors:
  - add_host_metadata: ~
  - add_cloud_metadata: ~

Filebeat kullanıyorsanız Logstash input kısmını da güncellemeniz gerekiyor:

input {
  beats {
    port => 5044
    ssl => false
  }
}

Üretim ortamında SSL mutlaka açın. Ama başlangıçta konuyu karmaşıklaştırmamak için bıraktım.

Kibana Yapılandırması

Kibana’yı dışarıdan erişilebilir yapmak için yapılandırma dosyasına bakalım:

sudo nano /etc/kibana/kibana.yml
server.port: 5601
server.host: "0.0.0.0"
server.name: "kibana-prod"
elasticsearch.hosts: ["http://localhost:9200"]
elasticsearch.username: "kibana_system"
elasticsearch.password: "KIBANA_SIFRE"

# Türkçe tarih ve zaman dilimi için
i18n.locale: "en"

# Log ayarları
logging.appenders.file.type: file
logging.appenders.file.fileName: /var/log/kibana/kibana.log
logging.appenders.file.layout.type: json
logging.root.appenders: [default, file]
sudo systemctl start kibana
sudo systemctl enable kibana

Kibana’ya http://SUNUCU_IP:5601 adresinden erişebilirsiniz. İlk girişte elastic kullanıcı adı ve şifrenizi kullanın.

Index Pattern Oluşturma ve İlk Dashboard

Kibana arayüzünde sol menüden Stack Management > Index Patterns yolunu izleyin. apache-access-* pattern’ini oluşturun ve @timestamp alanını zaman alanı olarak seçin.

Bu noktadan sonra Discover ekranında loglarınıza bakabilirsiniz. Ama asıl güç, visualization’larda yatıyor.

Temel Apache analizi için oluşturmanızı önerdiğim görselleştirmeler:

  • HTTP Status Code Dağılımı: response alanına göre pie chart veya bar chart
  • Top 10 IP Adresleri: clientip.keyword alanına göre data table
  • Saatlik İstek Trendi: @timestamp alanına göre line chart
  • Yavaş İstekler: bytes alanının 95. persentili
  • 404 Hata Haritası: geoip.location alanına göre map visualization

Elasticsearch’te Manuel Sorgu Yazmak

Bazen Kibana arayüzü yetmez, doğrudan Elasticsearch API’sini kullanmak gerekir. Özellikle otomatik raporlama veya script entegrasyonları için bu kritik.

# Son 24 saatte kaç istek geldi?
curl -X GET "localhost:9200/apache-access-*/_count" 
  -H 'Content-Type: application/json' 
  -u elastic:SIFRE 
  -d '{
  "query": {
    "range": {
      "@timestamp": {
        "gte": "now-24h",
        "lte": "now"
      }
    }
  }
}'

# 5xx hataları listele
curl -X GET "localhost:9200/apache-access-*/_search" 
  -H 'Content-Type: application/json' 
  -u elastic:SIFRE 
  -d '{
  "size": 100,
  "query": {
    "range": {
      "response": {
        "gte": 500,
        "lt": 600
      }
    }
  },
  "sort": [
    { "@timestamp": { "order": "desc" } }
  ],
  "_source": ["@timestamp", "clientip", "request", "response", "bytes"]
}'

Bu sorguları cron ile çalıştırıp mail atabilir veya bir monitoring sistemine besleyebilirsiniz.

Gerçek Dünya: DDoS Tespiti ve IP Bloklama

Bahsettiğim e-ticaret projesine döneyim. Logları Kibana’ya aldığımızda ilginç bir şey fark ettik: Tek bir IP adresi 10 dakikada 15.000 istek atmıştı. Klasik bir scraper veya DDoS girişimiydi.

Bunu tespit eden bir Logstash filtresi ve aksiyon almak için bir script:

# Elasticsearch'ten saldırgan IP'leri çeken script
#!/bin/bash

ELASTIC_HOST="localhost:9200"
ELASTIC_USER="elastic:SIFRENIZ"
THRESHOLD=1000
TIME_WINDOW="now-10m"

# Son 10 dakikada 1000'den fazla istek atan IP'ler
AGGRESSIVE_IPS=$(curl -s -X GET "${ELASTIC_HOST}/apache-access-*/_search" 
  -H 'Content-Type: application/json' 
  -u "${ELASTIC_USER}" 
  -d "{
  "size": 0,
  "query": {
    "range": {
      "@timestamp": {
        "gte": "${TIME_WINDOW}"
      }
    }
  },
  "aggs": {
    "top_ips": {
      "terms": {
        "field": "clientip.keyword",
        "min_doc_count": ${THRESHOLD},
        "size": 20
      }
    }
  }
}" | python3 -c "
import sys, json
data = json.load(sys.stdin)
buckets = data['aggregations']['top_ips']['buckets']
for b in buckets:
    print(b['key'])
")

# Tespit edilen IP'leri iptables ile blokla
for IP in ${AGGRESSIVE_IPS}; do
  echo "$(date): Blocking aggressive IP: ${IP}" >> /var/log/auto-block.log
  iptables -I INPUT -s "${IP}" -j DROP
done

Bu script’i crontab’a ekleyin:

# Her 5 dakikada bir çalıştır
*/5 * * * * /usr/local/bin/check-aggressive-ips.sh

Tabii bu yaklaşımın riskleri var. CDN arkasındaysanız gerçek IP yerine CDN IP’leri görebilirsiniz. Apache tarafında mod_remoteip modülünü aktif etmeyi unutmayın.

Index Yaşam Döngüsü Yönetimi

Logları sonsuza kadar tutmak disk sorununa yol açar. Elasticsearch’ün ILM (Index Lifecycle Management) özelliğiyle indeksleri otomatik olarak yönetebilirsiniz.

# ILM Policy oluştur
curl -X PUT "localhost:9200/_ilm/policy/apache-logs-policy" 
  -H 'Content-Type: application/json' 
  -u elastic:SIFRE 
  -d '{
  "policy": {
    "phases": {
      "hot": {
        "min_age": "0ms",
        "actions": {
          "rollover": {
            "max_primary_shard_size": "20gb",
            "max_age": "7d"
          }
        }
      },
      "warm": {
        "min_age": "7d",
        "actions": {
          "shrink": {
            "number_of_shards": 1
          },
          "forcemerge": {
            "max_num_segments": 1
          }
        }
      },
      "cold": {
        "min_age": "30d",
        "actions": {
          "freeze": {}
        }
      },
      "delete": {
        "min_age": "90d",
        "actions": {
          "delete": {}
        }
      }
    }
  }
}'

Bu policy ile loglarınız şu yaşam döngüsünü izleyecek:

  • Hot (0-7 gün): Aktif yazma, tam erişim
  • Warm (7-30 gün): Shard sayısı azaltılır, segment birleştirilir, okuma ağırlıklı
  • Cold (30-90 gün): Dondurulmuş indeks, minimum kaynak kullanımı
  • Delete (90+ gün): Otomatik silme

Kibana Alerting ile Proaktif İzleme

Kibana’nın Alerting özelliği ile belirli koşullar sağlandığında bildirim alabilirsiniz. Stack Management > Rules and Connectors yolunu izleyin.

Örneğin “5 dakikada 100’den fazla 500 hatası” kuralı için Elasticsearch query rule tipi kullanılabilir. Bu kural tetiklendiğinde Slack, PagerDuty veya email üzerinden bildirim gönderilir.

Üretim ortamında şu kuralları mutlaka tanımlayın:

  • 5xx Error Rate: 5 dakikada 50’den fazla sunucu hatası
  • Response Time Spike: Ortalama yanıt süresi 2 saniyeyi geçerse
  • Disk Space Warning: Elasticsearch disk kullanımı %80’i aşarsa
  • Log Volume Anomaly: Normal hacmin 3 katından fazla log gelirse

Performans Optimizasyonu İpuçları

Yüksek trafikli ortamlarda ELK Stack’in kendisi darboğaz haline gelebilir. Karşılaştığım sorunlar ve çözümleri:

Elasticsearch shard boyutu konusunda çok dikkatli olun. “Günlük indeks oluştur” mantığıyla başladık, sonradan bazı günler 50 GB’ı aşan indeksler oluşturduk. Shard başına 20-50 GB ideal. ILM’deki rollover ayarı bunu çözüyor.

Logstash’ın worker sayısını CPU çekirdeğinize göre ayarlayın:

# /etc/logstash/logstash.yml
pipeline.workers: 4
pipeline.batch.size: 500
pipeline.batch.delay: 50

Elasticsearch’ün heap size ayarı kritik. Fiziksel RAM’in yarısını verin ama 30 GB’ı geçmeyin:

# /etc/elasticsearch/jvm.options
-Xms8g
-Xmx8g

/etc/elasticsearch/elasticsearch.yml dosyasında da şu ayarlar önemli:

# Tek node kurulum için
discovery.type: single-node

# Index buffer boyutu
indices.memory.index_buffer_size: 20%

# Shard başına arama thread sayısı
thread_pool.search.queue_size: 1000

Sonuç

ELK Stack ile Apache log analizi, başlangıçta karmaşık görünse de doğru yapılandırıldığında inanılmaz bir görünürlük sağlıyor. Bahsettiğim e-ticaret projesinde bu sistemi kurduktan sonra hem DDoS girişimlerini gerçek zamanlı tespit etmeye başladık hem de en yavaş çalışan endpoint’leri belirleyip kodda optimize ettik. Performans sorununun %70’i aslında belirli bir ürün listesi sorgusundan kaynaklanıyordu ve bunu ancak ELK ile görebildik.

Kurulum sıralaması önemli: Önce Elasticsearch ayağa kaldırın ve sağlıklı çalıştığından emin olun. Sonra Logstash veya Filebeat ile veri akışını sağlayın. En son Kibana’yı bağlayın. Tersten gitmeye çalışmak gereksiz hata ayıklama süreleri doğuruyor.

ILM policy’lerini işin başından kurun; “ileride ayarlarım” deyip geçiştirmeyin. Aylar sonra dolan diskle uğraşmak zorunda kalmak istemezsiniz. Ve Kibana alerting’i mutlaka yapılandırın; logları toplamak güzel ama proaktif uyarılar olmadan ELK, sadece pahalı bir log depolama sistemi olarak kalır.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir