IIS Shared Configuration ile Çoklu Sunucu Yönetimi

On sunuculu bir web farm’ı tek tek yönetmeye çalışmak… Bunu yaşayanlar bilir, bir uygulama havuzunu güncellemek için 10 sunucuya RDP açmak ne kadar sinir bozucu olduğunu. IIS Shared Configuration tam da bu acıyı gidermek için var ve doğru kurulduğunda hayat kurtarır. Ben bu konuyu teorik olarak değil, birkaç kez hem doğru hem de yanlış kurduğum için aktarıyorum.

IIS Shared Configuration Nedir ve Neden Kullanmalısınız?

IIS Shared Configuration, birden fazla IIS sunucusunun tek bir merkezi yapılandırma dosyasını paylaşmasını sağlayan bir mekanizmadır. Temel mantık şu: applicationHost.config dosyasını ve ilgili şifreleme anahtarlarını bir ağ paylaşımına koyarsınız, tüm sunucular bu dosyayı okur. Bir sunucuda yaptığınız değişiklik anında diğer tüm sunuculara yansır.

Özellikle şu senaryolarda kritik önem taşır:

  • Web farm ortamları: Load balancer arkasında birden fazla IIS sunucusu çalıştırıyorsanız
  • NLB (Network Load Balancing) kümeleri: Oturum tutarlılığı gerektiren uygulamalar
  • Felaket kurtarma senaryoları: Aktif-pasif yapılarda hızlı devreye alma
  • Büyük ölçekli kurumsal ortamlar: 5 ve üzeri IIS sunucusu içeren ortamlar

Şunu da açıkça söyleyeyim: 2 sunuculuk ortamlar için bu kadar efor sarf etmek bazen fazla gelebilir. Ama 5 sunucu ve üzeri için bu olmadan yaşamak gerçekten zor.

Mimari ve Ön Hazırlık

Paylaşımlı yapılandırma için önce mimarinizi kafanızda netleştirmeniz gerekiyor. Tipik bir kurulum şu bileşenlerden oluşur:

  • Dosya sunucusu (UNC Share): Yapılandırma dosyalarının tutulduğu merkezi konum
  • IIS sunucuları: Bu paylaşıma bağlanan web sunucuları
  • Servis hesabı: Tüm IIS sunucularının paylaşıma erişmek için kullandığı domain hesabı

Dosya sunucusu için ayrı bir makine kullanmanızı öneririm. Bazıları bunu IIS sunucularından birine kuruyor, bu da beraberinde tek nokta arıza riski getiriyor. Eğer ayrı bir dosya sunucunuz yoksa en azından DFS (Distributed File System) ile replikasyon yapın.

Servis Hesabı Oluşturma

Domain ortamında çalışıyorsanız önce bir servis hesabı oluşturmanız gerekiyor. Bu hesap IIS Application Pool Identity olarak kullanılmayacak, sadece paylaşıma erişim için kullanılacak.

# Active Directory'de servis hesabı oluşturma
New-ADUser -Name "svc-iis-config" `
           -SamAccountName "svc-iis-config" `
           -UserPrincipalName "[email protected]" `
           -AccountPassword (ConvertTo-SecureString "P@ssw0rd123!" -AsPlainText -Force) `
           -PasswordNeverExpires $true `
           -CannotChangePassword $true `
           -Enabled $true `
           -Description "IIS Shared Configuration Service Account"

Şifreyi konsolda açık yazmak yerine daha güvenli bir yöntem kullanmak isterseniz:

# Şifreyi interaktif olarak almak
$SecurePassword = Read-Host -AsSecureString -Prompt "Servis hesabı şifresi"
New-ADUser -Name "svc-iis-config" `
           -SamAccountName "svc-iis-config" `
           -AccountPassword $SecurePassword `
           -PasswordNeverExpires $true `
           -Enabled $true

Dosya Sunucusunda Paylaşım Oluşturma

Dosya sunucusunda yapılandırma dosyalarını tutacak dizini ve paylaşımı oluşturuyoruz.

# Dosya sunucusunda çalıştırın
$SharePath = "C:IISSharedConfig"
$ShareName = "IISConfig"

# Dizin oluştur
New-Item -ItemType Directory -Path $SharePath -Force

# NTFS izinlerini ayarla
# Önce mevcut inherited izinleri kaldır
$Acl = Get-Acl $SharePath
$Acl.SetAccessRuleProtection($true, $false)
Set-Acl $SharePath $Acl

# Servis hesabına okuma/yazma ver
$Permission = "DOMAINsvc-iis-config","Modify","ContainerInherit,ObjectInherit","None","Allow"
$AccessRule = New-Object System.Security.AccessControl.FileSystemAccessRule $Permission
$Acl = Get-Acl $SharePath
$Acl.SetAccessRule($AccessRule)
Set-Acl $SharePath $Acl

# Administrators grubuna full control ver
$AdminPermission = "BUILTINAdministrators","FullControl","ContainerInherit,ObjectInherit","None","Allow"
$AdminRule = New-Object System.Security.AccessControl.FileSystemAccessRule $AdminPermission
$Acl.SetAccessRule($AdminRule)
Set-Acl $SharePath $Acl

# Ağ paylaşımı oluştur
New-SmbShare -Name $ShareName `
             -Path $SharePath `
             -FullAccess "DOMAINsvc-iis-config","DOMAINDomain Admins" `
             -Description "IIS Shared Configuration Files"

UNC yolunuz \FILESERVERIISConfig şeklinde olacak. Bunu not alın, sonraki adımlarda kullanacağız.

Birinci IIS Sunucusunda Yapılandırma Dışa Aktarma

Şimdi asıl konfigürasyona geliyoruz. Önce bir “master” IIS sunucusu seçin, mevcut yapılandırmayı oradan dışa aktaracaksınız. Bu işlemi hem IIS Manager GUI ile hem de PowerShell ile yapabilirsiniz, ben PowerShell’i tercih ediyorum çünkü tekrarlanabilir ve belgelenebilir.

# Master IIS sunucusunda çalıştırın
# WebAdministration modülünü yükle
Import-Module WebAdministration

# Paylaşılan yapılandırmayı etkinleştir ve dışa aktar
$UNCPath = "\FILESERVERIISConfig"
$UserName = "DOMAINsvc-iis-config"
$Password = "P@ssw0rd123!"

# IIS Manager üzerinden export (bu komut mevcut yapılandırmayı UNC'ye kopyalar)
& "$env:windirsystem32inetsrvappcmd.exe" set config `
    -section:system.applicationHost/configurationRedirection `
    /enabled:true `
    /path:"$UNCPath" `
    /userName:"$UserName" `
    /password:"$Password"

Alternatif olarak GUI üzerinden de yapabilirsiniz: IIS Manager > Server > Shared Configuration > Export Configuration. Ama ben bunu PowerShell ile yapmayı tercih ederim, özellikle bunu bir kurulum scripti haline getirmeniz gerektiğinde.

Dışa aktarma işleminden sonra UNC paylaşımında şu dosyaların oluştuğunu göreceksiniz:

  • applicationHost.config: Ana IIS yapılandırma dosyası
  • administration.config: IIS yönetim yapılandırması
  • configEncKey.key: Şifreleme anahtarı dosyası

Bu .key dosyası kritik öneme sahiptir. Şifreli değerleri (uygulama havuzu şifreleri gibi) çözmek için kullanılır. Bu dosyayı kaybederseniz şifreli değerleri okuyamazsınız.

Diğer IIS Sunucularını Yapılandırma

Master sunucudan dışa aktarma tamamlandıktan sonra diğer sunuculara geçiyoruz. Bu adımı otomatize etmek için bir script yazalım:

# Tüm IIS sunucularında çalıştırmak üzere script
# Remote execution için kullanabilirsiniz

$Servers = @("WEBSERVER02", "WEBSERVER03", "WEBSERVER04", "WEBSERVER05")
$UNCPath = "\FILESERVERIISConfig"
$UserName = "DOMAINsvc-iis-config"
$Password = ConvertTo-SecureString "P@ssw0rd123!" -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential($UserName, $Password)

foreach ($Server in $Servers) {
    Write-Host "Yapılandırılıyor: $Server" -ForegroundColor Cyan
    
    Invoke-Command -ComputerName $Server -ScriptBlock {
        param($UNCPath, $UserName, $PlainPassword)
        
        # Web-Server özelliğinin yüklü olduğundan emin ol
        $IISInstalled = Get-WindowsFeature -Name Web-Server
        if (-not $IISInstalled.Installed) {
            Write-Error "IIS bu sunucuda yüklü değil!"
            return
        }
        
        # Shared Configuration'ı etkinleştir
        & "$env:windirsystem32inetsrvappcmd.exe" set config `
            -section:system.applicationHost/configurationRedirection `
            /enabled:true `
            /path:"$UNCPath" `
            /userName:"$UserName" `
            /password:"$PlainPassword"
        
        # IIS'i yeniden başlat
        iisreset /restart /noforce
        
        Write-Host "$env:COMPUTERNAME yapılandırması tamamlandı" -ForegroundColor Green
        
    } -ArgumentList $UNCPath, $UserName, "P@ssw0rd123!"
}

Şifreleme Anahtarı Yönetimi

Bu konu genellikle atlanan ama sonradan baş ağrısı yaratan bir detay. Shared Configuration etkinleştirildiğinde, tüm sunucuların aynı şifreleme anahtarını kullanması gerekiyor. Aksi halde uygulama havuzları şifreli parolalarını okuyamaz ve başlamaz.

# Şifreleme anahtarını doğrulama scripti
# Her sunucuda çalıştırın

function Test-IISEncryptionKey {
    param(
        [string]$UNCPath,
        [string]$UserName,
        [string]$Password
    )
    
    $KeyFile = Join-Path $UNCPath "configEncKey.key"
    
    # Anahtar dosyasına erişimi test et
    try {
        $NetCred = New-Object System.Net.NetworkCredential($UserName, $Password)
        $UNCDrive = New-PSDrive -Name "IISConfig" -PSProvider FileSystem -Root $UNCPath `
                    -Credential (New-Object System.Management.Automation.PSCredential(
                        $UserName, (ConvertTo-SecureString $Password -AsPlainText -Force)))
        
        if (Test-Path $KeyFile) {
            Write-Host "Anahtar dosyası erişilebilir: $KeyFile" -ForegroundColor Green
            $KeyInfo = Get-Item $KeyFile
            Write-Host "Son değiştirilme: $($KeyInfo.LastWriteTime)" -ForegroundColor Yellow
        } else {
            Write-Error "Anahtar dosyası bulunamadı!"
        }
        
        Remove-PSDrive -Name "IISConfig" -Force
    }
    catch {
        Write-Error "Erişim hatası: $_"
    }
}

Test-IISEncryptionKey -UNCPath "\FILESERVERIISConfig" `
                      -UserName "DOMAINsvc-iis-config" `
                      -Password "P@ssw0rd123!"

Yapılandırma Değişikliklerini Yönetme

Shared Configuration’ın en büyük avantajı, değişikliklerin anında tüm sunuculara yansıması. Ama bu aynı zamanda en büyük risk. Yanlış bir değişiklik tüm farm’ı etkiler.

Bu yüzden değişiklik yönetimi için şu yaklaşımı benimsedim:

# Değişiklik öncesi yapılandırma yedeği alma scripti
function Backup-IISSharedConfig {
    param(
        [string]$UNCPath = "\FILESERVERIISConfig",
        [string]$BackupBasePath = "\FILESERVERIISConfigBackup"
    )
    
    $TimeStamp = Get-Date -Format "yyyyMMdd_HHmmss"
    $BackupPath = Join-Path $BackupBasePath $TimeStamp
    
    # Backup dizini oluştur
    New-Item -ItemType Directory -Path $BackupPath -Force | Out-Null
    
    # Dosyaları kopyala
    $FilesToBackup = @("applicationHost.config", "administration.config", "configEncKey.key")
    
    foreach ($File in $FilesToBackup) {
        $SourceFile = Join-Path $UNCPath $File
        if (Test-Path $SourceFile) {
            Copy-Item -Path $SourceFile -Destination $BackupPath -Force
            Write-Host "Yedeklendi: $File" -ForegroundColor Green
        }
    }
    
    Write-Host "`nYedek alındı: $BackupPath" -ForegroundColor Cyan
    
    # Eski yedekleri temizle (30 günden eski)
    $CutoffDate = (Get-Date).AddDays(-30)
    Get-ChildItem -Path $BackupBasePath -Directory | 
        Where-Object { $_.CreationTime -lt $CutoffDate } | 
        Remove-Item -Recurse -Force
    
    return $BackupPath
}

# Değişiklik öncesi çağır
$BackupLocation = Backup-IISSharedConfig
Write-Host "Backup alındı: $BackupLocation"

Bu scripti bir değişiklik yönetim sürecine entegre edin. Ben genellikle bunu bir Git reposuyla da birleştiriyorum, böylece applicationHost.config değişiklik geçmişini de takip edebiliyorum.

Sorun Giderme: Sık Karşılaşılan Durumlar

Yıllar içinde bu yapıyı kurarken ve yönetirken karşılaştığım başlıca sorunları ve çözümlerini paylaşayım.

Sorun 1: IIS başlamıyor, “Cannot read configuration file” hatası

Bu genellikle UNC yoluna erişim sorunundan kaynaklanır. Kontrol listesi:

  • Servis hesabının paylaşıma okuma iznine sahip olduğunu doğrulayın
  • IIS Application Host Helper Service’in doğru hesapla çalıştığını kontrol edin
  • Firewall’da SMB (445) portunun açık olduğundan emin olun
# IIS servislerinin durumunu kontrol etme
$IISServices = @("W3SVC", "WAS", "IISADMIN", "AppHostSvc")
foreach ($Service in $IISServices) {
    $Svc = Get-Service -Name $Service -ErrorAction SilentlyContinue
    if ($Svc) {
        $Color = if ($Svc.Status -eq "Running") { "Green" } else { "Red" }
        Write-Host "$($Svc.DisplayName): $($Svc.Status)" -ForegroundColor $Color
    }
}

# UNC erişimini test etme
$UNCPath = "\FILESERVERIISConfig"
if (Test-Path $UNCPath) {
    Write-Host "UNC erişimi başarılı" -ForegroundColor Green
    
    # applicationHost.config erişimini test et
    $ConfigFile = Join-Path $UNCPath "applicationHost.config"
    if (Test-Path $ConfigFile) {
        Write-Host "applicationHost.config erişilebilir" -ForegroundColor Green
        Write-Host "Dosya boyutu: $((Get-Item $ConfigFile).Length) bytes"
    }
} else {
    Write-Error "UNC yoluna erişilemiyor: $UNCPath"
}

Sorun 2: Uygulama havuzları “Identity” hatasıyla başlamıyor

Bu, şifreleme anahtarının uyumsuzluğundan kaynaklanır. Master sunucudan anahtarı tekrar export edin ve diğer sunucularda yapılandırmayı sıfırlayıp yeniden etkinleştirin.

Sorun 3: Yapılandırma değişiklikleri yansımıyor

IIS yapılandırma değişiklikleri genellikle anında yansır ama bazen önbellek sorunu yaşanabilir:

# Tüm sunucularda IIS yapılandırmasını yenileme
$Servers = @("WEBSERVER01", "WEBSERVER02", "WEBSERVER03")

foreach ($Server in $Servers) {
    Invoke-Command -ComputerName $Server -ScriptBlock {
        # Yapılandırmayı yenile (IIS yeniden başlatmadan)
        & "$env:windirsystem32inetsrvappcmd.exe" recycle apppool /apppool.name:DefaultAppPool
        
        # Veya tüm uygulama havuzlarını yenile
        Get-WebConfiguration system.applicationHost/applicationPools/add | 
            ForEach-Object { 
                & "$env:windirsystem32inetsrvappcmd.exe" recycle apppool /apppool.name:$($_.name)
            }
    }
    Write-Host "$Server yenilendi" -ForegroundColor Green
}

Shared Configuration ile SSL Sertifika Yönetimi

Önemli bir nokta daha: SSL sertifikaları applicationHost.config içinde referans olarak tutulur ama sertifikanın kendisi her sunucunun kendi sertifika deposunda olması gerekir. Bunu merkezi olarak yönetmek için:

# Sertifikayı tüm sunuculara dağıtma scripti
$Servers = @("WEBSERVER02", "WEBSERVER03", "WEBSERVER04")
$CertPath = "C:Certswildcard.pfx"
$CertPassword = ConvertTo-SecureString "CertP@ss" -AsPlainText -Force

foreach ($Server in $Servers) {
    # Sertifika dosyasını kopyala
    $RemotePath = "\$ServerC$Tempcert.pfx"
    Copy-Item -Path $CertPath -Destination $RemotePath -Force
    
    # Uzak sunucuda sertifikayı içe aktar
    Invoke-Command -ComputerName $Server -ScriptBlock {
        param($PlainPassword)
        
        $SecurePass = ConvertTo-SecureString $PlainPassword -AsPlainText -Force
        Import-PfxCertificate -FilePath "C:Tempcert.pfx" `
                              -CertStoreLocation "Cert:LocalMachineMy" `
                              -Password $SecurePass
        
        # Geçici dosyayı temizle
        Remove-Item "C:Tempcert.pfx" -Force
        
        Write-Host "Sertifika içe aktarıldı: $env:COMPUTERNAME"
    } -ArgumentList "CertP@ss"
}

İzleme ve Sağlık Kontrolü

Shared Configuration kurulumunun sağlıklı çalıştığını düzenli olarak doğrulayan bir script:

# Günlük çalıştırılabilecek sağlık kontrolü
function Test-IISSharedConfigHealth {
    param(
        [string[]]$Servers = @("WEBSERVER01", "WEBSERVER02", "WEBSERVER03"),
        [string]$UNCPath = "\FILESERVERIISConfig",
        [string]$AlertEmail = "[email protected]"
    )
    
    $Report = @()
    $MasterConfigHash = $null
    
    # Master sunucudan config hash'ini al
    $MasterConfig = Join-Path $UNCPath "applicationHost.config"
    if (Test-Path $MasterConfig) {
        $MasterConfigHash = (Get-FileHash $MasterConfig -Algorithm MD5).Hash
    } else {
        Write-Error "Master yapılandırma dosyasına erişilemiyor!"
        return
    }
    
    foreach ($Server in $Servers) {
        $ServerResult = [PSCustomObject]@{
            Server = $Server
            IISRunning = $false
            SharedConfigEnabled = $false
            SiteCount = 0
            AppPoolCount = 0
            Status = "Unknown"
        }
        
        try {
            $Result = Invoke-Command -ComputerName $Server -ScriptBlock {
                $W3SVC = Get-Service -Name W3SVC
                $Sites = Get-Website
                $AppPools = Get-WebConfiguration system.applicationHost/applicationPools/add
                
                # Shared Config durumunu kontrol et
                $SharedConfigNode = Get-WebConfigurationProperty `
                    -pspath "MACHINE/WEBROOT" `
                    -filter "system.applicationHost/configurationRedirection" `
                    -name "enabled"
                
                return @{
                    ServiceStatus = $W3SVC.Status
                    SiteCount = ($Sites | Measure-Object).Count
                    AppPoolCount = ($AppPools | Measure-Object).Count
                    SharedConfigEnabled = $SharedConfigNode.Value
                }
            } -ErrorAction Stop
            
            $ServerResult.IISRunning = ($Result.ServiceStatus -eq "Running")
            $ServerResult.SharedConfigEnabled = $Result.SharedConfigEnabled
            $ServerResult.SiteCount = $Result.SiteCount
            $ServerResult.AppPoolCount = $Result.AppPoolCount
            $ServerResult.Status = "OK"
        }
        catch {
            $ServerResult.Status = "ERROR: $_"
        }
        
        $Report += $ServerResult
    }
    
    # Sonuçları göster
    $Report | ForEach-Object {
        $Color = if ($_.Status -eq "OK") { "Green" } else { "Red" }
        Write-Host "[$($_.Server)] IIS: $($_.IISRunning) | SharedConfig: $($_.SharedConfigEnabled) | Sites: $($_.SiteCount) | Status: $($_.Status)" `
                   -ForegroundColor $Color
    }
    
    return $Report
}

# Çalıştır
Test-IISSharedConfigHealth

Güvenlik Notları

Shared Configuration kullanırken göz ardı edilmemesi gereken güvenlik konuları:

  • Anahtar dosyasını koruyun: configEncKey.key dosyasına erişimi sadece servis hesabı ve yöneticilerle sınırlayın. Bu dosya çalınırsa şifreli tüm değerler deşifre edilebilir.
  • Paylaşım izinlerini en az yetki prensibiyle yönetin: Servis hesabına sadece ihtiyacı olan izinleri verin.
  • Ağ şifreleme: Mümkünse SMB imzalamayı zorunlu kılın. Man-in-the-middle saldırılarına karşı önlem.
  • Denetim günlükleri: Paylaşımdaki dosyalara erişim ve değişiklikleri Windows Security Log’unda tutun.
  • Ayrı bir VLAN: Mümkünse yönetim ağ trafiğini üretim trafiğinden ayırın.

Sonuç

IIS Shared Configuration, doğru kurulduğunda web farm yönetimini gerçek anlamda basitleştiren güçlü bir özellik. On sunucuyu tek tek yönetmek yerine bir yerden yapılandırma değişikliği yapıp tüm farm’ın bunu alması, hem operasyonel verimliliği artırıyor hem de tutarsızlık hatalarını ortadan kaldırıyor.

Bununla birlikte bazı gerçekleri de gözden kaçırmamak gerekiyor: Bu yapı, dosya sunucusunu kritik bir bileşen haline getiriyor. Dosya sunucusu erişilemez olursa IIS sunucuları çalışmaya devam eder (önbelleğe alınmış yapılandırmayla) ama yeni başlatmalarda sorun çıkabilir. Bu yüzden dosya sunucusu için yüksek erişilebilirlik planlaması yapmak şart.

Paylaşılan yapılandırmayı bir değişiklik yönetim süreci olmadan kullanmayın. Bir web.config yerine applicationHost.config’i yanlış düzenlemek tüm farm’ı etkileyebilir. Yedekleme scriptini mutlaka kullanın ve tercihen Git gibi bir versiyon kontrol sistemiyle de entegre edin.

Son olarak, bu teknolojiyi üretim ortamına almadan önce mutlaka test ortamında deneyin. Kavramsal olarak basit görünse de detaylarda beklenmedik durumlarla karşılaşabilirsiniz. Özellikle SSL sertifikası yönetimi ve uygulama havuzu kimlik yönetimi konularında dikkatli olun.

Bir yanıt yazın

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