Files
solution-erp/scripts/migrate-domains.ps1
pqhuy1987 b93dacff44
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m46s
[CLAUDE] Scripts: fix migrate-domains.ps1 ASCII-only (gotcha #30 PS 5.1)
2026-04-24 09:55:57 +07:00

207 lines
7.5 KiB
PowerShell

# Migrate domains from *.huypham.vn to solutions.com.vn (Phase 6+ rebrand).
# Run on VPS with admin privilege. Idempotent - retry if fail mid-way.
#
# Workflow (3 IIS sites):
# 1. Add binding for new domain (port 80)
# 2. Run win-acme for Let's Encrypt cert via HTTP-01 challenge
# 3. Verify /health/ready + /health/live via new domain
# 4. Remove old binding (optional, via -RemoveOld)
#
# Usage:
# .\migrate-domains.ps1 # keep old binding, add new
# .\migrate-domains.ps1 -RemoveOld # remove old after verify
# .\migrate-domains.ps1 -SkipCert # skip win-acme step
#
# ASCII-only per gotcha #30 (PS 5.1 parser fail on UTF-8 diacritics).
[CmdletBinding()]
param(
[string]$NewApi = "api.solutions.com.vn",
[string]$NewAdmin = "admin.solutions.com.vn",
[string]$NewUser = "eoffice.solutions.com.vn",
[string]$OldApi = "api.huypham.vn",
[string]$OldAdmin = "admin.huypham.vn",
[string]$OldUser = "user.huypham.vn",
[string]$AdminEmail = "admin@huypham.vn",
[switch]$RemoveOld,
[switch]$SkipCert
)
$ErrorActionPreference = 'Stop'
Import-Module WebAdministration
function Write-Step($msg) { Write-Host "==> $msg" -ForegroundColor Cyan }
function Write-OK($msg) { Write-Host " [OK] $msg" -ForegroundColor Green }
function Write-Warn2($msg){ Write-Host " [!!] $msg" -ForegroundColor Yellow }
# ===================== 1. Pre-flight checks =====================
Write-Step "Pre-flight checks"
$vpsIp = "103.124.94.38"
try {
$vpsIp = (Invoke-WebRequest -Uri "https://api.ipify.org" -UseBasicParsing -TimeoutSec 5).Content.Trim()
} catch {
Write-Warn2 "Cannot detect public IP via ipify - fallback to hardcoded $vpsIp"
}
Write-Host " VPS public IP: $vpsIp"
foreach ($d in @($NewApi, $NewAdmin, $NewUser)) {
try {
$resolved = (Resolve-DnsName -Name $d -Type A -ErrorAction Stop | Select-Object -First 1).IPAddress
if ($resolved -eq $vpsIp) {
Write-OK "DNS $d = $resolved"
} else {
Write-Warn2 "DNS $d = $resolved (not matching VPS IP $vpsIp) - Let's Encrypt may fail"
}
} catch {
Write-Warn2 "DNS resolve FAIL for $d"
exit 1
}
}
$siteMap = @(
@{ Site = "SolutionErp-Api"; Old = $OldApi; New = $NewApi },
@{ Site = "SolutionErp-Admin"; Old = $OldAdmin; New = $NewAdmin },
@{ Site = "SolutionErp-User"; Old = $OldUser; New = $NewUser }
)
foreach ($s in $siteMap) {
if (-not (Test-Path "IIS:\Sites\$($s.Site)")) {
Write-Error "Site '$($s.Site)' not found. Run setup-iis-sites.ps1 first."
exit 1
}
Write-OK "IIS site $($s.Site) ready"
}
# ===================== 2. Add new bindings (keep old) =====================
Write-Step "Add HTTP binding for 3 new domains"
foreach ($s in $siteMap) {
$site = $s.Site
$new = $s.New
$existingHttp = Get-WebBinding -Name $site -Protocol http -HostHeader $new -ErrorAction SilentlyContinue
if (-not $existingHttp) {
New-WebBinding -Name $site -IPAddress "*" -Port 80 -HostHeader $new -Protocol http | Out-Null
Write-OK "Add HTTP binding: $site *:80:$new"
} else {
Write-Host " HTTP binding exists: $site *:80:$new"
}
}
# ===================== 3. Request cert via win-acme =====================
if (-not $SkipCert) {
Write-Step "Request Let's Encrypt cert for 3 new domains"
$WacsExe = "C:\Program Files\win-acme\wacs.exe"
if (-not (Test-Path $WacsExe)) {
Write-Error "win-acme not installed. Run setup-ssl.ps1 first, or use -SkipCert."
exit 1
}
foreach ($s in $siteMap) {
Write-Host ""
Write-Host "==> Cert for $($s.New)" -ForegroundColor Cyan
$siteId = (Get-Website $s.Site).Id
$wacsArgs = @(
"--target", "manual",
"--host", $s.New,
"--store", "certificatestore",
"--installation", "iis",
"--installationsiteid", $siteId,
"--accepttos",
"--emailaddress", $AdminEmail
)
& $WacsExe @wacsArgs
if ($LASTEXITCODE -ne 0) {
Write-Warn2 "Cert $($s.New) FAIL exit $LASTEXITCODE - check:"
Write-Warn2 " 1. Port 80 internet -> VPS open?"
Write-Warn2 " 2. DNS $($s.New) -> $vpsIp?"
Write-Warn2 " 3. HTTP binding created?"
} else {
Write-OK "Cert $($s.New) installed (HTTPS binding + http->https)"
}
}
} else {
Write-Host "==> SkipCert flag - bypass win-acme" -ForegroundColor Yellow
}
# ===================== 4. Verify new endpoints =====================
Write-Step "Verify new endpoints"
Start-Sleep -Seconds 3
function Test-Endpoint($url) {
try {
$r = Invoke-WebRequest -Uri $url -UseBasicParsing -TimeoutSec 10 -SkipCertificateCheck
if ($r.StatusCode -eq 200) { Write-OK "$url = 200 OK"; return $true }
Write-Warn2 "$url = $($r.StatusCode) (expected 200)"; return $false
} catch {
Write-Warn2 "$url FAIL"
return $false
}
}
$apiLive = Test-Endpoint "https://$NewApi/health/live"
$apiReady = Test-Endpoint "https://$NewApi/health/ready"
$adminOk = Test-Endpoint "https://$NewAdmin"
$userOk = Test-Endpoint "https://$NewUser"
$allOk = $apiLive -and $apiReady -and $adminOk -and $userOk
# ===================== 5. Remove old bindings (optional) =====================
if ($RemoveOld) {
if (-not $allOk) {
Write-Warn2 "New endpoints not verified OK - skip removing old (keep fallback)"
} else {
Write-Step "Remove old bindings (huypham.vn)"
foreach ($s in $siteMap) {
$site = $s.Site
$old = $s.Old
$httpOld = Get-WebBinding -Name $site -Protocol http -HostHeader $old -ErrorAction SilentlyContinue
if ($httpOld) {
Remove-WebBinding -Name $site -Protocol http -HostHeader $old -Port 80
Write-OK "Removed HTTP *:80:$old from $site"
}
$httpsOld = Get-WebBinding -Name $site -Protocol https -HostHeader $old -ErrorAction SilentlyContinue
if ($httpsOld) {
Remove-WebBinding -Name $site -Protocol https -HostHeader $old -Port 443
Write-OK "Removed HTTPS *:443:$old from $site"
}
}
}
} else {
Write-Host ""
Write-Host "[INFO] Old bindings (*.huypham.vn) still active. Run with -RemoveOld after verify." -ForegroundColor Yellow
}
# ===================== 6. Summary =====================
Write-Host ""
Write-Host ("=" * 70) -ForegroundColor Cyan
Write-Host " MIGRATION DONE" -ForegroundColor Cyan
Write-Host ("=" * 70) -ForegroundColor Cyan
Write-Host ""
Write-Host "3 new domains:"
$statusApi = if ($apiLive) { "[OK]" } else { "[FAIL]" }
$statusReady = if ($apiReady) { "[OK]" } else { "[FAIL]" }
$statusAdmin = if ($adminOk) { "[OK]" } else { "[FAIL]" }
$statusUser = if ($userOk) { "[OK]" } else { "[FAIL]" }
Write-Host " - https://$NewApi/health/live $statusApi"
Write-Host " - https://$NewApi/health/ready $statusReady"
Write-Host " - https://$NewAdmin $statusAdmin"
Write-Host " - https://$NewUser $statusUser"
Write-Host ""
Write-Host "Next:"
Write-Host " 1. Trigger CI/CD redeploy (push empty commit)"
Write-Host " - BE rebuild with new CORS"
Write-Host " - FE rebuild with VITE_API_BASE_URL=https://$NewApi"
Write-Host " 2. Test login via browser"
Write-Host " 3. After 1-2 days verify stable: .\migrate-domains.ps1 -RemoveOld -SkipCert"
Write-Host ""
if (-not $allOk) {
Write-Warn2 "Some endpoints failed - check Event Log and IIS log before proceed."
exit 1
}