Objetivo y arquitectura
El objetivo es publicar SQL Server Reporting Services bajo la URL frontal de IIS para que WinCC Unified lo cargue dentro de un Web Control sin infringir la politica de mismo origen del navegador.
Con reverse proxy, el cliente accede siempre por el endpoint frontal de IIS, por ejemplo https://wserver-eng/Reports. IIS intercepta la peticion, la reescribe internamente y la reenvia al backend de SSRS en https://wserver-eng:4430. Asi centralizas TLS en un unico punto, simplificas la topologia de red y eliminas los bloqueos de embebido por origen cruzado.
Requisitos minimos
- IIS con URL Rewrite y Application Request Routing (ARR).
- Permisos para administrar IIS y ejecutar PowerShell como administrador.
- SSRS operativo en backend con rutas
/Reportsy/ReportServer. - Certificado valido para el hostname usado por Unified.
1) Aplicar el reverse proxy con PowerShell
El script crea un backup de la configuracion IIS, habilita ARR Proxy a nivel global, crea (o verifica) las reglas de rewrite para /Reports y /ReportServer, y configura Content-Security-Policy: frame-ancestors 'self' para permitir el embebido en Unified sin bloqueos de iframe.
Import-Module WebAdministration
# =====================================================================
# CONFIGURACION
# =====================================================================
$siteName = "WinCC Unified SCADA"
$ssrsBackend = "https://WSERVER-ENG:4430"
$psPath = "IIS:\Sites\$siteName"
$headersSection = "system.webServer/httpProtocol/customHeaders"
$ruleReportServer = "ReverseProxySSRS_ReportServer"
$ruleReports = "ReverseProxySSRS_Reports"
# =====================================================================
# 0) BACKUP IIS (OPCIONAL PERO RECOMENDADO)
# =====================================================================
$backupName = "Before_ReverseProxySSRS_" + (Get-Date -Format "yyyyMMdd_HHmmss")
Backup-WebConfiguration -Name $backupName | Out-Null
Write-Host "BACKUP IIS creado: $backupName"
# =====================================================================
# 1) HABILITAR ARR PROXY A NIVEL GLOBAL
# =====================================================================
Set-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' `
-filter "system.webServer/proxy" -name "enabled" -value "True"
Write-Host "1.- Proxy ARR habilitado a nivel global"
# =====================================================================
# 2) CREAR/VERIFICAR REGLAS URL REWRITE EN EL SITIO
# - /ReportServer/*
# - /Reports/*
# =====================================================================
$rules = Get-WebConfigurationProperty -pspath $psPath -Filter "system.webServer/rewrite/rules" -Name "."
function Ensure-RewriteRule {
param(
[string]$Name,
[string]$MatchWildcard,
[string]$TargetUrl
)
$existing = $rules.Collection | Where-Object { $_.Name -eq $Name }
if (-not $existing) {
Add-WebConfiguration -pspath $psPath -filter "system.webServer/rewrite/rules" -value @{
name = $Name
enabled = "true"
patternSyntax = "Wildcard"
stopProcessing= "true"
match = @{ url = $MatchWildcard }
action = @{
type = "Rewrite"
url = $TargetUrl
logRewrittenUrl = "true"
}
}
Write-Host "2.- Regla URL Rewrite '$Name' creada (match: $MatchWildcard)"
$script:rules = Get-WebConfigurationProperty -pspath $psPath -Filter "system.webServer/rewrite/rules" -Name "."
}
else {
Write-Host "2.- Regla '$Name' ya existe"
}
}
Ensure-RewriteRule -Name $ruleReportServer -MatchWildcard "ReportServer/*" -TargetUrl "$ssrsBackend/ReportServer/{R:1}"
Ensure-RewriteRule -Name $ruleReports -MatchWildcard "Reports/*" -TargetUrl "$ssrsBackend/Reports/{R:1}"
# =====================================================================
# 3) HEADERS: ELIMINAR X-FRAME-OPTIONS (SI EXISTE COMO CUSTOM HEADER)
# =====================================================================
$customHeaders = Get-WebConfiguration -pspath $psPath -Filter $headersSection
$headerXFO = $customHeaders.Collection | Where-Object { $_.Name -eq "X-Frame-Options" }
if ($headerXFO) {
Remove-WebConfigurationProperty -pspath $psPath -Filter $headersSection -Name "." -AtElement @{name="X-Frame-Options"}
Write-Host "3.- Encabezado X-Frame-Options eliminado (customHeader)"
} else {
Write-Host "3.- No se encontró encabezado X-Frame-Options (customHeader)"
}
# =====================================================================
# 4) CONTENT-SECURITY-POLICY: AGREGAR O ACTUALIZAR (EVITAR DUPLICADOS)
# =====================================================================
$customHeaders = Get-WebConfiguration -pspath $psPath -Filter $headersSection
$headerCSP = $customHeaders.Collection | Where-Object { $_.Name -eq "Content-Security-Policy" }
if ($headerCSP) {
Set-WebConfigurationProperty -pspath $psPath `
-Filter "$headersSection/add[@name='Content-Security-Policy']" `
-Name "value" -Value "frame-ancestors 'self'"
Write-Host "4.- Content-Security-Policy actualizado a: frame-ancestors 'self'"
} else {
Add-WebConfigurationProperty -pspath $psPath -Filter $headersSection -Name "." `
-Value @{name="Content-Security-Policy"; value="frame-ancestors 'self'"}
Write-Host "4.- Content-Security-Policy agregado con: frame-ancestors 'self'"
}
# =====================================================================
# 5) REINICIAR IIS
# =====================================================================
Write-Host "5.- Reiniciando IIS (iisreset)..."
iisreset
Write-Host "FINALIZADO."
Write-Host "Rollback completo (si hiciera falta): Restore-WebConfiguration -Name $backupName ; iisreset"
Antes de ejecutar, revisa $siteName y $ssrsBackend para tu entorno real.
2) Verificar IIS y reglas URL Rewrite
Con el script aplicado, abre el Administrador de IIS, navega al sitio y abre el modulo URL Rewrite. Debes ver las dos reglas inbound: ReverseProxySSRS con patron ReportServer/* y ReverseProxySSRS_Reports con patron Reports/*.
Abriendo el detalle de cada regla, verifica que la accion es Rewrite, la URL destino apunta al backend SSRS (https://WSERVER-ENG:4430/...) y la opcion Stop processing subsequent rules esta activa para que otras reglas del sitio no interfieran.
3) Comprobar funcionamiento
Estas capturas verifican dos cosas: que el backend de SSRS responde correctamente y que la ruta a traves del reverse proxy resuelve el mismo contenido sin puerto explicito.
Acceso directo al backend de SSRS en wserver-eng:4430/Reports/browse/. El portal responde y muestra los informes y origenes de datos disponibles.
El mismo portal accedido a traves del reverse proxy en wserver-eng/Reports/browse. Contenido identico, URL sin puerto explicito. Este es el endpoint que debe configurarse en el Web Control de Unified.
Por que funciona en el embebido de Unified
WinCC Unified usa un motor de navegador embebido que aplica la politica de mismo origen (Same-Origin Policy). En esa politica, el origen se define como la combinacion de esquema + host + puerto: https://wserver-eng:4430 y https://wserver-eng son origenes distintos aunque compartan el nombre de host, porque el numero de puerto difiere.
Si el Web Control de Unified apunta directamente al backend SSRS con la URL que incluye el puerto, el navegador detecta origen cruzado respecto al sitio padre y bloquea el iframe, aunque SSRS devuelva HTTP 200.
Cuando Unified carga SSRS a traves del reverse proxy, la URL no incluye puerto explicito (https://wserver-eng/Reports/browse), por lo que el origen del iframe coincide con el del sitio padre. El script configuro Content-Security-Policy: frame-ancestors 'self' en IIS, lo que permite el embebido desde el mismo origen. El header X-Powered-By: ARR/3.0 visible en DevTools confirma que Application Request Routing esta activo y enrutando al backend.