Apache ile WordPress Hataları: Özel Log Yapılandırması
WordPress siteniz gece yarısı çöktüğünde ve müşteriniz sizi arıyor olduğunda, elinizde tek silahınız log dosyalarıdır. Ama varsayılan Apache log yapılandırmasıyla WordPress hatalarını bulmak, karanlıkta iğne aramak gibidir. Bu yazıda Apache’yi WordPress için özel olarak nasıl yapılandıracağınızı, hangi hataların nerede kayıt altına alındığını ve gerçek dünya senaryolarında bu logları nasıl analiz edeceğinizi konuşacağız.
Apache Log Sistemini Anlamak
Apache’nin log mekanizması iki temel dosya üzerine kuruludur: access.log ve error.log. Varsayılan yapılandırmada tüm sanal hostlar ya tek bir log dosyasına yazıyor ya da çok genel bir formatta tutuluyor. WordPress gibi karmaşık bir uygulama çalıştırıyorsanız bu yaklaşım yetersiz kalıyor.
WordPress’in kendine has bir yapısı var. PHP hataları, .htaccess kaynaklı 500 hataları, wp-cron sorunları, eklenti çakışmaları… Bunların hepsini tek bir log dosyasında takip etmeye çalışmak, zamanla log dosyasının içinde kaybolmanıza yol açıyor. Çözüm ise her WordPress sitesi için özelleştirilmiş bir log yapılandırması oluşturmak.
Apache’nin log sistemi şu bileşenlerden oluşur:
- ErrorLog: Sunucu hatalarının yazıldığı dosya
- CustomLog: Erişim loglarının yazıldığı dosya ve formatı
- LogLevel: Hangi seviyedeki hataların loglanacağı
- LogFormat: Log satırlarının nasıl görüneceği
Özel Log Formatı Oluşturmak
Varsayılan combined log formatı çoğu zaman yeterli değildir. WordPress için özellikle şu bilgilere ihtiyaç duyarsınız: hangi PHP dosyası çalıştı, yanıt süresi ne kadardı, hangi WordPress sayfası tetikledi.
Önce Apache’nin global yapılandırma dosyasını açalım:
sudo nano /etc/apache2/apache2.conf
# veya CentOS/RHEL için:
sudo nano /etc/httpd/conf/httpd.conf
Aşağıdaki özel log formatını ekleyin:
# WordPress için özel log formatı
LogFormat "%h %l %u %t "%r" %>s %O "%{Referer}i" "%{User-Agent}i" %D %{X-Forwarded-For}i" wordpress_combined
LogFormat "%{%Y-%m-%d %H:%M:%S}t [%L] %h "%r" %>s %D" wordpress_debug
LogFormat "%h %t "%r" %>s %b "%{Referer}i" %T/%D" wordpress_performance
Bu formatlardaki parametrelerin anlamları:
- %h: İstek yapan IP adresi
- %t: İsteğin zaman damgası
- %r: HTTP istek satırı (GET/POST ve URL)
- %>s: Son yanıt durum kodu
- %O: Yanıtta gönderilen toplam byte sayısı
- %D: İsteğin işlenme süresi mikrosaniye cinsinden
- %{Referer}i: Referer header bilgisi
- %{X-Forwarded-For}i: Proxy arkasındaki gerçek IP
- %T: İşlem süresi saniye cinsinden
- %L: İstek için benzersiz log ID
WordPress Virtual Host Yapılandırması
Her WordPress sitesi için ayrı bir virtual host dosyası oluşturun ve log direktiflerini bu dosyaya özelleştirin:
sudo nano /etc/apache2/sites-available/wordpress-site.conf
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/wordpress
# Özel log dizini
ErrorLog /var/log/apache2/wordpress/error.log
CustomLog /var/log/apache2/wordpress/access.log wordpress_combined
# Hata seviyesi - WordPress için warn yeterli, sorun varsa debug'a çek
LogLevel warn
# PHP hataları için ek log
php_admin_value error_log /var/log/apache2/wordpress/php-errors.log
php_admin_flag log_errors on
php_admin_value error_reporting E_ALL
# Yavaş istek loglaması - 3 saniyeden uzun istekleri logla
# mod_log_forensic veya özel pipe kullanımı
CustomLog /var/log/apache2/wordpress/slow-requests.log wordpress_performance env=slow_request
<Directory /var/www/wordpress>
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
Log dizinini oluşturun ve izinleri ayarlayın:
sudo mkdir -p /var/log/apache2/wordpress
sudo chown www-data:adm /var/log/apache2/wordpress
sudo chmod 750 /var/log/apache2/wordpress
PHP Hatalarını Ayrı Loglamak
WordPress’in büyük bir kısmı PHP üzerinde çalıştığı için PHP hatalarını Apache error log’undan ayırmak hayat kurtarır. Yukarıdaki virtual host yapılandırmasına ek olarak php.ini veya php-fpm yapılandırmasını da güncelleyin.
PHP-FPM kullanıyorsanız (ki modern sunucularda genellikle kullanılır):
sudo nano /etc/php/8.1/fpm/pool.d/wordpress.conf
[wordpress]
user = www-data
group = www-data
listen = /run/php/php8.1-fpm-wordpress.sock
listen.owner = www-data
listen.group = www-data
; WordPress'e özel PHP hata loglama
php_admin_value[error_log] = /var/log/apache2/wordpress/php-errors.log
php_admin_flag[log_errors] = on
php_admin_value[error_reporting] = E_ALL & ~E_DEPRECATED & ~E_STRICT
; Yavaş log - 5 saniyeden uzun PHP işlemlerini logla
slowlog = /var/log/apache2/wordpress/php-slow.log
request_slowlog_timeout = 5s
request_terminate_timeout = 120s
PHP-FPM servisini yeniden başlatın:
sudo systemctl restart php8.1-fpm
sudo systemctl reload apache2
WordPress Taraflı Debug Loglaması
Apache ve PHP loglarının yanı sıra WordPress’in kendi debug sistemini de aktif etmek gerekiyor. wp-config.php dosyasına şunları ekleyin:
sudo nano /var/www/wordpress/wp-config.php
// WordPress debug modunu aç
define('WP_DEBUG', true);
// Hataları ekrana yazdırma, sadece logla
define('WP_DEBUG_DISPLAY', false);
// Hata loglamasını aktif et
define('WP_DEBUG_LOG', true);
// WordPress debug log dosyasının yolu
// Varsayılan: wp-content/debug.log - Güvenlik için değiştirin
define('WP_DEBUG_LOG', '/var/log/apache2/wordpress/wp-debug.log');
// Sorgu loglaması (performans analizi için)
define('SAVEQUERIES', false); // Sadece gerektiğinde true yap
// Script debug modu
define('SCRIPT_DEBUG', false);
Bu yapılandırmayla artık dört ayrı log kaynağınız var:
/var/log/apache2/wordpress/error.log– Apache sunucu hataları/var/log/apache2/wordpress/access.log– HTTP erişim logları/var/log/apache2/wordpress/php-errors.log– PHP hataları/var/log/apache2/wordpress/wp-debug.log– WordPress uygulama hataları
Gerçek Dünya Senaryosu: 500 Internal Server Error Avı
Bir müşteri sitesi sürekli 500 hatası veriyor. Kullanıcılar şikayet ediyor ama hata aralıklı, yani her zaman olmuyor. Bu klasik bir “üretim ortamında aralıklı hata” senaryosu.
Önce Apache error log’una bakın:
# Son 100 satırı gerçek zamanlı izle
sudo tail -f -n 100 /var/log/apache2/wordpress/error.log
# Sadece 500 hatalarını filtrele
sudo grep -i "error|crit|alert|emerg" /var/log/apache2/wordpress/error.log | tail -50
# Belirli bir zaman aralığını incele
sudo awk '/[Thu Nov 14/ || /[Fri Nov 15/' /var/log/apache2/wordpress/error.log
Çıktıda şöyle bir şey görüyorsunuz:
[Thu Nov 14 02:15:33.412847 2024] [php:error] [pid 12453] [client 185.x.x.x:52341] PHP Fatal error: Allowed memory size of 268435456 bytes exhausted (tried to allocate 20480 bytes) in /var/www/wordpress/wp-content/plugins/woocommerce/includes/class-wc-product-query.php on line 284
Hafıza sorunu ve gece 2’de oluyor. WooCommerce’in büyük ürün sorgusu hafızayı bitiriyor. Çözüm:
# PHP-FPM pool yapılandırmasına ekle
sudo nano /etc/php/8.1/fpm/pool.d/wordpress.conf
# Şunu ekle:
php_admin_value[memory_limit] = 512M
Gerçek Dünya Senaryosu: Yavaş Sayfa Yüklemeleri
Bir diğer yaygın senaryo: site çalışıyor ama yavaş. Kullanıcılar şikayet ediyor, Google PageSpeed kötü puan veriyor.
wordpress_performance formatıyla oluşturduğumuz access log’u analiz edelim:
# İşlem süresi 2 saniyeden uzun istekleri bul (mikrosaniye cinsinden 2000000)
sudo awk '$NF > 2000000 {print $0}' /var/log/apache2/wordpress/access.log
# En yavaş 10 isteği listele
sudo awk '{print $NF, $7}' /var/log/apache2/wordpress/access.log | sort -rn | head -10
# wp-admin ve wp-cron isteklerini ayır
sudo grep "wp-cron|wp-admin/admin-ajax" /var/log/apache2/wordpress/access.log |
awk '{print $NF, $7}' | sort -rn | head -20
Sıkça karşılaşılan senaryo: admin-ajax.php her istekte 3-4 saniye sürüyor. Bu genellikle bir eklentinin kontrolsüz AJAX çağrısından kaynaklanır.
WordPress slow query logunu da kontrol edin:
sudo cat /var/log/apache2/wordpress/php-slow.log | grep "pool|script|function" | head -30
Log Rotasyonu Yapılandırması
WordPress sitesi aktifse loglar hızla büyür. Logrotate yapılandırması zorunludur:
sudo nano /etc/logrotate.d/wordpress-apache
/var/log/apache2/wordpress/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 640 www-data adm
sharedscripts
postrotate
# Apache'ye yeni log dosyası açmasını söyle
if invoke-rc.d apache2 status > /dev/null 2>&1; then
invoke-rc.d apache2 reload > /dev/null 2>&1
fi
# PHP-FPM'i de yeniden yükle
if invoke-rc.d php8.1-fpm status > /dev/null 2>&1; then
invoke-rc.d php8.1-fpm reload > /dev/null 2>&1
fi
endscript
}
Çoklu WordPress Sitesi İçin Merkezi Log Yönetimi
Sunucunuzda birden fazla WordPress sitesi varsa logları merkezi bir noktadan yönetmek işinizi kolaylaştırır. Şu bash scriptini kullanabilirsiniz:
#!/bin/bash
# /usr/local/bin/wp-log-check.sh
# WordPress log özetini gösteren script
SITES=("site1" "site2" "site3")
LOG_BASE="/var/log/apache2"
REPORT_DATE=$(date '+%Y-%m-%d')
echo "=== WordPress Log Raporu: $REPORT_DATE ==="
echo ""
for SITE in "${SITES[@]}"; do
LOG_DIR="$LOG_BASE/$SITE"
if [ ! -d "$LOG_DIR" ]; then
echo "[$SITE] Log dizini bulunamadi: $LOG_DIR"
continue
fi
echo "--- $SITE ---"
# Bugünkü 500 hata sayısı
ERROR_500=$(grep "" 500 " "$LOG_DIR/access.log" 2>/dev/null |
grep "$(date '+%d/%b/%Y')" | wc -l)
echo " 500 Hata: $ERROR_500"
# PHP fatal error sayısı
PHP_FATAL=$(grep "PHP Fatal error" "$LOG_DIR/php-errors.log" 2>/dev/null |
grep "$(date '+%d-%b-%Y|%Y-%m-%d')" | wc -l)
echo " PHP Fatal: $PHP_FATAL"
# WordPress debug hata sayısı
WP_ERRORS=$(grep "PHP (Fatal|Warning|Notice)"
"$LOG_DIR/wp-debug.log" 2>/dev/null |
grep "$(date '+%d-%b-%Y')" | wc -l)
echo " WP Debug Hatalar: $WP_ERRORS"
# En son hata
LAST_ERROR=$(tail -1 "$LOG_DIR/error.log" 2>/dev/null)
if [ -n "$LAST_ERROR" ]; then
echo " Son Hata: ${LAST_ERROR:0:120}..."
fi
echo ""
done
# Disk kullanimi
echo "=== Log Disk Kullanimi ==="
du -sh $LOG_BASE/*/ 2>/dev/null | sort -rh | head -10
Script’i çalıştırılabilir yapın ve günlük cron’a ekleyin:
sudo chmod +x /usr/local/bin/wp-log-check.sh
sudo crontab -e
# Sabah 8'de rapor gönder
0 8 * * * /usr/local/bin/wp-log-check.sh | mail -s "WordPress Log Raporu" [email protected]
mod_status ile Anlık Durum İzleme
Apache’nin mod_status modülü, aktif bağlantıları ve sunucu durumunu anlık görmenizi sağlar. WordPress sorunlarını debug ederken bu modül altın değerinde:
sudo a2enmod status
sudo nano /etc/apache2/mods-enabled/status.conf
<Location "/server-status">
SetHandler server-status
Require ip 127.0.0.1
Require ip 192.168.1.0/24
</Location>
# Genişletilmiş durum bilgisi
ExtendedStatus On
Anlık durum kontrolü için:
# Komut satırından anlık durum
watch -n 2 'curl -s http://localhost/server-status?auto | grep -E "BusyWorkers|IdleWorkers|Total Accesses|ReqPerSec"'
# Hangi URL'lerin işlendiğini gör
curl -s http://localhost/server-status | grep "GET|POST" | awk '{print $13, $12}' | sort | uniq -c | sort -rn
Güvenlik Odaklı Log Analizi
WordPress siteleri sürekli brute-force ve exploit denemelerine maruz kalır. Log’lardan bu saldırıları tespit etmek:
# wp-login.php'ye çok fazla POST isteği gönderen IP'leri bul
sudo awk '/POST /wp-login.php/ {print $1}' /var/log/apache2/wordpress/access.log |
sort | uniq -c | sort -rn | head -20
# 404 hatası üretip exploit arayan IP'ler
sudo awk '$9 == "404" {print $1}' /var/log/apache2/wordpress/access.log |
sort | uniq -c | sort -rn | head -20
# xmlrpc.php'ye saldırı girişimleri
sudo grep "xmlrpc.php" /var/log/apache2/wordpress/access.log |
awk '{print $1}' | sort | uniq -c | sort -rn | head -10
Şüpheli IP’leri otomatik olarak engellemek için fail2ban entegrasyonu yapılabilir ama bu ayrı bir yazı konusu.
Apache ErrorDocument ile Özel Hata Sayfaları ve Loglama
WordPress’te özelleştirilmiş hata yakalama için virtual host yapılandırmasına ErrorDocument ekleyin:
# Virtual host içine ekle
ErrorDocument 404 /index.php?error=404
ErrorDocument 500 /index.php?error=500
ErrorDocument 503 /maintenance.php
# 404'leri ayrı dosyaya logla
SetEnvIf Request_URI "^/(wp-content|wp-includes)" static_file
CustomLog /var/log/apache2/wordpress/404-errors.log wordpress_combined env=!static_file
Bu sayede static dosya 404’lerini uygulama 404’lerinden ayırabilirsiniz. WordPress’in medya dosyası kayıplarını gerçek sayfa hatalarından ayırt etmek çok önemli.
Log Analizi için Temel Komutlar
Günlük hayatta sık kullandığım log analizi komutlarını paylaşayım:
# Son 1 saatteki hata özeti
sudo awk -v date="$(date -d '1 hour ago' '+%d/%b/%Y:%H')"
'$0 ~ date {print}' /var/log/apache2/wordpress/access.log |
awk '{print $9}' | sort | uniq -c | sort -rn
# Belirli bir eklentiye ait hataları bul
sudo grep "wp-content/plugins/woocommerce" /var/log/apache2/wordpress/php-errors.log |
awk -F': ' '{print $2}' | sort | uniq -c | sort -rn | head -10
# Ortalama yanıt süresi hesapla (mikrosaniye cinsinden)
sudo awk '{sum += $NF; count++} END {print "Ortalama:", sum/count, "us =", sum/count/1000000, "s"}'
/var/log/apache2/wordpress/access.log
# İstek başına byte dağılımı
sudo awk '{print $10}' /var/log/apache2/wordpress/access.log |
awk 'BEGIN{small=0;medium=0;large=0}
$1<1000{small++} $1>=1000&&$1<100000{medium++} $1>=100000{large++}
END{print "Kucuk(<1KB):", small, "Orta(1-100KB):", medium, "Buyuk(>100KB):", large}'
Sonuç
Apache log yapılandırmasını WordPress için özelleştirmek, başlangıçta fazladan iş gibi görünse de uzun vadede saatlerce hata ayıklama zamanı kazandırır. Her site için ayrı log dizini, PHP hatalarını ayrı loglamak, performance formatı kullanmak ve log rotasyonunu doğru ayarlamak, sorun anında durumu hızlıca anlamanızı sağlar.
Burada anlattığım yapılandırmayı kendi ortamınıza uyarlarken birkaç noktaya dikkat edin: disk alanını gözetin, log seviyesini production’da warn veya error seviyesinde tutun (debug çok fazla yazma işlemi yapar), ve logları düzenli olarak analiz edin, sadece sorun çıktığında değil. Proaktif log analizi, sorunu kullanıcı şikayet etmeden önce tespit etmenizi sağlar.
Son olarak, log dosyalarının güvenliğini de gözetmek gerekiyor. Müşteri IP’leri, kullanıcı davranışları hassas verilerdir. Log dizinine dışarıdan erişimi engelleyin, log dosyalarını şifreli alanlara taşıyın ve GDPR uyumluluğu için gerekli saklama sürelerini logrotate yapılandırmasında belirtin.
