# Cài HTTPS cert Let's Encrypt cho 3 domain SOLUTION_ERP qua win-acme (WACS). # Chạy trên VPS Windows Server với admin privilege. # Idempotent: chạy lại sẽ bỏ qua cert còn valid. # # Usage: # .\setup-ssl.ps1 # # Prereq: # - IIS sites đã tạo (chạy setup-iis-sites.ps1 trước) # - Port 80 từ Internet → VPS mở (Let's Encrypt HTTP-01 challenge) # - 3 domain api/admin/user.huypham.vn đã trỏ DNS về VPS IP # # Output: # - 3 cert trong Windows Cert Store (LocalMachine\My) # - HTTPS binding port 443 cho 3 site # - Scheduled task auto-renew (90 day cycle Let's Encrypt, win-acme tự renew khi còn 30 ngày) $ErrorActionPreference = 'Stop' $WacsDir = "C:\Program Files\win-acme" $WacsExe = Join-Path $WacsDir "wacs.exe" # ===================== 1. Download + install win-acme ===================== if (-not (Test-Path $WacsExe)) { Write-Host "==> Download win-acme (WACS)..." -ForegroundColor Cyan $url = "https://github.com/win-acme/win-acme/releases/download/v2.2.9.1701/win-acme.v2.2.9.1701.x64.trimmed.zip" $zip = "$env:TEMP\wacs.zip" Invoke-WebRequest -Uri $url -OutFile $zip -UseBasicParsing if (-not (Test-Path $WacsDir)) { New-Item -ItemType Directory -Force -Path $WacsDir | Out-Null } Expand-Archive -Path $zip -DestinationPath $WacsDir -Force Remove-Item $zip Write-Host " Installed to $WacsDir" } else { Write-Host "==> win-acme đã cài tại $WacsDir" } # ===================== 2. Check IIS sites exist ===================== Import-Module WebAdministration $domains = @( @{ Site = "SolutionErp-Api"; Host = "api.huypham.vn" }, @{ Site = "SolutionErp-Admin"; Host = "admin.huypham.vn" }, @{ Site = "SolutionErp-User"; Host = "user.huypham.vn" } ) foreach ($d in $domains) { if (-not (Test-Path "IIS:\Sites\$($d.Site)")) { Write-Error "Site '$($d.Site)' chưa tồn tại. Chạy setup-iis-sites.ps1 trước." exit 1 } } Write-Host " 3 IIS site đã ready" # ===================== 3. Run win-acme cho từng domain ===================== foreach ($d in $domains) { Write-Host "`n==> Issue cert cho $($d.Host)" -ForegroundColor Cyan # win-acme CLI non-interactive: # --target iis → lấy hostname từ IIS binding # --host → domain cụ thể # --installation iis → auto bind HTTPS 443 + http→https redirect # --accepttos → auto chấp nhận Let's Encrypt terms # --emailaddress → email contact nhận alert expiry (đổi cho phù hợp) $args = @( "--target", "manual", "--host", $d.Host, "--siteid", (Get-Website $d.Site).Id, "--store", "certificatestore", "--installation", "iis", "--accepttos", "--emailaddress", "admin@huypham.vn" ) & $WacsExe @args if ($LASTEXITCODE -ne 0) { Write-Warning "Issue cert cho $($d.Host) FAIL exit $LASTEXITCODE — kiểm tra:" Write-Warning " 1. Port 80 Internet → VPS mở (Let's Encrypt reach qua HTTP-01)?" Write-Warning " 2. DNS $($d.Host) → $((Resolve-DnsName $d.Host -Type A -ErrorAction SilentlyContinue).IPAddress)?" Write-Warning " 3. IIS site $($d.Site) binding port 80 có host header $($d.Host)?" } else { Write-Host " ✅ Cert installed" } } # ===================== 4. HTTP → HTTPS redirect rule ===================== Write-Host "`n==> Setup HTTP → HTTPS redirect (URL Rewrite)" -ForegroundColor Cyan $redirectConfig = @' '@ # win-acme --installation iis đã tự add redirect rule khi binding xong — skip manual. Write-Host " (win-acme tự setup redirect)" # ===================== 5. Verify scheduled task ===================== Write-Host "`n==> Verify scheduled task auto-renew" $task = Get-ScheduledTask -TaskName "win-acme renew (acme-v02.api.letsencrypt.org)" -ErrorAction SilentlyContinue if ($task) { Write-Host " ✅ Task '$($task.TaskName)' exists — auto renew 9h daily" } else { Write-Warning " Task chưa tạo — chạy tay: $WacsExe --renew --baseuri https://acme-v02.api.letsencrypt.org/" } Write-Host "`n✅ SSL setup DONE" -ForegroundColor Green Write-Host " Test: openssl s_client -connect api.huypham.vn:443 < /dev/null | openssl x509 -noout -subject -dates" Write-Host " hoặc browser: https://api.huypham.vn/health/live"