IIS’te Custom Hata Sayfası Oluşturma ve Yapılandırma
Prodüksiyonda bir IIS sunucusu yönetiyorsanız, kullanıcılarınızın varsayılan hata sayfalarıyla karşılaşması hem kötü bir kullanıcı deneyimi yaratır hem de bazı durumlarda sunucu hakkında gereksiz bilgi sızdırabilir. “Server Error in Application” yazan o çirkin sarı ekranı hepimiz gördük. Bu yazıda IIS’te custom hata sayfalarını her açıdan ele alacağız: IIS Manager’dan yapılandırma, web.config üzerinden ince ayar, farklı hata kodları için özelleştirme ve production ortamında dikkat etmeniz gereken güvenlik detayları.
Neden Custom Hata Sayfası?
Teknik tarafı bir kenara bırakırsak, bu konunun insan boyutu daha önemli. Kullanıcı bir 404 sayfasıyla karşılaştığında iki şey olabilir: ya sitenizden ayrılır ya da doğru yönlendirilerek sitede kalmaya devam eder. Varsayılan IIS hata sayfası kullanıcıya hiçbir yol göstermez. Öte yandan 500 hatalarındaki varsayılan çıktı, stack trace ve sunucu bilgisi içerebilir ki bu ciddi bir güvenlik açığıdır.
Custom hata sayfaları ayrıca kurumsal kimliğin bir parçasıdır. Bankacılık, e-ticaret veya kurumsal web uygulamalarında marka tutarlılığı kritik öneme sahiptir. Hata sayfanız bile marka kimliğinizi yansıtmalıdır.
IIS Hata Sayfası Modlarını Anlamak
IIS, hata sayfalarını üç farklı modda sunabilir. Bunları anlamadan yapılandırma yapmak, ileride beklenmedik sonuçlar doğurabilir.
DetailedLocalOnly: Hata detayları yalnızca sunucuya yerel erişimde gösterilir. Uzak istemcilere genel hata sayfası döner. Bu production için en makul başlangıç noktasıdır.
Custom: Her zaman özel hata sayfanız gösterilir. Hem local hem de remote bağlantılarda aynı sayfa döner.
Detailed: Her zaman detaylı hata sayfası gösterilir. Geliştirme ortamında kullanışlıdır ama production’da kesinlikle kullanmayın.
IIS Manager ile Temel Yapılandırma
IIS Manager üzerinden hata sayfalarını yapılandırmak en görsel yöntemdir. Önce bu yolu anlayalım, sonra daha güçlü olan web.config yöntemine geçeceğiz.
IIS Manager’ı açın, sol panelden ilgili sitenizi seçin. Orta panelde “Error Pages” seçeneğini göreceksiniz. Çift tıklayın. Burada mevcut HTTP durum kodlarının listesini göreceksiniz. Herhangi birine çift tıklayarak düzenleyebilir, sağ paneldeki “Add” ile yeni bir giriş ekleyebilirsiniz.
Bir hata kodu için özel sayfa tanımlarken üç seçenek sunulur:
- Insert content from static file into the error response: Statik bir HTML dosyasını doğrudan yanıta gömer. Dosya boyutu sınırlıdır, dinamik içerik çalışmaz.
- Execute a URL on this Web site: Site içindeki bir URL’yi çalıştırır. ASPX, PHP gibi dinamik sayfalar için idealdir.
- Redirect to a URL: Kullanıcıyı başka bir URL’ye yönlendirir. Bu seçenek HTTP durum kodunu 302’ye çevirir, dikkatli kullanın.
web.config ile Yapılandırma
Gerçek dünyada her şeyi web.config üzerinden yönetmek hem daha taşınabilir hem de daha kontrol edilebilirdir. IIS Manager’da yapılan değişiklikler zaten web.config’e yansır, ama doğrudan web.config’i düzenlemek daha temiz bir yaklaşımdır.
Temel bir custom hata sayfası yapılandırması şöyle görünür:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="404" subStatusCode="-1" />
<error statusCode="404"
path="/hata/404.html"
responseMode="ExecuteURL" />
<remove statusCode="500" subStatusCode="-1" />
<error statusCode="500"
path="/hata/500.html"
responseMode="ExecuteURL" />
<remove statusCode="403" subStatusCode="-1" />
<error statusCode="403"
path="/hata/403.html"
responseMode="ExecuteURL" />
</httpErrors>
</system.webServer>
</configuration>
Buradaki existingResponse="Replace" parametresi önemli. Eğer uygulama katmanı (örneğin ASP.NET) kendi hata yanıtını oluşturuyorsa, IIS bu yanıtı sizin tanımladığınız sayfa ile değiştirir. PassThrough değerini kullanırsanız IIS uygulamanın ürettiği yanıta dokunmaz.
responseMode Parametresi
ExecuteURL: Belirtilen URL sunucu tarafında çalıştırılır, orijinal HTTP durum kodu korunur. En sık kullandığım mod bu.
Redirect: Kullanıcı belirtilen URL’ye yönlendirilir, durum kodu 302 olur. SEO açısından sorunlu olabilir.
File: Dosya içeriği doğrudan yanıta yazılır. Mutlak fiziksel yol verilmesi gerekir.
ASP.NET Uygulamalarında Ek Yapılandırma
Sadece IIS seviyesinde yapılandırma yapmak ASP.NET uygulamaları için yeterli olmayabilir. ASP.NET kendi hata işleme mekanizmasına sahiptir ve bu mekanizma devreye girdiğinde IIS’in httpErrors bölümü devre dışı kalabilir.
web.config içinde system.web bölümünde şu yapılandırmayı da eklemeniz gerekir:
<configuration>
<system.web>
<customErrors mode="Off" />
</system.web>
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="404" subStatusCode="-1" />
<error statusCode="404"
path="/hata/404.aspx"
responseMode="ExecuteURL" />
</httpErrors>
</system.webServer>
</configuration>
Burada customErrors mode="Off" demek, ASP.NET’in kendi custom hata mekanizmasını devre dışı bırakmak ve kontrolü tamamen IIS httpErrors’a bırakmak anlamına gelir. Bu sayede tutarlı bir davranış elde edersiniz.
Eğer hem ASP.NET customErrors hem de IIS httpErrors’u birlikte kullanmak istiyorsanız, existingResponse değerini iyi ayarlamanız kritiktir.
PowerShell ile Toplu Yapılandırma
Birden fazla site yönetiyorsanız veya yapılandırmayı scriptlemek istiyorsanız, PowerShell ve WebAdministration modülü hayat kurtarıcıdır. Özellikle onlarca sitenin olduğu ortamlarda bunu kullanmamak ciddi zaman kaybıdır.
Import-Module WebAdministration
$siteName = "Default Web Site"
$errorPagesPath = "system.webServer/httpErrors"
# Mevcut 404 girişini kaldır ve yenisini ekle
Remove-WebConfigurationProperty -pspath "IIS:Sites$siteName" `
-filter "$errorPagesPath" `
-name "." `
-AtElement @{statusCode='404'}
Add-WebConfiguration -pspath "IIS:Sites$siteName" `
-filter "$errorPagesPath" `
-value @{
statusCode = '404'
subStatusCode = '-1'
path = '/hata/404.html'
responseMode = 'ExecuteURL'
}
# errorMode'u Custom olarak ayarla
Set-WebConfigurationProperty -pspath "IIS:Sites$siteName" `
-filter "$errorPagesPath" `
-name "errorMode" `
-value "Custom"
Write-Host "Hata sayfasi yapilandirmasi tamamlandi." -ForegroundColor Green
Bu scripti bir deployment pipeline’ına dahil ederek her ortamda (dev, staging, prod) tutarlı yapılandırma sağlayabilirsiniz.
Appcmd ile Komut Satırı Yapılandırması
Eski alışkanlıklar kolay bırakılmıyor. Bazı ortamlarda PowerShell yoktur ya da kısıtlıdır. appcmd.exe her zaman güvenilir bir alternatif olmuştur.
# 404 için custom hata sayfası ekle
%windir%system32inetsrvappcmd.exe set config "Default Web Site" `
/section:httpErrors `
/+"[statusCode='404',subStatusCode='-1',path='/hata/404.html',responseMode='ExecuteURL']"
# errorMode'u Custom olarak ayarla
%windir%system32inetsrvappcmd.exe set config "Default Web Site" `
/section:httpErrors `
/errorMode:Custom
# Mevcut yapılandırmayı listele
%windir%system32inetsrvappcmd.exe list config "Default Web Site" `
/section:httpErrors
Dinamik Hata Sayfası Örneği
Statik HTML hata sayfaları çoğu zaman yeterlidir ama bazen daha akıllıca bir çözüm gerekebilir. Örneğin 404 sayfasında arama önerileri göstermek veya kullanıcıyı hata tipine göre farklı içerikle yönlendirmek isteyebilirsiniz. İşte basit bir ASP.NET hata sayfası örneği:
<%@ Page Language="C#" %>
<%
Response.TrySkipIisCustomErrors = true;
int statusCode = 404;
string mesaj = "Aradığınız sayfa bulunamadı.";
if (Context.Request.QueryString["404"] != null)
{
statusCode = 404;
mesaj = "Bu sayfa artık mevcut değil veya taşındı.";
Response.StatusCode = 404;
}
else if (Context.Request.QueryString["500"] != null)
{
statusCode = 500;
mesaj = "Sunucuda beklenmedik bir hata oluştu.";
Response.StatusCode = 500;
}
else if (Context.Request.QueryString["403"] != null)
{
statusCode = 403;
mesaj = "Bu kaynağa erişim yetkiniz bulunmamaktadır.";
Response.StatusCode = 403;
}
%>
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<title>Hata <%= statusCode %></title>
</head>
<body>
<h1>Hata <%= statusCode %></h1>
<p><%= mesaj %></p>
<a href="/">Ana Sayfaya Dön</a>
</body>
</html>
Burada dikkat edilmesi gereken kritik nokta Response.TrySkipIisCustomErrors = true satırıdır. Bu satır olmadan ASP.NET sayfanızdan dönen yanıt, IIS tarafından tekrar hata sayfasıyla değiştirilebilir. Bu özellikle döngüsel yönlendirme sorunlarına yol açar.
Alt Durum Kodları ile İnce Ayar
IIS bazı hata kodları için alt durum kodları (subStatusCode) kullanır. Örneğin 404.0 dosya bulunamadı, 404.3 MIME türü eşleşmesi yok, 404.4 handler bulunamadı anlamına gelir. Bu düzeyde özelleştirme yapmak istiyorsanız:
<httpErrors errorMode="Custom" existingResponse="Replace">
<!-- Genel 404 -->
<remove statusCode="404" subStatusCode="-1" />
<error statusCode="404"
subStatusCode="-1"
path="/hata/404.html"
responseMode="ExecuteURL" />
<!-- MIME türü desteklenmiyor -->
<remove statusCode="404" subStatusCode="3" />
<error statusCode="404"
subStatusCode="3"
path="/hata/404-mime.html"
responseMode="ExecuteURL" />
<!-- 500.19 web.config okuma hatası -->
<remove statusCode="500" subStatusCode="19" />
<error statusCode="500"
subStatusCode="19"
path="/hata/500-config.html"
responseMode="ExecuteURL" />
</httpErrors>
Bu düzeyde granüler kontrol çoğu senaryo için gerekmez ama büyük ve karmaşık uygulamalarda kullanıcı deneyimini önemli ölçüde iyileştirebilir.
Güvenlik Açısından Dikkat Edilmesi Gerekenler
Hata sayfaları güvenlik açısından sıkça ihmal edilen bir konudur. Birkaç kritik nokta var:
Stack trace ve sunucu bilgisi sızdırmayın. Production ortamında 500 hata sayfanız asla gerçek hata mesajını göstermemelidir. Bunun yerine bir hata referans kodu oluşturun ve bu kodu loglarınıza kaydedin.
X-Powered-By ve Server header’larını gizleyin. Hata sayfası döndürülürken bile bu header’lar sunucu teknolojinizi ele verir. web.config’e şunu ekleyin:
<system.webServer>
<httpProtocol>
<customHeaders>
<remove name="X-Powered-By" />
</customHeaders>
</httpProtocol>
<security>
<requestFiltering removeServerHeader="true" />
</security>
</system.webServer>
Hata sayfalarının kendisi hata vermemeli. Hata sayfanız bağımlı olduğu bir veritabanına veya dış servise bağlı olmamalıdır. Hata sayfası olabildiğince bağımsız ve hafif olmalıdır.
401 ve 403 ayrımına dikkat edin. Güvenlik perspektifinden bazı uygulamalar 404 döndürerek kaynak varlığını gizler. Bu bir tasarım kararıdır ama dikkatli düşünülmesi gerekir.
IIS Rewrite Module ile 404 Yönetimi
URL Rewrite modülü yüklüyse, 404 durumlarını daha sofistike şekilde yönetebilirsiniz. Örneğin eski URL yapısından yeni yapıya geçiş sırasında:
<system.webServer>
<rewrite>
<rules>
<rule name="Eski URL Yönlendirme" stopProcessing="true">
<match url="^eski-klasor/(.*)$" />
<action type="Redirect"
url="/yeni-klasor/{R:1}"
redirectType="Permanent" />
</rule>
</rules>
<rewriteMaps>
<rewriteMap name="StaticRewrites">
<add key="/eski-sayfa.html" value="/yeni-sayfa" />
<add key="/hakkimizda.aspx" value="/hakkimizda" />
</rewriteMap>
</rewriteMaps>
</rewrite>
</system.webServer>
Bu yaklaşım 404 sayısını azaltarak hata sayfası görüntülenme sıklığını düşürür. Migrasyonlarda önce rewrite kuralları sonra custom 404 sayfası mantığını oluşturmak daha sağlıklı bir yaklaşımdır.
Hata Sayfalarını Test Etme
Yapılandırdıktan sonra test etmeden geçmeyin. Test için basit bir PowerShell scripti:
$testUrls = @(
"http://localhost/olmayan-sayfa",
"http://localhost/403-test",
"http://localhost/500-test"
)
foreach ($url in $testUrls) {
try {
$response = Invoke-WebRequest -Uri $url `
-ErrorAction SilentlyContinue `
-UseBasicParsing
Write-Host "$url -> HTTP $($response.StatusCode)" `
-ForegroundColor Green
}
catch {
$statusCode = $_.Exception.Response.StatusCode.value__
Write-Host "$url -> HTTP $statusCode" `
-ForegroundColor Yellow
}
}
Bu script her URL için dönen HTTP durum kodunu gösterir. 404 sayfanız 200 döndürüyorsa SEO açısından sorun yaratır. Hata sayfası doğru durum kodunu döndürmeli, bu kesinleşmelidir.
Loglama ve İzleme
Custom hata sayfaları, loglamayı da etkileyebilir. IIS Failed Request Tracing ile hata sayfalarını tetikleyen istekleri detaylı şekilde izleyebilirsiniz:
# Failed Request Tracing'i 404 için etkinleştir
%windir%system32inetsrvappcmd.exe set config "Default Web Site" `
-section:system.webServer/tracing/traceFailedRequests `
/+"[path='*'].[statusCodes='404',traceAllAfterTimeout='false']"
Bunun yanı sıra uygulama tarafında 404 ve 500 hatalarını kendi log sisteminize kaydetmenizi öneriyorum. Windows Event Log veya bir uygulama loglama kütüphanesi (NLog, Serilog) kullanarak hata trendlerini takip edebilirsiniz.
Sonuç
IIS’te custom hata sayfası yapılandırması ilk bakışta basit görünse de, ASP.NET pipeline’ı ile IIS httpErrors arasındaki etkileşimi, responseMode seçeneklerini ve güvenlik boyutunu göz önünde bulundurduğunuzda oldukça derinlikli bir konu haline geliyor. Bu yazıda ele aldığımız noktaları özetlersek:
- errorMode ve existingResponse parametrelerini doğru anlamak, beklenmedik davranışların önüne geçer.
- ASP.NET uygulamalarında hem customErrors hem de httpErrors bölümünü birlikte düşünmek gerekir.
- Production’da detaylı hata mesajı asla kullanıcıya gösterilmemelidir.
- PowerShell veya appcmd ile yapılandırmayı scriptlemek, çok siteli ortamlarda büyük kolaylık sağlar.
- Hata sayfanızın doğru HTTP durum kodunu döndürdüğünü test edin, bu hem SEO hem de izleme açısından kritiktir.
- TrySkipIisCustomErrors bayrağını dinamik hata sayfalarında unutmayın.
Hata yönetimi, kullanıcı deneyiminin ve güvenliğin kesiştiği bir noktadır. İyi yapılandırılmış bir hata sayfası sistemi, sorunları gizlemek yerine onları yönetmenizi sağlar.
