BEXO ERP — Complete Setup & Deployment Guide
For Deployment Engineers and DevOps Teams
Pre-Deployment Checklist
☐ Dedicated server provisioned (not shared)
☐ Windows Server 2016 or newer installed
☐ .NET 8 ASP.NET Core Runtime available
☐ SQL Server 2016+ running and accessible
☐ SSL certificate obtained (production)
☐ Network firewall rules approved
☐ Database backup location prepared
☐ Documentation reviewed by team
☐ Test deployment completed successfully
☐ Rollback procedure documented
Phase 1: Server Infrastructure Setup
Hardware Requirements
MINIMUM:
CPU: Intel Core i5 / AMD Ryzen 5 (4 cores)
RAM: 8 GB
Disk: 50 GB free (SSD preferred)
Network: Gigabit LAN connection
RECOMMENDED:
CPU: Intel Xeon / AMD EPYC (8+ cores)
RAM: 16 GB +
Disk: 100 GB+ SSD
Network: 10 Gbps LAN
Redundancy: RAID 1 disk mirroring
Windows Server Setup
1. Install Windows Server
Edition: Windows Server 2022 Standard (64-bit)
Options: Server with Desktop Experience
Disk: Use C: for OS, D: for data (separate disk if possible)
2. Configure Network
# Set static IP
$ipConfig = Get-NetIPConfiguration
$interface = Get-NetAdapter -InterfaceIndex $ipConfig.InterfaceIndex
New-NetIPAddress -InterfaceIndex $interface.ifIndex `
-IPAddress 192.168.0.XX -PrefixLength 24 `
-DefaultGateway 192.168.0.1
# Set DNS
Set-DnsClientServerAddress -InterfaceIndex $interface.ifIndex `
-ServerAddresses ("8.8.8.8", "8.8.4.4")
# Rename computer
Rename-Computer -NewName "BEXO-PROD-01" -Restart
3. Enable RDP & Firewall
# Enable RDP
Set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server' `
-Name 'fDenyTSConnections' -Value 0
# Configure Windows Firewall
Enable-NetFirewallRule -DisplayName "Remote Desktop - User Mode (TCP-In)"
Phase 2: Install .NET 8 Runtime
Download & Install
# Download .NET 8 ASP.NET Core Runtime
# From: https://dotnet.microsoft.com/download/dotnet/8.0
# Run installer
.\dotnet-hosting-8.0.5-win-x64.exe
# Verify installation
dotnet --version
dotnet --list-runtimes
# Output should show:
# .NET 8.0.5
# Microsoft.AspNetCore.App 8.0.5
Phase 3: SQL Server Setup
Installation
Edition: Standard or Enterprise
Instance: MSSQLSERVER (default)
Data Path: D:\Data\MSSQL (separate disk)
Log Path: E:\Logs\MSSQL (separate disk if available)
Backup Path: C:\Backups\BEXO_SQL
Post-Installation Configuration
1. Enable SQL Server Agent
# Required for scheduled backups
$svc = Get-Service SQLSERVERAGENT
Set-Service $svc -StartupType Automatic
Start-Service $svc
2. Create BEXO Database
-- Connect as SA
-- Database will auto-create via EF migrations when API starts
-- Manual creation (optional):
CREATE DATABASE BEXO_ERP
ON PRIMARY (
NAME = 'BEXO_ERP_Data',
FILENAME = 'D:\Data\MSSQL\BEXO_ERP.mdf',
SIZE = 100MB,
FILEGROWTH = 50MB
)
LOG ON (
NAME = 'BEXO_ERP_Log',
FILENAME = 'E:\Logs\MSSQL\BEXO_ERP_log.ldf',
SIZE = 100MB,
FILEGROWTH = 50MB
)
3. Create Service Account
-- Create SQL login for API
CREATE LOGIN [BEXO_API] WITH PASSWORD = 'YourStrongPassword123!'
-- Create database user
USE BEXO_ERP
CREATE USER [BEXO_API] FOR LOGIN [BEXO_API]
-- Grant permissions
ALTER ROLE db_owner ADD MEMBER [BEXO_API]
4. Enable Backups
-- Configure backup directory
EXEC xp_cmdshell 'mkdir C:\Backups\BEXO_SQL'
-- Create maintenance plan (or use PowerShell scheduled task)
-- Daily full backup at 02:00 AM
Phase 4: Deploy BEXO API
Prepare Binaries
1. Get Release Package
# From NAS or CI/CD pipeline
$releasePackage = "\\nas\releases\BEXO\v1.0.0\BEXO_API.zip"
# Extract to deployment location
Expand-Archive -Path $releasePackage -DestinationPath "C:\Release\BEXO"
# Verify files
Get-ChildItem C:\Release\BEXO\
# Should contain:
# - BEXO.API.dll
# - appsettings.json (REDACTED - needs secrets)
# - web.config (if IIS hosting)
# - Other assemblies & dependencies
Configure appsettings.json
Template
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning"
}
},
"ConnectionStrings": {
"DefaultConnection": "Server=.\\BEXO_ERP;Database=BEXO_ERP;Integrated Security=true;TrustServerCertificate=true"
},
"DatabaseProvider": "SqlServer",
"Jwt": {
"SigningKey": "your-256-bit-base64-key-here",
"Issuer": "bexo-api",
"Audience": "bexo-client",
"ExpirationMinutes": 1440
},
"Kestrel": {
"Endpoints": {
"Https": {
"Url": "https://0.0.0.0:5443",
"Certificate": {
"Path": "C:\\certs\\bexo.pfx",
"Password": "cert-password-here"
}
}
}
}
}
Setup JWT Key (256-bit)
# Generate secure JWT key
[Convert]::ToBase64String((1..32 | ForEach-Object { [byte](Get-Random -Minimum 0 -Maximum 256) }))
# Output example:
# a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6r7s8t9u0v1w2x3y4z5a6b7c8d9e0f1
For Production - Use Environment Variables
# Set environment variables (survives service restart)
[Environment]::SetEnvironmentVariable("BEXO_JWT_SIGNING_KEY", "your-key", "Machine")
[Environment]::SetEnvironmentVariable("BEXO_API_CERT_PWD", "cert-password", "Machine")
# Restart required
Restart-Computer
Install SSL Certificate
Option 1: Self-Signed (Dev/Test)
# Create self-signed cert valid for 365 days
$cert = New-SelfSignedCertificate `
-DnsName "localhost", "192.168.0.XX", "bexo.company.local" `
-CertStoreLocation "Cert:\LocalMachine\My" `
-NotAfter (Get-Date).AddDays(365) `
-KeyAlgorithm RSA `
-KeyLength 2048 `
-Subject "CN=BEXO ERP Server"
# Export with private key
$pwd = ConvertTo-SecureString -String "cert-password" -Force -AsPlainText
Export-PfxCertificate -Cert $cert -FilePath "C:\certs\bexo.pfx" -Password $pwd
# Note thumbprint for config
$cert.Thumbprint
Option 2: Production Certificate
# Import issued certificate
Import-PfxCertificate -FilePath "C:\certs\bexo_prod.pfx" `
-CertStoreLocation "Cert:\LocalMachine\My" `
-Password (ConvertTo-SecureString "password" -AsPlainText -Force)
Phase 5: Install API as Windows Service
Option A: Windows Service (NSSM)
# Download NSSM (Non-Sucking Service Manager)
# https://nssm.cc/download
# Install service
nssm install BEXO_API_Prod `
"C:\Program Files\dotnet\dotnet.exe" `
"C:\Release\BEXO\BEXO.API.dll"
# Configure service
nssm set BEXO_API_Prod AppDirectory C:\Release\BEXO
nssm set BEXO_API_Prod AppStdout C:\Tools\logs\stdout.log
nssm set BEXO_API_Prod AppStderr C:\Tools\logs\stderr.log
nssm set BEXO_API_Prod AppRotateFiles 1
nssm set BEXO_API_Prod AppRotateOnline 1
# Start service
Start-Service BEXO_API_Prod
# Verify
Get-Service BEXO_API_Prod
Option B: Scheduled Task (Windows Task Scheduler)
# Create scheduled task to run at startup
$trigger = New-ScheduledTaskTrigger -AtStartup
$action = New-ScheduledTaskAction `
-Execute "C:\Program Files\dotnet\dotnet.exe" `
-Argument "C:\Release\BEXO\BEXO.API.dll" `
-WorkingDirectory "C:\Release\BEXO"
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -RunLevel Highest
Register-ScheduledTask `
-TaskName "BEXO_API_Prod" `
-Trigger $trigger `
-Action $action `
-Principal $principal `
-Force
# Start task
Start-ScheduledTask -TaskName "BEXO_API_Prod"
Phase 6: Deploy WPF Client
Installation on Client Machines
# Copy release folder to Program Files
Copy-Item -Path "\\nas\releases\BEXO\v1.0.0\BEXO.UI" `
-Destination "C:\Program Files\BEXO\" `
-Recurse -Force
# Create shortcut on desktop
$WshShell = New-Object -ComObject WScript.Shell
$Shortcut = $WshShell.CreateShortcut("C:\Users\Public\Desktop\BEXO.lnk")
$Shortcut.TargetPath = "C:\Program Files\BEXO\BEXO.UI.exe"
$Shortcut.WorkingDirectory = "C:\Program Files\BEXO\"
$Shortcut.Save()
# Set API endpoint in config (or via login dialog)
# Edit: C:\Program Files\BEXO\appsettings.json
Phase 7: Backup & Recovery Setup
Create Backup Folder
# Local backup
New-Item -Path "C:\Backups\BEXO_SQL" -ItemType Directory -Force
# NAS backup (off-box copy)
New-NetAdapter -Name "BEXO_NAS" # (if needed)
New-SmbMapping -LocalPath "Z:" `
-RemotePath "\\192.168.0.33\common-data\BEXO_Deploy\db_backups" `
-Persist
Schedule Daily Backup
Option 1: Scheduled Task
# Create backup script
$script = @'
[string[]]$sqltoolspath = "C:\Program Files\Microsoft SQL Server\*\Tools\Binn"
[string]$backupdir = "C:\Backups\BEXO_SQL"
[string]$timestamp = (Get-Date).ToString("yyyy-MM-dd_HH-mm")
$env:Path += ";" + (Resolve-Path $sqltoolspath).Path
# Backup
sqlcmd -S . -Q "BACKUP DATABASE BEXO_ERP TO DISK = '$backupdir\BEXO_ERP_$timestamp.bak' WITH INIT, COPY_ONLY, STATS=10, COMPRESSION"
# Verify
sqlcmd -S . -Q "RESTORE VERIFYONLY FROM DISK = '$backupdir\BEXO_ERP_$timestamp.bak'"
# Copy to NAS
Copy-Item "$backupdir\BEXO_ERP_$timestamp.bak" -Destination "Z:\"
# Cleanup old backups (7-day retention)
Get-ChildItem $backupdir -Filter "*.bak" | Where {$_.LastWriteTime -lt (Get-Date).AddDays(-7)} | Remove-Item
'@
$script | Out-File "C:\Tools\scripts\backup_bexo.ps1" -Force
# Create scheduled task
$trigger = New-ScheduledTaskTrigger -Daily -At "02:00 AM"
$action = New-ScheduledTaskAction `
-Execute "powershell.exe" `
-Argument "-NoProfile -ExecutionPolicy Bypass -File C:\Tools\scripts\backup_bexo.ps1"
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -RunLevel Highest
Register-ScheduledTask `
-TaskName "BEXO_DB_Backup" `
-Trigger $trigger `
-Action $action `
-Principal $principal `
-Force
# Verify
Get-ScheduledTask -TaskName "BEXO_DB_Backup"
Phase 8: Health Monitoring
Create Health Check Script
# C:\Tools\scripts\health_watchdog.ps1
[int]$maxRetries = 3
[int]$retryDelay = 80
[string]$logFile = "C:\Tools\logs\bexo_alerts.log"
function LogAlert {
param([string]$message)
Add-Content -Path $logFile -Value "$(Get-Date): $message"
}
# Test health endpoint
$healthy = $false
for ($i = 0; $i -lt $maxRetries; $i++) {
try {
$response = Invoke-RestMethod `
-Uri "https://localhost:5443/api/health" `
-SkipCertificateCheck `
-TimeoutSec 10
if ($response.status -eq "Healthy") {
$healthy = $true
LogAlert "OK: API is healthy"
break
}
}
catch {
LogAlert "WARN: Health check failed (attempt $($i+1)/$maxRetries): $_"
if ($i -lt ($maxRetries - 1)) {
LogAlert "INFO: Restarting API service..."
Restart-Service BEXO_API_Prod -Force
Start-Sleep -Seconds $retryDelay
}
}
}
if (-not $healthy) {
LogAlert "ERROR: API failed all health checks. Manual intervention required."
}
Schedule Watchdog (Every 5 Minutes)
$trigger = New-ScheduledTaskTrigger -RepetitionInterval (New-TimeSpan -Minutes 5) -Once -At (Get-Date)
$action = New-ScheduledTaskAction `
-Execute "powershell.exe" `
-Argument "-NoProfile -ExecutionPolicy Bypass -File C:\Tools\scripts\health_watchdog.ps1"
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -RunLevel Highest
Register-ScheduledTask `
-TaskName "BEXO_Health_Watchdog" `
-Trigger $trigger `
-Action $action `
-Principal $principal `
-Force
Phase 9: Firewall Configuration
# Allow API traffic (LAN only)
New-NetFirewallRule `
-DisplayName "BEXO API - LAN (5443)" `
-Direction Inbound `
-LocalPort 5443 `
-Protocol TCP `
-RemoteAddress 192.168.0.0/16 `
-Action Allow
# Allow SQL Server (if not local)
New-NetFirewallRule `
-DisplayName "SQL Server - BEXO (1433)" `
-Direction Outbound `
-RemotePort 1433 `
-Protocol TCP `
-RemoteAddress 192.168.0.XX `
-Action Allow
Phase 10: Post-Deployment Verification
Test API Connectivity
# Health check
Invoke-RestMethod -Uri "https://localhost:5443/api/health" -SkipCertificateCheck
# Sample data endpoint
Invoke-RestMethod -Uri "https://localhost:5443/api/companies" `
-SkipCertificateCheck `
-Headers @{Authorization = "Bearer <jwt-token>"}
# Database test
sqlcmd -S . -Q "SELECT COUNT(*) FROM BEXO_ERP.dbo.Companies"
Performance Baseline
# Measure endpoint response times
$uri = "https://localhost:5443/api/invoices"
$times = @()
for ($i = 0; $i -lt 10; $i++) {
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
Invoke-RestMethod -Uri $uri -SkipCertificateCheck | Out-Null
$stopwatch.Stop()
$times += $stopwatch.ElapsedMilliseconds
}
"Average Response: $([int]($times | Measure-Object -Average).Average) ms"
"P95: $($times | Sort-Object)[[int]($times.Count * 0.95)] ms"
Rollback Procedure
If deployment fails:
# 1. Stop API
Stop-Service BEXO_API_Prod
# 2. Restore previous version
Remove-Item "C:\Release\BEXO" -Recurse -Force
Rename-Item "C:\Release\BEXO_backup" -NewName "BEXO"
# 3. Restore database (if needed)
sqlcmd -S . -Q "RESTORE DATABASE BEXO_ERP FROM DISK = 'C:\Backups\BEXO_SQL\BEXO_ERP_previous.bak' WITH REPLACE, RECOVERY"
# 4. Restart
Start-Service BEXO_API_Prod
# 5. Verify
Invoke-RestMethod -Uri https://localhost:5443/api/health -SkipCertificateCheck
Checklist - Ready for UAT
☐ API service running and healthy
☐ Database contains test data
☐ All 68 UI views accessible & fast
☐ Health checks passing (5-min intervals)
☐ Backups completed successfully
☐ Logs being written (no errors)
☐ SSL certificate valid (not expired)
☐ Firewall rules allowing LAN access
☐ WPF clients can login successfully
☐ Sample transaction workflows tested
☐ Performance baseline measured
☐ Rollback procedure documented
☐ Admin trained on operations
☐ Documentation deployed to NAS
Last Updated: 2026-05-30
Version: 1.0
