URL yönlendirme meselesi, web sunucusu yönetiminin en kritik konularından biridir. Yanlış yapılandırılmış bir yönlendirme kuralı, SEO puanınızı yerle bir edebilir, kullanıcıları hatalı sayfalara yönlendirebilir ya da güvenlik açıkları yaratabilir. Apache’nin mod_rewrite modülü ise bu işi doğru yapmanın en güçlü araçlarından biridir. Bugün bu modülü derinlemesine inceleyeceğiz ve gerçek dünya senaryolarıyla nasıl kullanacağınızı adım adım göstereceğiz.
mod_rewrite Nedir ve Neden Önemlidir?
mod_rewrite, Apache HTTP sunucusunun gelen URL isteklerini analiz edip farklı URL’lere veya kaynaklara yönlendirebilen bir modüldür. Regular expression (regex) tabanlı çalışır ve son derece esnek kurallar yazmanıza olanak tanır. Basit bir “www olmayan adresi www’ye yönlendir” işleminden tutun da, karmaşık sorgu parametresi dönüşümlerine kadar her şeyi yapabilirsiniz.
Peki neden bu kadar önemli? Çünkü:
- SEO: Aynı içeriğe birden fazla URL ile ulaşılabilmesi, duplicate content sorununa yol açar.
mod_rewriteile tüm trafiği tek bir kanonik URL’e yönlendirirsiniz. - Güvenlik: Hassas dosya uzantılarını (
.php,.sql,.env) gizleyebilirsiniz. - Kullanıcı deneyimi: Okunaksız sorgu parametrelerini içeren URL’leri temiz, anlaşılır yapılara dönüştürürsünüz.
- Esneklik: Site yapısı değiştiğinde eski linklerin çalışmaya devam etmesini sağlarsınız.
Modülü Etkinleştirmek
Ubuntu/Debian tabanlı sistemlerde:
sudo a2enmod rewrite
sudo systemctl restart apache2
CentOS/RHEL tabanlı sistemlerde modül genellikle varsayılan olarak etkindir, ama kontrol etmek için:
httpd -M | grep rewrite
Çıktıda rewrite_module (shared) görüyorsanız modül aktiftir. Etkin değilse /etc/httpd/conf.modules.d/00-base.conf dosyasını açıp LoadModule rewrite_module modules/mod_rewrite.so satırının başındaki # işaretini kaldırın.
.htaccess dosyaları ile çalışacaksanız, ilgili VirtualHost veya Directory bloğunda AllowOverride direktifini ayarlamanız gerekir:
<Directory /var/www/html>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
Temel Direktifler ve Söz Dizimi
mod_rewrite‘ın temel taşlarını anlamadan ileri gitmeyin. Kafanızda sağlam bir temel oluşturması için önemli direktifleri açıklayalım.
RewriteEngine: Modülü açıp kapar.
RewriteEngine On
RewriteBase: .htaccess kullanımında göreli yolların hangi dizine göre hesaplanacağını belirtir.
RewriteCond: Bir koşul tanımlar. Sonrasındaki RewriteRule bu koşul sağlandığında çalışır.
RewriteRule: Asıl yönlendirme kuralını tanımlar. Söz dizimi şöyledir:
RewriteRule [Eşleşme Deseni] [Hedef] [Bayraklar]
Yaygın Kullanılan Bayraklar
- [R=301]: Kalıcı yönlendirme (SEO açısından önemli)
- [R=302]: Geçici yönlendirme
- [L]: “Last” – Bu kural eşleşirse başka kural işleme
- [NC]: “No Case” – Büyük/küçük harf duyarsız eşleşme
- [QSA]: “Query String Append” – Mevcut sorgu parametrelerini hedefe ekle
- [F]: “Forbidden” – 403 döndür
- [G]: “Gone” – 410 döndür
- [P]: “Proxy” – mod_proxy ile yönlendirme
- [NE]: “No Escape” – Özel karakterleri encode etme
Gerçek Dünya Senaryoları
Senaryo 1: HTTP’den HTTPS’ye Yönlendirme
En yaygın kullanım senaryolarından biri. SSL sertifikanız varsa tüm HTTP trafiğini HTTPS’ye yönlendirmeniz hem güvenlik hem de SEO açısından şarttır:
RewriteEngine On
# Proxy arkasındaysak X-Forwarded-Proto header'ını kontrol et
RewriteCond %{HTTP:X-Forwarded-Proto} =http
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# Doğrudan bağlantı için HTTPS kontrolü
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Burada %{HTTP_HOST} ve %{REQUEST_URI} sunucu değişkenleri (server variables) kullanıyoruz. Bu sayede kural her domain için ayrı yazılmak zorunda kalmadan çalışır.
Senaryo 2: www ile www Olmayan Arasında Yönlendirme
Bazı siteler www.example.com ile example.com‘u ayrı ayrı serve eder, bu SEO’yu mahveder. Tüm trafiği www‘ye çekmek için:
RewriteEngine On
RewriteCond %{HTTP_HOST} !^www. [NC]
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Ya da tam tersine, www‘siz sürümü tercih ediyorsanız:
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www.(.+)$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [L,R=301]
%1 burada RewriteCond‘daki ilk parantez grubu içindeki yakalamayı ifade eder. Yani www.example.com isteklerinde %1 değeri example.com olur.
Senaryo 3: Temiz URL Yapısı (SEO Friendly URLs)
Eski bir PHP uygulamanız var ve URL’ler şöyle görünüyor: product.php?id=42&cat=elektronik. Bunu /urunler/elektronik/42 şeklinde göstermek istiyorsunuz:
RewriteEngine On
RewriteBase /
# Gerçek dosya veya dizin varsa dokunma
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Temiz URL'leri parse et
RewriteRule ^urunler/([a-z-]+)/([0-9]+)/?$ product.php?cat=$1&id=$2 [L,QSA]
$1 ve $2 değerleri RewriteRule desenindeki parantez gruplarından gelir. [QSA] bayrağı, kullanıcının URL’ye ek parametre eklemişse bunları korur.
RewriteCond %{REQUEST_FILENAME} !-f koşulu çok önemli: Eğer istenen bir gerçek dosyaysa (örneğin /images/logo.png) kuralla uğraşma, doğrudan sun. -d ise dizinler için aynı işi yapar.
Senaryo 4: Eski URL Yapısından Yeni Yapıya Geçiş
Site yenileme yaptınız ve URL yapısı değişti. Eski linklerin çalışmaya devam etmesi için:
RewriteEngine On
# Eski blog URL yapısı: /blog.php?slug=makale-adi
RewriteCond %{QUERY_STRING} ^slug=([a-z0-9-]+)$
RewriteRule ^blog.php$ /blog/%1? [L,R=301]
# Eski kategori sayfaları: /kategori.php?id=5
RewriteCond %{QUERY_STRING} ^id=([0-9]+)$
RewriteRule ^kategori.php$ /kategoriler/%1? [L,R=301]
# Eski haber sayfaları: /haber-detay.php?no=123&baslik=test
RewriteCond %{QUERY_STRING} ^no=([0-9]+)
RewriteRule ^haber-detay.php$ /haberler/%1? [L,R=301]
URL’nin sonundaki ? işaretine dikkat edin. Bu, orijinal sorgu parametrelerinin hedefe eklenmesini engeller. Aksi takdirde ?slug=makale-adi parametresi de yeni URL’e yapışır ve çirkin görünür.
Senaryo 5: IP Bazlı Erişim Kısıtlaması ve Yönlendirme
Bakım modundaysanız ve sadece belirli IP’lerin siteye erişmesini istiyorsanız:
RewriteEngine On
# Yönetici IP'lerine izin ver (ofis IP'si)
RewriteCond %{REMOTE_ADDR} ^185.123.45.67$
RewriteRule ^ - [L]
# Localhost'a izin ver
RewriteCond %{REMOTE_ADDR} ^127.0.0.1$
RewriteRule ^ - [L]
# Bakım sayfasının kendisini engelleme (sonsuz döngü önleme)
RewriteRule ^maintenance.html$ - [L]
# Geriye kalan herkesi bakım sayfasına yönlendir
RewriteRule ^ /maintenance.html [R=302,L]
Burada 302 kullanıyoruz çünkü bakım geçici bir durum. Kalıcı olmayan yönlendirmelerde R=302 tercih edin, aksi halde tarayıcılar bu yönlendirmeyi cache’leyebilir.
Senaryo 6: Dosya Uzantısı Gizleme ve Güvenlik
.php uzantısını URL’den gizlemek ve aynı zamanda .env, .git, .htaccess gibi hassas dosyalara erişimi engellemek:
RewriteEngine On
# Hassas dosya ve dizinlere erişimi engelle
RewriteRule ^.env$ - [F,L]
RewriteRule ^.git - [F,L]
RewriteRule ^.htaccess$ - [F,L]
RewriteRule ^composer.(json|lock)$ - [F,L]
RewriteRule ^package(-lock)?.json$ - [F,L]
# PHP uzantısını gizle
# Önce gerçek dosya var mı kontrol et
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^([^.]+)$ $1.php [L]
# .php uzantısıyla direkt erişimi temiz URL'e yönlendir
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9} /([^ ]+).php
RewriteRule ^(.+).php$ /$1 [R=301,L]
%{THE_REQUEST} değişkeni HTTP isteğinin ham halini içerir, örneğin GET /sayfa.php HTTP/1.1. Bu sayede tarayıcının .php uzantılı URL ile geldiğini anlayıp onu temiz URL’e yönlendirebiliyoruz.
Senaryo 7: Subdomain Bazlı Yönlendirme
api.example.com ve static.example.com gibi subdomainleri aynı sunucu üzerinden farklı dizinlere yönlendirmek:
RewriteEngine On
# api subdomain'ini /var/www/api dizinine yönlendir
RewriteCond %{HTTP_HOST} ^api.example.com$ [NC]
RewriteCond %{REQUEST_URI} !^/api/
RewriteRule ^(.*)$ /api/$1 [L]
# static subdomain'ini CDN'e yönlendir
RewriteCond %{HTTP_HOST} ^static.example.com$ [NC]
RewriteRule ^(.*)$ https://cdn.baskabir-cdn.com$1 [R=301,L]
# Mobil cihazları m. subdomain'ine yönlendir
RewriteCond %{HTTP_HOST} !^m. [NC]
RewriteCond %{HTTP_USER_AGENT} "Mobile|Android|iPhone|iPad" [NC]
RewriteRule ^(.*)$ https://m.example.com/$1 [R=302,L]
Hata Ayıklama ve Sorun Giderme
mod_rewrite kurallarını debug etmek bazen sinir bozucu olabilir. Apache’nin log mekanizmasını kullanmak en sağlıklı yöntem.
httpd.conf veya apache2.conf dosyasına veya ilgili VirtualHost içine şunu ekleyin:
# Log seviyesini geçici olarak yükselt
LogLevel alert rewrite:trace6
# Log dosyasını belirle
ErrorLog ${APACHE_LOG_DIR}/rewrite_debug.log
Sonra log dosyasını izleyin:
tail -f /var/log/apache2/rewrite_debug.log
trace3 genellikle yeterlidir. trace6 çok detaylı bilgi verir ama log dosyası çabuk şişer, production’da kullanmayın.
Yaygın Hatalar ve Çözümleri
Sonsuz Döngü (Infinite Loop): En sık karşılaşılan sorundur. Kural kendi kendini tekrar tetiklerse Apache 500 hatası verir. Çözüm için [L] bayrağını doğru kullanın ve gerektiğinde RewriteCond ile döngüyü kırın.
Kural Sırası Önemli: mod_rewrite kuralları yukarıdan aşağıya işler. Daha spesifik kuralları genel kuralların önüne yazın.
Regex Test Etme: Kural yazmadan önce regex’inizi test edin:
echo "/urunler/elektronik/42" | grep -oP "^urunler/([a-z-]+)/([0-9]+)/?$"
Ya da online regex tester araçlarından (regex101.com gibi) faydalanın.
.htaccess vs VirtualHost: Mümkünse kurallarınızı .htaccess yerine VirtualHost içinde tanımlayın. .htaccess dosyaları her istek için disk’ten okunur ve performansı olumsuz etkiler. .htaccess yalnızca paylaşımlı hosting gibi ana konfigürasyona erişemediğiniz durumlarda tercih edilmeli.
Performans Optimizasyonu
mod_rewrite kullanımında performansı gözetmek önemlidir.
# Gereksiz regex işlemlerini önle
# Önce basit kontrolleri yap
RewriteCond %{REQUEST_URI} .(jpg|jpeg|png|gif|css|js|ico|woff|woff2)$ [NC]
RewriteRule ^ - [L]
# Statik dosyalar için rewrite engine'i devre dışı bırak
<LocationMatch ".(jpg|jpeg|png|gif|css|js)$">
RewriteEngine Off
</LocationMatch>
Statik dosyaları rewrite zincirinden erken çıkarmak, sunucunun gereksiz regex işlemi yapmasını engeller. Yoğun trafikli sitelerde bu küçük optimizasyon ciddi fark yaratır.
Güvenlik Açısından Dikkat Edilmesi Gerekenler
mod_rewrite ile güvenlik kuralları yazarken şu noktalara dikkat edin:
- Regex enjeksiyonuna karşı dikkatli olun: Kullanıcı girdilerini (URL parametreleri) kural içinde kullanırken mutlaka karakter sınırlaması yapın.
([a-z0-9-]+)gibi beyaz liste yaklaşımı benimsein. [F]ve[G]bayraklarını aktif kullanın: 403 ve 410 döndürmek, yetkisiz erişim girişimlerini hem loglar hem de saldırganları caydırır.AllowOverride‘ı minimum tutun: Eğer.htaccess‘e ihtiyaç yoksaAllowOverride Nonekullanın. Bu hem güvenlik hem de performans sağlar.- Test ortamında deneyin: Production sunucuda kural değişikliği yapmadan önce staging ortamında test edin. Yanlış bir kural bütün siteyi çökertebilir.
Sonuç
mod_rewrite, doğru kullanıldığında Apache kurulumunuzun en değerli bileşenlerinden biri haline gelir. HTTP’den HTTPS’ye geçiş, SEO dostu URL yapıları, eski linklerin yaşatılması, güvenlik kısıtlamaları gibi kritik işlemleri sadece birkaç satır konfigürasyonla halledebilirsiniz. Ancak bu güç, beraberinde dikkat gerektiren bir sorumluluk da getirir.
Kural yazarken her zaman şu sırayı takip etmenizi öneririm: Önce neyi başarmak istediğinizi net tanımlayın, regex’inizi ayrı ayrı test edin, kuralları sırasıyla yazın, debug loglarıyla doğrulayın ve son olarak staging’de deneyin. Bu disiplini korduğunuzda mod_rewrite sizi hiç yarı yolda bırakmaz.
Bir sonraki yazıda mod_proxy ile birlikte kullanım senaryolarını ve reverse proxy konfigürasyonlarını ele alacağız. O zamana kadar, sunucularınız sorunsuz çalışsın.