MinusNow Documentation

๐Ÿ“‘ Table of Contents

๐Ÿ” Overview

This guide covers deploying MinusNow ITSM on Windows Server instances in major cloud platforms. Windows deployment leverages IIS with URL Rewrite and Application Request Routing (ARR) for reverse proxy functionality.

Architecture Overview

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Cloud Load Balancer / โ”‚ โ”‚ Azure Application Gateway โ”‚ โ”‚ SSL Termination โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ–ผ โ–ผ โ–ผ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Windows VM โ”‚โ”‚ Windows VM โ”‚โ”‚ Windows VM โ”‚ โ”‚ IIS + ARR โ”‚โ”‚ IIS + ARR โ”‚โ”‚ IIS + ARR โ”‚ โ”‚ Node.js โ”‚โ”‚ Node.js โ”‚โ”‚ Node.js โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ–ผ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Managed PostgreSQL Database โ”‚ โ”‚ (Azure / RDS / Cloud SQL) โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Cloud Provider Comparison

FeatureAzureAWSGCP
Windows VMAzure VMEC2Compute Engine
Managed DBAzure PostgreSQLRDS PostgreSQLCloud SQL
Load BalancerApplication GatewayALBHTTP(S) LB
Best ForEnterprise WindowsHybrid workloadsML integration

๐Ÿ’ป Instance Requirements

Development/Small

InstanceStandard_D8s_v5 / m6i.2xlarge
vCPU8
RAM32 GB
Storage500 GB Premium SSD v2
OSWindows Server 2022

Production (Standard)

InstanceStandard_D16s_v5 / m6i.4xlarge
vCPU16
RAM64 GB
Storage1 TB Premium SSD v2
OSWindows Server 2022

Production (HA)

Instances3+ VMs (Availability Sets)
RAM per VM64-128 GB
DatabaseManaged PostgreSQL HA (GP_Gen5_8+)
Load BalancerApp Gateway v2 / ALB

Azure Azure Deployment

1Create Resource Group and VNet

# Login to Azure az login # Create resource group az group create --name minusnow-rg --location eastus # Create VNet with subnets az network vnet create ` --resource-group minusnow-rg ` --name minusnow-vnet ` --address-prefix 10.0.0.0/16 az network vnet subnet create ` --resource-group minusnow-rg ` --vnet-name minusnow-vnet ` --name app-subnet ` --address-prefix 10.0.1.0/24 az network vnet subnet create ` --resource-group minusnow-rg ` --vnet-name minusnow-vnet ` --name db-subnet ` --address-prefix 10.0.2.0/24

2Create Azure Database for PostgreSQL

# Create PostgreSQL Flexible Server az postgres flexible-server create ` --resource-group minusnow-rg ` --name minusnow-itsm-db ` --location eastus ` --admin-user minusnowadmin ` --admin-password YourSecurePassword123! ` --sku-name Standard_B2s ` --tier Burstable ` --storage-size 128 ` --version 15 ` --high-availability ZoneRedundant # Create database az postgres flexible-server db create ` --resource-group minusnow-rg ` --server-name minusnow-itsm-db ` --database-name minusnow_itsm # Allow Azure services az postgres flexible-server firewall-rule create ` --resource-group minusnow-rg ` --name minusnow-itsm-db ` --rule-name AllowAzureServices ` --start-ip-address 0.0.0.0 ` --end-ip-address 0.0.0.0

3Create Windows Server VM

# Create Network Security Group az network nsg create --resource-group minusnow-rg --name minusnow-nsg # Allow RDP, HTTP, HTTPS az network nsg rule create --resource-group minusnow-rg --nsg-name minusnow-nsg ` --name AllowRDP --priority 1000 --destination-port-ranges 3389 --access Allow az network nsg rule create --resource-group minusnow-rg --nsg-name minusnow-nsg ` --name AllowHTTP --priority 1100 --destination-port-ranges 80 --access Allow az network nsg rule create --resource-group minusnow-rg --nsg-name minusnow-nsg ` --name AllowHTTPS --priority 1200 --destination-port-ranges 443 --access Allow # Create Windows Server 2022 VM az vm create ` --resource-group minusnow-rg ` --name minusnow-vm ` --image MicrosoftWindowsServer:WindowsServer:2022-datacenter-azure-edition:latest ` --size Standard_D4s_v3 ` --admin-username minusnowadmin ` --admin-password YourVMPassword123! ` --vnet-name minusnow-vnet ` --subnet app-subnet ` --nsg minusnow-nsg ` --public-ip-address minusnow-pip

4Create Application Gateway

# Create subnet for App Gateway az network vnet subnet create ` --resource-group minusnow-rg ` --vnet-name minusnow-vnet ` --name agw-subnet ` --address-prefix 10.0.3.0/24 # Create Application Gateway with SSL az network application-gateway create ` --resource-group minusnow-rg ` --name minusnow-agw ` --location eastus ` --sku Standard_v2 ` --capacity 2 ` --vnet-name minusnow-vnet ` --subnet agw-subnet ` --public-ip-address minusnow-agw-pip ` --http-settings-port 80 ` --http-settings-protocol Http ` --frontend-port 443 ` --servers 10.0.1.4

AWS AWS Deployment

1Create VPC and Security Groups

# Create VPC aws ec2 create-vpc --cidr-block 10.0.0.0/16 --tag-specifications "ResourceType=vpc,Tags=[{Key=Name,Value=minusnow-vpc}]" # Create subnets in different AZs aws ec2 create-subnet --vpc-id vpc-xxx --cidr-block 10.0.1.0/24 --availability-zone us-east-1a aws ec2 create-subnet --vpc-id vpc-xxx --cidr-block 10.0.2.0/24 --availability-zone us-east-1b # Create security group for Windows aws ec2 create-security-group --group-name minusnow-windows-sg --description "MinusNow Windows Server" --vpc-id vpc-xxx # Allow RDP, HTTP, HTTPS aws ec2 authorize-security-group-ingress --group-id sg-xxx --protocol tcp --port 3389 --cidr 0.0.0.0/0 aws ec2 authorize-security-group-ingress --group-id sg-xxx --protocol tcp --port 80 --cidr 0.0.0.0/0 aws ec2 authorize-security-group-ingress --group-id sg-xxx --protocol tcp --port 443 --cidr 0.0.0.0/0

2Create RDS PostgreSQL

# Create DB subnet group aws rds create-db-subnet-group ` --db-subnet-group-name minusnow-db-subnet ` --db-subnet-group-description "MinusNow DB Subnets" ` --subnet-ids subnet-xxx subnet-yyy # Create RDS PostgreSQL instance aws rds create-db-instance ` --db-instance-identifier minusnow-itsm-db ` --db-instance-class db.t3.medium ` --engine postgres ` --engine-version 15.4 ` --master-username minusnowadmin ` --master-user-password YourSecurePassword123! ` --allocated-storage 100 ` --storage-type gp3 ` --multi-az ` --backup-retention-period 7 ` --storage-encrypted ` --db-name minusnow_itsm

3Launch Windows Server EC2

# Get latest Windows Server 2022 AMI $AMI_ID = aws ec2 describe-images ` --owners amazon ` --filters "Name=name,Values=Windows_Server-2022-English-Full-Base-*" ` --query "sort_by(Images, &CreationDate)[-1].ImageId" ` --output text # Launch EC2 instance aws ec2 run-instances ` --image-id $AMI_ID ` --instance-type t3.xlarge ` --key-name minusnow-key ` --security-group-ids sg-xxx ` --subnet-id subnet-xxx ` --associate-public-ip-address ` --block-device-mappings "[{\"DeviceName\":\"/dev/sda1\",\"Ebs\":{\"VolumeSize\":256,\"VolumeType\":\"gp3\",\"Encrypted\":true}}]" ` --tag-specifications "ResourceType=instance,Tags=[{Key=Name,Value=minusnow-itsm-windows}]"

GCP Google Cloud Deployment

1Create VPC and Firewall

# Set project gcloud config set project your-project-id # Create VPC gcloud compute networks create minusnow-vpc --subnet-mode=custom # Create subnet gcloud compute networks subnets create minusnow-subnet \ --network=minusnow-vpc \ --region=us-central1 \ --range=10.0.1.0/24 # Create firewall rules gcloud compute firewall-rules create minusnow-allow-rdp \ --network=minusnow-vpc \ --allow=tcp:3389 \ --source-ranges=0.0.0.0/0 gcloud compute firewall-rules create minusnow-allow-web \ --network=minusnow-vpc \ --allow=tcp:80,tcp:443 \ --source-ranges=0.0.0.0/0

2Create Cloud SQL PostgreSQL

# Create Cloud SQL instance gcloud sql instances create minusnow-itsm-db \ --database-version=POSTGRES_15 \ --tier=db-custom-2-4096 \ --region=us-central1 \ --storage-type=SSD \ --storage-size=100GB \ --availability-type=REGIONAL # Create database gcloud sql databases create minusnow_itsm --instance=minusnow-itsm-db # Create user gcloud sql users create minusnowadmin \ --instance=minusnow-itsm-db \ --password=YourSecurePassword123!

3Create Windows Server Instance

# Create Windows Server 2022 instance gcloud compute instances create minusnow-vm \ --zone=us-central1-a \ --machine-type=e2-standard-4 \ --image-family=windows-2022 \ --image-project=windows-cloud \ --boot-disk-size=256GB \ --boot-disk-type=pd-ssd \ --network=minusnow-vpc \ --subnet=minusnow-subnet # Reset Windows password gcloud compute reset-windows-password minusnow-vm --zone=us-central1-a --user=minusnowadmin

๐ŸŒ IIS Configuration

After connecting to your Windows VM via RDP, configure IIS with URL Rewrite and ARR.

1Install IIS and Features

# Install IIS with all required features Install-WindowsFeature -Name Web-Server -IncludeManagementTools Install-WindowsFeature -Name Web-WebSockets Install-WindowsFeature -Name Web-Url-Auth Install-WindowsFeature -Name Web-IP-Security # Install URL Rewrite Module $url = "https://download.microsoft.com/download/1/2/8/128E2E22-C1B9-44A4-BE2A-5859ED1D4592/rewrite_amd64_en-US.msi" Invoke-WebRequest -Uri $url -OutFile "$env:TEMP\urlrewrite.msi" Start-Process msiexec.exe -ArgumentList "/i `"$env:TEMP\urlrewrite.msi`" /qn" -Wait # Install Application Request Routing $url = "https://download.microsoft.com/download/A/0/4/A04DF5F6-0A0B-43C6-B29C-2C6E1E63547D/requestRouter_amd64.msi" Invoke-WebRequest -Uri $url -OutFile "$env:TEMP\arr.msi" Start-Process msiexec.exe -ArgumentList "/i `"$env:TEMP\arr.msi`" /qn" -Wait

2Install Node.js

# Download and install Node.js LTS $nodeUrl = "https://nodejs.org/dist/v20.11.0/node-v20.11.0-x64.msi" Invoke-WebRequest -Uri $nodeUrl -OutFile "$env:TEMP\nodejs.msi" Start-Process msiexec.exe -ArgumentList "/i `"$env:TEMP\nodejs.msi`" /qn" -Wait # Refresh environment variables $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") # Verify installation node --version npm --version

3Deploy Application

# Create application directory New-Item -ItemType Directory -Path "C:\inetpub\minusnow-itsm" -Force Set-Location "C:\inetpub\minusnow-itsm" # Download application package (or copy via SCP/Azure Storage/S3) # Invoke-WebRequest -Uri "https://your-storage/minusnow-itsm.zip" -OutFile "minusnow-itsm.zip" # Expand-Archive -Path "minusnow-itsm.zip" -DestinationPath "." # Install dependencies npm install --production # Create .env file @" NODE_ENV=production DATABASE_URL=postgresql://minusnowadmin:password@your-db-host:5432/minusnow_itsm?sslmode=require SESSION_SECRET=$(New-Guid) "@ | Out-File -FilePath ".env" -Encoding UTF8

4Configure web.config

<?xml version="1.0" encoding="utf-8"?> <configuration> <system.webServer> <handlers> <add name="iisnode" path="dist/index.js" verb="*" modules="iisnode" /> </handlers> <rewrite> <rules> <!-- Reverse proxy with X-Forwarded headers --> <rule name="ReverseProxyToNode" stopProcessing="true"> <match url="(.*)" /> <serverVariables> <set name="HTTP_X_FORWARDED_FOR" value="{REMOTE_ADDR}" /> <set name="HTTP_X_FORWARDED_PROTO" value="{HTTPS}" /> <set name="HTTP_X_FORWARDED_HOST" value="{HTTP_HOST}" /> <set name="HTTP_X_REAL_IP" value="{REMOTE_ADDR}" /> </serverVariables> <action type="Rewrite" url="http://localhost:5000/{R:1}" /> </rule> </rules> <allowedServerVariables> <add name="HTTP_X_FORWARDED_FOR" /> <add name="HTTP_X_FORWARDED_PROTO" /> <add name="HTTP_X_FORWARDED_HOST" /> <add name="HTTP_X_REAL_IP" /> </allowedServerVariables> </rewrite> <proxy enabled="true" preserveHostHeader="true" /> <webSocket enabled="true" /> <iisnode node_env="production" loggingEnabled="true" /> </system.webServer> </configuration>
X-Forwarded Headers: Required when behind cloud load balancers (ALB, App Gateway, HTTP LB) to pass original client IP and protocol to the application.

5Create Windows Service with NSSM

# Download NSSM Invoke-WebRequest -Uri "https://nssm.cc/release/nssm-2.24.zip" -OutFile "$env:TEMP\nssm.zip" Expand-Archive -Path "$env:TEMP\nssm.zip" -DestinationPath "$env:TEMP" Copy-Item "$env:TEMP\nssm-2.24\win64\nssm.exe" -Destination "C:\Windows\System32" # Install service nssm install MinusNowITSM "C:\Program Files\nodejs\node.exe" nssm set MinusNowITSM AppParameters "dist/index.js" nssm set MinusNowITSM AppDirectory "C:\inetpub\minusnow-itsm" nssm set MinusNowITSM AppEnvironmentExtra "NODE_ENV=production" nssm set MinusNowITSM DisplayName "MinusNow ITSM Service" nssm set MinusNowITSM Description "MinusNow ITSM Application" nssm set MinusNowITSM Start SERVICE_AUTO_START nssm set MinusNowITSM AppStdout "C:\inetpub\minusnow-itsm\logs\stdout.log" nssm set MinusNowITSM AppStderr "C:\inetpub\minusnow-itsm\logs\stderr.log" nssm set MinusNowITSM AppRotateFiles 1 nssm set MinusNowITSM AppRotateBytes 10485760 # Start service nssm start MinusNowITSM

๐Ÿ—„๏ธ Managed Database Connection

Connection String Examples

# Azure Database for PostgreSQL DATABASE_URL=postgresql://minusnowadmin:password@minusnow-itsm-db.postgres.database.azure.com:5432/minusnow_itsm?sslmode=require # AWS RDS PostgreSQL DATABASE_URL=postgresql://minusnowadmin:password@minusnow-itsm-db.xxxx.us-east-1.rds.amazonaws.com:5432/minusnow_itsm?sslmode=require # GCP Cloud SQL (via Cloud SQL Auth Proxy) DATABASE_URL=postgresql://minusnowadmin:password@localhost:5432/minusnow_itsm
SSL/TLS: Always use sslmode=require for production database connections to ensure encrypted communication.

๐Ÿ”’ SSL/TLS Configuration

Option 1: Let's Encrypt with win-acme

# Download win-acme Invoke-WebRequest -Uri "https://github.com/win-acme/win-acme/releases/download/v2.2.9/win-acme.v2.2.9.1701.x64.trimmed.zip" -OutFile "$env:TEMP\win-acme.zip" Expand-Archive -Path "$env:TEMP\win-acme.zip" -DestinationPath "C:\win-acme" # Run interactive mode C:\win-acme\wacs.exe

Option 2: Import PFX Certificate

# Import certificate $password = ConvertTo-SecureString -String "CertPassword" -AsPlainText -Force Import-PfxCertificate -FilePath "C:\certs\minusnow-itsm.pfx" -CertStoreLocation Cert:\LocalMachine\My -Password $password # Bind to IIS site $cert = Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object {$_.Subject -like "*itsm.yourdomain.com*"} New-IISSiteBinding -Name "MinusNowITSM" -BindingInformation "*:443:" -Protocol https -CertificateThumbPrint $cert.Thumbprint -CertStoreLocation "Cert:\LocalMachine\My"

โš–๏ธ Load Balancing

Azure App Gateway

  • Layer 7 load balancing
  • WAF protection
  • SSL termination
  • Cookie-based affinity

AWS ALB

  • Application Load Balancer
  • Target groups
  • Health checks
  • Auto scaling integration

GCP HTTP(S) LB

  • Global load balancing
  • Cloud Armor WAF
  • Managed certificates
  • CDN integration

Health Check Endpoint

# Configure health check path: /health # Response: HTTP 200 OK with JSON body { "status": "healthy", "timestamp": "2024-01-15T10:30:00Z" }

๐Ÿ“Š Monitoring

Azure Monitor

# Install Azure Monitor agent Invoke-WebRequest -Uri "https://aka.ms/AzureMonitorAgentInstaller" -OutFile "$env:TEMP\AMAInstaller.exe" Start-Process "$env:TEMP\AMAInstaller.exe" -ArgumentList "/silent" -Wait

AWS CloudWatch

# Install CloudWatch agent $url = "https://s3.amazonaws.com/amazoncloudwatch-agent/windows/amd64/latest/amazon-cloudwatch-agent.msi" Invoke-WebRequest -Uri $url -OutFile "$env:TEMP\cw-agent.msi" Start-Process msiexec.exe -ArgumentList "/i `"$env:TEMP\cw-agent.msi`" /qn" -Wait

Windows Event Logging

# Create custom event log source New-EventLog -LogName Application -Source "MinusNowITSM" # Write events Write-EventLog -LogName Application -Source "MinusNowITSM" -EventId 1000 -EntryType Information -Message "Application started" # View logs Get-EventLog -LogName Application -Source "MinusNowITSM" -Newest 50

๐Ÿ”„ Backup & Recovery

Database Backup

Managed database services provide automated backups:

  • Azure: Point-in-time restore up to 35 days
  • AWS RDS: Automated snapshots, 35-day retention
  • GCP: Automated backups with geo-redundancy

Application Backup

# Backup script $timestamp = Get-Date -Format "yyyyMMdd-HHmmss" $backupPath = "C:\Backups\minusnow-$timestamp" Copy-Item -Path "C:\inetpub\minusnow-itsm\data" -Destination $backupPath -Recurse # Upload to Azure Blob azcopy copy $backupPath "https://mystorageaccount.blob.core.windows.net/backups/" --recursive

๐Ÿ”ง Troubleshooting

IIS Issues

# Check IIS logs Get-Content "C:\inetpub\logs\LogFiles\W3SVC1\*.log" -Tail 50 # Reset IIS iisreset /restart # Check URL Rewrite rules Get-WebConfiguration -Filter "/system.webServer/rewrite/rules/*" -PSPath "IIS:\Sites\MinusNowITSM"

Service Issues

# Check service status Get-Service MinusNowITSM nssm status MinusNowITSM # View service logs Get-Content "C:\inetpub\minusnow-itsm\logs\stderr.log" -Tail 100 # Restart service Restart-Service MinusNowITSM

Database Connection

# Test PostgreSQL connection Test-NetConnection -ComputerName "your-db-host" -Port 5432 # Check firewall rules Get-NetFirewallRule | Where-Object {$_.DisplayName -like "*PostgreSQL*"}

Network Diagnostics

# Check listening ports netstat -an | findstr "5000" netstat -an | findstr "80" netstat -an | findstr "443" # Test local app Invoke-WebRequest -Uri "http://localhost:5000/health" -UseBasicParsing