IIS Backup ve Restore: Yapılandırma Yedekleme
Yıllar önce bir müşterimizin IIS sunucusu tam da kritik bir güncelleme sonrasında çöktüğünde, yedeğin olmadığını fark etmek nasıl bir his, bunu yaşamadan bilemezsiniz. O gece saat 02:00’de application pool ayarlarını tek tek elle girmek zorunda kaldık. O günden bu yana IIS yapılandırma yedeklemesi benim için bir alışkanlık değil, bir refleks haline geldi. Bu yazıda size sadece teorik bilgi değil, gerçekten işe yarayan pratik yöntemleri aktaracağım.
IIS Yapılandırması Neden Bu Kadar Kritik?
IIS, yapılandırmasını birkaç farklı katmanda tutar. applicationHost.config dosyası bunların en önemlisi. Bu dosya; site tanımlarınızı, application pool’larınızı, binding’lerinizi, kimlik doğrulama ayarlarınızı ve yüzlerce başka parametrenizi barındırır. %SystemRoot%System32inetsrvconfig dizininde oturur ve bir şekilde bozulduğunda ya da yanlış ellerin değiştirdiğinde tüm IIS kurulumunuz hizmet veremez hale gelir.
Bunun yanında web.config dosyaları da var. Bunlar uygulama bazında çalışır ve her sitenin kök dizininde bulunur. Framework ayarları, handler mapping’ler, custom error sayfaları, redirect kuralları… hepsi burada. Peki şimdi düşünün: 20 farklı web uygulamasının olduğu bir sunucuda bu dosyaların her birini elle yönetmek ne kadar sürdürülebilir?
Yedekleme stratejiniz bu iki katmanı da kapsamalı.
Built-in IIS Backup Mekanizması: appcmd
IIS 7.0’dan itibaren hayatımıza giren appcmd.exe, IIS yönetiminin İsviçre çakısı gibidir. Yedekleme için özel bir komut seti sunar ve bu komutlar şaşırtıcı derecede yeteneklidir.
Temel Yedekleme Komutu
%windir%system32inetsrvappcmd.exe add backup "YedekAdi"
Bu kadar basit. Çalıştırdığınızda IIS, %SystemDrive%inetpubhistory altında yeni bir klasör oluşturur ve tüm konfigürasyonu oraya kopyalar. Yedek adı vermezseniz tarih-saat damgasını otomatik kullanır.
Oluşturduğunuz yedekleri listelemek için:
%windir%system32inetsrvappcmd.exe list backup
Restore işlemi de aynı şekilde tek satır:
%windir%system32inetsrvappcmd.exe restore backup "YedekAdi"
Dikkat edin, restore sırasında IIS servisi otomatik olarak yeniden başlatılır. Bunu production ortamında gece penceresi dışında yapmayın.
Yedek Dosyalarının İçeriği
appcmd yedeği aldığında şu dosyaları kopyalar:
- applicationHost.config: Ana IIS yapılandırması
- redirection.config: Paylaşımlı yapılandırma yönlendirmesi
- administration.config: IIS Manager izinleri ve rolleri
- Schema dosyaları:
%SystemRoot%System32inetsrvconfigschemaaltındaki XML şema tanımları
Ancak burada kritik bir nokta var: web.config dosyaları bu yedeklere dahil değildir. Onlar uygulama dizinlerinde yaşar ve ayrıca yedeklenmeleri gerekir. Bunu birçok kişi gözden kaçırıyor.
PowerShell ile Gelişmiş Yedekleme
appcmd iyi bir başlangıç noktası, ama PowerShell ile çok daha kapsamlı ve otomasyon dostu çözümler üretebilirsiniz. WebAdministration modülü IIS 7.5’ten itibaren kullanılabilir.
PowerShell WebAdministration Modülü
Import-Module WebAdministration
# Tüm site konfigürasyonlarını export et
$sites = Get-Website
foreach ($site in $sites) {
$siteName = $site.Name -replace '[\/:*?"<>|]', '_'
$backupPath = "C:IIS_BackupSites$siteName"
if (-not (Test-Path $backupPath)) {
New-Item -ItemType Directory -Path $backupPath -Force
}
# Site binding bilgilerini kaydet
$site | Export-Clixml -Path "$backupPathsite_config.xml"
Write-Host "Site yedeklendi: $($site.Name)"
}
Bu script basit ama geliştirilmeye açık. Gerçek dünya senaryolarında buna log yazma, hata yakalama ve e-posta bildirimi eklemeniz gerekir.
Kapsamlı Yedekleme Script’i
İşte ben bunu production’da kullandığım, biraz daha gelişmiş bir versiyon:
# IIS_FullBackup.ps1
param(
[string]$BackupRoot = "C:IIS_Backup",
[string]$BackupName = (Get-Date -Format "yyyy-MM-dd_HH-mm-ss"),
[int]$RetentionDays = 30
)
Import-Module WebAdministration -ErrorAction Stop
$BackupPath = Join-Path $BackupRoot $BackupName
$LogFile = Join-Path $BackupRoot "backup_log.txt"
function Write-Log {
param([string]$Message, [string]$Level = "INFO")
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$logEntry = "[$timestamp] [$Level] $Message"
Add-Content -Path $LogFile -Value $logEntry
Write-Host $logEntry
}
try {
New-Item -ItemType Directory -Path $BackupPath -Force | Out-Null
Write-Log "Yedekleme baslatildi: $BackupPath"
# appcmd ile IIS konfigurasyonu yedekle
$appcmd = "$env:SystemRootSystem32inetsrvappcmd.exe"
& $appcmd add backup $BackupName 2>&1 | ForEach-Object { Write-Log $_ }
# applicationHost.config dosyasini ekstra kopyala
$sourceConfig = "$env:SystemRootSystem32inetsrvconfigapplicationHost.config"
Copy-Item $sourceConfig -Destination $BackupPath -Force
Write-Log "applicationHost.config kopyalandi"
# Web.config dosyalarini yedekle
$inetpubPath = (Get-ItemProperty "HKLM:SoftwareMicrosoftInetStp").PathWWWRoot
$inetpubParent = Split-Path $inetpubPath -Parent
$webConfigFiles = Get-ChildItem -Path $inetpubParent -Filter "web.config" -Recurse -ErrorAction SilentlyContinue
$webConfigBackupPath = Join-Path $BackupPath "WebConfigs"
New-Item -ItemType Directory -Path $webConfigBackupPath -Force | Out-Null
foreach ($wcFile in $webConfigFiles) {
$relativePath = $wcFile.FullName.Replace($inetpubParent, "").TrimStart('')
$destPath = Join-Path $webConfigBackupPath $relativePath
$destDir = Split-Path $destPath -Parent
if (-not (Test-Path $destDir)) {
New-Item -ItemType Directory -Path $destDir -Force | Out-Null
}
Copy-Item $wcFile.FullName -Destination $destPath -Force
}
Write-Log "$($webConfigFiles.Count) adet web.config dosyasi yedeklendi"
# Eski yedekleri temizle
$oldBackups = Get-ChildItem $BackupRoot -Directory |
Where-Object { $_.CreationTime -lt (Get-Date).AddDays(-$RetentionDays) }
foreach ($old in $oldBackups) {
Remove-Item $old.FullName -Recurse -Force
Write-Log "Eski yedek silindi: $($old.Name)"
}
Write-Log "Yedekleme basariyla tamamlandi"
}
catch {
Write-Log "HATA: $($_.Exception.Message)" "ERROR"
exit 1
}
Bu script’i Task Scheduler ile her gece 02:00’de çalıştırıyorum. 30 günlük retention politikası uyguluyor ve her işlemi log’a yazıyor. Basit ama güvenilir.
Scheduled Task ile Otomatik Yedekleme
Script’i elle çalıştırmak yeterli değil. Bunu otomatikleştirmeniz şart. Windows Task Scheduler ile bu işi kolayca halledebilirsiniz:
# Task Scheduler'a yedekleme gorevi ekle
$action = New-ScheduledTaskAction `
-Execute "PowerShell.exe" `
-Argument "-NonInteractive -ExecutionPolicy Bypass -File C:ScriptsIIS_FullBackup.ps1"
$trigger = New-ScheduledTaskTrigger -Daily -At "02:00AM"
$principal = New-ScheduledTaskPrincipal `
-UserId "SYSTEM" `
-LogonType ServiceAccount `
-RunLevel Highest
$settings = New-ScheduledTaskSettingsSet `
-ExecutionTimeLimit (New-TimeSpan -Hours 1) `
-RestartCount 3 `
-RestartInterval (New-TimeSpan -Minutes 10)
Register-ScheduledTask `
-TaskName "IIS_Yapilandirma_Yedekleme" `
-Action $action `
-Trigger $trigger `
-Principal $principal `
-Settings $settings `
-Description "IIS yapılandırmasının gunluk otomatik yedegi"
Write-Host "Zamanlanmis gorev olusturuldu"
SYSTEM hesabıyla çalıştırmanızı öneririm çünkü IIS konfigürasyon dosyalarına erişim için yeterli izne ihtiyaç var. Servis hesabı kullanacaksanız SeBackupPrivilege iznini vermeyi unutmayın.
IIS Shared Configuration (Paylaşımlı Yapılandırma)
Web farm ortamlarında birden fazla IIS sunucusunu yönetiyorsanız, Shared Configuration özelliği hayat kurtarıcı. Merkezi bir paylaşım üzerindeki tek bir applicationHost.config dosyasını tüm sunucular okur. Yedekleme açısından bu aslında işi kolaylaştırır; tek bir noktayı yedeklemek yeterli.
Shared Configuration’ı etkinleştirmek için:
# Shared Configuration'i PowerShell ile yapilandır
# Once paylasim yolunu belirle
$sharedConfigPath = "\FileServerIISConfig$"
$userName = "DOMAINiis-svc"
$password = ConvertTo-SecureString "P@ssw0rd123" -AsPlainText -Force
# IISAdministration modulunu kullan (IIS 10+)
Import-Module IISAdministration
# Shared config export
$manager = Get-IISServerManager
# Bu islemi IIS Manager GUI uzerinden yapmak daha guvenli
# Alternatif olarak appcmd kullan:
& "$env:SystemRootSystem32inetsrvappcmd.exe" set config `
-section:system.webServer/management/trustedProviders
Write-Host "Shared Configuration icin IIS Manager GUI kullanimi onerilir"
Write-Host "IIS Manager > Sol panel > Shared Configuration"
Shared Configuration için kritik bir uyarı: Bu yöntemi kullanırken uygulama havuzu kimliklerinin (application pool identities) her sunucuda geçerli olduğundan emin olun. Aksi takdirde restore sonrası servisler başlamaz.
Restore Senaryoları ve Best Practice’ler
Yedek almanın yarısı, restore’un nasıl yapılacağını bilmek. Birkaç farklı senaryo için yaklaşımları paylaşayım.
Senaryo 1: Yanlışlıkla Silinen Site Konfigürasyonu
Bir geliştirici yanlışlıkla bir sitenin binding’ini sildi diyelim. appcmd restore tam burada işe yarar ama tüm konfigürasyonu geri döndürdüğü için o günden bu yana yapılan diğer değişiklikler de kaybolur. Daha cerrahi bir müdahale için şu yaklaşımı kullanın:
# Mevcut applicationHost.config'i yedekle (once!)
Copy-Item "$env:SystemRootSystem32inetsrvconfigapplicationHost.config" `
-Destination "C:TempapplicationHost_$(Get-Date -Format 'yyyyMMdd_HHmm').config"
# Yedekten sadece ilgili site bilgisini cek
[xml]$backupConfig = Get-Content "C:IIS_Backup2024-01-15_02-00-00applicationHost.config"
[xml]$currentConfig = Get-Content "$env:SystemRootSystem32inetsrvconfigapplicationHost.config"
# Silinen siteyi bul
$deletedSite = $backupConfig.configuration.'system.applicationHost'.sites.site |
Where-Object { $_.name -eq "SildiğimSite" }
if ($deletedSite) {
Write-Host "Site bulundu, manuel olarak eklenecek:"
Write-Host ($deletedSite | ConvertTo-Xml -As String)
}
Bu yaklaşım size tam restore yerine cerrahi müdahale imkanı verir.
Senaryo 2: Sunucu Migrasyonu
Eski sunucudan yeni sunucuya taşıma yapıyorsunuz. En temiz yöntem:
# Kaynak sunucuda calistir
$exportPath = "C:IIS_Migration_$(Get-Date -Format 'yyyyMMdd')"
New-Item -ItemType Directory -Path $exportPath -Force
# IIS konfigurasyonunu export et
& "$env:SystemRootSystem32inetsrvappcmd.exe" add backup "MigrasyonYedegi"
# Yedegi kopyala
$backupSource = "$env:SystemDriveinetpubhistoryMigrasyonYedegi"
Copy-Item $backupSource -Destination $exportPath -Recurse
# SSL sertifikalarini export et
Get-ChildItem -Path Cert:LocalMachineMy | ForEach-Object {
$certPath = Join-Path $exportPath "Certificates"
New-Item -ItemType Directory -Path $certPath -Force | Out-Null
$certName = $_.Subject -replace '[^a-zA-Z0-9]', '_'
$certFile = Join-Path $certPath "$certName.cer"
Export-Certificate -Cert $_ -FilePath $certFile -Force
Write-Host "Sertifika export edildi: $($_.Subject)"
}
Write-Host "Migrasyon paketi hazir: $exportPath"
Write-Host "DIKKAT: PFX dosyalari icin private key'i ayrica export edin!"
SSL sertifikalarının private key ile birlikte export edilmesi gerektiğini unutmayın. .cer dosyaları public key’i içerir, HTTPS için yetmez.
Senaryo 3: Tam Disaster Recovery
Sunucu tamamen çöktü ve sıfırdan kuruyorsunuz. Bu senaryo için adım adım:
- Adım 1: Windows Server’ı ve IIS rolünü temiz kur. IIS rolü kurulurken kaynak sunucuyla aynı modülleri seçin.
- Adım 2: Uygulama dosyalarını restore et. Bu yedek scriptinizde web içerik dizinleri de varsa buradan al.
- Adım 3: Yedek konfigürasyonu kopyala ve restore et.
- Adım 4: SSL sertifikalarını import et.
- Adım 5: Application pool kimliklerini ve servis hesaplarını yeniden yapılandır.
# Hedef sunucuda calistir (IIS kurulu olmasi lazim)
$backupName = "MigrasyonYedegi"
# Yedek dosyalarini dogru konuma kopyala
$backupDest = "$env:SystemDriveinetpubhistory$backupName"
New-Item -ItemType Directory -Path $backupDest -Force
# Kaynak sunucudan kopyalanan dosyalari buraya koyun, sonra:
& "$env:SystemRootSystem32inetsrvappcmd.exe" restore backup $backupName
# Servis durumunu kontrol et
$iisStatus = Get-Service W3SVC
Write-Host "IIS Durumu: $($iisStatus.Status)"
# Siteleri listele
& "$env:SystemRootSystem32inetsrvappcmd.exe" list site
IIS Konfigürasyon Değişiklik Takibi
Yedekleme kadar önemli bir konu da değişiklikleri izlemek. “Kim bu ayarı değiştirdi?” sorusuna cevap veremezsek yedek almak yarım kalır. Windows’un yerleşik dosya denetimi (file auditing) burada devreye girer:
# applicationHost.config dosyasina audit ekle
$filePath = "$env:SystemRootSystem32inetsrvconfigapplicationHost.config"
# Audit policy'yi etkinlestir
auditpol /set /subcategory:"File System" /success:enable /failure:enable
# Dosyaya audit ACE ekle
$acl = Get-Acl $filePath
$auditRule = New-Object System.Security.AccessControl.FileSystemAuditRule(
"Everyone",
"Write,Delete,ChangePermissions",
"None",
"None",
"Success,Failure"
)
$acl.AddAuditRule($auditRule)
Set-Acl -Path $filePath -AclObject $acl
Write-Host "Audit basarıyla eklendi"
Write-Host "Degisiklikler Event Log > Security > Event ID 4663 altinda gorunecek"
Bu sayede Security event log’unda her değişikliği görebilirsiniz. Event ID 4663, dosya üzerine yazma işlemini yakalar.
Web.config Şifrelemesi ve Yedekleme
web.config dosyalarında connection string veya API key varsa bunları şifrelemek gerekir. Yedekleme yaparken şifreli bölümleri de doğru şekilde ele almanız lazım:
# aspnet_regiis ile connection strings bolumunu sifrele
# Bu komutu uygulama klasoru icinde calistirin
$sitePath = "C:inetpubwwwrootMyApp"
Set-Location $sitePath
$aspnetRegiis = "$env:SystemRootMicrosoft.NETFramework64v4.0.30319aspnet_regiis.exe"
& $aspnetRegiis -pef "connectionStrings" $sitePath -prov "RsaProtectedConfigurationProvider"
Write-Host "Connection strings sifrelendi"
Write-Host "DIKKAT: RSA anahtar konteynerini de yedekleyin!"
# RSA anahtar konteynerini yedekle
& $aspnetRegiis -px "NetFrameworkConfigurationKey" "C:Backuprsa_key_backup.xml" -pri
Write-Host "RSA anahtari export edildi: C:Backuprsa_key_backup.xml"
Kritik nokta: RSA anahtar konteynerini yedeklemezseniz, şifreli web.config dosyalarını başka bir sunucuda çözemezsiniz. Bu dosyayı güvenli bir yerde saklamalısınız.
Yedekleme Stratejisini Test Etmek
Yedek alıyorsunuz, güzel. Peki test ediyor musunuz? Birçok ekip yıllarca yedek alır ve asla test etmez. Sonra gerçek bir disaster geldiğinde yedeğin bozuk olduğunu öğrenirler. Bu acıyı yaşamamak için:
- Ayda bir: Staging ortamında tam restore testi yapın
- Her yedek sonrası: Yedek dosyalarının boyutunu ve içeriğini kontrol edin
- Her çeyrekte: Farklı bir sunucuya migrasyon simülasyonu yapın
# Yedek dogrulama scripti
param([string]$BackupPath)
$requiredFiles = @(
"applicationHost.config",
"redirection.config",
"administration.config"
)
$allGood = $true
foreach ($file in $requiredFiles) {
$filePath = Join-Path $BackupPath $file
if (Test-Path $filePath) {
$fileSize = (Get-Item $filePath).Length
if ($fileSize -gt 0) {
Write-Host "OK: $file ($fileSize bytes)"
} else {
Write-Host "UYARI: $file bos!" -ForegroundColor Yellow
$allGood = $false
}
} else {
Write-Host "HATA: $file bulunamadi!" -ForegroundColor Red
$allGood = $false
}
}
# XML gecerliligini kontrol et
$configFile = Join-Path $BackupPath "applicationHost.config"
try {
[xml]$testXml = Get-Content $configFile
Write-Host "OK: applicationHost.config gecerli XML"
} catch {
Write-Host "HATA: applicationHost.config bozuk XML - $($_.Exception.Message)" -ForegroundColor Red
$allGood = $false
}
if ($allGood) {
Write-Host "`nYedek dogrulamasi BASARILI" -ForegroundColor Green
} else {
Write-Host "`nYedek dogrulamasi BASARISIZ - Kontrol gerekiyor!" -ForegroundColor Red
exit 1
}
Sonuç
IIS yedekleme konusunda özetlemek gerekirse: appcmd günlük ihtiyaçlar için yeterli ve hızlı bir çözüm. Daha fazla kontrol istiyorsanız PowerShell ile kendi scriptinizi yazın. Her iki durumda da şu noktalara dikkat edin.
Neyi yedeklemeniz gerekiyor:
applicationHost.configve diğer IIS konfigürasyon dosyaları- Tüm uygulama
web.configdosyaları - SSL sertifikaları (private key ile birlikte PFX olarak)
- RSA şifreleme anahtarları (şifreli web.config kullanıyorsanız)
- Application pool kimliklerinin belgelenmesi
Ne sıklıkla yedek almalısınız:
- Otomatik günlük yedek zorunlu
- Her konfigürasyon değişikliği öncesi manuel yedek al
- Büyük güncellemeler ve migrasyon öncesi ekstra yedek
IIS bir Windows sunucusunun en kritik bileşenlerinden biri. Onu yedeklemek, tüm sistemi yedeklemekle aynı şey değil. Çok daha granüler bir yaklaşım gerekiyor. Bu yazıdaki script ve komutları kendi ortamınıza uyarlayın, test edin ve production’a almadan önce staging’de doğrulayın. Sabah 03:00’te paniklemek yerine, gündüz saatlerinde rahat bir restore yapmak çok daha keyifli, inanın.
