MinusNow Documentation

⚠️ CRITICAL: Why Single Server Deployment is NOT Recommended

A single-server deployment (application + database on same server) poses significant risks:

RiskImpactConsequence
Hardware FailureComplete system outageAll ITSM operations halt, tickets unreachable
Disk FailureData lossIncidents, changes, assets, CMDB data permanently lost
Memory ExhaustionApplication crashDatabase corruption possible during crash
No FailoverExtended downtimeSLA breaches, customer dissatisfaction
Maintenance WindowsService unavailableCannot patch/upgrade without downtime
Performance BottleneckSlow responseApp and DB compete for resources
Real-World Scenario: If a single server hosting both application and database experiences disk failure, you lose:
  • All incident history and SLA records
  • CMDB and asset relationships
  • Change management audit trails
  • Knowledge base articles
  • Customer data and configurations
Recovery could take days and data may be unrecoverable.

📋 Third-Party Integration & Licensing Requirements

Important Licensing Notice

MinusNow integrates with various third-party systems. Customers are responsible for obtaining appropriate licenses from their respective vendors for any third-party software or services used.

Open Source vs Licensed Components

ComponentOpen Source (Free)Licensed Version (Requires Purchase)
PostgreSQLPostgreSQL (MIT)EnterpriseDB, AWS RDS PostgreSQL
RedisRedis OSSRedis Enterprise (clustering, HA)
LDAP/ADOpenLDAPMicrosoft Active Directory
SMTPPostfix, hMailServerExchange, Office 365, SendGrid
MonitoringPrometheus, Grafana OSSDatadog, New Relic, Grafana Enterprise
Backuppg_dump, rsyncVeeam, Commvault, AWS Backup
Load BalancerHAProxy, Nginx OSSF5, AWS ALB/NLB, Azure LB
SSL CertificatesLet's EncryptDigiCert, GlobalSign, Sectigo

License Procurement Checklist

Before deploying MinusNow in production, ensure you have:

  • Database License - PostgreSQL (free) or commercial variant with support
  • Operating System License - Windows Server CALs, RHEL subscription, or free alternatives
  • SSL/TLS Certificate - Valid certificate from trusted CA
  • SMTP Service - Email relay service (SendGrid, AWS SES, or enterprise email)
  • Load Balancer - Hardware or software load balancer license if applicable
  • Monitoring Tools - Enterprise monitoring licenses if using commercial tools
  • Backup Software - Enterprise backup solution license
  • Active Directory - Windows Server CALs for AD integration

Vendor Contact Information

VendorProductLicensing Portal
MicrosoftWindows Server, SQL Server, ADmicrosoft.com/licensing
Red HatRHELredhat.com/en/store
EnterpriseDBPostgreSQL Enterpriseenterprisedb.com/pricing
Redis LabsRedis Enterpriseredis.com/pricing
VMwarevSpherevmware.com/products

🏗️ Recommended Enterprise Architecture

Minimum Production Architecture (High Availability)

┌─────────────────────────────────────┐ │ INTERNET │ └──────────────┬──────────────────────┘ │ ▼ ┌──────────────────────────────┐ │ Load Balancer (HA) │ │ (HAProxy / Nginx / ALB) │ │ Port 443 (HTTPS) │ └──────────┬───────────────────┘ │ ┌─────────────────┴─────────────────┐ │ │ ▼ ▼ ┌───────────────────────┐ ┌───────────────────────┐ │ APP SERVER 1 │ │ APP SERVER 2 │ │ (Primary Node) │ │ (Secondary Node) │ │ • Node.js 20 LTS │ │ • Node.js 20 LTS │ │ • Port 5000 │ │ • Port 5000 │ │ CPU: 4+ cores │ │ CPU: 4+ cores │ │ RAM: 8-16 GB │ │ RAM: 8-16 GB │ └───────────┬───────────┘ └───────────┬───────────┘ │ │ └─────────────────┬───────────────┘ │ ▼ ┌──────────────────────────────┐ │ SHARED FILE STORAGE │ │ (NFS / Azure Files / EFS) │ │ • /data • /audit-logs │ └──────────────────────────────┘ │ ┌─────────────────┴─────────────────┐ │ │ ▼ ▼ ┌───────────────────────┐ ┌───────────────────────┐ │ DATABASE SERVER 1 │ │ DATABASE SERVER 2 │ │ (Primary) │◄───────►│ (Replica/Standby) │ │ • PostgreSQL 15+ │ Sync │ • PostgreSQL 15+ │ │ CPU: 4+ cores │ │ CPU: 4+ cores │ │ RAM: 16-32 GB │ │ RAM: 16-32 GB │ │ Storage: 500 GB SSD │ │ Storage: 500 GB SSD │ └───────────────────────┘ └───────────────────────┘

Server Roles and Responsibilities

Server RolePrimary FunctionMinimum SpecsRecommended Specs
Load BalancerTraffic distribution, SSL termination, health checks2 CPU, 4 GB RAM4 CPU, 8 GB RAM
App Server (Primary)Request processing, business logic, API handling4 CPU, 8 GB RAM8 CPU, 16 GB RAM
App Server (Secondary)Failover, load sharing, horizontal scaling4 CPU, 8 GB RAM8 CPU, 16 GB RAM
DB Server (Primary)Data storage, query processing, transactions4 CPU, 16 GB RAM8 CPU, 32 GB RAM
DB Server (Replica)Read replicas, failover, backup source4 CPU, 16 GB RAM8 CPU, 32 GB RAM

🔧 Step 1: Load Balancer Configuration

Option A: HAProxy (Open Source)

Installation (Ubuntu/Debian):

sudo apt update sudo apt install haproxy -y

Configuration (/etc/haproxy/haproxy.cfg):

global log /dev/log local0 chroot /var/lib/haproxy stats socket /run/haproxy/admin.sock mode 660 level admin user haproxy group haproxy daemon ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256 ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets defaults log global mode http option httplog timeout connect 5000 timeout client 50000 timeout server 50000 frontend https_front bind *:443 ssl crt /etc/ssl/private/minusnow.pem bind *:80 redirect scheme https code 301 if !{ ssl_fc } # Security headers http-response set-header Strict-Transport-Security "max-age=31536000; includeSubDomains" http-response set-header X-Content-Type-Options "nosniff" http-response set-header X-Frame-Options "SAMEORIGIN" default_backend minusnow_app_servers backend minusnow_app_servers balance roundrobin option httpchk GET /health http-check expect status 200 # Sticky sessions cookie SERVERID insert indirect nocache # Application servers server app1 10.0.1.10:5000 check cookie app1 weight 100 server app2 10.0.1.11:5000 check cookie app2 weight 100 backup listen stats bind 127.0.0.1:8404 stats enable stats uri /stats stats refresh 10s

Enable and start HAProxy:

sudo systemctl enable haproxy sudo systemctl start haproxy sudo systemctl status haproxy

Option B: Nginx (Open Source)

upstream minusnow_backend { least_conn; server 10.0.1.10:5000 weight=5; server 10.0.1.11:5000 weight=5 backup; keepalive 32; } server { listen 80; server_name minusnow.yourdomain.com; return 301 https://$server_name$request_uri; } server { listen 443 ssl http2; server_name minusnow.yourdomain.com; ssl_certificate /etc/ssl/certs/minusnow.crt; ssl_certificate_key /etc/ssl/private/minusnow.key; ssl_protocols TLSv1.2 TLSv1.3; # Security Headers add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header X-Content-Type-Options "nosniff" always; add_header X-Frame-Options "SAMEORIGIN" always; location / { proxy_pass http://minusnow_backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }

🔧 Step 2: Application Server Configuration

Install Node.js 20 LTS

Ubuntu/Debian:

curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - sudo apt install -y nodejs node --version # Should show v20.x.x npm --version

RHEL/CentOS:

curl -fsSL https://rpm.nodesource.com/setup_20.x | sudo bash - sudo yum install -y nodejs

Windows Server (PowerShell):

winget install OpenJS.NodeJS.LTS

Deploy MinusNow Application

# Create application directory sudo mkdir -p /opt/minusnow sudo chown -R $USER:$USER /opt/minusnow cd /opt/minusnow # Copy application files from deployment package # Install dependencies npm install --production # Build the application npm run build

Create Systemd Service (Linux)

File: /etc/systemd/system/minusnow.service

[Unit] Description=MinusNow ITSM Platform After=network.target [Service] Type=simple User=minusnow Group=minusnow WorkingDirectory=/opt/minusnow ExecStart=/usr/bin/node dist/index.cjs Restart=always RestartSec=10 Environment=NODE_ENV=production Environment=PORT=5000 Environment=DATABASE_URL=postgres://minusnow:password@10.0.2.10:5432/minusnow_db LimitNOFILE=65535 NoNewPrivileges=true ProtectSystem=strict ReadWritePaths=/opt/minusnow/data /opt/minusnow/audit-logs [Install] WantedBy=multi-user.target
sudo systemctl daemon-reload sudo systemctl enable minusnow sudo systemctl start minusnow

🔧 Step 3: Database Server Configuration

PostgreSQL Installation

Ubuntu/Debian:

sudo apt install postgresql-15 postgresql-contrib-15 -y sudo systemctl enable postgresql sudo systemctl start postgresql

RHEL/CentOS:

sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-8-x86_64/pgdg-redhat-repo-latest.noarch.rpm sudo dnf install -y postgresql15-server postgresql15-contrib sudo /usr/pgsql-15/bin/postgresql-15-setup initdb sudo systemctl enable postgresql-15 sudo systemctl start postgresql-15

Configure PostgreSQL for Production

Edit /etc/postgresql/15/main/postgresql.conf:

# Connection Settings listen_addresses = '*' port = 5432 max_connections = 200 # Memory Settings (adjust based on RAM) shared_buffers = 4GB # 25% of RAM effective_cache_size = 12GB # 75% of RAM maintenance_work_mem = 1GB work_mem = 64MB # Write Ahead Log (for replication) wal_level = replica max_wal_senders = 3 wal_keep_size = 1GB # Performance (for SSD) random_page_cost = 1.1 effective_io_concurrency = 200

Create Database and User

sudo -u postgres psql -- Create application user CREATE USER minusnow WITH ENCRYPTED PASSWORD 'YourSecurePassword123!'; -- Create database CREATE DATABASE minusnow_db OWNER minusnow; -- Grant privileges GRANT ALL PRIVILEGES ON DATABASE minusnow_db TO minusnow; -- Create replication user CREATE USER replicator WITH REPLICATION ENCRYPTED PASSWORD 'ReplicatorPassword123!'; \q

🔧 Step 4: Database Replication (Replica Server)

Set Up Streaming Replication

On Replica Server:

# 1. Stop PostgreSQL and clear data directory sudo systemctl stop postgresql sudo rm -rf /var/lib/postgresql/15/main/* # 2. Take base backup from primary sudo -u postgres pg_basebackup -h 10.0.2.10 -D /var/lib/postgresql/15/main -U replicator -P -R -X stream # 3. Verify standby.signal file exists ls -la /var/lib/postgresql/15/main/standby.signal # 4. Start PostgreSQL on replica sudo systemctl start postgresql # 5. Verify replication status on primary psql -U postgres -c "SELECT client_addr, state, sync_state FROM pg_stat_replication;"

🔧 Step 5: Shared Storage Configuration

Option A: NFS (Linux)

NFS Server Setup:

sudo apt install nfs-kernel-server -y sudo mkdir -p /exports/minusnow/{data,audit-logs,support-tickets,artifacts} sudo chown -R nobody:nogroup /exports/minusnow echo "/exports/minusnow 10.0.1.0/24(rw,sync,no_subtree_check,no_root_squash)" | sudo tee -a /etc/exports sudo exportfs -ra sudo systemctl restart nfs-kernel-server

NFS Client Setup (App Servers):

sudo apt install nfs-common -y sudo mkdir -p /opt/minusnow/{data,audit-logs,support-tickets,artifacts} # Add to /etc/fstab echo "10.0.3.10:/exports/minusnow/data /opt/minusnow/data nfs defaults 0 0" | sudo tee -a /etc/fstab sudo mount -a

🔧 Step 6: Environment Variables Configuration

Create Environment File

File: /opt/minusnow/.env

# Application Settings NODE_ENV=production PORT=5000 APP_BASE_URL=https://minusnow.yourdomain.com # Session Security SESSION_SECRET=your-secure-random-string-minimum-32-characters-long # Database Configuration DATABASE_URL=postgres://minusnow:YourSecurePassword@10.0.2.10:5432/minusnow_db # Email Configuration (SMTP) SMTP_HOST=smtp.yourdomain.com SMTP_PORT=587 SMTP_USER=noreply@yourdomain.com SMTP_PASS=your-smtp-password # Support Email SUPPORT_EMAIL=support@yourdomain.com # Optional: Redis (for session clustering) REDIS_URL=redis://10.0.4.10:6379

🔗 Step 7: Application and Database Server Integration

Network Architecture

┌─────────────────────────────────────────────────────────────────────────────┐ │ PRIVATE NETWORK (10.0.0.0/16) │ ├─────────────────────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────────────┐ ┌─────────────────────────────────────┐ │ │ │ APP SERVER 1 │ │ DATABASE TIER │ │ │ │ 10.0.1.10:5000 │────────►│ │ │ │ │ │ │ ┌─────────────────┐ │ │ │ │ DATABASE_URL= │ │ │ PRIMARY DB │ │ │ │ │ postgres://minusnow: │ │ │ 10.0.2.10:5432 │ │ │ │ │ @10.0.2.10:5432/db │ │ └────────┬────────┘ │ │ │ └─────────────────────┘ │ │ Streaming │ │ │ │ │ Replication │ │ │ ┌─────────────────────┐ │ ▼ │ │ │ │ APP SERVER 2 │ │ ┌─────────────────┐ │ │ │ │ 10.0.1.11:5000 │────────►│ │ REPLICA DB │ │ │ │ │ │ │ │ 10.0.2.11:5432 │ │ │ │ └─────────────────────┘ │ │ (Read-Only) │ │ │ │ │ └─────────────────┘ │ │ └─────────────────────────────────────────────────────────────────────────────┘

Pre-Integration Checklist

StepTaskCommand to Verify
1Database server is runningsystemctl status postgresql
2Database user createdpsql -U postgres -c "\du"
3Database createdpsql -U postgres -c "\l"
4Network connectivitync -zv 10.0.2.10 5432
5Firewall allows 5432sudo iptables -L -n | grep 5432
6pg_hba.conf allows app IPsCheck /etc/postgresql/15/main/pg_hba.conf

Configure Database Access

On Database Server - Add to pg_hba.conf:

# Allow connections from Application Servers host minusnow_db minusnow 10.0.1.10/32 scram-sha-256 host minusnow_db minusnow 10.0.1.11/32 scram-sha-256 # Or allow entire app subnet host minusnow_db minusnow 10.0.1.0/24 scram-sha-256

Open firewall:

# Ubuntu/Debian (ufw) sudo ufw allow from 10.0.1.0/24 to any port 5432 # RHEL/CentOS (firewalld) sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.0.1.0/24" port protocol="tcp" port="5432" accept' sudo firewall-cmd --reload

Test Database Connectivity

# Install PostgreSQL client sudo apt install postgresql-client -y # Test connection from App Server psql -h 10.0.2.10 -U minusnow -d minusnow_db -c "SELECT version();"

Initialize Database Schema

cd /opt/minusnow # Run database migrations npm run db:push # Or if using Drizzle npx drizzle-kit push # Verify tables created psql -h 10.0.2.10 -U minusnow -d minusnow_db -c "\dt"

🔄 Step 8: Primary and Secondary Application Server Configuration

Active-Active vs Active-Passive

ConfigurationDescriptionUse Case
Active-ActiveBoth servers handle requests simultaneouslyHigh traffic, load balancing
Active-PassiveSecondary only activates if primary failsCost-sensitive, disaster recovery

Active-Active Configuration (Recommended)

┌─────────────────────┐ │ Load Balancer │ │ (HAProxy/Nginx) │ └──────────┬──────────┘ │ ┌────────────────┴────────────────┐ │ │ ▼ ▼ ┌─────────────────┐ ┌─────────────────┐ │ APP SERVER 1 │ │ APP SERVER 2 │ │ 10.0.1.10:5000 │ │ 10.0.1.11:5000 │ │ Weight: 100 │ │ Weight: 100 │ └─────────┬───────┘ └─────────┬───────┘ │ │ └────────────┬────────────────────┘ │ ▼ ┌─────────────────────┐ │ Shared Storage │ └─────────────────────┘

HAProxy Configuration:

backend minusnow_app_servers balance roundrobin option httpchk GET /health http-check expect status 200 cookie SERVERID insert indirect nocache # Both servers active with equal weight server app1 10.0.1.10:5000 check cookie app1 weight 100 server app2 10.0.1.11:5000 check cookie app2 weight 100 default-server inter 5s fall 3 rise 2

Session Management with Redis

For multi-server deployments, use Redis for centralized session storage:

# Install Redis sudo apt install redis-server -y # Configure Redis (/etc/redis/redis.conf) bind 10.0.4.10 protected-mode no maxmemory 256mb maxmemory-policy allkeys-lru

Add to application .env:

REDIS_URL=redis://10.0.4.10:6379 SESSION_STORE=redis

Shared File Storage Requirements

Both application servers must mount the same shared directories:

/opt/minusnow/ ├── data/ ← MUST BE SHARED (NFS/EFS) ├── audit-logs/ ← MUST BE SHARED ├── support-tickets/ ← MUST BE SHARED ├── artifacts/ ← MUST BE SHARED └── uploads/ ← MUST BE SHARED

Rolling Deployment (Zero Downtime)

# Step 1: Remove app2 from load balancer (set weight to 0) # Step 2: Deploy to app2 ssh app2 "cd /opt/minusnow && git pull && npm run build && sudo systemctl restart minusnow" # Step 3: Verify app2 is healthy curl -s http://10.0.1.11:5000/health # Step 4: Add app2 back, remove app1 # Step 5: Deploy to app1 ssh app1 "cd /opt/minusnow && git pull && npm run build && sudo systemctl restart minusnow" # Step 6: Add app1 back to load balancer

📊 Monitoring & Health Checks

Application Health Endpoints

EndpointDescriptionExpected Response
GET /healthBasic health check200 OK
GET /api/telemetry/healthDetailed health statusJSON with component status
GET /api/telemetry/overviewSystem metricsJSON with performance data

Alerting Thresholds

MetricWarningCritical
CPU Usage> 70%> 90%
Memory Usage> 75%> 90%
Disk Usage> 70%> 85%
Response Time> 2s> 5s
Error Rate> 1%> 5%
DB Replication Lag> 1 min> 5 min

🔄 Backup & Disaster Recovery

Backup Strategy

Data TypeFrequencyRetentionMethod
DatabaseEvery 6 hours30 dayspg_dump + WAL archiving
File StorageDaily30 daysrsync / cloud snapshots
ConfigurationOn change90 daysGit / version control
Audit LogsWeekly1 yearArchive to cold storage

Database Backup Script

#!/bin/bash # /opt/scripts/backup-database.sh BACKUP_DIR="/backups/postgresql" DATE=$(date +%Y%m%d_%H%M%S) DB_NAME="minusnow_db" DB_USER="minusnow" DB_HOST="10.0.2.10" # Create backup PGPASSWORD="$DB_PASSWORD" pg_dump -h $DB_HOST -U $DB_USER -Fc $DB_NAME > $BACKUP_DIR/${DB_NAME}_${DATE}.dump # Compress gzip $BACKUP_DIR/${DB_NAME}_${DATE}.dump # Remove backups older than 30 days find $BACKUP_DIR -name "*.dump.gz" -mtime +30 -delete # Copy to offsite storage aws s3 cp $BACKUP_DIR/${DB_NAME}_${DATE}.dump.gz s3://your-backup-bucket/postgresql/

✅ Pre-Production Checklist

Infrastructure

  • Load balancer configured and tested
  • Primary and secondary app servers deployed
  • Primary and replica database configured
  • Shared storage mounted and accessible
  • Network firewall rules in place
  • SSL certificates installed and valid

Security

  • All passwords meet complexity requirements
  • SSH key-based authentication only
  • Database access restricted to app servers
  • WAF configured (if applicable)
  • Security headers configured
  • Rate limiting enabled

Operational

  • Monitoring agents installed
  • Alerting rules configured
  • Backup jobs scheduled
  • Disaster recovery plan documented
  • Runbooks created for common issues
  • On-call rotation established

Licensing

  • All third-party licenses procured
  • License keys documented and secured
  • Renewal dates tracked
  • Compliance requirements met

📞 Support

Need Help with Enterprise Deployment?

For additional assistance with enterprise deployment: