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%System32inetsrvconfigschema altı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.config ve diğer IIS konfigürasyon dosyaları
  • Tüm uygulama web.config dosyaları
  • 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.

Bir yanıt yazın

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