Files
admin/cms-config-rewrite-pattern.md
vitya 19422352ba docs(.wiki): ingest NAS recovery session 2026-05-18/19
15-hour cross-hypervisor recovery from WD40EFAX SMR RAID5
cascade failure. 5 entities + 7 concepts + 1 source documenting:

- Root cause: WD40EFAX SMR cascade in 3-disk RAID 5
- Hyper Backup .hbk structure + SFTP-jail / ACL workarounds
- OVA from Synology VMM (KVM) → VirtualBox: SCSI→SATA,
  Hyper-V driver disable, paravirt=kvm, GA install, NAT switch
- MSSQL restore via named volume + chown, sqlcmd -x, mssql-conf
- Web.config UTF-16 vs UTF-8 BOM IIS 500.19 trap
- Traefik on Windows DD: configFile, named volume for acme.json,
  file-provider as docker.sock workaround
- Snapshot of current recovery architecture + SPOF list
- Placeholder for future resilient-architecture work

Plus .tasks/nas-recovery.md and STATUS.md updates closing the task.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 11:07:38 +03:00

5.0 KiB
Raw Blame History

title, type, tags, sources, updated
title type tags sources updated
Web.config rewrite — кодировка и connection-string patterns concept
iis
webconfig
encoding
powershell
traceback
../sources/nas-recovery-session-2026-05-18.md
2026-05-19

Web.config rewrite на Windows: encoding pitfall

Сценарий

После cross-host миграции CMS в VM, нужно переписать connection strings (192.168.1.1010.0.2.2 или другой host). Делается через SSH/PowerShell Get-Content+-replace+Set-Content.

Pitfall: Set-Content без -Encoding

# WRONG — на PowerShell 5.1 пишет UTF-16 LE
(Get-Content $f -Raw) -replace 'old', 'new' | Set-Content $f -NoNewline

Симптом после этого:

  • IIS возвращает HTTP 500.19 - Internal Server Error, "Файл конфигурации создан в неправильном формате XML", error code 0x8007000d.
  • В детале: первые строки файла показывают артефакты ???????? (UTF-16 в окне UTF-8 ожидаемой проверки).

Корень: PowerShell 5.1 (Windows встроенный) Set-Content без -Encoding использует default = UTF-16 LE (Unicode). IIS ожидает UTF-8 (BOM или без BOM).

Правильный способ

$utf8WithBom = New-Object System.Text.UTF8Encoding($true)
$content = Get-Content $file -Raw
$new = $content -replace 'old', 'new'
[System.IO.File]::WriteAllText($file, $new, $utf8WithBom)

Или, если хочется без BOM:

$utf8NoBom = New-Object System.Text.UTF8Encoding($false)
[System.IO.File]::WriteAllText($file, $new, $utf8NoBom)

ASP.NET / IIS работают и с BOM, и без — но для дефолтного XML конфига Microsoft предпочитает с BOM.

PowerShell 7+ workaround

В Core: Set-Content -Encoding utf8 пишет UTF-8 БЕЗ BOM (отличается от PS 5!). -Encoding utf8BOMс BOM.

Connection string patterns в CMS

Нашли в MoreThenCms.WebUI/Web.config source (development):

<add name="MoreThenCmsEntities" 
     connectionString="Data Source=DESKTOP-XYZ\SQLEXPRESS;Initial Catalog=MoreThenCms;
                       Integrated Security=True;MultipleActiveResultSets=True"
     providerName="System.Data.SqlClient" />

В production (внутри OVA, после восстановления):

<add name="MoreThenCmsEntities" 
     connectionString="Data Source=192.168.1.10;Initial Catalog=MoreThenCms;
                       Integrated Security=False;User Id=snolla;
                       Password=fXkH4@8O%3pc;MultipleActiveResultSets=True"
     providerName="System.Data.SqlClient" />

То есть в prod CMS использует SQL login snolla, не Integrated Security. Сам логин остался в master.mdf после восстановления — никаких дополнительных шагов не понадобилось.

Mass-edit нескольких сайтов

Под Windows VM было 4 Web.config с одинаковым паттерном:

  • C:\inetpub\wwwroot\MoreThenCms.Web\Web.config
  • C:\inetpub\wwwroot\Snolla.IdentityManager\Web.config
  • C:\stayer\stostayer.old\web.config
  • (плюс C:\stayer\MoreThenCms.Web\ — main stostayer без 192.168.1.10 reference)

Скрипт через SSH в VM:

$files = @(
  'C:\inetpub\wwwroot\MoreThenCms.Web\Web.config',
  'C:\inetpub\wwwroot\Snolla.IdentityManager\Web.config',
  'C:\stayer\stostayer.old\web.config'
)
$utf8WithBom = New-Object System.Text.UTF8Encoding($true)
foreach ($f in $files) {
  $content = Get-Content $f -Raw
  $new = $content -replace [regex]::Escape('192.168.1.10'), '10.0.2.2'
  [System.IO.File]::WriteAllText($f, $new, $utf8WithBom)
}
# затем
iisreset

Storage providers (Azure / MinIO)

В appSettings нашли:

<add name="azureGalleries" storageType="MoreThenCms.FileStorage.Azure.AzureCloudStorage, ...">
  <settings>
    <add name="connectionString" 
         value="DefaultEndpointsProtocol=http;AccountName=snolla;
                AccountKey=<base64>" />
    <add name="container" value="galleries" />
  </settings>
</add>

Используется Azure Storage SDK с custom endpoint. В production endpoint указывает на MinIO (S3-compat но не Azure-compat — пользователь упомянул "не так всё" и обещал пояснить). Точная схема подключения — TBD, надо изучать MoreThenCms.FileStorage.Azure.AzureCloudStorage класс.

[regex]::Escape для безопасной замены IP

192.168.1.10 без escape — точки в regex matchят любой char. Лучше escape:

$pattern = [regex]::Escape('192.168.1.10')
$new = $content -replace $pattern, '10.0.2.2'

Связано: snolla-recovery-vm, traefik-on-windows-docker-desktop.