403 ve 404 Hataları: Apache’de Erişim Sorunlarını Giderme

Yıllar içinde fark ettim ki sysadmin hayatının en sinir bozucu anlarından biri, bir web sitesi kurulumunu tamamladıktan sonra tarayıcıda “403 Forbidden” veya “404 Not Found” görmek. Kulağa basit geliyor ama bu hatalar bazen saatlerce süren debug seanslarına dönüşebiliyor. Bu yazıda Apache üzerinde yaşanan 403 ve 404 hatalarını köklü biçimde nasıl çözeceğinizi, log analizi nasıl yapacağınızı ve gerçek dünya senaryolarıyla bu sorunların üstesinden nasıl geleceğinizi anlatacağım.

Hataların Temel Mantığını Anlamak

403 ve 404 hataları çok farklı köklere sahip olsa da ikisi de Apache’nin “bir şeyler ters gitti” mesajıdır. Aralarındaki farkı net anlamak, debug sürecini ciddi ölçüde hızlandırır.

404 Not Found: Apache istenen dosyayı ya da dizini bulamıyor. Dosya yok, yanlış yerde ya da yanlış isimle var.

403 Forbidden: Apache dosyayı buluyor ama size göstermiyor. İzin sorunu, yanlış yapılandırma ya da güvenlik kısıtlaması devreye girmiş.

Bu ayrımı net tutun çünkü debug yaklaşımı tamamen farklı olacak.

Log Dosyalarına Bakmadan Hiçbir Şey Yapma

Apache’nin iki kritik log dosyası var ve her şey orada yazıyor. Önce bunların nerede olduğunu bulalım:

# Ubuntu/Debian sistemlerde
tail -f /var/log/apache2/error.log
tail -f /var/log/apache2/access.log

# RHEL/CentOS/Rocky Linux sistemlerde
tail -f /var/log/httpd/error_log
tail -f /var/log/httpd/access_log

# Virtual host spesifik loglar için
grep -r "ErrorLog" /etc/apache2/sites-enabled/
grep -r "CustomLog" /etc/apache2/sites-enabled/

Birinin erişim sorunu bildirdiğinde ilk refleksim şu komutu çalıştırmak:

# Son 50 satırı getir ve hem 403 hem 404 hatalarını filtrele
tail -n 200 /var/log/apache2/error.log | grep -E "403|404|Permission|denied|not found"

# Belirli bir IP'nin hatalarını izle
tail -f /var/log/apache2/access.log | grep "192.168.1.100"

# Sadece hata kodlarını say ve sırala
awk '{print $9}' /var/log/apache2/access.log | sort | uniq -c | sort -rn | head -20

Log formatını anlamak da kritik. Standart combined log formatında bir satır şöyle görünür:

192.168.1.50 - johndoe [15/Jan/2024:14:23:11 +0300] "GET /images/logo.png HTTP/1.1" 404 512 "https://example.com" "Mozilla/5.0..."

Burada sırasıyla IP adresi, kimlik, kullanıcı adı, zaman damgası, istek, HTTP kodu, yanıt boyutu, referrer ve user agent bilgileri var.

404 Hatalarını Giderme

Dosya Gerçekten Yok mu Kontrol Et

İlk adım her zaman en basit olanı kontrol etmek:

# Dosyanın varlığını ve izinlerini kontrol et
ls -la /var/www/html/images/logo.png

# DocumentRoot'u bul
grep -r "DocumentRoot" /etc/apache2/sites-enabled/
apache2ctl -S 2>&1 | grep -i "documentroot"

# Apache'nin hangi dizine baktığını doğrula
apachectl -t -D DUMP_VHOSTS

Gerçek dünyada en sık karşılaştığım senaryo: Geliştirici dosyayı /var/www/html/MyApp/images/Logo.PNG olarak yüklemiş ama URL’de /myapp/images/logo.png yazıyor. Linux case-sensitive, Windows değil. Geliştirici Windows’ta test etmiş, production Linux’a geçince 404 almaya başlamış.

.htaccess Sorunları

.htaccess dosyaları 404’ün gizli kaynağı olabilir. Özellikle RewriteRule yanlış yazılmışsa Apache mevcut dosyaları bile bulamıyormuş gibi davranabilir:

# .htaccess dosyasını bul ve içeriğine bak
find /var/www/html -name ".htaccess" -exec cat {} ;

# Apache'nin .htaccess'i işleyip işlemediğini kontrol et
grep -r "AllowOverride" /etc/apache2/sites-enabled/
grep -r "AllowOverride" /etc/apache2/apache2.conf

Eğer AllowOverride None ayarlıysa .htaccess dosyaları tamamen yoksayılır. Bu hem 404’e hem de beklenmedik davranışlara yol açar. Düzeltmek için:

# /etc/apache2/sites-available/000-default.conf dosyasını düzenle
<Directory /var/www/html>
    AllowOverride All
    Options Indexes FollowSymLinks
    Require all granted
</Directory>

Değişikliği yaptıktan sonra mutlaka test et ve yeniden başlat:

apache2ctl configtest
systemctl reload apache2

Alias ve ProxyPass Karışıklıkları

Daha karmaşık Apache kurulumlarında Alias direktifleri 404’e neden olabilir:

# Mevcut alias tanımlarını listele
grep -r "Alias|AliasMatch|ScriptAlias" /etc/apache2/

# Örnek alias tanımı
# Alias /static /opt/myapp/static
# Bu tanım yoksa /static altındaki istekler DocumentRoot'ta aranır ve bulunamaz

403 Hatalarını Giderme

403 hataları çok daha çeşitli kaynaklardan gelebilir. Sistematik bir yaklaşım şart.

Dosya ve Dizin İzinleri

Bu en yaygın 403 sebebi. Apache genellikle www-data (Debian/Ubuntu) veya apache (RHEL/CentOS) kullanıcısı olarak çalışır:

# Apache'nin hangi kullanıcıyla çalıştığını öğren
ps aux | grep apache2 | grep -v root | head -1
# veya
grep -E "^User|^Group" /etc/apache2/envvars /etc/apache2/apache2.conf 2>/dev/null

# Dosya izinlerini kontrol et
ls -la /var/www/html/
stat /var/www/html/index.php

# Üst dizinlerin de erişilebilir olması gerekiyor
namei -l /var/www/html/index.php

namei -l komutu muhteşem bir araç. Dosya yolundaki her bileşenin iznini tek seferde gösteriyor. Örnek çıktı:

f: /var/www/html/index.php
drwxr-xr-x root     root     /
drwxr-xr-x root     root     var
drwxr-xr-x root     root     www
drwxr-xr-x root     root     html
-rw-r--r-- www-data www-data index.php

Eğer herhangi bir dizinde x biti yoksa Apache içine giremez. Standart izin düzeltmesi:

# Dizinler 755, dosyalar 644 olmalı (genel kural)
find /var/www/html -type d -exec chmod 755 {} ;
find /var/www/html -type f -exec chmod 644 {} ;

# Sahipliği düzelt
chown -R www-data:www-data /var/www/html/

# PHP veya uygulama yazma gerektiriyorsa
chmod 775 /var/www/html/uploads/
chown www-data:www-data /var/www/html/uploads/

SELinux ve AppArmor Tuzakları

RHEL/CentOS kullanıyorsanız SELinux, Ubuntu’da AppArmor 403 hatasının gerçek sorumlusu olabilir ama log’a bakana kadar asla anlayamazsınız:

# SELinux durumunu kontrol et
sestatus
getenforce

# SELinux hata loglarını incele
ausearch -m AVC -ts recent | grep httpd
sealert -a /var/log/audit/audit.log | grep httpd

# Geçici olarak SELinux'u permissive yap (SADECE TEST İÇİN)
setenforce 0

# Kalıcı çözüm: Doğru SELinux context'i ata
chcon -R -t httpd_sys_content_t /var/www/html/
# veya restorecon kullan
restorecon -R /var/www/html/

# Özel dizin için SELinux context ayarla
semanage fcontext -a -t httpd_sys_content_t "/opt/myapp(/.*)?"
restorecon -R /opt/myapp/

Ubuntu/Debian’da AppArmor için:

# AppArmor durumu
aa-status | grep apache

# AppArmor logları
grep apparmor /var/log/syslog | grep apache | tail -20

# Geçici olarak complain moduna al
aa-complain /etc/apparmor.d/usr.sbin.apache2

Apache Yapılandırmasından Gelen 403

Bazen 403 tamamen Apache direktiflerinden kaynaklanır. En sık gördüğüm durumlar:

# Require direktifini kontrol et
grep -r "Require|deny|allow" /etc/apache2/sites-enabled/
grep -r "Require|deny|allow" /etc/apache2/conf-enabled/

# Options direktifinde Indexes yoksa dizin listeleme 403 verir
grep -r "Options" /etc/apache2/sites-enabled/

Apache 2.4’te erişim kontrolü değişti. Eski Order Allow,Deny yerine Require kullanılıyor:

# YANLIS (Apache 2.4'te çalışmaz)
Order Allow,Deny
Allow from all

# DOGRU (Apache 2.4 syntax)
Require all granted

# Belirli IP'ye izin ver
Require ip 192.168.1.0/24

# Belirli kullanıcıya izin ver
Require user admin

# IP veya kimlik doğrulama ile
<RequireAny>
    Require ip 192.168.1.0/24
    Require valid-user
</RequireAny>

Eğer Apache 2.4 üzerinde hala Order Allow,Deny kullanıyorsanız, mod_access_compat modülünün yüklü olması gerekir. Kontrol edin:

apache2ctl -M | grep access_compat
# Yoksa yükle
a2enmod access_compat
systemctl reload apache2

Gerçek Dünya Senaryoları

Senaryo 1: WordPress Kurulumu Sonrası 403

Klasik bir durum. WordPress kurulumu yaptınız, admin paneline girebiliyorsunuz ama bazı sayfalar 403 veriyor. Error log’a bakıyorsunuz:

[error] [client 1.2.3.4] client denied by server configuration: /var/www/html/wp-admin/

Bu genellikle wp-admin’i IP kısıtlamasıyla korumaya çalışan bir .htaccess bloğundan kaynaklanır. Ama bazen de şöyle bir durumla karşılaşırsınız:

# wp-content/uploads altında .php çalıştırılmasını engelleyen kural var mı?
cat /var/www/html/wp-content/uploads/.htaccess

# Tipik güvenli kural (bu 403'e yol açar ama kasıtlı)
# <Files *.php>
#     deny from all
# </Files>

Bu kasıtlı bir güvenlik önlemi. Uploads dizininde PHP çalışmamalı.

Senaryo 2: Reverse Proxy Arkasında 403

Nginx veya HAProxy arkasında Apache çalışıyorsa ve erişim kontrolü yapıyorsanız, gerçek IP adresi Apache’ye gelmiyor olabilir. Apache Nginx’in IP’sini görüyor ve kısıtlama devreye giriyor:

# mod_remoteip'i etkinleştir
a2enmod remoteip

# Konfigürasyon ekle
# /etc/apache2/conf-available/remoteip.conf
RemoteIPHeader X-Forwarded-For
RemoteIPTrustedProxy 127.0.0.1
RemoteIPTrustedProxy 10.0.0.0/8

a2enconf remoteip
systemctl reload apache2

Senaryo 3: Symbolic Link ile 404

Geliştirici /var/www/html/app dizinine bir symlink oluşturdu ama 404 alıyor:

ls -la /var/www/html/
# lrwxrwxrwx 1 root root 15 Jan 15 14:00 app -> /opt/myapp/public

# Sorun: FollowSymLinks veya SymLinksIfOwnerMatch olmadan Apache symlink'i takip etmez
grep -r "FollowSymLinks" /etc/apache2/sites-enabled/

# Çözüm: Options direktifine ekle
# <Directory /var/www/html>
#     Options FollowSymLinks
# </Directory>

Toplu Log Analizi

Tek seferlik debug değil de periyodik analiz yapmak istiyorsanız şu araçları kullanabilirsiniz:

# Belirli tarihte 403/404 veren URL'leri bul
grep "15/Jan/2024" /var/log/apache2/access.log | awk '$9 == "403" || $9 == "404" {print $9, $7}' | sort | uniq -c | sort -rn | head -20

# En çok 404 veren sayfaları bul (kırık linkler için)
awk '$9 == 404 {print $7}' /var/log/apache2/access.log | sort | uniq -c | sort -rn | head -10

# Belirli user-agent'ın yaptığı istekleri filtrele (bot analizi)
grep "Googlebot" /var/log/apache2/access.log | awk '$9 >= 400 {print $9, $7}' | sort | uniq -c | sort -rn

# Saatlik hata dağılımı
awk '$9 == "403" {print substr($4, 14, 2)}' /var/log/apache2/access.log | sort | uniq -c

GoAccess aracını da mutlaka kurun, gerçek zamanlı log analizi için mükemmel:

apt install goaccess  # Debian/Ubuntu
yum install goaccess  # RHEL/CentOS

# Terminal'de gerçek zamanlı izleme
goaccess /var/log/apache2/access.log --log-format=COMBINED

# HTML rapor oluştur
goaccess /var/log/apache2/access.log --log-format=COMBINED -o /var/www/html/report.html

Hata Sayfalarını Özelleştirme

Sorunları çözerken kullanıcıya daha iyi bir deneyim sunmak için hata sayfalarını özelleştirebilirsiniz:

# Apache global konfigürasyonuna veya virtual host'a ekle
ErrorDocument 404 /errors/404.html
ErrorDocument 403 /errors/403.html

# Dinamik sayfa için (PHP ile)
ErrorDocument 404 /errors/404.php
ErrorDocument 403 /errors/403.php

# Harici yönlendirme
ErrorDocument 404 https://example.com/not-found

Özel hata sayfaları oluştururken dikkat: Bu sayfalar kendileri 200 döndürmeli, yoksa arama motorları ile monitoring araçları karışabilir.

Debug Kontrol Listesi

403 veya 404 aldığınızda izlenecek sistematik yol:

  • Error log’u oku: tail -f /var/log/apache2/error.log ile başla, sorun genellikle orada yazıyor
  • Dosyanın varlığını doğrula: ls -la ve namei -l kullan
  • İzinleri kontrol et: Dizinler 755, dosyalar 644 olmalı, sahip www-data olmalı
  • DocumentRoot’u doğrula: Apache’nin hangi dizine baktığından emin ol
  • AllowOverride ayarını incele: .htaccess çalışıyor mu?
  • SELinux/AppArmor’u kontrol et: Özellikle RHEL ve Ubuntu sunucularda
  • Require direktiflerini gözden geçir: Yanlış erişim kısıtlaması var mı?
  • Virtual host konfigürasyonunu test et: apache2ctl -S ile doğrula
  • Modülleri kontrol et: Gerekli modüller yüklü mü? apache2ctl -M
  • Konfigürasyon syntax’ını test et: apache2ctl configtest her değişiklikten sonra

Önleyici Tedbirler

Sorunları önceden önlemek için şunları öneriyorum:

  • Staging ortamında test et, production’a direkt geçme
  • Konfigürasyon değişikliklerini versiyon kontrolüne al (git ile)
  • Monitoring kur: Zabbix, Nagios veya Prometheus ile HTTP durum kodlarını izle
  • Log rotasyonu yapılandır: Büyük log dosyaları analizi zorlaştırır
  • Düzenli apache2ctl configtest çalıştır, özellikle büyük değişikliklerden sonra
# Basit bir monitoring scripti
#!/bin/bash
ERRORS=$(grep "$(date '+%d/%b/%Y')" /var/log/apache2/access.log | awk '$9 == 403 || $9 == 404' | wc -l)
if [ $ERRORS -gt 100 ]; then
    echo "UYARI: Bugün $ERRORS adet 403/404 hatası tespit edildi" | mail -s "Apache Hata Uyarısı" [email protected]
fi

Sonuç

403 ve 404 hataları ilk bakışta basit görünse de altında ciddi konfigürasyon sorunları yatabilir. En önemli nokta: her zaman error log’la başlayın. Çoğu sorun orada açıkça yazıyor ve sizi saatlik debug seanslarından kurtarıyor.

Sıralamayı unutmayın: Önce log’a bak, sonra dosyanın varlığını kontrol et, ardından izinlere geç, en son Apache konfigürasyonunu incele. SELinux ve AppArmor’u da unutma, bu ikisi sysadminlerin sık sık gözden kaçırdığı ama sık sık suçlu olan mekanizmalar.

apache2ctl configtest ve apache2ctl -S komutlarını refleks haline getirin. Herhangi bir değişiklikten sonra bu iki komutu çalıştırmak, “neden çalışmıyor” diye saatlerce bakmaktan çok daha verimli. Ve tabii ki değişiklikleri versiyon kontrolüne almak, bir sorun çıktığında hızlıca geri dönebilmenizi sağlar.

Benzer Konular

Bir yanıt yazın

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