# 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 '' # 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 '' ``` ## 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= # - 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 ' /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