All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m52s
User request: anh trỏ 3 subdomain mới về VPS IP 103.124.94.38:
- api.huypham.vn → api.solutions.com.vn
- admin.huypham.vn → admin.solutions.com.vn
- user.huypham.vn → eoffice.solutions.com.vn
Verified DNS: cả 3 resolve 103.124.94.38 ✓
Update 17 file repo:
FE (4): fe-admin/.env.production + fe-user/.env.production
(VITE_API_BASE_URL → https://api.solutions.com.vn)
fe-admin/src/lib/{api,realtime}.ts + fe-user equivalents (comment)
BE (1): appsettings.Production.json.example — CORS AllowedOrigins
CI/CD (1): .gitea/workflows/deploy.yml — smoke test URL
Scripts (3): setup-iis-sites (DomainApi/Admin/User), setup-ssl (3 host),
deploy-all (verify curls)
Docs (5): STATUS, HANDOFF, PROJECT-MAP, vps-setup, gotchas
Skill (1): iis-deploy-runbook — 3 site table + description
Email admin@huypham.vn giữ nguyên (Let's Encrypt contact — không phải
domain serve).
Thêm scripts/migrate-domains.ps1 — 1-shot VPS migration:
1. Pre-flight: resolve DNS 3 domain → verify IP VPS khớp
2. Add HTTP binding mới cho 3 IIS site (giữ binding cũ làm fallback)
3. Run win-acme xin 3 cert Let's Encrypt qua HTTP-01 challenge
(auto add HTTPS binding + http→https redirect)
4. Verify /health/live + /health/ready + 2 FE endpoint
5. (Optional -RemoveOld) xóa binding huypham.vn sau verify OK
Rollback: nếu fail, binding cũ vẫn active → site serve qua huypham.vn.
Anh chạy trên VPS:
cd C:\solution-erp\scripts ; .\migrate-domains.ps1
# Sau 1-2 ngày verify stable:
.\migrate-domains.ps1 -RemoveOld -SkipCert
150 lines
6.2 KiB
Markdown
150 lines
6.2 KiB
Markdown
# VPS Setup — Master Runbook
|
|
|
|
> Step-by-step deploy SOLUTION_ERP lên VPS Windows Server shared với VIETREPORT.
|
|
> VPS: `103.124.94.38` (cùng chỗ với Gitea, SQL, IIS).
|
|
|
|
## 0. Context
|
|
|
|
- **VPS OS:** Windows Server (có IIS + SQL Server)
|
|
- **Shared với:** VIETREPORT project — naming isolation bắt buộc
|
|
- **DNS đã trỏ:** `api.solutions.com.vn`, `admin.solutions.com.vn`, `eoffice.solutions.com.vn`, `git.baocaogiaoduc.vn` → `103.124.94.38`
|
|
- **Prefix resources:** `SolutionErp-*` (app pool, site), `SolutionErp` (DB), `C:\inetpub\solution-erp\` (path)
|
|
|
|
## 1. Prerequisites trên VPS (đã có sẵn với VIETREPORT)
|
|
|
|
- [x] Windows Server 2019/2022
|
|
- [x] IIS + URL Rewrite + Application Initialization (VIETREPORT đã dùng)
|
|
- [x] SQL Server với login `sa` + `vrapp` (shared app user)
|
|
- [x] Gitea tại `git.baocaogiaoduc.vn`
|
|
- [x] Port 80/443 firewall open
|
|
|
|
Cần **verify trên VPS**:
|
|
- [ ] .NET 10 Hosting Bundle cài chưa? Check: `dotnet --list-runtimes | grep 'Microsoft.AspNetCore.App 10'`
|
|
- [ ] Nếu chưa → tải từ https://dotnet.microsoft.com/en-us/download/dotnet/10.0 → "Hosting Bundle"
|
|
- [ ] Sau cài → `iisreset`
|
|
|
|
## 2. Run setup scripts trên VPS
|
|
|
|
Copy folder `scripts/` từ repo lên VPS (vd `C:\solution-erp\scripts\`):
|
|
|
|
```powershell
|
|
# 1. SQL DB + grant vrapp
|
|
cd C:\solution-erp\scripts
|
|
.\setup-sql-db.ps1 -SaPassword '<SA_PASSWORD_FROM_SECRETS_VAULT>'
|
|
|
|
# 2. IIS sites + app pool
|
|
.\setup-iis-sites.ps1
|
|
# → Tạo SolutionErp-Api pool + 3 site (SolutionErp-Api/Admin/User)
|
|
# → C:\inetpub\solution-erp\{api,fe-admin,fe-user,logs,uploads}
|
|
|
|
# 3. HTTPS cert (win-acme, Let's Encrypt)
|
|
.\setup-ssl.ps1
|
|
# → Issue cert cho 3 domain + auto-renew scheduled task
|
|
|
|
# 4. Gitea runner (registration token lấy từ Gitea admin settings)
|
|
.\setup-gitea-runner.ps1 -RegistrationToken '<token>'
|
|
```
|
|
|
|
## 3. Set Gitea Actions secrets
|
|
|
|
Vào https://git.baocaogiaoduc.vn/vietreport-admin/solution-erp/settings/actions/secrets — 5 secret:
|
|
|
|
| Name | Value | Ghi chú |
|
|
|---|---|---|
|
|
| `IIS_HOST` | `103.124.94.38` | ✅ đã set |
|
|
| `IIS_USER` | `Administrator` | ✅ đã set (hoặc username Windows khác) |
|
|
| `IIS_PASSWORD` | _(Windows admin password)_ | ⚠️ user set tay — token/secret chat không commit |
|
|
| `JWT_SECRET` | _(64 chars từ `vps-jwt-key.txt`)_ | ⚠️ cần update — placeholder hiện tại |
|
|
| `DB_CONNECTION` | `Server=localhost;Database=SolutionErp;User Id=vrapp;Password=...` | ✅ đã set với vrapp password |
|
|
|
|
## 4. First deploy
|
|
|
|
```powershell
|
|
# Trên máy dev — push main trigger workflow
|
|
git push origin main
|
|
|
|
# Trên Gitea:
|
|
# https://git.baocaogiaoduc.vn/vietreport-admin/solution-erp/actions
|
|
# → 1 run đang chạy (build BE + 2 FE + deploy)
|
|
```
|
|
|
|
## 5. Set `appsettings.Production.json` trên VPS
|
|
|
|
```powershell
|
|
cd C:\inetpub\solution-erp\api
|
|
# Copy từ template
|
|
cp appsettings.Production.json.example appsettings.Production.json
|
|
|
|
# Edit thay placeholder:
|
|
# - ConnectionStrings.Default → Password=<vrapp password>
|
|
# - Jwt.Secret → <64 chars từ vps-jwt-key.txt>
|
|
```
|
|
|
|
Hoặc dùng user-secrets (safer — không file trên disk):
|
|
|
|
```powershell
|
|
cd C:\inetpub\solution-erp\api
|
|
dotnet user-secrets set "Jwt:Secret" "<64-char-from-file>"
|
|
dotnet user-secrets set "ConnectionStrings:Default" "Server=localhost;Database=SolutionErp;User Id=vrapp;Password=...;..."
|
|
```
|
|
|
|
## 6. Smoke test sau deploy
|
|
|
|
```bash
|
|
# Health check
|
|
curl https://api.solutions.com.vn/health/live # → Healthy
|
|
curl https://api.solutions.com.vn/health/ready # → Healthy (DB probe)
|
|
|
|
# Login
|
|
curl -X POST https://api.solutions.com.vn/api/auth/login \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"email":"admin@solutionerp.local","password":"Admin@123456"}'
|
|
# → accessToken JWT
|
|
|
|
# FE
|
|
open https://admin.solutions.com.vn # fe-admin login page
|
|
open https://eoffice.solutions.com.vn # fe-user login page
|
|
|
|
# SSL grade
|
|
# https://www.ssllabs.com/ssltest/analyze.html?d=api.solutions.com.vn
|
|
```
|
|
|
|
## 7. Sau go-live (bắt buộc)
|
|
|
|
- [ ] **Đổi password admin** từ `Admin@123456` → mạnh. Warning log xuất hiện khi còn dùng default.
|
|
- [ ] **Rotate secrets** đã post trong chat (SA, vrapp, Gitea token, JWT) — tất cả đã vượt khỏi VPS, cần đổi mới
|
|
- [ ] **Backup SQL** daily schedule: `schtasks /Create /TN 'SolutionErp SQL Backup' /TR 'powershell -File C:\solution-erp\scripts\backup-sql.ps1 -SaPassword <pw>' /SC DAILY /ST 02:00 /RU SYSTEM`
|
|
- [ ] **Disable Swagger prod**: Program.cs đã có `if (IsDevelopment())` — verify URL `https://api.solutions.com.vn/swagger` → 404
|
|
- [ ] **Monitor**: kiểm `C:\inetpub\solution-erp\logs\` ngày đầu, watch for ERR
|
|
|
|
## 8. Co-existence với VIETREPORT — checklist
|
|
|
|
| Resource | SOLUTION_ERP | VIETREPORT | Conflict? |
|
|
|---|---|---|---|
|
|
| App pool name | `SolutionErp-Api` | `VietReport-*` (assumed) | ❌ |
|
|
| Site name | `SolutionErp-Api/Admin/User` | `VietReport-*` | ❌ |
|
|
| Path | `C:\inetpub\solution-erp\` | `C:\inetpub\vietreport\` (assumed) | ❌ |
|
|
| SQL DB | `SolutionErp` | `VietReport` (assumed) | ❌ |
|
|
| SQL user | `vrapp` (shared db_owner) | `vrapp` | ✅ Shared — OK (cùng login, khác DB) |
|
|
| Port 80/443 | Host header routing | Host header routing | ✅ IIS cho phép share qua Host header |
|
|
| Firewall rule | `HTTP In (SolutionErp)` | `HTTP In (VietReport)` | ❌ |
|
|
| Gitea runner | `vps-win-*` labels `windows-latest` | shared | ✅ Runner serve multi repo qua labels |
|
|
|
|
## 9. Troubleshooting
|
|
|
|
Xem [`runbook.md`](runbook.md) cho operations hàng ngày + [`deployment-iis.md`](deployment-iis.md) cho troubleshoot chi tiết.
|
|
|
|
Common issues khi co-exist:
|
|
- **Port 80 conflict** — check `netstat -ano | findstr :80` → kill service ngoài IIS
|
|
- **IIS default site block new site** — disable "Default Web Site" hoặc đổi binding
|
|
- **win-acme fail HTTP-01** — port 80 phải reachable từ Internet (không local firewall block)
|
|
- **SQL user vrapp không có quyền DB SolutionErp** — script `setup-sql-db.ps1` đã handle, re-run nếu skip
|
|
|
|
## 10. Liên quan
|
|
|
|
- [`deployment-iis.md`](deployment-iis.md) — IIS setup chi tiết
|
|
- [`cicd.md`](cicd.md) — Gitea Actions
|
|
- [`security-checklist.md`](security-checklist.md) — pre go-live
|
|
- [`runbook.md`](runbook.md) — operations
|
|
- `scripts/setup-*.ps1` — automation scripts
|