fix: IIS sub-application deployment for production
Fixes 3 critical issues preventing production deployment on Windows IIS: 1. **IIS Sub-Application Path Stripping** - Changed URL patterns from ^roa2web/api/(.*) to ^api/(.*) - IIS sub-app at /roa2web automatically strips prefix - Requests arrive as /api/* not /roa2web/api/* 2. **SPA Fallback Absolute Path** - Changed from url="/index.html" to url="index.html" - Absolute paths (/) refer to site root, not sub-app - Relative path correctly serves from sub-app 3. **MIME Type Duplicates (500 Error)** - Added <remove> before <mimeMap> for .js, .json, .webmanifest - Prevents "duplicate collection entry" errors - Allows override of server-level MIME types Build Script Improvements: - Build-ROA2WEB.ps1: Copy public/ folder to temp build dir - Build-ROA2WEB.ps1: Added verification logging for web.config - ROA2WEB-Console.ps1: Fixed web.config verification location Cleanup: - Removed outdated web.config.10.0.20.36-INTERNAL - Removed temporary test files and docs Tested: https://roa2web.romfast.ro/roa2web/ - login page loads successfully 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,378 +0,0 @@
|
|||||||
# ROA2WEB Production Deployment Issue - Diagnostic Report
|
|
||||||
|
|
||||||
**Date**: 2025-12-30
|
|
||||||
**Environment**: Windows Production (roa2web.romfast.ro)
|
|
||||||
**Issue**: 404 errors on API calls after deployment
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
Frontend loads successfully but all API calls return **404 Not Found** errors:
|
|
||||||
- `POST /roa2web/api/auth/login` → 404
|
|
||||||
- `GET /roa2web/api/companies` → 404
|
|
||||||
|
|
||||||
Browser console shows:
|
|
||||||
```
|
|
||||||
POST https://roa2web.romfast.ro/roa2web/api/auth/login 404 (Not Found)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Architecture Overview
|
|
||||||
|
|
||||||
**2-Tier IIS Deployment**:
|
|
||||||
|
|
||||||
```
|
|
||||||
Internet → Public IIS (10.0.20.122 - roa2web.romfast.ro)
|
|
||||||
↓ HTTPS reverse proxy
|
|
||||||
Internal IIS (10.0.20.36 - application server)
|
|
||||||
↓ API proxy to localhost
|
|
||||||
Backend Service (localhost:8000 on 10.0.20.36)
|
|
||||||
↓
|
|
||||||
Oracle Database
|
|
||||||
```
|
|
||||||
|
|
||||||
### Verified Components
|
|
||||||
|
|
||||||
✅ **Public IIS** (10.0.20.122 - roa2web.romfast.ro):
|
|
||||||
- ✅ web.config correctly proxies all requests to `https://10.0.20.36/{R:1}`
|
|
||||||
- ✅ Forwards headers: `X-Forwarded-Proto`, `X-Forwarded-Host`, `X-Real-IP`
|
|
||||||
- ✅ Configuration verified - THIS SERVER IS CORRECT
|
|
||||||
|
|
||||||
✅ **Frontend** (10.0.20.36):
|
|
||||||
- Built with `base: '/roa2web/'` (correct for IIS sub-application)
|
|
||||||
- API calls use `baseURL: '/roa2web/api'` (correct)
|
|
||||||
- Static files load successfully
|
|
||||||
|
|
||||||
❌ **Internal IIS** (10.0.20.36) - **PROBLEMA ESTE AICI**:
|
|
||||||
- **CRITICAL**: web.config lipsește SAU nu este configurat corect
|
|
||||||
- **MUST**: Trebuie să facă proxy de la `/roa2web/api/*` către `http://localhost:8000/api/*`
|
|
||||||
- **Location**: `C:\inetpub\wwwroot\roa2web\web.config` (pe serverul 10.0.20.36)
|
|
||||||
|
|
||||||
❓ **Backend Service** (pe 10.0.20.36):
|
|
||||||
- **UNKNOWN**: Need to verify service is running
|
|
||||||
- Should be accessible at `http://localhost:8000/health` (de pe 10.0.20.36)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Root Cause Analysis
|
|
||||||
|
|
||||||
Based on Playwright testing, the issue is most likely:
|
|
||||||
|
|
||||||
### Primary Suspect: Internal Server web.config
|
|
||||||
|
|
||||||
The internal server's web.config **MUST** handle the `/roa2web/` prefix correctly.
|
|
||||||
|
|
||||||
**WRONG Configuration** (causes 404):
|
|
||||||
```xml
|
|
||||||
<rule name="Proxy Unified API" stopProcessing="true">
|
|
||||||
<match url="^api/(.*)" /> ❌ Missing roa2web prefix!
|
|
||||||
<action type="Rewrite" url="http://localhost:8000/api/{R:1}" />
|
|
||||||
</rule>
|
|
||||||
```
|
|
||||||
|
|
||||||
**CORRECT Configuration**:
|
|
||||||
```xml
|
|
||||||
<rule name="Proxy Unified API" stopProcessing="true">
|
|
||||||
<match url="^roa2web/api/(.*)" /> ✅ Includes roa2web prefix
|
|
||||||
<action type="Rewrite" url="http://localhost:8000/api/{R:1}" />
|
|
||||||
</rule>
|
|
||||||
```
|
|
||||||
|
|
||||||
**Why**: Requests arrive at internal server as `/roa2web/api/auth/login` (NOT `/api/auth/login`), because the public server preserves the full path when proxying.
|
|
||||||
|
|
||||||
### Secondary Suspects
|
|
||||||
|
|
||||||
1. **Backend service not running**
|
|
||||||
- Check: `Get-Service ROA2WEB-Backend`
|
|
||||||
|
|
||||||
2. **IIS ARR not enabled**
|
|
||||||
- Check: `Get-WebConfigurationProperty -PSPath "MACHINE/WEBROOT/APPHOST" -Filter "system.webServer/proxy" -Name "enabled"`
|
|
||||||
|
|
||||||
3. **IIS sub-application misconfigured**
|
|
||||||
- Frontend should be deployed at IIS path `/roa2web`, not root
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Diagnostic Steps
|
|
||||||
|
|
||||||
### Step 1: Check Backend Service (on 10.0.20.36)
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
# Check service status
|
|
||||||
Get-Service ROA2WEB-Backend
|
|
||||||
|
|
||||||
# If stopped, start it
|
|
||||||
Start-Service ROA2WEB-Backend
|
|
||||||
|
|
||||||
# Test backend directly
|
|
||||||
Invoke-WebRequest http://localhost:8000/health
|
|
||||||
```
|
|
||||||
|
|
||||||
**Expected Output**:
|
|
||||||
```json
|
|
||||||
{"status": "healthy", "version": "..."}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 2: Check Internal IIS web.config (on 10.0.20.36)
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
# View current web.config
|
|
||||||
Get-Content C:\inetpub\wwwroot\roa2web\web.config
|
|
||||||
|
|
||||||
# OR if frontend is in subdirectory:
|
|
||||||
Get-Content C:\inetpub\wwwroot\roa2web\frontend\web.config
|
|
||||||
```
|
|
||||||
|
|
||||||
**Verify these rules**:
|
|
||||||
- `<match url="^roa2web/api/(.*)" />` (NOT `^api/(.*)`)
|
|
||||||
- `<match url="^roa2web/uploads/(.*)" />` (NOT `^uploads/(.*)`)
|
|
||||||
- `<match url="^roa2web/.*" />` for SPA fallback
|
|
||||||
|
|
||||||
### Step 3: Check IIS ARR (on 10.0.20.36)
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
# Check if ARR is installed
|
|
||||||
Get-WindowsFeature -Name Web-ARR
|
|
||||||
|
|
||||||
# Check if proxy is enabled
|
|
||||||
Get-WebConfigurationProperty -PSPath "MACHINE/WEBROOT/APPHOST" `
|
|
||||||
-Filter "system.webServer/proxy" `
|
|
||||||
-Name "enabled"
|
|
||||||
```
|
|
||||||
|
|
||||||
**Expected**: `enabled` should be `True`
|
|
||||||
|
|
||||||
### Step 4: Test Internal IIS Proxy (on 10.0.20.36)
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
# Test API endpoint through IIS
|
|
||||||
Invoke-WebRequest https://localhost/roa2web/api/health
|
|
||||||
|
|
||||||
# Should proxy to backend and return response
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 5: Check IIS Application Structure (on 10.0.20.36)
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
# List IIS applications
|
|
||||||
Get-WebApplication -Site "Default Web Site" | Format-Table Path, PhysicalPath
|
|
||||||
|
|
||||||
# Should show:
|
|
||||||
# /roa2web -> C:\inetpub\wwwroot\roa2web\
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Fix Recommendations
|
|
||||||
|
|
||||||
### Fix #1: Update Internal Server web.config
|
|
||||||
|
|
||||||
**Server**: 10.0.20.36 (internal application server)
|
|
||||||
**Location**: `C:\inetpub\wwwroot\roa2web\web.config`
|
|
||||||
|
|
||||||
**IMPORTANT**: Acest web.config este pe serverul 10.0.20.36, NU pe 10.0.20.122!
|
|
||||||
|
|
||||||
**Required Configuration**:
|
|
||||||
|
|
||||||
```xml
|
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<configuration>
|
|
||||||
<system.webServer>
|
|
||||||
<rewrite>
|
|
||||||
<rules>
|
|
||||||
<!-- Proxy API requests to unified backend -->
|
|
||||||
<rule name="Proxy Unified API" stopProcessing="true">
|
|
||||||
<match url="^roa2web/api/(.*)" />
|
|
||||||
<action type="Rewrite" url="http://localhost:8000/api/{R:1}" />
|
|
||||||
</rule>
|
|
||||||
|
|
||||||
<!-- Proxy uploads to unified backend -->
|
|
||||||
<rule name="Proxy Uploads" stopProcessing="true">
|
|
||||||
<match url="^roa2web/uploads/(.*)" />
|
|
||||||
<action type="Rewrite" url="http://localhost:8000/uploads/{R:1}" />
|
|
||||||
</rule>
|
|
||||||
|
|
||||||
<!-- SPA fallback - serve index.html for non-file requests -->
|
|
||||||
<rule name="SPA Fallback" stopProcessing="true">
|
|
||||||
<match url="^roa2web/.*" />
|
|
||||||
<conditions logicalGrouping="MatchAll">
|
|
||||||
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
|
|
||||||
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
|
|
||||||
</conditions>
|
|
||||||
<action type="Rewrite" url="/roa2web/index.html" />
|
|
||||||
</rule>
|
|
||||||
</rules>
|
|
||||||
</rewrite>
|
|
||||||
|
|
||||||
<staticContent>
|
|
||||||
<mimeMap fileExtension=".webmanifest" mimeType="application/manifest+json" />
|
|
||||||
<mimeMap fileExtension=".js" mimeType="application/javascript" />
|
|
||||||
<mimeMap fileExtension=".json" mimeType="application/json" />
|
|
||||||
</staticContent>
|
|
||||||
|
|
||||||
<httpProtocol>
|
|
||||||
<customHeaders>
|
|
||||||
<add name="Cache-Control" value="public, max-age=31536000" />
|
|
||||||
</customHeaders>
|
|
||||||
</httpProtocol>
|
|
||||||
</system.webServer>
|
|
||||||
</configuration>
|
|
||||||
```
|
|
||||||
|
|
||||||
**Deployment**:
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
# ⚠️ IMPORTANT: Rulează aceste comenzi pe serverul 10.0.20.36, NU pe 10.0.20.122!
|
|
||||||
# Conectează-te la 10.0.20.36 (internal application server)
|
|
||||||
|
|
||||||
# Backup current config
|
|
||||||
Copy-Item C:\inetpub\wwwroot\roa2web\web.config `
|
|
||||||
C:\inetpub\wwwroot\roa2web\web.config.backup.$(Get-Date -Format 'yyyyMMdd-HHmmss')
|
|
||||||
|
|
||||||
# Update web.config with corrected version
|
|
||||||
# (copy from repository: public/web.config after updating it)
|
|
||||||
|
|
||||||
# Restart IIS
|
|
||||||
iisreset
|
|
||||||
|
|
||||||
# Test
|
|
||||||
Invoke-WebRequest https://localhost/roa2web/api/health
|
|
||||||
```
|
|
||||||
|
|
||||||
### Fix #2: Ensure Backend Service is Running
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
# On internal server (10.0.20.36)
|
|
||||||
|
|
||||||
# Check service
|
|
||||||
Get-Service ROA2WEB-Backend
|
|
||||||
|
|
||||||
# If stopped
|
|
||||||
Start-Service ROA2WEB-Backend
|
|
||||||
|
|
||||||
# View startup logs
|
|
||||||
Get-Content C:\inetpub\wwwroot\roa2web\logs\backend-stdout.log -Tail 50
|
|
||||||
|
|
||||||
# Check for errors
|
|
||||||
Get-Content C:\inetpub\wwwroot\roa2web\logs\backend-stderr.log -Tail 50
|
|
||||||
```
|
|
||||||
|
|
||||||
### Fix #3: Enable IIS ARR (if not enabled)
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
# On internal server (10.0.20.36)
|
|
||||||
|
|
||||||
# Enable proxy
|
|
||||||
Set-WebConfigurationProperty -PSPath "MACHINE/WEBROOT/APPHOST" `
|
|
||||||
-Filter "system.webServer/proxy" `
|
|
||||||
-Name "enabled" `
|
|
||||||
-Value "True"
|
|
||||||
|
|
||||||
# Restart IIS
|
|
||||||
iisreset
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Verification Steps (After Fix)
|
|
||||||
|
|
||||||
### 1. Backend Health Check (Direct)
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
# On 10.0.20.36
|
|
||||||
Invoke-WebRequest http://localhost:8000/health
|
|
||||||
```
|
|
||||||
|
|
||||||
**Expected**: `200 OK` with JSON response
|
|
||||||
|
|
||||||
### 2. Internal IIS Proxy Test
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
# On 10.0.20.36
|
|
||||||
Invoke-WebRequest https://localhost/roa2web/api/health
|
|
||||||
```
|
|
||||||
|
|
||||||
**Expected**: `200 OK` (proxied from backend)
|
|
||||||
|
|
||||||
### 3. Public Access Test
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
# From any client
|
|
||||||
Invoke-WebRequest https://roa2web.romfast.ro/roa2web/
|
|
||||||
```
|
|
||||||
|
|
||||||
**Expected**: Frontend loads (HTML page)
|
|
||||||
|
|
||||||
### 4. Login Flow Test (Playwright)
|
|
||||||
|
|
||||||
Use Playwright to test complete login flow:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# On development machine
|
|
||||||
cd /mnt/e/proiecte/roa2web
|
|
||||||
npx playwright test --headed --project=chromium tests/login.spec.js
|
|
||||||
```
|
|
||||||
|
|
||||||
**Expected**: Login succeeds without 404 errors
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prevention
|
|
||||||
|
|
||||||
To prevent this issue in future deployments:
|
|
||||||
|
|
||||||
1. **Use Correct web.config Template**
|
|
||||||
- Repository should have separate web.config templates:
|
|
||||||
- `public/web.config` - for internal server (with `/roa2web/` prefix)
|
|
||||||
- `deployment/windows/config/web.config` - same as above
|
|
||||||
|
|
||||||
2. **Automated Deployment Script**
|
|
||||||
- PowerShell script should validate web.config before deployment
|
|
||||||
- Check for required URL patterns: `^roa2web/api/`, `^roa2web/uploads/`
|
|
||||||
|
|
||||||
3. **Deployment Checklist**
|
|
||||||
- Add to `deployment/windows/docs/DEPLOYMENT-CHECKLIST.md`:
|
|
||||||
- [ ] Verify web.config includes `/roa2web/` prefix in match rules
|
|
||||||
- [ ] Test backend: `Invoke-WebRequest http://localhost:8000/health`
|
|
||||||
- [ ] Test IIS proxy: `Invoke-WebRequest https://localhost/roa2web/api/health`
|
|
||||||
- [ ] Test public access: `Invoke-WebRequest https://roa2web.romfast.ro/roa2web/`
|
|
||||||
|
|
||||||
4. **Monitoring**
|
|
||||||
- Add health check endpoint monitoring
|
|
||||||
- Alert if backend service stops
|
|
||||||
- Monitor IIS logs for 404/502 errors
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Next Steps
|
|
||||||
|
|
||||||
1. ✅ **Immediate**: Check internal server web.config (on 10.0.20.36)
|
|
||||||
2. ✅ **Immediate**: Verify backend service is running
|
|
||||||
3. ✅ **Immediate**: Apply Fix #1 if web.config is incorrect
|
|
||||||
4. ⏭️ **After Fix**: Run verification steps
|
|
||||||
5. ⏭️ **After Fix**: Update repository web.config template
|
|
||||||
6. ⏭️ **Future**: Add automated deployment validation
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Documentation Created
|
|
||||||
|
|
||||||
- ✅ `deployment/windows/docs/TWO-TIER-IIS-DEPLOYMENT.md` - Complete 2-tier architecture guide
|
|
||||||
- ✅ Updated `CLAUDE.md` with deployment documentation reference
|
|
||||||
- ✅ This diagnostic report: `DIAGNOSIS-2025-12-30.md`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Contact Information
|
|
||||||
|
|
||||||
**Issue Reported By**: User via Playwright testing
|
|
||||||
**Diagnosed By**: Claude Code
|
|
||||||
**Date**: 2025-12-30
|
|
||||||
**Severity**: HIGH (blocking production login)
|
|
||||||
**Priority**: IMMEDIATE
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*For detailed architecture documentation, see: `deployment/windows/docs/TWO-TIER-IIS-DEPLOYMENT.md`*
|
|
||||||
@@ -1,371 +0,0 @@
|
|||||||
# Deployment Fixes - 2025-12-29
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
Fixed critical Telegram bot deployment issue and updated all deployment scripts and documentation to use `--workers 1` configuration.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Problems Fixed
|
|
||||||
|
|
||||||
### 1. ❌ Telegram Bot Conflict (CRITICAL)
|
|
||||||
|
|
||||||
**Error:**
|
|
||||||
```
|
|
||||||
telegram.error.Conflict: Conflict: terminated by other getUpdates request;
|
|
||||||
make sure that only one bot instance is running
|
|
||||||
```
|
|
||||||
|
|
||||||
**Root Cause:**
|
|
||||||
- NSSM service was configured with `--workers 4`
|
|
||||||
- Each uvicorn worker spawned its own Telegram bot instance
|
|
||||||
- Telegram API allows only ONE bot instance to poll for updates
|
|
||||||
- Multiple instances conflicted → continuous errors
|
|
||||||
|
|
||||||
**Solution:**
|
|
||||||
- Changed NSSM service configuration to `--workers 1`
|
|
||||||
- Single worker = Single bot instance = No conflicts
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 2. ❌ Cache Stats Endpoint (502 Bad Gateway)
|
|
||||||
|
|
||||||
**Error:**
|
|
||||||
- `/api/reports/cache/stats` returned 502 Bad Gateway
|
|
||||||
|
|
||||||
**Root Cause:**
|
|
||||||
- Multiple workers accessing same SQLite cache database
|
|
||||||
- SQLite locking conflicts caused worker crashes
|
|
||||||
|
|
||||||
**Solution:**
|
|
||||||
- **Automatically fixed** by using `--workers 1`
|
|
||||||
- Single worker = No SQLite locking conflicts
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 3. ⚠️ Pydantic v2 Warnings
|
|
||||||
|
|
||||||
**Warning:**
|
|
||||||
```
|
|
||||||
UserWarning: Valid config keys have changed in V2:
|
|
||||||
* 'schema_extra' has been renamed to 'json_schema_extra'
|
|
||||||
```
|
|
||||||
|
|
||||||
**Solution:**
|
|
||||||
- Updated `backend/modules/reports/models/trial_balance.py:72`
|
|
||||||
- Changed `schema_extra` → `json_schema_extra`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Files Modified
|
|
||||||
|
|
||||||
### 1. Deployment Scripts
|
|
||||||
|
|
||||||
#### `Install-ROA2WEB.ps1` (Line 370-371)
|
|
||||||
**Changed:**
|
|
||||||
```powershell
|
|
||||||
# Before
|
|
||||||
& nssm install ... "--workers" "4"
|
|
||||||
|
|
||||||
# After
|
|
||||||
# NOTE: Using --workers 1 because Telegram bot requires single instance (polling conflict)
|
|
||||||
& nssm install ... "--workers" "1"
|
|
||||||
```
|
|
||||||
|
|
||||||
#### `Fix-TelegramWorkers.ps1` (NEW)
|
|
||||||
**Created:** Automatic fix script for existing installations
|
|
||||||
- Stops ROA2WEB-Backend service
|
|
||||||
- Updates NSSM parameters to `--workers 1`
|
|
||||||
- Restarts service
|
|
||||||
- Verifies configuration and health
|
|
||||||
- Checks logs for Telegram errors
|
|
||||||
|
|
||||||
**Usage:**
|
|
||||||
```powershell
|
|
||||||
cd C:\TEMP\ROA2WEB-Scripts
|
|
||||||
.\Fix-TelegramWorkers.ps1
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 2. Documentation
|
|
||||||
|
|
||||||
#### `TELEGRAM-BOT-DEPLOYMENT.md` (NEW)
|
|
||||||
**Created:** Complete deployment guide for Telegram bot
|
|
||||||
- Explains the worker conflict issue
|
|
||||||
- Installation and upgrade procedures
|
|
||||||
- Verification steps
|
|
||||||
- Troubleshooting guide
|
|
||||||
- Architecture notes and performance analysis
|
|
||||||
|
|
||||||
**Key Points:**
|
|
||||||
- ✅ Always use `--workers 1`
|
|
||||||
- ✅ Performance is excellent (async I/O bound, not CPU bound)
|
|
||||||
- ✅ Single worker handles 100+ concurrent users
|
|
||||||
- ✅ Lower memory usage (~400 MB vs ~1.6 GB)
|
|
||||||
|
|
||||||
#### `WINDOWS_DEPLOYMENT.md`
|
|
||||||
**Updated sections:**
|
|
||||||
|
|
||||||
1. **High CPU/Memory Usage** (Line 716-743)
|
|
||||||
- Removed outdated `WORKERS=2` in .env suggestion
|
|
||||||
- Clarified workers are configured in NSSM, not .env
|
|
||||||
- Added warning about not changing `--workers 1`
|
|
||||||
|
|
||||||
2. **Backend Configuration (.env)** (Line 353-360)
|
|
||||||
- Removed `WORKERS=4` from example .env
|
|
||||||
- Added note that WORKERS is configured in NSSM
|
|
||||||
- Added reference to TELEGRAM-BOT-DEPLOYMENT.md
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 3. Backend Code
|
|
||||||
|
|
||||||
#### `backend/modules/reports/models/trial_balance.py` (Line 72)
|
|
||||||
**Changed:**
|
|
||||||
```python
|
|
||||||
# Before
|
|
||||||
class Config:
|
|
||||||
schema_extra = { ... }
|
|
||||||
|
|
||||||
# After
|
|
||||||
class Config:
|
|
||||||
json_schema_extra = { ... }
|
|
||||||
```
|
|
||||||
|
|
||||||
**Impact:** Eliminates Pydantic v2 warnings in logs
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Deployment Instructions
|
|
||||||
|
|
||||||
### For New Installations
|
|
||||||
|
|
||||||
Use updated `Install-ROA2WEB.ps1`:
|
|
||||||
```powershell
|
|
||||||
.\Install-ROA2WEB.ps1
|
|
||||||
```
|
|
||||||
|
|
||||||
The script now automatically uses `--workers 1` - no manual configuration needed.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### For Existing Installations
|
|
||||||
|
|
||||||
**Option 1: Automatic Fix (Recommended)**
|
|
||||||
```powershell
|
|
||||||
cd C:\TEMP\ROA2WEB-Scripts
|
|
||||||
.\Fix-TelegramWorkers.ps1
|
|
||||||
```
|
|
||||||
|
|
||||||
**Option 2: Manual Fix**
|
|
||||||
```powershell
|
|
||||||
# Stop service
|
|
||||||
Stop-Service ROA2WEB-Backend
|
|
||||||
|
|
||||||
# Update NSSM
|
|
||||||
nssm set ROA2WEB-Backend AppParameters "-m uvicorn main:app --host 127.0.0.1 --port 8000 --workers 1"
|
|
||||||
|
|
||||||
# Verify
|
|
||||||
nssm get ROA2WEB-Backend AppParameters
|
|
||||||
|
|
||||||
# Start service
|
|
||||||
Start-Service ROA2WEB-Backend
|
|
||||||
|
|
||||||
# Monitor logs
|
|
||||||
Get-Content C:\inetpub\wwwroot\roa2web\logs\backend-stderr.log -Tail 50 -Wait
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Verification
|
|
||||||
|
|
||||||
### 1. Check NSSM Configuration
|
|
||||||
```powershell
|
|
||||||
nssm get ROA2WEB-Backend AppParameters
|
|
||||||
```
|
|
||||||
|
|
||||||
**Expected:**
|
|
||||||
```
|
|
||||||
-m uvicorn main:app --host 127.0.0.1 --port 8000 --workers 1
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Check Process Count
|
|
||||||
```powershell
|
|
||||||
Get-Process -Name python
|
|
||||||
```
|
|
||||||
|
|
||||||
**Expected:**
|
|
||||||
- 1-2 Python processes (1 parent + 1 worker, or just 1 combined)
|
|
||||||
- **NOT** 5 processes (1 parent + 4 workers)
|
|
||||||
|
|
||||||
### 3. Check Telegram Bot in Logs
|
|
||||||
```powershell
|
|
||||||
Get-Content C:\inetpub\wwwroot\roa2web\logs\backend-stderr.log -Tail 100 | Select-String "Bot running"
|
|
||||||
```
|
|
||||||
|
|
||||||
**Expected:**
|
|
||||||
- Message appears **EXACTLY ONCE**
|
|
||||||
- No "Conflict: terminated by other getUpdates" errors
|
|
||||||
|
|
||||||
### 4. Test Cache Stats Endpoint
|
|
||||||
```
|
|
||||||
https://roa2web.romfast.ro/roa2web/reports/cache-stats
|
|
||||||
```
|
|
||||||
|
|
||||||
**Expected:**
|
|
||||||
- Page loads successfully (200 OK)
|
|
||||||
- No 502 Bad Gateway error
|
|
||||||
|
|
||||||
### 5. Test Telegram Bot
|
|
||||||
Send a message to @ROA2WEBBot in Telegram
|
|
||||||
|
|
||||||
**Expected:**
|
|
||||||
- Bot responds without errors
|
|
||||||
- No conflict errors in backend logs
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Performance Impact
|
|
||||||
|
|
||||||
### Before Fix (--workers 4)
|
|
||||||
- ❌ Telegram bot conflicts (unusable)
|
|
||||||
- ❌ Cache stats endpoint crashes (502)
|
|
||||||
- 📊 5 Python processes
|
|
||||||
- 📊 ~1.6 GB memory usage
|
|
||||||
- ✅ Same performance (async I/O)
|
|
||||||
|
|
||||||
### After Fix (--workers 1)
|
|
||||||
- ✅ Telegram bot works perfectly
|
|
||||||
- ✅ Cache stats endpoint works
|
|
||||||
- ✅ No SQLite locking conflicts
|
|
||||||
- 📊 2 Python processes
|
|
||||||
- 📊 ~400 MB memory usage
|
|
||||||
- ✅ Same performance (async I/O)
|
|
||||||
|
|
||||||
**Conclusion:** `--workers 1` is **SUPERIOR** for this application in every way.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Architecture Notes
|
|
||||||
|
|
||||||
### Why Single Worker is Better
|
|
||||||
|
|
||||||
1. **Telegram Bot Requirement**
|
|
||||||
- Telegram API allows only ONE bot instance per token
|
|
||||||
- Multiple workers = Multiple bot instances = Conflicts
|
|
||||||
|
|
||||||
2. **SQLite Cache Database**
|
|
||||||
- Shared SQLite database for cache
|
|
||||||
- Multiple workers = Locking conflicts = Crashes
|
|
||||||
|
|
||||||
3. **Async I/O Performance**
|
|
||||||
- Application is I/O bound (Oracle database queries)
|
|
||||||
- NOT CPU bound
|
|
||||||
- Single worker with async/await handles 100+ concurrent requests
|
|
||||||
- Multiple workers provide NO performance benefit
|
|
||||||
|
|
||||||
4. **Lower Resource Usage**
|
|
||||||
- Less memory (~400 MB vs ~1.6 GB)
|
|
||||||
- Fewer processes to manage
|
|
||||||
- Simpler debugging
|
|
||||||
|
|
||||||
### Performance Characteristics
|
|
||||||
|
|
||||||
**With `--workers 1`:**
|
|
||||||
- Concurrent requests: 100+ (async/await)
|
|
||||||
- Database pooling: 5-10 Oracle connections (shared)
|
|
||||||
- Memory usage: ~300-500 MB per worker
|
|
||||||
- CPU usage: Low (I/O bound)
|
|
||||||
- Response times: 50-200ms (mostly DB query time)
|
|
||||||
|
|
||||||
**Adequate for:**
|
|
||||||
- 50-100 concurrent users
|
|
||||||
- 1000+ requests per minute
|
|
||||||
- Multiple modules (Reports, Data Entry, Telegram)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Future Considerations
|
|
||||||
|
|
||||||
### Alternative: Separate Bot Service
|
|
||||||
|
|
||||||
If scalability becomes an issue, consider:
|
|
||||||
|
|
||||||
**Option A (Current):** Integrated bot, single worker
|
|
||||||
- ✅ Simple deployment
|
|
||||||
- ✅ Single service to manage
|
|
||||||
- ⚠️ Must use `--workers 1`
|
|
||||||
|
|
||||||
**Option B (Alternative):** Separate bot service
|
|
||||||
- ✅ Could use `--workers 4` for web backend
|
|
||||||
- ❌ Two Windows services to manage
|
|
||||||
- ❌ More complex deployment
|
|
||||||
- ❌ Two processes to monitor
|
|
||||||
|
|
||||||
**Decision:** Keep current architecture. Performance is excellent and deployment is simpler.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Checklist for Deployment
|
|
||||||
|
|
||||||
### Pre-Deployment
|
|
||||||
- [ ] Read this document
|
|
||||||
- [ ] Read `TELEGRAM-BOT-DEPLOYMENT.md`
|
|
||||||
- [ ] Backup current installation
|
|
||||||
- [ ] Note current NSSM parameters
|
|
||||||
|
|
||||||
### Deployment
|
|
||||||
- [ ] Copy updated scripts to server
|
|
||||||
- [ ] Run `Fix-TelegramWorkers.ps1` (existing) OR `Install-ROA2WEB.ps1` (new)
|
|
||||||
- [ ] Wait 30 seconds for service startup
|
|
||||||
- [ ] Verify NSSM parameters show `--workers 1`
|
|
||||||
|
|
||||||
### Post-Deployment Verification
|
|
||||||
- [ ] Check process count (should be 1-2, not 5)
|
|
||||||
- [ ] Check logs for single bot startup message
|
|
||||||
- [ ] Verify NO "Conflict" errors in logs
|
|
||||||
- [ ] Test health endpoint: http://localhost:8000/health
|
|
||||||
- [ ] Test cache stats: https://roa2web.romfast.ro/roa2web/reports/cache-stats
|
|
||||||
- [ ] Test Telegram bot functionality
|
|
||||||
- [ ] Monitor logs for 5 minutes
|
|
||||||
|
|
||||||
### If Issues Occur
|
|
||||||
- [ ] Check `TELEGRAM-BOT-DEPLOYMENT.md` troubleshooting section
|
|
||||||
- [ ] Review backend logs for errors
|
|
||||||
- [ ] Verify Oracle connection
|
|
||||||
- [ ] Check PYTHONPATH in NSSM config
|
|
||||||
- [ ] Contact development team with logs
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Rollback Procedure
|
|
||||||
|
|
||||||
If you need to rollback (not recommended):
|
|
||||||
|
|
||||||
```powershell
|
|
||||||
# Stop service
|
|
||||||
Stop-Service ROA2WEB-Backend
|
|
||||||
|
|
||||||
# Restore old parameters (WILL BREAK TELEGRAM BOT)
|
|
||||||
nssm set ROA2WEB-Backend AppParameters "-m uvicorn main:app --host 127.0.0.1 --port 8000 --workers 4"
|
|
||||||
|
|
||||||
# Start service
|
|
||||||
Start-Service ROA2WEB-Backend
|
|
||||||
```
|
|
||||||
|
|
||||||
**Warning:** Rollback will restore the Telegram bot conflict issue.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Support
|
|
||||||
|
|
||||||
For questions or issues:
|
|
||||||
1. Check `TELEGRAM-BOT-DEPLOYMENT.md` troubleshooting
|
|
||||||
2. Review `WINDOWS_DEPLOYMENT.md` for general deployment issues
|
|
||||||
3. Check backend logs: `C:\inetpub\wwwroot\roa2web\logs\backend-stderr.log`
|
|
||||||
4. Contact development team with:
|
|
||||||
- Current NSSM parameters
|
|
||||||
- Recent log excerpts (last 100 lines)
|
|
||||||
- Process count and memory usage
|
|
||||||
- Specific error messages
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!--
|
|
||||||
====================================================================
|
|
||||||
ROA2WEB - Internal Application Server Configuration
|
|
||||||
====================================================================
|
|
||||||
Server: 10.0.20.36 (internal application server)
|
|
||||||
Role: Application host + API proxy to localhost backend
|
|
||||||
|
|
||||||
This web.config ONLY goes on the INTERNAL server (10.0.20.36).
|
|
||||||
It serves the frontend and proxies API calls to localhost:8000.
|
|
||||||
|
|
||||||
Location: C:\inetpub\wwwroot\roa2web\web.config (on 10.0.20.36)
|
|
||||||
|
|
||||||
⚠️ DO NOT use this config on 10.0.20.122 (public server)!
|
|
||||||
====================================================================
|
|
||||||
-->
|
|
||||||
<configuration>
|
|
||||||
<system.webServer>
|
|
||||||
<rewrite>
|
|
||||||
<rules>
|
|
||||||
<!-- Proxy API requests to unified backend on localhost -->
|
|
||||||
<rule name="Proxy Unified API" stopProcessing="true">
|
|
||||||
<match url="^roa2web/api/(.*)" />
|
|
||||||
<action type="Rewrite" url="http://localhost:8000/api/{R:1}" />
|
|
||||||
</rule>
|
|
||||||
|
|
||||||
<!-- Proxy uploads to unified backend on localhost -->
|
|
||||||
<rule name="Proxy Uploads" stopProcessing="true">
|
|
||||||
<match url="^roa2web/uploads/(.*)" />
|
|
||||||
<action type="Rewrite" url="http://localhost:8000/uploads/{R:1}" />
|
|
||||||
</rule>
|
|
||||||
|
|
||||||
<!-- SPA fallback - all other routes serve index.html -->
|
|
||||||
<rule name="SPA Fallback" stopProcessing="true">
|
|
||||||
<match url="^roa2web/.*" />
|
|
||||||
<conditions logicalGrouping="MatchAll">
|
|
||||||
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
|
|
||||||
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
|
|
||||||
</conditions>
|
|
||||||
<action type="Rewrite" url="/roa2web/index.html" />
|
|
||||||
</rule>
|
|
||||||
</rules>
|
|
||||||
</rewrite>
|
|
||||||
|
|
||||||
<!-- Static content configuration -->
|
|
||||||
<staticContent>
|
|
||||||
<mimeMap fileExtension=".webmanifest" mimeType="application/manifest+json" />
|
|
||||||
<mimeMap fileExtension=".js" mimeType="application/javascript" />
|
|
||||||
<mimeMap fileExtension=".json" mimeType="application/json" />
|
|
||||||
</staticContent>
|
|
||||||
|
|
||||||
<!-- Client cache for static assets (1 year) -->
|
|
||||||
<httpProtocol>
|
|
||||||
<customHeaders>
|
|
||||||
<add name="Cache-Control" value="public, max-age=31536000" />
|
|
||||||
</customHeaders>
|
|
||||||
</httpProtocol>
|
|
||||||
</system.webServer>
|
|
||||||
</configuration>
|
|
||||||
@@ -117,6 +117,11 @@ function Write-Warning {
|
|||||||
Write-Host " [WARN] $Message" -ForegroundColor Yellow
|
Write-Host " [WARN] $Message" -ForegroundColor Yellow
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Write-Info {
|
||||||
|
param([string]$Message)
|
||||||
|
Write-Host " [INFO] $Message" -ForegroundColor Gray
|
||||||
|
}
|
||||||
|
|
||||||
function Resolve-FullPath {
|
function Resolve-FullPath {
|
||||||
param([string]$Path)
|
param([string]$Path)
|
||||||
|
|
||||||
@@ -352,6 +357,26 @@ function Build-Frontend {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Copy public/ folder (contains web.config and other static assets)
|
||||||
|
$publicSourcePath = Join-Path $projectRoot "public"
|
||||||
|
if (Test-Path $publicSourcePath) {
|
||||||
|
$publicDestPath = Join-Path $tempBuildDir "public"
|
||||||
|
Write-Step "Copying public/ folder..."
|
||||||
|
Write-Info "Source: $publicSourcePath"
|
||||||
|
Write-Info "Dest: $publicDestPath"
|
||||||
|
Copy-Item -Path $publicSourcePath -Destination $publicDestPath -Recurse -Force
|
||||||
|
Write-Success "public/ folder copied (includes web.config)"
|
||||||
|
|
||||||
|
# Verify web.config was copied
|
||||||
|
$copiedWebConfig = Join-Path $publicDestPath "web.config"
|
||||||
|
if (Test-Path $copiedWebConfig) {
|
||||||
|
Write-Success "web.config found in public/"
|
||||||
|
} else {
|
||||||
|
Write-Warning "web.config NOT found in public/ - check source"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Write-Warning "public/ folder not found at: $publicSourcePath"
|
||||||
|
}
|
||||||
|
|
||||||
# Copy shared folder to maintain relative imports (../shared/)
|
# Copy shared folder to maintain relative imports (../shared/)
|
||||||
# For ultrathin monolith: src/ and shared/ are siblings at project root
|
# For ultrathin monolith: src/ and shared/ are siblings at project root
|
||||||
@@ -463,6 +488,15 @@ function Build-Frontend {
|
|||||||
$totalSize = ($distFiles | Measure-Object -Property Length -Sum).Sum / 1MB
|
$totalSize = ($distFiles | Measure-Object -Property Length -Sum).Sum / 1MB
|
||||||
Write-Success "Generated $(($distFiles).Count) files ($([math]::Round($totalSize, 2)) MB)"
|
Write-Success "Generated $(($distFiles).Count) files ($([math]::Round($totalSize, 2)) MB)"
|
||||||
|
|
||||||
|
# Verify web.config was built
|
||||||
|
$webConfigPath = Join-Path $distPath "web.config"
|
||||||
|
if (Test-Path $webConfigPath) {
|
||||||
|
Write-Success "web.config found in build output"
|
||||||
|
} else {
|
||||||
|
Write-Warning "web.config NOT found in build output: $webConfigPath"
|
||||||
|
Write-Warning "Check if public/web.config exists in source"
|
||||||
|
}
|
||||||
|
|
||||||
return $distPath
|
return $distPath
|
||||||
} finally {
|
} finally {
|
||||||
Pop-Location
|
Pop-Location
|
||||||
@@ -879,7 +913,18 @@ function New-DeploymentPackage {
|
|||||||
$frontendDest = Join-Path $OutputPath "frontend"
|
$frontendDest = Join-Path $OutputPath "frontend"
|
||||||
New-Item -ItemType Directory -Path $frontendDest -Force | Out-Null
|
New-Item -ItemType Directory -Path $frontendDest -Force | Out-Null
|
||||||
Write-Step "Copying Unified Frontend files (SPA)..."
|
Write-Step "Copying Unified Frontend files (SPA)..."
|
||||||
|
Write-Info "Source: $frontendDistPath"
|
||||||
|
Write-Info "Destination: $frontendDest"
|
||||||
Copy-Item -Path "$frontendDistPath\*" -Destination $frontendDest -Recurse -Force
|
Copy-Item -Path "$frontendDistPath\*" -Destination $frontendDest -Recurse -Force
|
||||||
|
|
||||||
|
# Verify web.config was copied
|
||||||
|
$copiedWebConfig = Join-Path $frontendDest "web.config"
|
||||||
|
if (Test-Path $copiedWebConfig) {
|
||||||
|
Write-Success "web.config copied to package"
|
||||||
|
} else {
|
||||||
|
Write-Warning "web.config NOT copied to package"
|
||||||
|
}
|
||||||
|
|
||||||
Write-Success "Unified Frontend files copied"
|
Write-Success "Unified Frontend files copied"
|
||||||
|
|
||||||
# Unified Backend (includes Reports, Data Entry, Telegram modules)
|
# Unified Backend (includes Reports, Data Entry, Telegram modules)
|
||||||
@@ -901,7 +946,18 @@ function New-DeploymentPackage {
|
|||||||
$frontendDest = Join-Path $OutputPath "frontend"
|
$frontendDest = Join-Path $OutputPath "frontend"
|
||||||
New-Item -ItemType Directory -Path $frontendDest -Force | Out-Null
|
New-Item -ItemType Directory -Path $frontendDest -Force | Out-Null
|
||||||
Write-Step "Copying Unified Frontend files (SPA)..."
|
Write-Step "Copying Unified Frontend files (SPA)..."
|
||||||
|
Write-Info "Source: $frontendDistPath"
|
||||||
|
Write-Info "Destination: $frontendDest"
|
||||||
Copy-Item -Path "$frontendDistPath\*" -Destination $frontendDest -Recurse -Force
|
Copy-Item -Path "$frontendDistPath\*" -Destination $frontendDest -Recurse -Force
|
||||||
|
|
||||||
|
# Verify web.config was copied
|
||||||
|
$copiedWebConfig = Join-Path $frontendDest "web.config"
|
||||||
|
if (Test-Path $copiedWebConfig) {
|
||||||
|
Write-Success "web.config copied to package"
|
||||||
|
} else {
|
||||||
|
Write-Warning "web.config NOT copied to package"
|
||||||
|
}
|
||||||
|
|
||||||
Write-Success "Unified Frontend files copied"
|
Write-Success "Unified Frontend files copied"
|
||||||
|
|
||||||
# Unified Backend (includes all modules)
|
# Unified Backend (includes all modules)
|
||||||
|
|||||||
@@ -465,15 +465,21 @@ function Deploy-Frontend {
|
|||||||
Copy-Item -Path $sourceFe -Destination $Config.FrontendPath -Recurse -Force
|
Copy-Item -Path $sourceFe -Destination $Config.FrontendPath -Recurse -Force
|
||||||
Write-Success "Frontend files deployed"
|
Write-Success "Frontend files deployed"
|
||||||
|
|
||||||
# Copy web.config if present in package
|
# Verify web.config was deployed (should be in frontend/ from dist/)
|
||||||
$webConfig = Join-Path $SourcePath "config\web.config"
|
$deployedWebConfig = Join-Path $Config.FrontendPath "web.config"
|
||||||
if (Test-Path $webConfig) {
|
if (Test-Path $deployedWebConfig) {
|
||||||
$destConfig = Join-Path $Config.FrontendPath "web.config"
|
Write-Success "web.config deployed successfully"
|
||||||
Copy-Item -Path $webConfig -Destination $destConfig -Force
|
# Verify it has correct configuration for /roa2web/ path
|
||||||
Write-Success "web.config deployed"
|
$configContent = Get-Content $deployedWebConfig -Raw
|
||||||
|
if ($configContent -match 'url="[^"]*roa2web/api') {
|
||||||
|
Write-Success "web.config contains correct /roa2web/api proxy rules"
|
||||||
|
} else {
|
||||||
|
Write-Warning "web.config may not have correct /roa2web/api proxy configuration"
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Write-Warning "web.config not found in package: $webConfig"
|
Write-Warning "web.config not found in deployed frontend: $deployedWebConfig"
|
||||||
Write-Warning "IIS reverse proxy will not work without web.config"
|
Write-Warning "IIS reverse proxy will not work without web.config"
|
||||||
|
Write-Warning "Ensure 'public/web.config' exists in source and rebuild frontend"
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-Success "Frontend deployment completed successfully"
|
Write-Success "Frontend deployment completed successfully"
|
||||||
|
|||||||
@@ -1,26 +1,32 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!--
|
<!--
|
||||||
====================================================================
|
====================================================================
|
||||||
ROA2WEB - Internal Application Server Configuration
|
ROA2WEB - IIS Sub-Application Configuration
|
||||||
====================================================================
|
====================================================================
|
||||||
|
|
||||||
⚠️ IMPORTANT - READ BEFORE DEPLOYMENT! ⚠️
|
⚠️ CRITICAL - For IIS Sub-Application Deployment! ⚠️
|
||||||
|
|
||||||
This web.config is for the INTERNAL application server (10.0.20.36)
|
This web.config is for when IIS is configured as SUB-APPLICATION:
|
||||||
|
- IIS Application Path: /roa2web
|
||||||
|
- Physical Path: C:\inetpub\wwwroot\roa2web\frontend (or dist/)
|
||||||
|
|
||||||
|
**How IIS Sub-Applications Work**:
|
||||||
|
- Browser request: https://example.com/roa2web/api/auth/login
|
||||||
|
- IIS application PATH strips the "/roa2web" prefix
|
||||||
|
- Inside application: request arrives as /api/auth/login
|
||||||
|
- Therefore: URL patterns must NOT include "roa2web/" prefix!
|
||||||
|
|
||||||
**Production Architecture (2-Tier IIS)**:
|
**Production Architecture (2-Tier IIS)**:
|
||||||
|
|
||||||
Public Server (10.0.20.122) → uses different web.config!
|
Public Server (10.0.20.122 - roa2web.romfast.ro)
|
||||||
└─ Proxies to Internal Server (10.0.20.36) → uses THIS web.config
|
└─ Proxies ALL to → https://10.0.20.36/{REQUEST_PATH}
|
||||||
└─ Proxies to Backend (localhost:8000)
|
|
||||||
|
Internal Server (10.0.20.36)
|
||||||
|
└─ IIS Sub-App: /roa2web → Physical: C:\inetpub\wwwroot\roa2web\frontend
|
||||||
|
└─ This web.config proxies /api/* to localhost:8000
|
||||||
|
|
||||||
See: deployment/windows/docs/TWO-TIER-IIS-DEPLOYMENT.md
|
See: deployment/windows/docs/TWO-TIER-IIS-DEPLOYMENT.md
|
||||||
|
|
||||||
**Deployment**:
|
|
||||||
- This file is built into dist/ by Vite
|
|
||||||
- Copy to: C:\inetpub\wwwroot\roa2web\web.config (on 10.0.20.36)
|
|
||||||
- For public server config, see: deployment/windows/config/web.config.10.0.20.122-PUBLIC
|
|
||||||
|
|
||||||
====================================================================
|
====================================================================
|
||||||
-->
|
-->
|
||||||
<configuration>
|
<configuration>
|
||||||
@@ -28,33 +34,38 @@
|
|||||||
<rewrite>
|
<rewrite>
|
||||||
<rules>
|
<rules>
|
||||||
<!-- Proxy API requests to unified backend on localhost -->
|
<!-- Proxy API requests to unified backend on localhost -->
|
||||||
|
<!-- NOTE: NO /roa2web/ prefix - IIS sub-app already stripped it! -->
|
||||||
<rule name="Proxy Unified API" stopProcessing="true">
|
<rule name="Proxy Unified API" stopProcessing="true">
|
||||||
<match url="^roa2web/api/(.*)" />
|
<match url="^api/(.*)" />
|
||||||
<action type="Rewrite" url="http://localhost:8000/api/{R:1}" />
|
<action type="Rewrite" url="http://localhost:8000/api/{R:1}" />
|
||||||
</rule>
|
</rule>
|
||||||
|
|
||||||
<!-- Proxy uploads to unified backend on localhost -->
|
<!-- Proxy uploads to unified backend on localhost -->
|
||||||
<rule name="Proxy Uploads" stopProcessing="true">
|
<rule name="Proxy Uploads" stopProcessing="true">
|
||||||
<match url="^roa2web/uploads/(.*)" />
|
<match url="^uploads/(.*)" />
|
||||||
<action type="Rewrite" url="http://localhost:8000/uploads/{R:1}" />
|
<action type="Rewrite" url="http://localhost:8000/uploads/{R:1}" />
|
||||||
</rule>
|
</rule>
|
||||||
|
|
||||||
<!-- SPA fallback - all other routes serve index.html -->
|
<!-- SPA fallback - all other routes serve index.html -->
|
||||||
<rule name="SPA Fallback" stopProcessing="true">
|
<rule name="SPA Fallback" stopProcessing="true">
|
||||||
<match url="^roa2web/.*" />
|
<match url=".*" />
|
||||||
<conditions logicalGrouping="MatchAll">
|
<conditions logicalGrouping="MatchAll">
|
||||||
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
|
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
|
||||||
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
|
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
|
||||||
</conditions>
|
</conditions>
|
||||||
<action type="Rewrite" url="/roa2web/index.html" />
|
<action type="Rewrite" url="index.html" />
|
||||||
</rule>
|
</rule>
|
||||||
</rules>
|
</rules>
|
||||||
</rewrite>
|
</rewrite>
|
||||||
|
|
||||||
<!-- Static content configuration -->
|
<!-- Static content configuration -->
|
||||||
<staticContent>
|
<staticContent>
|
||||||
|
<!-- Remove first to avoid duplicates with server-level config, then add -->
|
||||||
|
<remove fileExtension=".webmanifest" />
|
||||||
<mimeMap fileExtension=".webmanifest" mimeType="application/manifest+json" />
|
<mimeMap fileExtension=".webmanifest" mimeType="application/manifest+json" />
|
||||||
|
<remove fileExtension=".js" />
|
||||||
<mimeMap fileExtension=".js" mimeType="application/javascript" />
|
<mimeMap fileExtension=".js" mimeType="application/javascript" />
|
||||||
|
<remove fileExtension=".json" />
|
||||||
<mimeMap fileExtension=".json" mimeType="application/json" />
|
<mimeMap fileExtension=".json" mimeType="application/json" />
|
||||||
</staticContent>
|
</staticContent>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user