Nginx Log Analizi: Access ve Error Log Ayrıştırma

Sunucu yönetiminde işler sarpa sardığında ilk başvuracağın yer her zaman loglar olacak. Nginx logları özellikle trafik analizi, güvenlik tespiti ve performans sorunlarının çözümünde altın değerinde bilgiler barındırıyor. Ama ham log dosyaları bazen yüzlerce megabyte, hatta gigabyte boyutuna ulaşabiliyor. Bu noktada “dosyayı aç, içine bak” yaklaşımı işe yaramıyor. Doğru araçları ve teknikleri kullanarak bu ham veriyi anlamlı bilgiye dönüştürmek gerekiyor.

Nginx Log Yapısını Anlamak

Analiz etmeden önce neyle çalıştığını bilmek şart. Nginx iki temel log dosyası üretiyor: access.log ve error.log.

Access Log Formatı

Nginx’in varsayılan access log formatı combined olarak adlandırılır ve şu yapıya sahiptir:

$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"

Gerçek hayattan bir örnek satır şöyle görünür:

192.168.1.105 - - [15/Jan/2024:14:32:10 +0300] "GET /api/products HTTP/1.1" 200 4823 "https://example.com/shop" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"

Bu satırı parçalayalım:

  • 192.168.1.105: İstemci IP adresi
  • : Ident protokolü (genellikle boş)
  • : Kimlik doğrulaması yapılmış kullanıcı adı
  • [15/Jan/2024:14:32:10 +0300]: İstek zamanı
  • “GET /api/products HTTP/1.1”: HTTP metodu, URI ve protokol
  • 200: HTTP durum kodu
  • 4823: Gönderilen byte miktarı
  • “https://example.com/shop”: Referer
  • “Mozilla/5.0…”: User-Agent

Error Log Formatı

Error log formatı biraz daha farklı:

2024/01/15 14:32:10 [error] 1234#1234: *56789 connect() failed (111: Connection refused) while connecting to upstream, client: 192.168.1.105, server: example.com, request: "GET /api/products HTTP/1.1", upstream: "http://127.0.0.1:8080/api/products", host: "example.com"

Error log severity seviyeleri:

  • debug: Çok ayrıntılı, geliştirme ortamında kullanılır
  • info: Bilgi amaçlı mesajlar
  • notice: Normal ama önemli olaylar
  • warn: Uyarılar
  • error: Hata mesajları
  • crit: Kritik sorunlar
  • alert: Acil müdahale gerektiren durumlar
  • emerg: Sistem kullanılamaz

Temel Log Analiz Araçları

Analiz için ağır silahlar çekmeden önce terminalde her sunucuda bulunan klasik araçlarla neler yapabileceğini görelim.

grep, awk ve sed Kombinasyonu

En çok ziyaret edilen 10 URL’yi bulmak:

awk '{print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10

Sadece 500 hata kodlarını filtrelemek:

grep ' 500 ' /var/log/nginx/access.log | tail -50

Belirli bir IP adresinin tüm isteklerini görmek:

grep '^203.0.113.42' /var/log/nginx/access.log

Belirli bir zaman aralığındaki istekleri filtrelemek:

awk '$4 >= "[15/Jan/2024:10:00:00" && $4 <= "[15/Jan/2024:11:00:00"' /var/log/nginx/access.log

Gerçek Dünya Senaryosu: Yavaş API Endpoint Tespiti

Nginx’e $request_time değişkenini ekleyerek yavaş endpoint’leri tespit edebilirsin. Önce nginx.conf’da log formatını düzenle:

log_format detailed '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent" '
                    '$request_time $upstream_response_time';

access_log /var/log/nginx/access.log detailed;

Nginx’i reload et:

nginx -t && systemctl reload nginx

Şimdi 2 saniyeden uzun süren istekleri bulalım:

awk '$(NF-1) > 2.0 {print $(NF-1), $7}' /var/log/nginx/access.log | sort -rn | head -20

Bu komut sana hangi endpoint’lerin yavaş çalıştığını net olarak gösterecek.

GoAccess ile Görsel Analiz

GoAccess, terminal tabanlı olmasına rağmen son derece kullanışlı bir log analiz aracı. Hem gerçek zamanlı hem de statik rapor üretebiliyor.

# Ubuntu/Debian
apt install goaccess

# RHEL/CentOS
yum install goaccess

Temel kullanım:

goaccess /var/log/nginx/access.log --log-format=COMBINED

HTML rapor üretmek için:

goaccess /var/log/nginx/access.log 
  --log-format=COMBINED 
  -o /var/www/html/report.html 
  --real-time-html

Sıkıştırılmış eski logları da dahil etmek istersen:

zcat /var/log/nginx/access.log.*.gz | goaccess 
  --log-format=COMBINED 
  - -o /tmp/monthly_report.html

GoAccess sana şunları gösterir:

  • Unique visitors: Tekil ziyaretçi sayısı
  • Requested files: En çok istenen dosyalar
  • Not found URLs: 404 dönen URL’ler
  • Visitor hostnames: Hostname’e göre ziyaretçiler
  • Operating systems: İşletim sistemi dağılımı
  • Browsers: Tarayıcı dağılımı
  • Time distribution: Saate göre trafik dağılımı
  • Virtual hosts: Sanal host bazında istatistikler

Python ile Özel Log Analizi

Daha karmaşık analizler için Python harika bir seçenek. Özellikle log verilerini bir veritabanına aktarmak veya özel raporlar oluşturmak istediğinde işe yarıyor.

#!/usr/bin/env python3
import re
import sys
from collections import defaultdict
from datetime import datetime

# Nginx combined log format için regex
LOG_PATTERN = re.compile(
    r'(?P<ip>S+) S+ S+ [(?P<time>[^]]+)] '
    r'"(?P<method>S+) (?P<url>S+) S+" '
    r'(?P<status>d+) (?P<bytes>S+) '
    r'"(?P<referer>[^"]*)" "(?P<agent>[^"]*)"'
)

def parse_log_file(filepath):
    stats = {
        'total_requests': 0,
        'status_codes': defaultdict(int),
        'top_ips': defaultdict(int),
        'top_urls': defaultdict(int),
        'errors': []
    }
    
    with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
        for line in f:
            match = LOG_PATTERN.match(line.strip())
            if not match:
                continue
            
            data = match.groupdict()
            stats['total_requests'] += 1
            stats['status_codes'][data['status']] += 1
            stats['top_ips'][data['ip']] += 1
            stats['top_urls'][data['url']] += 1
            
            if data['status'].startswith('5'):
                stats['errors'].append({
                    'time': data['time'],
                    'ip': data['ip'],
                    'url': data['url'],
                    'status': data['status']
                })
    
    return stats

def print_report(stats):
    print(f"n=== Nginx Log Analiz Raporu ===")
    print(f"Toplam İstek: {stats['total_requests']}")
    
    print(f"n--- HTTP Durum Kodları ---")
    for code, count in sorted(stats['status_codes'].items()):
        print(f"  {code}: {count}")
    
    print(f"n--- En Aktif 10 IP ---")
    top_ips = sorted(stats['top_ips'].items(), key=lambda x: x[1], reverse=True)[:10]
    for ip, count in top_ips:
        print(f"  {ip}: {count} istek")
    
    print(f"n--- En Çok İstenen 10 URL ---")
    top_urls = sorted(stats['top_urls'].items(), key=lambda x: x[1], reverse=True)[:10]
    for url, count in top_urls:
        print(f"  {url}: {count} istek")
    
    print(f"n--- Son 5xx Hataları ---")
    for error in stats['errors'][-10:]:
        print(f"  [{error['time']}] {error['ip']} -> {error['url']} ({error['status']})")

if __name__ == '__main__':
    logfile = sys.argv[1] if len(sys.argv) > 1 else '/var/log/nginx/access.log'
    stats = parse_log_file(logfile)
    print_report(stats)

Bu scripti çalıştırmak için:

python3 nginx_analyzer.py /var/log/nginx/access.log

Güvenlik Analizi: Saldırı Tespiti

Log analizi güvenlik açısından da kritik önem taşıyor. Yaygın saldırı kalıplarını tespit etmek için şu yaklaşımları kullanabilirsin.

Brute Force Saldırısı Tespiti

Kısa sürede çok fazla 401/403 üreten IP’leri bul:

awk '$9 == "401" || $9 == "403" {print $1}' /var/log/nginx/access.log | 
  sort | uniq -c | sort -rn | 
  awk '$1 > 100 {print "Şüpheli IP:", $2, "- Deneme sayısı:", $1}'

SQL Injection ve XSS Denemesi Tespiti

grep -i -E "(union|select|insert|drop|script|eval|base64)" 
  /var/log/nginx/access.log | 
  awk '{print $1, $7}' | 
  sort | uniq -c | sort -rn | head -20

Bot Trafiğini Filtrelemek

Meşru bot trafiğini (Googlebot, Bingbot) ayırt etmek önemli:

# Tüm bot trafiğini say
grep -i "bot|crawler|spider" /var/log/nginx/access.log | 
  awk '{print $12}' | sort | uniq -c | sort -rn | head -20

# Googlebot isteklerini filtrele
grep "Googlebot" /var/log/nginx/access.log | 
  awk '{print $7}' | sort | uniq -c | sort -rn

Gerçek Dünya Senaryosu: DDoS Sonrası Analiz

Diyelim ki gece bir DDoS saldırısı yaşandı ve sabah geldiğinde durumu analiz etmen gerekiyor. Dakika başına istek sayısını grafiksel olarak görmek için:

awk '{print $4}' /var/log/nginx/access.log | 
  cut -d: -f1-3 | 
  sort | uniq -c | 
  awk '{printf "%s %sn", $2, $1}' | 
  tail -60

En çok istek atan IP’leri bul ve bunların toplam trafikteki payını hesapla:

TOTAL=$(wc -l < /var/log/nginx/access.log)
echo "Toplam istek: $TOTAL"
echo ""
echo "En aktif IP'ler ve yüzdeleri:"
awk '{print $1}' /var/log/nginx/access.log | 
  sort | uniq -c | sort -rn | head -10 | 
  awk -v total="$TOTAL" '{printf "%-20s %8d istek (%5.2f%%)n", $2, $1, ($1/total)*100}'

Error Log Analizi

Access log kadar error log da önemli. Error logları genellikle daha az hacimli ama daha değerli bilgiler içeriyor.

Hata Türlerini Gruplandırmak

# Hata tiplerini say
grep '[error]' /var/log/nginx/error.log | 
  grep -oP '*d+ K[^,]+' | 
  sort | uniq -c | sort -rn | head -20

Upstream Bağlantı Hatalarını Bulmak

PHP-FPM veya diğer upstream servislerle bağlantı sorunları:

grep "connect() failed|upstream timed out|no live upstreams" 
  /var/log/nginx/error.log | 
  awk '{print $1, $2, $3}' | 
  sort | uniq -c | sort -rn

502/504 Hatalarının Nedeni

Bu hatalar genellikle upstream servisle ilgili. Hem access hem error logunu birlikte analiz et:

# Access logdan 502 veren zamanları bul
grep ' 502 ' /var/log/nginx/access.log | 
  awk '{print $4}' | 
  cut -d: -f1-3 | 
  sort | uniq -c

# Bu zamanları error logla karşılaştır
grep '[error]' /var/log/nginx/error.log | 
  grep "upstream" | tail -20

Log Rotasyonu ve Arşivleme

Loglar büyüdükçe disk dolmaya başlar. Logrotate ile bu sorunu çözebilirsin:

cat /etc/logrotate.d/nginx

Tipik bir nginx logrotate konfigürasyonu:

/var/log/nginx/*.log {
    daily
    missingok
    rotate 52
    compress
    delaycompress
    notifempty
    create 640 nginx adm
    sharedscripts
    postrotate
        if [ -f /var/run/nginx.pid ]; then
            kill -USR1 `cat /var/run/nginx.pid`
        fi
    endscript
}

daily: Her gün döndür rotate 52: 52 adet eski log dosyasını sakla compress: gzip ile sıkıştır delaycompress: Bir önceki günkü logu sıkıştırmadan beklet notifempty: Boş log dosyalarını döndürme postrotate: Nginx’e USR1 sinyali gönder (log dosyasını yeniden aç)

Logrotate’i elle test etmek için:

logrotate -d /etc/logrotate.d/nginx  # dry-run
logrotate -f /etc/logrotate.d/nginx  # zorla çalıştır

Elasticsearch ile Merkezi Log Yönetimi

Birden fazla sunucu yönetiyorsan merkezi log yönetimi kaçınılmaz oluyor. ELK Stack (Elasticsearch, Logstash, Kibana) bu iş için endüstri standardı.

Filebeat ile nginx loglarını Elasticsearch’e göndermek için filebeat.yml konfigürasyonu:

filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /var/log/nginx/access.log
  fields:
    log_type: nginx_access
  fields_under_root: true

- type: log
  enabled: true
  paths:
    - /var/log/nginx/error.log
  fields:
    log_type: nginx_error
  fields_under_root: true

processors:
- dissect:
    tokenizer: '%{client_ip} - %{user} [%{timestamp}] "%{method} %{url} %{http_version}" %{status} %{bytes} "%{referer}" "%{agent}"'
    field: "message"
    target_prefix: "nginx"

output.elasticsearch:
  hosts: ["localhost:9200"]
  index: "nginx-logs-%{+yyyy.MM.dd}"

Filebeat’i başlat:

systemctl enable filebeat
systemctl start filebeat

Bash ile Otomatik Uyarı Sistemi

Log analizi sadece manuel yapılmayacak kadar önemli. Kritik durumlarda otomatik uyarı alabilmek için basit bir script yazabilirsin:

#!/bin/bash

LOG_FILE="/var/log/nginx/access.log"
ERROR_LOG="/var/log/nginx/error.log"
ALERT_EMAIL="[email protected]"
THRESHOLD_500=50
THRESHOLD_RPS=1000

# Son 5 dakikanın loglarını al
RECENT_LOGS=$(awk -v d="$(date -d '5 minutes ago' '+%d/%b/%Y:%H:%M')" 
  '$4 > "[" d' "$LOG_FILE")

# 5xx hata sayısını kontrol et
ERROR_COUNT=$(echo "$RECENT_LOGS" | awk '$9 ~ /^5/' | wc -l)

if [ "$ERROR_COUNT" -gt "$THRESHOLD_500" ]; then
  SUBJECT="[ALERT] Nginx: Son 5 dakikada $ERROR_COUNT adet 5xx hatası!"
  BODY="Sunucu: $(hostname)nZaman: $(date)nnEn fazla hata veren URL'ler:n"
  BODY+=$(echo "$RECENT_LOGS" | awk '$9 ~ /^5/ {print $7}' | sort | uniq -c | sort -rn | head -10)
  
  echo -e "$BODY" | mail -s "$SUBJECT" "$ALERT_EMAIL"
  echo "[$(date)] ALERT gönderildi: $ERROR_COUNT adet 5xx hatası" >> /var/log/nginx_monitor.log
fi

# Saniye başına istek sayısını kontrol et
RPS=$(echo "$RECENT_LOGS" | wc -l)
RPS=$((RPS / 300))  # 5 dakika = 300 saniye

if [ "$RPS" -gt "$THRESHOLD_RPS" ]; then
  echo "[$(date)] Yüksek trafik: $RPS RPS" >> /var/log/nginx_monitor.log
  echo "Yüksek trafik tespit edildi: $RPS istek/saniye" | 
    mail -s "[ALERT] Nginx: Yüksek Trafik" "$ALERT_EMAIL"
fi

Bu scripti crontab’a ekle:

*/5 * * * * /usr/local/bin/nginx_monitor.sh

Performans Metrikleri ve Raporlama

Düzenli raporlama, kapasitе planlaması için vazgeçilmez. Haftalık özet raporu oluşturmak için:

#!/bin/bash

LOGDIR="/var/log/nginx"
REPORT_DATE=$(date -d "yesterday" '+%d/%b/%Y')
REPORT_FILE="/tmp/nginx_weekly_report.txt"

{
  echo "=== Nginx Haftalık Rapor - $(date '+%Y-%m-%d') ==="
  echo ""
  
  echo "## Genel İstatistikler"
  TOTAL=$(wc -l < "$LOGDIR/access.log")
  echo "Toplam İstek Sayısı: $TOTAL"
  
  echo ""
  echo "## HTTP Durum Kodu Dağılımı"
  awk '{print $9}' "$LOGDIR/access.log" | sort | uniq -c | sort -rn
  
  echo ""
  echo "## En Çok İstenen 20 URL"
  awk '{print $7}' "$LOGDIR/access.log" | sort | uniq -c | sort -rn | head -20
  
  echo ""
  echo "## En Aktif 20 IP"
  awk '{print $1}' "$LOGDIR/access.log" | sort | uniq -c | sort -rn | head -20
  
  echo ""
  echo "## 404 Hata Veren URL'ler"
  awk '$9 == "404" {print $7}' "$LOGDIR/access.log" | sort | uniq -c | sort -rn | head -20
  
  echo ""
  echo "## Saatlik Trafik Dağılımı"
  awk '{print $4}' "$LOGDIR/access.log" | cut -d: -f2 | sort | uniq -c
  
} > "$REPORT_FILE"

mail -s "Nginx Haftalık Rapor - $(date '+%Y-%m-%d')" [email protected] < "$REPORT_FILE"

Sonuç

Nginx log analizi, sistem yöneticiliğinin temel becerilerinden biri. Basit grep ve awk komutlarından başlayıp GoAccess gibi görsel araçlara, Python scriptlerine ve ELK Stack gibi enterprise çözümlere kadar geniş bir araç skalası mevcut. Önemli olan ihtiyacına uygun araçları seçmek.

Küçük bir sunucu yönetiyorsan awk + grep kombinasyonu ve GoAccess büyük ihtimalle yeterli olacak. Birden fazla sunucu veya yüksek trafik varsa ELK Stack veya Grafana + Loki gibi merkezi çözümlere yatırım yapmaya değer.

Log analizi için birkaç altın kural aklında kalsın:

  • Log formatına $request_time ve $upstream_response_time ekle: Bu iki değer olmadan performans sorunlarını tespit etmek çok zorlaşır
  • Logları gerçek zamanlı izle: Sorun oluştuktan sonra değil, oluşurken yakalamak çok daha değerli
  • Otomatik uyarılar kur: Gece 3’te 5xx patlamasını sabah öğrenmek istemezsin
  • Düzenli arşivleme yap: Eski loglar kapasite planlaması için kritik veri kaynağı
  • Güvenlik analizini ihmal etme: Loglar sadece performans için değil, saldırı tespiti için de hayati öneme sahip

Logları düzenli analiz etmeye başladığında sunucunun “konuştuğunu” fark edeceksin. Her satır sana bir şeyler söylüyor, dinlemeyi öğrenmek seni çok daha etkili bir sysadmin yapacak.

Benzer Konular

Bir yanıt yazın

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