Windows (IIS)
Deploy RAMP to a Windows Server with IIS using Windows Integrated Authentication (Kerberos/NTLM). This is ideal for corporate Windows environments with Active Directory where users authenticate with their domain credentials.
What the deployment covers
Section titled “What the deployment covers”The automated deployment script (Deploy-RAMPToHyperV.ps1) handles:
- Building RAMP (backend + frontend)
- Connecting to a remote VM via PowerShell Remoting
- Installing and configuring IIS
- Deploying application files
- Configuring Windows Integrated Authentication
- Setting up the database (SQLite or SQL Server)
- Validating deployment with health checks
Prerequisites
Section titled “Prerequisites”On your development machine
Section titled “On your development machine”- PowerShell 5.1+ or PowerShell 7+
- RAMP source code with all dependencies
- .NET 10 SDK for building the backend
- Node.js 18+ for building the frontend
- Network access to the target VM
On the target VM (Windows Server)
Section titled “On the target VM (Windows Server)”- Windows Server 2016+ (2019 or 2022 recommended)
- Active Directory Domain Controller or domain-joined machine
- IIS (installed by the script if missing)
- ASP.NET Core 10 Runtime (Hosting Bundle) — download from dotnet.microsoft.com
- PowerShell Remoting enabled:
Enable-PSRemoting -ForceFirewall rules
Section titled “Firewall rules”Ensure these ports are open on the target VM:
| Port | Protocol | Purpose |
|---|---|---|
| 5985 | HTTP | PowerShell Remoting (WinRM) |
| 5986 | HTTPS | PowerShell Remoting over SSL (optional) |
| 80 | HTTP | RAMP Web Application |
| 443 | HTTPS | RAMP Web Application (if using SSL) |
Quick start
Section titled “Quick start”-
Navigate to the RAMP source directory:
Terminal window cd C:\Source\RAMP -
Run the deployment script with default settings:
Terminal window .\Deploy-RAMPToHyperV.ps1 -
Access RAMP at
http://<vm-ip-address>. You will be prompted for Windows credentials.
Default settings:
| Setting | Default value |
|---|---|
| Site Name | RAMP |
| App Pool | RAMP_AppPool |
| Port | 80 |
| Database | SQLite |
| Deployment Path | C:\inetpub\RAMP |
Deployment options
Section titled “Deployment options”# Deploy to default VM.\Deploy-RAMPToHyperV.ps1# Prompt for credentials$cred = Get-Credential
# Deploy to custom VM.\Deploy-RAMPToHyperV.ps1 -VMHost 192.168.1.100 -Credential $cred# Overwrite existing RAMP deployment.\Deploy-RAMPToHyperV.ps1 -Force# Skip build step (faster for redeployment).\Deploy-RAMPToHyperV.ps1 -SkipBuild# Deploy to custom port and site name.\Deploy-RAMPToHyperV.ps1 -Port 8080 -SiteName "RAMP_Production" -AppPoolName "RAMP_Prod_Pool"# Use SQL Server (configure connection string manually after deployment).\Deploy-RAMPToHyperV.ps1 -DatabaseType SQLServerDirectory structure
Section titled “Directory structure”After deployment, IIS serves from the following structure:
C:\inetpub\RAMP\├── wwwroot\ # Frontend build output│ ├── index.html│ └── assets\├── appsettings.json├── appsettings.Production.json # Generated by script├── RAMP.API.dll├── RAMP.API.exe├── web.config # Generated by script├── logs\│ └── stdout_*.log # IIS stdout logs└── data\ └── ramp.db # SQLite databaseConfiguration
Section titled “Configuration”appsettings.Production.json
Section titled “appsettings.Production.json”The deployment script generates this file. Key sections:
{ "ConnectionStrings": { "DefaultConnection": "Data Source=C:\\inetpub\\RAMP\\data\\ramp.db" }, "Authentication": { "WindowsAuthentication": { "Enabled": true, "AutomaticChallenge": true }, "Jwt": { "Issuer": "http://your-server", "Audience": "http://your-server", "SecretKey": "CHANGE_THIS_IN_PRODUCTION_MIN_32_CHARS" } }, "CORS": { "AllowedOrigins": ["http://your-server"] }}For full configuration reference, see Application Settings.
web.config
Section titled “web.config”The deployment script generates web.config with the ASP.NET Core Module and Windows Authentication:
<?xml version="1.0" encoding="utf-8"?><configuration> <location path="." inheritInChildApplications="false"> <system.webServer> <handlers> <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" /> </handlers> <aspNetCore processPath="dotnet" arguments=".\RAMP.API.dll" stdoutLogEnabled="true" stdoutLogFile=".\logs\stdout" hostingModel="inprocess" /> <security> <authentication> <windowsAuthentication enabled="true"> <providers> <add value="Negotiate" /> <add value="NTLM" /> </providers> </windowsAuthentication> <anonymousAuthentication enabled="false" /> </authentication> </security> </system.webServer> </location></configuration>IIS settings
Section titled “IIS settings”| Setting | Value |
|---|---|
| Application Pool | RAMP_AppPool |
| .NET CLR Version | No Managed Code (uses .NET 10 Runtime) |
| Managed Pipeline Mode | Integrated |
| Enable 32-Bit Applications | False |
| Identity | ApplicationPoolIdentity |
| Windows Authentication | Enabled (Negotiate, NTLM) |
| Anonymous Authentication | Disabled |
Authentication flow
Section titled “Authentication flow”How Windows Integrated Authentication works
Section titled “How Windows Integrated Authentication works”-
User navigates to the application at
http://your-server. -
IIS challenges the browser with HTTP 401 and
WWW-Authenticate: Negotiateheader. -
Browser sends Windows credentials using Kerberos (preferred) or NTLM fallback.
-
IIS validates credentials against Active Directory and sets
HttpContext.User.Identityto theWindowsIdentity. -
User logs in to RAMP — the frontend calls
POST /_api/auth/windows-login. The backend extracts theWindowsIdentityand mapsDOMAIN\usernameto a RAMP user. -
RAMP issues JWT tokens — an access token (8-hour expiration) and a refresh token.
-
Frontend stores tokens in localStorage and sends
Authorization: Bearer <token>on subsequent requests.
Windows user to RAMP user mapping
Section titled “Windows user to RAMP user mapping”The username is extracted from the DOMAIN\username format:
| Windows Identity | Extracted Username | RAMP User |
|---|---|---|
CORP\john.doe | john.doe | john.doe |
DOMAIN\jsmith | jsmith | jsmith |
Creating RAMP users for Windows Auth
Section titled “Creating RAMP users for Windows Auth”- Log in as administrator
- Navigate to Users page
- Create a user with username matching the Windows username (e.g.,
john.doe) - Assign appropriate roles
Add users to the scaffold file (default.yaml):
users: - username: john.doe email: john.doe@corp.local firstName: John lastName: Doe isActive: true appRoles: - UserTroubleshooting
Section titled “Troubleshooting”PowerShell Remoting not working
Section titled “PowerShell Remoting not working”Error: Failed to connect to <ip-address>
Solution — run these commands as Administrator on the VM:
Enable-PSRemoting -ForceSet-Item WSMan:\localhost\Client\TrustedHosts -Value "<ip-address>" -ForceRestart-Service WinRM.NET Runtime not found
Section titled “.NET Runtime not found”Error: .NET 10 Runtime required
- Download the ASP.NET Core 10 Hosting Bundle from dotnet.microsoft.com.
- Install it on the VM.
- Restart IIS:
iisreset
HTTP 500.19 — Invalid Configuration
Section titled “HTTP 500.19 — Invalid Configuration”Cause: web.config is invalid or the ASP.NET Core Module is not installed.
Solution: Install the ASP.NET Core Hosting Bundle and restart IIS with iisreset.
HTTP 401 — Unauthorized (credentials loop)
Section titled “HTTP 401 — Unauthorized (credentials loop)”Cause: Windows Authentication not configured correctly.
Verify IIS authentication settings:
# Should return TrueGet-WebConfigurationProperty ` -Filter "/system.webServer/security/authentication/windowsAuthentication" ` -Name "enabled" -PSPath "IIS:\Sites\RAMP"
# Should include Negotiate and NTLMGet-WebConfiguration ` -Filter "/system.webServer/security/authentication/windowsAuthentication/providers" ` -PSPath "IIS:\Sites\RAMP"User not found in RAMP
Section titled “User not found in RAMP”Symptom: Windows login succeeds but RAMP returns 401 with “User not found”.
Solution: Create the user in RAMP with a username matching the Windows username (see Creating users above).
Database permissions error
Section titled “Database permissions error”Cause: IIS application pool identity cannot write to the database directory.
icacls "C:\inetpub\RAMP\data" /grant IIS_IUSRS:(OI)(CI)FViewing logs
Section titled “Viewing logs”Get-Content "C:\inetpub\RAMP\logs\stdout_*.log" -Tail 50Get-Content "C:\inetpub\RAMP\logs\ramp-*.log" -Tail 50Get-EventLog -LogName Application -Source "IIS AspNetCore Module V2" -Newest 10Production considerations
Section titled “Production considerations”Security hardening
Section titled “Security hardening”-
Use HTTPS — install an SSL certificate in IIS, bind to port 443, and force HTTPS redirect.
-
Change the JWT secret — update
Jwt:SecretKeyinappsettings.Production.jsonwith a strong, randomly generated key (minimum 32 characters). -
Restrict CORS origins — update
CORS:AllowedOriginsto only include your production domains. Removehttp://localhost:5173. -
Use SQL Server for production — SQLite is suitable for demos only. Configure a SQL Server connection string and run database migrations.
-
Configure Kerberos SPNs — for Kerberos authentication, register Service Principal Names:
Terminal window setspn -S HTTP/ramp.example.com DOMAIN\ServiceAccountsetspn -S HTTP/ramp DOMAIN\ServiceAccount -
Use a dedicated service account — create a dedicated AD service account for the IIS App Pool with minimal required permissions.
Performance optimization
Section titled “Performance optimization”# Set Idle Timeout to 0 (always running)Set-ItemProperty "IIS:\AppPools\RAMP_AppPool" ` -Name processModel.idleTimeout -Value ([TimeSpan]::FromMinutes(0))
# Disable periodic recyclingSet-ItemProperty "IIS:\AppPools\RAMP_AppPool" ` -Name recycling.periodicRestart.time -Value ([TimeSpan]::FromMinutes(0))Also enable IIS response compression (both static and dynamic) for better performance.
Health checks
Section titled “Health checks”| Endpoint | Purpose |
|---|---|
/_health | Comprehensive health check (database, Hangfire) |
/_health/ready | Readiness probe for load balancers |
/_health/live | Liveness probe |
Backup and recovery
Section titled “Backup and recovery”# Copy database fileCopy-Item "C:\inetpub\RAMP\data\ramp.db" ` "C:\Backups\ramp_$(Get-Date -Format 'yyyyMMdd_HHmmss').db"# Backup entire application folderCompress-Archive -Path "C:\inetpub\RAMP" ` -DestinationPath "C:\Backups\RAMP_Backup_$(Get-Date -Format 'yyyyMMdd').zip"High availability
Section titled “High availability”For high availability with IIS:
- Deploy to multiple IIS servers behind a load balancer (IIS ARR, Azure Load Balancer, F5, etc.)
- Use SQL Server with AlwaysOn Availability Groups for shared database
- Configure a distributed cache (Redis) for shared session state and refresh token storage