Apache’de Zaman Aşımı (Timeout) Hatalarını Tespit Etme ve Giderme
Uzun süren bir PHP betiği, büyük dosya yüklemeleri ya da yoğun bir veritabanı sorgusu… Bunların hepsinin ortak noktası nedir? Hepsi Apache’de zaman aşımı hatasına yol açabilir ve kullanıcı tarafında o korkunç “504 Gateway Timeout” veya “408 Request Timeout” ekranını doğurur. Sysadmin olarak bu tür hataları sadece “timeout süresini artır” diyerek geçiştirmek ne yazık ki işe yaramaz, hatta sistemi daha kötü bir duruma sokabilir. Bu yazıda, Apache timeout hatalarını kökten anlamak, doğru yerde tespit etmek ve kalıcı olarak gidermek için ihtiyacınız olan her şeyi ele alacağız.
Zaman Aşımı Hatalarını Anlamak
Apache’de timeout meselesi sandığından çok daha karmaşık bir yapıya sahip. Tek bir “timeout” ayarı yok; bunun yerine birbirinden farklı amaçlara hizmet eden birden fazla direktif var. Hangisinin devreye girdiğini bilmeden sorunu çözmeye çalışmak, karanlıkta el yordamıyla anahtar aramaya benziyor.
Temel Timeout Türleri:
- Timeout: İstemciden gelen bir isteğin tamamlanması için beklenen maksimum süre (varsayılan: 300 saniye)
- KeepAliveTimeout: Kalıcı bağlantıda bir sonraki isteği beklerken geçen süre (varsayılan: 5 saniye)
- ProxyTimeout: Ters proxy kurulumunda backend sunucudan yanıt bekleme süresi
- RequestReadTimeout: İstemciden başlık ve gövde verisi okunması için ayrılan zaman
- FcgidIOTimeout: mod_fcgid üzerinden FastCGI uygulamalarıyla iletişimde kullanılan süre
Bu direktiflerin her biri farklı bir katmanda devreye girer. Örneğin bir Laravel uygulamasının yavaş bir sorgu nedeniyle zaman aşımına uğramasında genellikle ProxyTimeout veya FcgidIOTimeout suçludur, sıradan Timeout direktifi değil.
Log Dosyalarından Timeout Tespiti
Bir sorun olduğunu anlamanın en güvenilir yolu Apache log dosyalarını doğru okumaktır. Önce log dosyalarının nerede olduğunu bulalım:
# Debian/Ubuntu tabanlı sistemlerde
tail -f /var/log/apache2/error.log
tail -f /var/log/apache2/access.log
# RHEL/CentOS tabanlı sistemlerde
tail -f /var/log/httpd/error_log
tail -f /var/log/httpd/access_log
# VirtualHost bazlı log dosyası
grep -i "timeout|timed out|408|504" /var/log/apache2/error.log | tail -50
Timeout kaynaklı hataları filtrelemek için daha spesifik bir grep kullanmak işinizi kolaylaştıracaktır:
# Son 24 saatteki timeout hatalarını bul
grep -i "timeout" /var/log/apache2/error.log |
awk -v d="$(date -d '24 hours ago' '+%a %b %e')" '$0 > d' |
grep -oP '[.*?].*' |
sort | uniq -c | sort -rn | head -20
# 504 ve 408 HTTP hata kodlarını access log'dan çek
awk '$9 == 408 || $9 == 504 {print $1, $7, $9, $10}' /var/log/apache2/access.log |
sort | uniq -c | sort -rn
Gerçek bir hata logu çıktısı şöyle görünebilir:
[Thu Jan 15 14:32:11.456789 2025] [proxy:error] [pid 12345] (110)Connection timed out: AH00957: HTTP: attempt to connect to 127.0.0.1:9000 (localhost) failed
[Thu Jan 15 14:32:11.456801 2025] [proxy_http:error] [pid 12345] [client 192.168.1.50:54321] AH01102: error reading status line from remote server 127.0.0.1:9000
Bu çıktı, sorunun PHP-FPM ile bağlantıda yaşandığını açıkça ortaya koyuyor. Port 9000 PHP-FPM’in dinlediği port, dolayısıyla sorun Apache’nin kendisinde değil, backend katmanında.
Timeout Türlerine Göre Hata Tespiti
AH00957 ve Proxy Hataları
Eğer bir ters proxy (reverse proxy) ya da PHP-FPM kurulumunuz varsa en çok karşılaşacağınız hata AH00957’dir. Bu durumda kontrol edilecek ilk şey backend servisin yanıt süresidir:
# PHP-FPM durumunu kontrol et
systemctl status php8.1-fpm
# veya
service php-fpm status
# PHP-FPM slow log kontrolü
tail -f /var/log/php8.1-fpm.www.slow.log
# Backend'in gerçekten yanıt verip vermediğini test et
curl -v --max-time 10 http://127.0.0.1:9000/status 2>&1 | grep -E "timeout|connect|HTTP"
RequestReadTimeout Hataları
Büyük dosya yüklemelerinde veya yavaş istemci bağlantılarında bu direktif devreye girer. Hatayı şöyle tanımlarsınız:
[error] [client x.x.x.x] Timeout waiting for data from client.
Bu durumu şu komutla doğrulayabilirsiniz:
# Aktif bağlantıları ve durumlarını listele
ss -tnp | grep apache2
netstat -anp | grep httpd | grep -v LISTEN | awk '{print $6}' | sort | uniq -c
# Apache'nin mevcut bağlantı durumunu göster (mod_status aktifse)
curl -s http://localhost/server-status?auto | grep -E "BusyWorkers|IdleWorkers|Scoreboard"
Apache Konfigürasyonunu Doğru Yapılandırma
Sorunu tespit ettikten sonra yapılandırma tarafında düzeltme yapmak gerekiyor. Ama önce mevcut durumu görmek için:
# Aktif Apache konfigürasyonunu kontrol et
apache2ctl -T 2>/dev/null || httpd -T 2>/dev/null
# Timeout değerlerini konfigürasyondan bul
grep -r -i "timeout|keepalive" /etc/apache2/ 2>/dev/null | grep -v ".dpkg|#"
grep -r -i "timeout|keepalive" /etc/httpd/ 2>/dev/null | grep -v "#"
Temel Timeout Konfigürasyonu
Aşağıdaki yapılandırma bloğu gerçek dünya senaryoları için makul bir başlangıç noktası oluşturuyor. Bu ayarları /etc/apache2/conf-available/timeouts.conf gibi ayrı bir dosyaya koymanızı öneririm:
# /etc/apache2/conf-available/timeouts.conf
# Genel timeout - isteğin tamamlanma süresi
Timeout 300
# Keep-alive bağlantısı için bekleme süresi
KeepAlive On
KeepAliveTimeout 5
MaxKeepAliveRequests 100
# İstemciden okuma zaman aşımı (header için 20s, body için 10s/KB)
<IfModule reqtimeout_module>
RequestReadTimeout header=20-40,MinRate=500 body=20,MinRate=500
</IfModule>
# Proxy timeout (PHP-FPM veya backend için)
<IfModule mod_proxy.c>
ProxyTimeout 300
</IfModule>
Konfigürasyonu aktif hale getirmek için:
a2enconf timeouts
apache2ctl configtest && systemctl reload apache2
VirtualHost Bazında Özel Timeout
Her uygulama farklı timeout gerektirebilir. Bir e-ticaret sitesi için checkout işlemi 10 saniyede bitebilirken, veri analizi yapan bir panel sayfası 120 saniyeye ihtiyaç duyabilir. Bunu VirtualHost seviyesinde yönetmek en sağlıklı yaklaşım:
<VirtualHost *:443>
ServerName api.sirketniz.com
# Bu VirtualHost için özel timeout
Timeout 120
<Location /api/reports>
# Uzun süren rapor endpointleri için
ProxyTimeout 180
</Location>
<Location /api/upload>
# Büyük dosya yüklemeleri için
RequestReadTimeout body=120,MinRate=1024
</Location>
ProxyPass / http://127.0.0.1:8080/
ProxyPassReverse / http://127.0.0.1:8080/
</VirtualHost>
Gerçek Dünya Senaryoları ve Çözümleri
Senaryo 1: WooCommerce Siparişlerinde 504 Hatası
Bir müşteri, büyük sipariş hacimli günlerde WooCommerce checkout sayfasının 504 hatası verdiğinden yakınıyor. Log incelemesinde şunu görüyorsunuz:
AH00957: HTTP: attempt to connect to 127.0.0.1:9000 failed
Sorunun PHP-FPM kapasitesiyle ilgili olduğu anlaşılıyor. Yapılacaklar:
# PHP-FPM pool konfigürasyonunu kontrol et
cat /etc/php/8.1/fpm/pool.d/www.conf | grep -E "pm.|max_children|start_servers"
# PHP-FPM process sayısını artır
# /etc/php/8.1/fpm/pool.d/www.conf içinde:
# pm = dynamic
# pm.max_children = 50
# pm.start_servers = 10
# pm.min_spare_servers = 5
# pm.max_spare_servers = 20
# pm.process_idle_timeout = 10s
# pm.max_requests = 500
# Değişiklik sonrası yeniden başlat
systemctl restart php8.1-fpm
systemctl reload apache2
# Sonucu gözlemle
watch -n 2 'grep "timeout|busy|idle" /var/log/php8.1-fpm.log | tail -5'
Senaryo 2: Büyük Dosya Yüklemelerinde 408 Hatası
Bir belge yönetim sistemi için 100 MB üzerindeki dosya yüklemelerinde 408 alıyorsunuz. Bu durumda hem Apache hem de PHP tarafında değişiklik gerekiyor:
# Apache konfigürasyonu
# /etc/apache2/sites-available/dms.conf
<VirtualHost *:443>
ServerName dms.sirketniz.com
# Büyük yüklemeler için limit
LimitRequestBody 524288000
# Yükleme endpointi için özel timeout
<Location /upload>
RequestReadTimeout body=300,MinRate=1024
Timeout 600
</Location>
</VirtualHost>
PHP tarafını da unutmamak gerekiyor:
# PHP-FPM veya php.ini
# upload_max_filesize = 100M
# post_max_size = 110M
# max_execution_time = 600
# max_input_time = 600
# Değerleri doğrula
php -r "echo ini_get('upload_max_filesize');"
Senaryo 3: Nginx + Apache Beraber Kullanımında Çift Timeout
Bazı ortamlarda Nginx ön yüzde (frontend) Apache ise arka yüzde (backend) çalışıyor. Bu durumda timeout hem Nginx hem de Apache tarafında ayarlanmalı, yoksa iki katman arasında çelişen değerler ortaya çıkıyor:
# Nginx tarafı (kontrol için)
grep -r "proxy_read_timeout|proxy_connect_timeout" /etc/nginx/
# Apache backend için önerilen ayar
# Nginx'in proxy_read_timeout değerinden biraz daha kısa olmalı
# Nginx: proxy_read_timeout 90s ise Apache Timeout: 85 olmalı
# Bu şekilde Apache önce hata verip temiz bir 504 dönebilir
# Nginx'in kendi timeout'una takılmak yerine
Timeout Sorunlarını Önlemek için Monitoring
Sorunları gerçekleştikten sonra değil, gerçekleşmeden önce yakalamak çok daha değerli. Apache mod_status modülünü aktif edip periyodik olarak izlemek iyi bir alışkanlık:
# mod_status'u aktif et
a2enmod status
# /etc/apache2/conf-available/server-status.conf
<Location /server-status>
SetHandler server-status
Require ip 127.0.0.1 10.0.0.0/8
</Location>
# Basit bir monitoring scripti
#!/bin/bash
# /usr/local/bin/check_apache_timeout.sh
LOG="/var/log/apache2/error.log"
THRESHOLD=10
COUNT=$(grep -c "timeout|timed out" "$LOG" 2>/dev/null)
if [ "$COUNT" -gt "$THRESHOLD" ]; then
echo "UYARI: Son log dosyasinda $COUNT adet timeout hatasi tespit edildi!"
grep "timeout|timed out" "$LOG" | tail -5
# Buraya e-posta veya Slack bildirimi eklenebilir
fi
Bu scripti crontab’a ekleyerek her 5 dakikada bir çalıştırabilirsiniz:
*/5 * * * * /usr/local/bin/check_apache_timeout.sh >> /var/log/timeout_monitor.log 2>&1
Konfigürasyon Testleri ve Doğrulama
Değişiklik yaptıktan sonra gerçekten işe yarayıp yaramadığını test etmek kritik bir adım. Aşağıdaki yöntemler işinize yarayacaktır:
# Apache konfigürasyon sözdizimini doğrula
apache2ctl configtest
# veya
httpd -t
# Mevcut timeout değerlerini parse et ve göster
apache2ctl -D DUMP_RUN_CFG 2>/dev/null || true
grep -r "Timeoutb" /etc/apache2/ | grep -v "^Binary|#" | grep -v ".dpkg"
# Kasıtlı yavaş bir endpoint oluşturarak timeout'u test et (geliştirme ortamında)
# test_slow.php:
# <?php sleep(400); echo "Bu asla gorulmeyecek"; ?>
# Sonra test et:
curl -v --max-time 350 http://localhost/test_slow.php 2>&1 | grep -E "timeout|Timeout|HTTP|curl"
Üretim ortamında daha güvenli bir yük testi için Apache Benchmark kullanabilirsiniz:
# 100 istek, 10 eşzamanlı bağlantı ile test
ab -n 100 -c 10 -t 30 http://uygulamanz.com/agir-endpoint
# Sonuçta "Failed requests" ve "Non-2xx responses" değerlerine bakın
# "Connect: 0, Receive: 0, Length: 0, Exceptions: X" satırı timeout'ları gösterir
İnce Ayarlar ve İpuçları
Sysadmin hayatında öğrendiğim birkaç pratik nokta:
- Timeout değerini rastgele artırmayın: 300 saniye yetmiyorsa önce kodun neden bu kadar sürdüğünü araştırın. Timeout artırmak semptomu gizler, hastalığı tedavi etmez.
- MinRate parametresini kullanın:
RequestReadTimeout body=60,MinRate=500ifadesi “60 saniye içinde tamamla ama en az 500 byte/saniye geliyorsa süreyi uzat” anlamına gelir. Bu, gerçek yavaş istemcileri beklerken kötü aktörlerin bağlantıları meşgul etmesini önler.
- KeepAliveTimeout’u düşük tutun: Varsayılan 5 saniye çoğu durumda yeterlidir. Bunu 30-60 saniyeye çıkarmak worker süreçlerini gereksiz yere meşgul eder.
- Log rotation’ı unutmayın: Çok sayıda timeout hatası logları hızla şişirir.
/etc/logrotate.d/apache2dosyasını kontrol edin ve günlük rotation kurulu olduğundan emin olun.
- Timeout ve ProxyTimeout değerlerini birbirine yakın tutun: ProxyTimeout değeri Timeout değerinden büyükse Apache kendi timeout’una takılır ve backend’in yanıtını beklemez bile. ProxyTimeout daima Timeout’tan birkaç saniye küçük olmalı.
- Sistemdeki diğer timeout değerlerini unutmayın: MySQL’de
wait_timeout, PHP’demax_execution_time, Nginx’teproxy_read_timeout… Bunların hepsi koordineli çalışmalı.
Sonuç
Apache timeout hataları, üzerinde düşünülmeden müdahale edildiğinde sistemi daha kötü bir hale getirebilecek sinsi sorunlardır. Doğru yaklaşım her zaman şu sırayı takip etmektir: önce log’lardan hatanın tam türünü belirle, sonra sorunun Apache’de mi yoksa backend katmanında mı olduğunu tespit et, ardından sadece ilgili direktifi ve sadece gereken ölçüde değiştir.
Timeout değerini körce artırmak yerine uygulamanın neden bu kadar uzun sürdüğünü sorgulamak uzun vadede çok daha fazlasını kazandırır. Yavaş bir veritabanı sorgusu, optimize edilmemiş bir PHP betiği ya da aşırı yüklenmiş bir PHP-FPM havuzu, timeout süresini ne kadar artırırsanız artırın eninde sonunda sistemi dize getirecektir.
Bu yazıdaki komutları ve konfigürasyonları kendi ortamınıza uyarlayarak kullanabilirsiniz. Her ortam farklıdır; önemli olan doğru aracı doğru sorun için kullanmaktır.
