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_timeve$upstream_response_timeekle: 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.
