MinusNow Documentation

📑 Table of Contents

🔍 Overview

This guide provides step-by-step instructions for deploying MinusNow ITSM on a Linux on-premises server. The application is a Node.js-based IT Service Management platform with PostgreSQL database backend.

Architecture Diagram

┌─────────────────────────────────────────────────────────────────┐ │ Load Balancer / DNS │ └─────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ Reverse Proxy (Nginx/Apache) │ │ Port 80/443 (SSL) │ └─────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ MinusNow ITSM Application │ │ Node.js (Port 5000) │ └─────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ PostgreSQL Database │ │ Port 5432 │ └─────────────────────────────────────────────────────────────────┘

💻 Server Requirements

Hardware Requirements

ComponentMinimumRecommendedEnterprise
CPU8 vCPU (x86_64)16 vCPU (Xeon/EPYC)32+ vCPU (Xeon/EPYC)
RAM32 GB DDR464 GB DDR4128+ GB DDR4/DDR5
Storage500 GB NVMe SSD1 TB NVMe SSD2+ TB NVMe SSD RAID
Swap64 GB128 GB256 GB
Network1 Gbps10 Gbps25 Gbps+

Software Requirements

ComponentVersionPurpose
OSUbuntu 24.04 LTS / RHEL 9+ / Rocky Linux 9+Operating System
Node.js22.x LTS (Minimum 20.x LTS)Application Runtime
PostgreSQL16+ (Minimum 15)Database Server
Nginx1.24+ (Minimum 1.22)Reverse Proxy
PM25.3+ LatestProcess Manager
Certbot2.x LatestSSL Certificates
OpenSSL3.x+TLS/SSL Support

Network Requirements

PortProtocolDirectionPurpose
22TCPInboundSSH Access
80TCPInboundHTTP (Redirect to HTTPS)
443TCPInboundHTTPS
5000TCPInternalApplication
5432TCPInternalPostgreSQL
25/587TCPOutboundSMTP Email

📋 Pre-Installation Checklist

Before proceeding, ensure you have:

  • Root or sudo access to the server
  • Static IP address assigned
  • DNS A record pointing to server IP (e.g., itsm.yourdomain.com)
  • SMTP server credentials for email notifications
  • SSL certificate (or use Let's Encrypt)
  • Firewall rules configured
  • Backup storage location identified

🔧 Server Preparation

1System Update

# Ubuntu/Debian sudo apt update && sudo apt upgrade -y sudo apt install -y curl wget git unzip htop vim net-tools # RHEL/CentOS sudo dnf update -y sudo dnf install -y curl wget git unzip htop vim net-tools

2Set Hostname and Timezone

# Set hostname sudo hostnamectl set-hostname itsm-server # Set timezone sudo timedatectl set-timezone America/New_York # Adjust to your timezone timedatectl # Update /etc/hosts echo "$(hostname -I | awk '{print $1}') itsm-server" | sudo tee -a /etc/hosts

3Configure Swap Space

# Check current swap swapon --show # Create swap file (4GB example) sudo fallocate -l 4G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile # Make permanent echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab # Optimize swap settings echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.conf echo 'vm.vfs_cache_pressure=50' | sudo tee -a /etc/sysctl.conf sudo sysctl -p

4Configure Firewall

# Ubuntu (UFW) sudo ufw allow 22/tcp sudo ufw allow 80/tcp sudo ufw allow 443/tcp sudo ufw enable sudo ufw status # RHEL/CentOS (firewalld) sudo firewall-cmd --permanent --add-service=ssh sudo firewall-cmd --permanent --add-service=http sudo firewall-cmd --permanent --add-service=https sudo firewall-cmd --reload sudo firewall-cmd --list-all

5Configure System Limits

# Edit limits.conf sudo tee -a /etc/security/limits.conf << EOF * soft nofile 65535 * hard nofile 65535 * soft nproc 65535 * hard nproc 65535 EOF # Edit sysctl.conf for network optimization sudo tee -a /etc/sysctl.conf << EOF net.core.somaxconn = 65535 net.ipv4.tcp_max_syn_backlog = 65535 net.ipv4.ip_local_port_range = 1024 65535 net.ipv4.tcp_tw_reuse = 1 EOF sudo sysctl -p

6Create Application User

# Create dedicated user for the application sudo useradd -m -s /bin/bash minusnow sudo usermod -aG sudo minusnow # Create application directories sudo mkdir -p /opt/minusnow-itsm sudo mkdir -p /var/log/minusnow sudo mkdir -p /var/lib/minusnow/data sudo mkdir -p /var/lib/minusnow/backups # Set ownership sudo chown -R minusnow:minusnow /opt/minusnow-itsm sudo chown -R minusnow:minusnow /var/log/minusnow sudo chown -R minusnow:minusnow /var/lib/minusnow

🗄️ Database Installation

1Install PostgreSQL

# Ubuntu/Debian sudo apt install -y postgresql postgresql-contrib # RHEL/CentOS sudo dnf install -y postgresql-server postgresql-contrib sudo postgresql-setup --initdb

2Start PostgreSQL Service

sudo systemctl start postgresql sudo systemctl enable postgresql sudo systemctl status postgresql

3Create Database and User

# Switch to postgres user sudo -u postgres psql # In PostgreSQL shell, run: CREATE USER minusnow WITH PASSWORD 'your_secure_password_here'; CREATE DATABASE minusnow_itsm OWNER minusnow; GRANT ALL PRIVILEGES ON DATABASE minusnow_itsm TO minusnow; # Enable required extensions \c minusnow_itsm CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; CREATE EXTENSION IF NOT EXISTS "pg_trgm"; \q

4Configure PostgreSQL Authentication

# Edit pg_hba.conf sudo vim /etc/postgresql/15/main/pg_hba.conf # Ubuntu # or sudo vim /var/lib/pgsql/data/pg_hba.conf # RHEL # Add/modify these lines: # TYPE DATABASE USER ADDRESS METHOD local all minusnow md5 host all minusnow 127.0.0.1/32 md5 host all minusnow ::1/128 md5

5Configure PostgreSQL Performance

# Edit postgresql.conf - Recommended settings (adjust based on server RAM): shared_buffers = 2GB # 25% of RAM effective_cache_size = 6GB # 75% of RAM maintenance_work_mem = 512MB checkpoint_completion_target = 0.9 wal_buffers = 64MB default_statistics_target = 100 random_page_cost = 1.1 effective_io_concurrency = 200 work_mem = 52428kB min_wal_size = 1GB max_wal_size = 4GB max_worker_processes = 4 max_parallel_workers_per_gather = 2 max_parallel_workers = 4

6Restart PostgreSQL

sudo systemctl restart postgresql sudo systemctl status postgresql # Test connection psql -U minusnow -d minusnow_itsm -h localhost -c "SELECT version();"

📦 Application Installation

1Install Node.js

# Install Node.js 20.x LTS curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - sudo apt install -y nodejs # Verify installation node --version # Should show v20.x.x npm --version # Install PM2 globally sudo npm install -g pm2

2Download Application

Option A: From Downloads Portal

# Download from portal # https://www.minusnow.com/site/downloads # Transfer to server scp minusnow-itsm-artifact.zip user@server:/tmp/ # On server cd /opt/minusnow-itsm sudo -u minusnow unzip /tmp/minusnow-itsm-artifact.zip -d .

Option B: Installation Script

# Download and run installation script curl -fsSL https://www.minusnow.com/site/download/install-linux.sh -o install.sh chmod +x install.sh sudo ./install.sh

Option C: From Source

# Clone repository cd /opt/minusnow-itsm sudo -u minusnow git clone https://github.com/minusnow/itsm.git . # Install dependencies sudo -u minusnow npm install # Build application sudo -u minusnow npm run build

3Configure Environment Variables

# Create environment file sudo -u minusnow tee /opt/minusnow-itsm/.env << EOF # Application NODE_ENV=production PORT=5000 HOST=0.0.0.0 # Database DATABASE_URL=postgresql://minusnow:your_secure_password_here@localhost:5432/minusnow_itsm # Session SESSION_SECRET=$(openssl rand -hex 32) # Email (SMTP) SMTP_HOST=smtp.yourdomain.com SMTP_PORT=587 SMTP_USER=noreply@yourdomain.com SMTP_PASS=your_smtp_password SMTP_FROM=MinusNow ITSM <noreply@yourdomain.com> # Application URL APP_URL=https://itsm.yourdomain.com # File Storage DATA_DIR=/var/lib/minusnow/data BACKUP_DIR=/var/lib/minusnow/backups # Logging LOG_LEVEL=info LOG_DIR=/var/log/minusnow EOF # Secure the file sudo chmod 600 /opt/minusnow-itsm/.env sudo chown minusnow:minusnow /opt/minusnow-itsm/.env

4Initialize Database Schema

cd /opt/minusnow-itsm sudo -u minusnow npm run db:push # Or run migrations sudo -u minusnow npm run db:migrate

⚙️ Service Configuration

1Create PM2 Ecosystem File

sudo -u minusnow tee /opt/minusnow-itsm/ecosystem.config.js << EOF module.exports = { apps: [{ name: 'minusnow-itsm', script: 'dist/index.js', cwd: '/opt/minusnow-itsm', instances: 'max', exec_mode: 'cluster', env: { NODE_ENV: 'production', PORT: 5000 }, env_file: '/opt/minusnow-itsm/.env', error_file: '/var/log/minusnow/error.log', out_file: '/var/log/minusnow/out.log', log_file: '/var/log/minusnow/combined.log', time: true, max_memory_restart: '1G', restart_delay: 5000, max_restarts: 10, autorestart: true, watch: false }] }; EOF

2Start Application with PM2

cd /opt/minusnow-itsm sudo -u minusnow pm2 start ecosystem.config.js # Save PM2 configuration sudo -u minusnow pm2 save # Setup PM2 startup script sudo env PATH=$PATH:/usr/bin pm2 startup systemd -u minusnow --hp /home/minusnow

3Alternative: Systemd Service

sudo tee /etc/systemd/system/minusnow-itsm.service << EOF [Unit] Description=MinusNow ITSM Application After=network.target postgresql.service [Service] Type=simple User=minusnow Group=minusnow WorkingDirectory=/opt/minusnow-itsm EnvironmentFile=/opt/minusnow-itsm/.env ExecStart=/usr/bin/node dist/index.js Restart=always RestartSec=10 StandardOutput=append:/var/log/minusnow/out.log StandardError=append:/var/log/minusnow/error.log # Security NoNewPrivileges=true PrivateTmp=true ProtectSystem=strict ReadWritePaths=/var/lib/minusnow /var/log/minusnow [Install] WantedBy=multi-user.target EOF # Enable and start service sudo systemctl daemon-reload sudo systemctl enable minusnow-itsm sudo systemctl start minusnow-itsm sudo systemctl status minusnow-itsm

🌐 Reverse Proxy Setup (Nginx)

# Install Nginx sudo apt install -y nginx # Create Nginx configuration sudo tee /etc/nginx/sites-available/minusnow-itsm << 'EOF' # Rate limiting limit_req_zone $binary_remote_addr zone=minusnow_limit:10m rate=10r/s; # Upstream upstream minusnow_backend { server 127.0.0.1:5000; keepalive 32; } # HTTP - Redirect to HTTPS server { listen 80; listen [::]:80; server_name itsm.yourdomain.com; location /.well-known/acme-challenge/ { root /var/www/certbot; } location / { return 301 https://$host$request_uri; } } # HTTPS server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name itsm.yourdomain.com; # SSL certificates (configure after certbot) ssl_certificate /etc/letsencrypt/live/itsm.yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/itsm.yourdomain.com/privkey.pem; # SSL configuration ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers off; ssl_session_timeout 1d; ssl_session_cache shared:SSL:50m; ssl_stapling on; ssl_stapling_verify on; # Security headers add_header X-Frame-Options "SAMEORIGIN" always; add_header X-XSS-Protection "1; mode=block" always; add_header X-Content-Type-Options "nosniff" always; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; # Logging access_log /var/log/nginx/minusnow-access.log; error_log /var/log/nginx/minusnow-error.log; # Client body size (for file uploads) client_max_body_size 100M; # Gzip compression gzip on; gzip_types text/plain text/css application/json application/javascript text/xml application/xml; gzip_min_length 1000; # Rate limiting limit_req zone=minusnow_limit burst=20 nodelay; # Main location 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; proxy_cache_bypass $http_upgrade; proxy_read_timeout 300s; proxy_connect_timeout 75s; } # Health check endpoint location /health { proxy_pass http://minusnow_backend; access_log off; } } EOF # Enable site sudo ln -sf /etc/nginx/sites-available/minusnow-itsm /etc/nginx/sites-enabled/ sudo rm -f /etc/nginx/sites-enabled/default # Test and reload Nginx sudo nginx -t sudo systemctl reload nginx

🔒 SSL/TLS Configuration

Using Let's Encrypt (Certbot)

# Install Certbot sudo apt install -y certbot python3-certbot-nginx # Obtain certificate sudo certbot --nginx -d itsm.yourdomain.com # Test automatic renewal sudo certbot renew --dry-run # Setup auto-renewal cron echo "0 0,12 * * * root certbot renew --quiet" | sudo tee /etc/cron.d/certbot

Using Custom Certificate

# Copy certificates sudo mkdir -p /etc/ssl/minusnow sudo cp your-certificate.crt /etc/ssl/minusnow/server.crt sudo cp your-private-key.key /etc/ssl/minusnow/server.key sudo cp your-ca-bundle.crt /etc/ssl/minusnow/ca-bundle.crt # Combine certificates sudo cat /etc/ssl/minusnow/server.crt /etc/ssl/minusnow/ca-bundle.crt > /etc/ssl/minusnow/fullchain.crt # Set permissions sudo chmod 600 /etc/ssl/minusnow/*.key sudo chmod 644 /etc/ssl/minusnow/*.crt

✅ Verification & Testing

Check Services Status

echo "=== PostgreSQL ===" sudo systemctl status postgresql echo "=== Application ===" sudo -u minusnow pm2 status echo "=== Nginx ===" sudo systemctl status nginx echo "=== Ports ===" sudo netstat -tlnp | grep -E '(5000|5432|80|443)'

Test Application

# Test local access curl -I http://localhost:5000/ curl -I http://localhost:5000/health # Test through Nginx curl -I https://itsm.yourdomain.com/ # Check application logs sudo -u minusnow pm2 logs minusnow-itsm --lines 50
✅ Browser Testing Checklist:
  1. Open https://itsm.yourdomain.com in browser
  2. Verify SSL certificate (padlock icon)
  3. Test login functionality
  4. Test all major features
  5. Check browser console for errors

🎛️ Service Management

Using PM2

# Start sudo -u minusnow pm2 start minusnow-itsm # Stop sudo -u minusnow pm2 stop minusnow-itsm # Restart sudo -u minusnow pm2 restart minusnow-itsm # Reload (zero-downtime) sudo -u minusnow pm2 reload minusnow-itsm # View logs sudo -u minusnow pm2 logs minusnow-itsm # Monitor sudo -u minusnow pm2 monit # Status sudo -u minusnow pm2 status

Using Systemd

# Start sudo systemctl start minusnow-itsm # Stop sudo systemctl stop minusnow-itsm # Restart sudo systemctl restart minusnow-itsm # Status sudo systemctl status minusnow-itsm # View logs sudo journalctl -u minusnow-itsm -f

🔧 Troubleshooting

Application Won't Start

# Check logs sudo -u minusnow pm2 logs minusnow-itsm --err # Check environment file sudo -u minusnow cat /opt/minusnow-itsm/.env # Check Node.js version node --version # Rebuild dependencies cd /opt/minusnow-itsm sudo -u minusnow npm rebuild

Database Connection Failed

# Check PostgreSQL status sudo systemctl status postgresql # Check PostgreSQL logs sudo tail -100 /var/log/postgresql/postgresql-15-main.log # Test connection manually psql -U minusnow -d minusnow_itsm -h localhost # Restart PostgreSQL sudo systemctl restart postgresql

Nginx 502 Bad Gateway

# Check if application is running sudo -u minusnow pm2 status # Check Nginx error logs sudo tail -100 /var/log/nginx/minusnow-error.log # Check upstream connection curl -I http://localhost:5000/ # Restart Nginx sudo systemctl restart nginx

SSL Certificate Issues

# Check certificate status sudo certbot certificates # Check certificate expiry openssl s_client -connect itsm.yourdomain.com:443 2>/dev/null | openssl x509 -noout -dates # Renew certificate sudo certbot renew

Log Locations

Log TypeLocation
Application/var/log/minusnow/combined.log
Application Errors/var/log/minusnow/error.log
PM2~/.pm2/logs/
Nginx Access/var/log/nginx/minusnow-access.log
Nginx Error/var/log/nginx/minusnow-error.log
PostgreSQL/var/log/postgresql/
System/var/log/syslog or journalctl

💾 Backup & Recovery

Automated Backup Script

sudo -u minusnow tee /opt/minusnow-itsm/scripts/backup.sh << 'EOF' #!/bin/bash set -e BACKUP_DIR="/var/lib/minusnow/backups" DATE=$(date +%Y%m%d_%H%M%S) RETENTION_DAYS=30 # Database backup pg_dump -U minusnow -h localhost minusnow_itsm | gzip > "$BACKUP_DIR/db_$DATE.sql.gz" # Application data backup tar -czf "$BACKUP_DIR/data_$DATE.tar.gz" -C /var/lib/minusnow data/ # Configuration backup tar -czf "$BACKUP_DIR/config_$DATE.tar.gz" \ /opt/minusnow-itsm/.env \ /opt/minusnow-itsm/ecosystem.config.js \ /etc/nginx/sites-available/minusnow-itsm # Remove old backups find "$BACKUP_DIR" -type f -mtime +$RETENTION_DAYS -delete echo "Backup completed: $DATE" EOF chmod +x /opt/minusnow-itsm/scripts/backup.sh # Setup daily cron echo "0 2 * * * minusnow /opt/minusnow-itsm/scripts/backup.sh >> /var/log/minusnow/backup.log 2>&1" | sudo tee /etc/cron.d/minusnow-backup

Recovery Procedure

# Stop application sudo -u minusnow pm2 stop minusnow-itsm # Restore database gunzip -c /var/lib/minusnow/backups/db_YYYYMMDD_HHMMSS.sql.gz | psql -U minusnow -h localhost minusnow_itsm # Restore data tar -xzf /var/lib/minusnow/backups/data_YYYYMMDD_HHMMSS.tar.gz -C /var/lib/minusnow # Restart application sudo -u minusnow pm2 start minusnow-itsm