Apache Virtual Host Yapılandırma Hataları ve Çözümleri

Web sunucusu yönetiminde en sık karşılaşılan sorunların başında Apache virtual host yapılandırma hataları gelir. Bir site aniden 403 döndürmeye başlar, başka bir sitenin içeriği yanlış domain üzerinde görünür ya da SSL sertifikası tamamen farklı bir virtual host’a bağlanır. Bu tür sorunlar production ortamında saatlerce aranabilir. Bu yazıda gerçek senaryolar üzerinden virtual host hatalarını nasıl tespit edip çözeceğimizi adım adım inceleyeceğiz.

Virtual Host Nedir ve Neden Karmaşıklaşır?

Apache’de virtual host, tek bir IP adresi vezerinde birden fazla web sitesi çalıştırmanızı sağlar. Name-based ve IP-based olmak üzere iki tipi vardır. Modern ortamlarda neredeyse her zaman name-based kullanılır çünkü IPv4 adresleri kıymetlidir.

Sorunların büyük çoğunluğu şu üç nedenden kaynaklanır:

  • Yanlış ServerName veya ServerAlias tanımı: Domain eşleşmesi yapılamaz
  • Dosya izinleri ve SELinux/AppArmor: Apache dizini okuyamaz
  • Virtual host sıralaması: İlk tanımlanan virtual host beklenmedik istekleri yakalar

Apache’nin virtual host seçim mantığını anlamadan sorunları çözmek çok zorlaşır. Bir istek geldiğinde Apache şu sırayla karar verir: önce IP ve port eşleşmesi, sonra ServerName ve ServerAlias eşleşmesi. Eğer hiçbir ServerName eşleşmezse ilk tanımlanan virtual host devreye girer. Bu davranış pek çok kafa karışıklığının ana sebebidir.

Hata Ayıklamaya Başlamadan Önce: Temel Araçlar

Herhangi bir virtual host sorununa bakmadan önce kullanmanız gereken birkaç temel komut vardır.

# Tüm virtual host'ları listele ve hangi config dosyasından geldiğini göster
apache2ctl -S
# veya CentOS/RHEL için
httpd -S

# Config dosyasının syntax hatası içerip içermediğini kontrol et
apache2ctl configtest
# veya
httpd -t

# Aktif olarak yüklenen tüm modülleri listele
apache2ctl -M

# Apache'nin hangi user ile çalıştığını öğren
ps aux | grep apache
ps aux | grep httpd

apache2ctl -S çıktısı altın değerindedir. Örnek çıktı şöyle görünür:

VirtualHost configuration:
*:443                  is a NameVirtualHost
                 default server ornek.com (/etc/apache2/sites-enabled/ornek.com.conf:1)
                 port 443 namevhost ornek.com (/etc/apache2/sites-enabled/ornek.com.conf:1)
                 port 443 namevhost www.ornek.com (/etc/apache2/sites-enabled/ornek.com.conf:2)
*:80                   is a NameVirtualHost
                 default server ornek.com (/etc/apache2/sites-enabled/000-default.conf:1)

Bu çıktıdan hangi virtual host’un default olarak seçildiğini, hangi portların dinlendiğini ve config dosyalarının tam yolunu görebilirsiniz.

Senaryo 1: Yanlış Siteye Yönlendirme

En klasik senaryo şudur: Yeni bir site eklediniz, ama yenisite.com‘a girince eski sitenin içeriği görünüyor.

# Önce DNS çözümlemesinin doğru olduğunu doğrula
dig yenisite.com +short
nslookup yenisite.com

# curl ile hangi virtual host'un cevap verdiğini test et
curl -v -H "Host: yenisite.com" http://sunucu-ip-adresi/

# Apache'nin virtual host sıralamasını kontrol et
apache2ctl -S | grep -A5 "port 80"

Büyük ihtimalle sorun şuradadır: yenisite.com.conf dosyası /etc/apache2/sites-enabled/ altında mevcut değildir ya da a2ensite komutu çalıştırılmamıştır.

# Mevcut durumu kontrol et
ls -la /etc/apache2/sites-available/
ls -la /etc/apache2/sites-enabled/

# Siteyi etkinleştir (Debian/Ubuntu)
a2ensite yenisite.com.conf
systemctl reload apache2

# CentOS/RHEL'de conf dosyasının doğru dizinde olduğundan emin ol
ls -la /etc/httpd/conf.d/

Eğer site enabled ama hala yanlış içerik görünüyorsa, config dosyasını inceleyin:

# YANLIŞ - ServerName eksik veya hatalı
<VirtualHost *:80>
    DocumentRoot /var/www/yenisite
    # ServerName satırı yok!
</VirtualHost>

# DOGRU
<VirtualHost *:80>
    ServerName yenisite.com
    ServerAlias www.yenisite.com
    DocumentRoot /var/www/yenisite
    ErrorLog ${APACHE_LOG_DIR}/yenisite-error.log
    CustomLog ${APACHE_LOG_DIR}/yenisite-access.log combined
</VirtualHost>

Senaryo 2: 403 Forbidden Hatası

403 hatası genellikle iki nedenden kaynaklanır: dosya izinleri veya Apache Require direktifi. Hata logunu ilk kontrol noktanız yapın.

# Hata logunu gerçek zamanlı izle
tail -f /var/log/apache2/error.log
# veya site özelinde log varsa
tail -f /var/log/apache2/yenisite-error.log

# Tipik 403 log satırı şöyle görünür:
# [authz_core:error] AH01630: client denied by server configuration: /var/www/yenisite

Dizin izinlerini kontrol etmek için:

# DocumentRoot'un tüm üst dizinlerini kontrol et
# Apache, /var/www/yenisite'ye ulaşmak için tüm üst dizinlerde x (execute) yetkisi ister
namei -l /var/www/yenisite/index.html

# Tipik çıktı:
# f: /var/www/yenisite/index.html
# drwxr-xr-x root     root     /
# drwxr-xr-x root     root     var
# drwxr-xr-x root     root     www
# drwxr-x--- www-data www-data yenisite   <-- burada sorun var, other için x yok
# -rw-r--r-- www-data www-data index.html

# İzinleri düzelt
chmod 755 /var/www/yenisite
# veya özyinelemeli olarak
find /var/www/yenisite -type d -exec chmod 755 {} ;
find /var/www/yenisite -type f -exec chmod 644 {} ;

Apache 2.4’te Require direktifi değişti. Eski Allow/Deny syntax’ı artık çalışmaz:

# ESKI SYNTAX (Apache 2.2) - 2.4'te 403 verir
<Directory /var/www/yenisite>
    Order allow,deny
    Allow from all
</Directory>

# YENI SYNTAX (Apache 2.4)
<Directory /var/www/yenisite>
    Require all granted
</Directory>

SELinux aktifse (özellikle CentOS/RHEL sistemlerde) dosya etiketleri de sorun çıkarır:

# SELinux durumunu kontrol et
getenforce
sestatus

# Apache ile ilgili SELinux hatalarını görüntüle
ausearch -m avc -ts recent | grep httpd
sealert -a /var/log/audit/audit.log

# Dosyaların doğru SELinux etiketine sahip olduğunu kontrol et
ls -Z /var/www/yenisite/

# Etiketleri düzelt
chcon -R -t httpd_sys_content_t /var/www/yenisite/
# veya kalıcı çözüm için
semanage fcontext -a -t httpd_sys_content_t "/var/www/yenisite(/.*)?"
restorecon -Rv /var/www/yenisite/

Senaryo 3: SSL Virtual Host Sorunları

SSL yapılandırmalarında en yaygın sorun, birden fazla SSL virtual host tanımlanırken SNI (Server Name Indication) göz ardı edilmesidir. Eski tarayıcılar SNI desteklemez ama modern ortamda bu genellikle sorun değildir.

# SSL virtual host'ların doğru yapılandırıldığını test et
openssl s_client -connect yenisite.com:443 -servername yenisite.com 2>/dev/null | grep -E "subject|issuer"

# Hangi sertifikanın sunulduğunu kontrol et
openssl s_client -connect yenisite.com:443 </dev/null 2>/dev/null | openssl x509 -noout -subject -dates

# curl ile SSL virtual host'u test et
curl -vI https://yenisite.com 2>&1 | grep -E "SSL|subject|expire"

Tipik bir SSL virtual host yapılandırma hatası:

# SORUNLU - Her iki virtual host da aynı sertifikayı kullanıyor gibi görünür
<VirtualHost *:443>
    ServerName birinci.com
    SSLEngine on
    SSLCertificateFile /etc/ssl/certs/birinci.crt
    SSLCertificateKeyFile /etc/ssl/private/birinci.key
    DocumentRoot /var/www/birinci
</VirtualHost>

<VirtualHost *:443>
    ServerName ikinci.com
    # SSLEngine satırı eksik!
    SSLCertificateFile /etc/ssl/certs/ikinci.crt
    SSLCertificateKeyFile /etc/ssl/private/ikinci.key
    DocumentRoot /var/www/ikinci
</VirtualHost>

# DOGRU yapılandırma
<VirtualHost *:443>
    ServerName birinci.com
    ServerAlias www.birinci.com
    SSLEngine on
    SSLCertificateFile /etc/ssl/certs/birinci.crt
    SSLCertificateKeyFile /etc/ssl/private/birinci.key
    SSLCertificateChainFile /etc/ssl/certs/birinci-chain.crt
    DocumentRoot /var/www/birinci
    ErrorLog ${APACHE_LOG_DIR}/birinci-ssl-error.log
</VirtualHost>

<VirtualHost *:443>
    ServerName ikinci.com
    ServerAlias www.ikinci.com
    SSLEngine on
    SSLCertificateFile /etc/ssl/certs/ikinci.crt
    SSLCertificateKeyFile /etc/ssl/private/ikinci.key
    SSLCertificateChainFile /etc/ssl/certs/ikinci-chain.crt
    DocumentRoot /var/www/ikinci
    ErrorLog ${APACHE_LOG_DIR}/ikinci-ssl-error.log
</VirtualHost>

Senaryo 4: Port Çakışması ve Dinleme Sorunları

Apache bazen başlamaz veya belirli portlarda yanıt vermez. Bu durumda port çakışması yaşanıyor olabilir.

# 80 ve 443 portlarını hangi servisin kullandığını öğren
ss -tlnp | grep -E ':80|:443'
# veya eski sistemlerde
netstat -tlnp | grep -E ':80|:443'

# Apache'nin hangi portları dinlediğini kontrol et
grep -r "Listen" /etc/apache2/ports.conf /etc/apache2/sites-enabled/
# veya CentOS için
grep -r "Listen" /etc/httpd/conf/httpd.conf /etc/httpd/conf.d/

# Örnek çıktı - sorunlu durum:
# LISTEN  0  128  0.0.0.0:80  0.0.0.0:*  users:(("nginx",pid=1234))
# nginx port 80'i zaten tutuyor, Apache başlayamıyor

ports.conf dosyasını kontrol edin ve virtual host portlarıyla uyumlu olduğundan emin olun:

# /etc/apache2/ports.conf içeriği böyle olmalı
cat /etc/apache2/ports.conf

# Listen direktiflerini kontrol et
# Eğer bir virtual host *:8080 kullanıyorsa ports.conf'ta Listen 8080 olmalı

Log Analizi ile Sorun Tespiti

Apache logları doğru okunduğunda sorunun kaynağını çok hızlı bulabilirsiniz. Log formatını anlamak kritik önem taşır.

# Error log'da en sık tekrarlayan hataları bul
grep "error" /var/log/apache2/error.log | awk '{print $NF}' | sort | uniq -c | sort -rn | head -20

# Belirli bir virtual host'a ait 500 hatalarını filtrele
grep "yenisite.com" /var/log/apache2/access.log | awk '$9 == "500"' | tail -50

# Son 1 saatteki hataları göster
awk -v date="$(date -d '1 hour ago' '+%d/%b/%Y:%H:%M:%S')" '$0 > date' /var/log/apache2/error.log

# Virtual host başına istek sayısını hesapla
awk '{print $1}' /var/log/apache2/access.log | sort | uniq -c | sort -rn

# Hangi virtual host en fazla 404 üretiyor
grep " 404 " /var/log/apache2/access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head -20

Log Level ayarı da önemlidir. Production’da warn seviyesi genellikle yeterlidir ama sorun ayıklarken debug seviyesine almak çok daha fazla bilgi sunar:

# Virtual host içinde log seviyesini artır (sadece o site için)
<VirtualHost *:80>
    ServerName sorunlu-site.com
    DocumentRoot /var/www/sorunlu-site
    LogLevel debug
    ErrorLog ${APACHE_LOG_DIR}/sorunlu-site-debug.log
</VirtualHost>
# Config'i yeniden yükle ve debug logunu izle
systemctl reload apache2
tail -f /var/log/apache2/sorunlu-site-debug.log

Senaryo 5: .htaccess Dosyası Çalışmıyor

Bu çok yaygın bir sorundur. WordPress veya başka bir CMS kuruyorsunuz, URL yeniden yazma çalışmıyor ve 404 hatası alıyorsunuz.

# mod_rewrite modülünün yüklü olduğunu doğrula
apache2ctl -M | grep rewrite
# Çıktı: rewrite_module (shared) görünmüyorsa:
a2enmod rewrite
systemctl restart apache2

Virtual host yapılandırmasında AllowOverride direktifi None olarak ayarlıysa .htaccess tamamen devre dışıdır:

# YANLIS - .htaccess tamamen devre disi
<VirtualHost *:80>
    ServerName wordpress-site.com
    DocumentRoot /var/www/wordpress

    <Directory /var/www/wordpress>
        Options Indexes FollowSymLinks
        AllowOverride None    # <-- Bu satır .htaccess'i devre disi birakiyor
        Require all granted
    </Directory>
</VirtualHost>

# DOGRU - .htaccess aktif
<VirtualHost *:80>
    ServerName wordpress-site.com
    DocumentRoot /var/www/wordpress

    <Directory /var/www/wordpress>
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>

Yapılandırma Değişikliklerini Test Etme

Production sunucusunda değişiklik yapmadan önce test etme alışkanlığı edinmek sizi büyük sorunlardan kurtarır.

# Config syntax kontrolü - en temel adım
apache2ctl configtest
# Çıktı: Syntax OK olmalı

# Değişiklikleri restart gerektirmeden uygula
# (yeni bağlantılar için geçerli, mevcut bağlantılar etkilenmez)
systemctl reload apache2

# Belirli bir config dosyasını ayrı ayrı test et
apache2ctl -f /etc/apache2/sites-available/yenisite.com.conf -t

# Virtual host yapılandırmasının nasıl göründüğünü kontrol et
apache2ctl -D DUMP_VHOSTS
# veya
apache2ctl -S

# Değişiklikten önce mevcut yapılandırmayı yedekle
cp /etc/apache2/sites-available/ornek.com.conf /etc/apache2/sites-available/ornek.com.conf.bak.$(date +%Y%m%d)

Sık Yapılan Hatalar ve Hızlı Kontrol Listesi

Bir virtual host sorunu yaşadığınızda şu adımları sırayla uygulayın:

  • apache2ctl -S çalıştırın: Virtual host sıralamasını ve hangi config dosyasından geldiğini görün
  • apache2ctl configtest çalıştırın: Syntax hatalarını elemek için
  • Error log’u kontrol edin: tail -f /var/log/apache2/error.log
  • DocumentRoot’un varlığını doğrulayın: Config’de yazılan dizin gerçekten mevcut mu
  • Dosya izinlerini kontrol edin: namei -l /var/www/siteniz/ komutuyla tüm yolu gözden geçirin
  • ServerName’in doğruluğunu test edin: curl -H "Host: siteniz.com" http://sunucu-ip/
  • DNS çözümlemesini doğrulayın: dig siteniz.com komutuyla IP’nin doğru olduğunu teyit edin
  • Port dinlemesini kontrol edin: ss -tlnp | grep apache
  • SELinux/AppArmor durumunu değerlendirin: CentOS/RHEL sistemlerde sık atlanan bir adım
  • mod_rewrite aktif mi: .htaccess sorunlarında ilk bakılacak yer

Önleyici Tedbirler

Sorunları başlamadan engellemek her zaman çözmekten daha verimlidir.

# Tüm virtual host config dosyalarını tek seferde kontrol eden basit bir script
for conf in /etc/apache2/sites-enabled/*.conf; do
    echo "=== $conf ==="
    apache2ctl -f "$conf" -t 2>&1
done

# Cron job ile periyodik config kontrolü
# /etc/cron.d/apache-config-check dosyasına ekle:
# 0 * * * * root apache2ctl configtest >> /var/log/apache-config-check.log 2>&1

# Virtual host log dosyalarının döngüsünü sağla
# /etc/logrotate.d/apache2 dosyasının mevcut olduğundan emin ol
cat /etc/logrotate.d/apache2

Yeni bir virtual host oluştururken kullanabileceğiniz şablon yapısı:

<VirtualHost *:80>
    ServerName ornek.com
    ServerAlias www.ornek.com

    DocumentRoot /var/www/ornek.com/public_html

    <Directory /var/www/ornek.com/public_html>
        Options -Indexes +FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/ornek.com-error.log
    CustomLog ${APACHE_LOG_DIR}/ornek.com-access.log combined

    # HTTP'den HTTPS'e yönlendir
    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</VirtualHost>

<VirtualHost *:443>
    ServerName ornek.com
    ServerAlias www.ornek.com

    DocumentRoot /var/www/ornek.com/public_html

    <Directory /var/www/ornek.com/public_html>
        Options -Indexes +FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/ornek.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/ornek.com/privkey.pem

    ErrorLog ${APACHE_LOG_DIR}/ornek.com-ssl-error.log
    CustomLog ${APACHE_LOG_DIR}/ornek.com-ssl-access.log combined
</VirtualHost>

Sonuç

Virtual host yapılandırma sorunları karmaşık görünse de sistematik bir yaklaşımla her zaman çözülebilir. En kritik nokta şudur: önce apache2ctl -S ve apache2ctl configtest çalıştırın, sonra error log’u inceleyin. Bu üç adım sorunların yüzde seksenini açıklığa kavuşturur.

Apache’nin davranışını doğru anlamak da en az araçları bilmek kadar önemlidir. Özellikle “ilk eşleşen virtual host kazanır” mantığını ve AllowOverride direktifinin .htaccess üzerindeki etkisini kavradıktan sonra çoğu sorunun neden oluştuğunu anlık olarak görebilirsiniz.

Son olarak, her değişiklikten önce yedek almanızı, config test etmeden restart veya reload yapmamanızı ve log seviyesini sorun ayıklama sırasında geçici olarak artırmanızı şiddetle öneririm. Bu alışkanlıklar sizi hem gece yarısı çağrılarından hem de gereksiz downtime’lardan korur.

Benzer Konular

Bir yanıt yazın

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