[CLAUDE] Skill · Docs: fix iis-deploy-runbook stale paths + S88 web.config closeout
iis-deploy-runbook SKILL corrected (discovered during the index.html-hardening task):
- physical paths apps\SolutionErp\{Api,Admin,User} were STALE (empty dir) -> real
solution-erp\{api,fe-admin,fe-user} (verified via appcmd list site).
- web.config rule list fixed to the ACTUAL live config (HTTP->HTTPS + SPA-Routes excl
/api + .webmanifest + 3 security headers; NO /api|/hubs ARR proxy -- FE calls api via CORS)
+ documented the S88 cache hardening (index.html no-cache, assets immutable).
- log/appsettings/scp/backup paths swept to the real base.
Session log: index.html no-cache hardening DONE (ca136d8) + lesson reference.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -46,15 +46,17 @@ Internet
|
||||
|
||||
| Site | Binding | Physical path | Apool | Purpose |
|
||||
|---|---|---|---|---|
|
||||
| `SolutionErp-Api` | `*:443:api.solutions.com.vn` HTTPS | `C:\inetpub\apps\SolutionErp\Api\` | out-of-process Kestrel | ASP.NET Core 10 API (port 5443 internal) |
|
||||
| `SolutionErp-Admin` | `*:443:admin.solutions.com.vn` HTTPS + `*:80` redirect | `C:\inetpub\apps\SolutionErp\Admin\` | static (no app pool .NET) | React build fe-admin |
|
||||
| `SolutionErp-User` | `*:443:eoffice.solutions.com.vn` HTTPS + `*:80` redirect | `C:\inetpub\apps\SolutionErp\User\` | static | React build fe-user |
|
||||
| `SolutionErp-Api` | `*:443:api.solutions.com.vn` (+`api.huypham.vn`) HTTPS | `C:\inetpub\solution-erp\api\` | out-of-process Kestrel | ASP.NET Core 10 API (port 5443 internal) |
|
||||
| `SolutionErp-Admin` | `*:443:admin.solutions.com.vn` (+`admin.huypham.vn`) HTTPS + `*:80` redirect | `C:\inetpub\solution-erp\fe-admin\` | static (no app pool .NET) | React build fe-admin |
|
||||
| `SolutionErp-User` | `*:443:eoffice.solutions.com.vn` HTTPS + `*:80` redirect | `C:\inetpub\solution-erp\fe-user\` | static | React build fe-user |
|
||||
|
||||
**SPA web.config:** 2 FE có `URL Rewrite` rule:
|
||||
1. HTTP → HTTPS redirect (bắt buộc, CORS whitelist chỉ https)
|
||||
2. `/api/* → http://127.0.0.1:5443/api/*` (ARR reverse proxy)
|
||||
3. `/hubs/* → http://127.0.0.1:5443/hubs/*` (SignalR)
|
||||
4. React Router fallback: `/*` → `/index.html`
|
||||
> ⚠️ **Physical paths verified via `appcmd list site` S88** — runbook trước ghi `C:\inetpub\apps\SolutionErp\{Api,Admin,User}` (STALE, dir rỗng). Đường THẬT = `C:\inetpub\solution-erp\{api,fe-admin,fe-user}`.
|
||||
|
||||
**SPA web.config** (`{fe-admin,fe-user}/public/web.config`, **version-controlled S88** — Vite copy `public/*`→`dist/`→deploy `Copy-Item -Force`; `deploy.yml` cũ `Remove-Item …\* -Exclude web.config` = trước S88 file manage-tay trên server). Rule THẬT (đọc live S88):
|
||||
1. **HTTP → HTTPS** redirect (`{HTTPS} ^OFF$`, Permanent; CORS whitelist chỉ https). KHÔNG có `.well-known` exclude (win-acme validation khác).
|
||||
2. **SPA Routes** fallback: non-file/non-dir/non-`^/api` → rewrite `/` (index.html). *(KHÔNG có `/api` hay `/hubs` ARR proxy — FE gọi thẳng `https://api.solutions.com.vn` qua CORS.)*
|
||||
3. `.webmanifest` mime + 3 security header (X-Content-Type-Options / X-Frame-Options DENY / Referrer-Policy).
|
||||
4. **[S88 hardening] Cache:** root `<clientCache cacheControlMode="DisableCache">` → `index.html` (+ SPA-rewrite shell `/dashboard`…) = `Cache-Control: no-cache` (luôn revalidate → chống stale-shell-after-deploy = white-screen S88) · `<location path="assets"><clientCache UseMaxAge 365d + cacheControlCustom="public, immutable">` → hashed asset `immutable, max-age=1y`. **Verify:** `curl -I https://eoffice.solutions.com.vn/` → `no-cache`; `curl -I .../assets/index-*.js` → `immutable`; `/dashboard` → 200 (routing intact).
|
||||
|
||||
## Quick commands
|
||||
|
||||
@ -77,13 +79,13 @@ Get-Website -Name "SolutionErp-*" | Format-Table Name, State, Bindings
|
||||
|
||||
```powershell
|
||||
# Serilog file rolling daily
|
||||
Get-Content "C:\inetpub\apps\SolutionErp\Api\Logs\log-$(Get-Date -Format 'yyyyMMdd').txt" -Tail 50
|
||||
Get-Content "C:\inetpub\solution-erp\api\Logs\log-$(Get-Date -Format 'yyyyMMdd').txt" -Tail 50
|
||||
|
||||
# IIS log
|
||||
Get-Content "C:\inetpub\logs\LogFiles\W3SVC<ID>\u_ex$(Get-Date -Format 'yyMMdd').log" -Tail 30
|
||||
|
||||
# Stdout log khi crash startup
|
||||
Get-Content "C:\inetpub\apps\SolutionErp\Api\Logs\stdout_*.log" -Tail 30
|
||||
Get-Content "C:\inetpub\solution-erp\api\Logs\stdout_*.log" -Tail 30
|
||||
```
|
||||
|
||||
### Health check
|
||||
@ -258,7 +260,7 @@ sqlcmd -S .\SQLEXPRESS -U vrapp -P <pw> -Q "SELECT DB_NAME()"
|
||||
# Expect: SolutionErp
|
||||
|
||||
# 4. appsettings connection string (qua Gitea secrets)
|
||||
# Check C:\inetpub\apps\SolutionErp\Api\appsettings.Production.json có ConnectionStrings:DefaultConnection
|
||||
# Check C:\inetpub\solution-erp\api\appsettings.Production.json có ConnectionStrings:DefaultConnection
|
||||
```
|
||||
|
||||
## Deploy steps (CI/CD xanh)
|
||||
@ -275,7 +277,7 @@ Push to main
|
||||
→ npm run build (fe-admin + fe-user)
|
||||
→ render appsettings.Production.json từ secrets (JWT_SECRET, DB_CONNECTION)
|
||||
→ stop app pool SolutionErp-Api
|
||||
→ xcopy publish → C:\inetpub\apps\SolutionErp\{Api,Admin,User}
|
||||
→ Copy-Item publish/dist → C:\inetpub\solution-erp\{api,fe-admin,fe-user} (Remove-Item -Exclude web.config first)
|
||||
→ start app pool
|
||||
→ curl /health/ready → must be 200 trong 30s
|
||||
→ report status
|
||||
@ -290,9 +292,9 @@ cd fe-admin; npm ci; npm run build; cd ..
|
||||
cd fe-user; npm ci; npm run build; cd ..
|
||||
|
||||
# Scp sang server (cần plink/pscp hoặc rsync)
|
||||
scp -r .\publish\api\* user@server:C:/inetpub/apps/SolutionErp/Api/
|
||||
scp -r .\fe-admin\dist\* user@server:C:/inetpub/apps/SolutionErp/Admin/
|
||||
scp -r .\fe-user\dist\* user@server:C:/inetpub/apps/SolutionErp/User/
|
||||
scp -r .\publish\api\* user@server:C:/inetpub/solution-erp/api/
|
||||
scp -r .\fe-admin\dist\* user@server:C:/inetpub/solution-erp/fe-admin/
|
||||
scp -r .\fe-user\dist\* user@server:C:/inetpub/solution-erp/fe-user/
|
||||
|
||||
# Trên server:
|
||||
Restart-WebAppPool -Name "SolutionErp-Api"
|
||||
@ -303,12 +305,12 @@ curl http://127.0.0.1:5443/health/ready
|
||||
|
||||
```powershell
|
||||
# DB backup (script sẵn, chưa schedule):
|
||||
& "C:\inetpub\apps\SolutionErp\scripts\backup-sql.ps1"
|
||||
& "C:\inetpub\solution-erp\scripts\backup-sql.ps1"
|
||||
# Output: backup/SolutionErp_<ts>.bak (compressed + retention 30d)
|
||||
|
||||
# Schedule daily 03:00:
|
||||
schtasks /create /tn "SolutionErp Backup" `
|
||||
/tr "powershell -ExecutionPolicy Bypass -File C:\inetpub\apps\SolutionErp\scripts\backup-sql.ps1" `
|
||||
/tr "powershell -ExecutionPolicy Bypass -File C:\inetpub\solution-erp\scripts\backup-sql.ps1" `
|
||||
/sc DAILY /st 03:00 /ru SYSTEM
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user