This guide provides the official procedure for manually updating UTMStack using the automated update script. The script handles the complete update process including downloading the latest installer, managing services, and monitoring the update progress.
Overview
The UTMStack update script is an automated solution that:
Downloads the latest UTMStack installer
Manages service lifecycle during updates
Monitors the update process
Provides detailed logging and error handling
The script is designed to always download and install the latest available version of UTMStack from the official GitHub repository.
Prerequisites
Before proceeding with the update, ensure the following requirements are met:
Critical Requirements:
Root or sudo privileges
Active internet connection
systemd-based Linux distribution
The script must be executed in the same directory where the UTMStack installer is located
Minimum 2GB of available disk space
All UTMStack services are running properly
Recent backup of your data (recommended)
Update Procedure
Follow these steps carefully to perform the manual update:
Navigate to Installation Directory
First, locate and navigate to the directory containing your UTMStack installer. If you don’t know the installer location, use this command to find it: find /root /home -name 'installer' -type f 2> /dev/null
Once located, navigate to that directory: cd /path/to/installer/directory
Replace /path/to/installer/directory with the actual path found in the previous command.
Create the Update Script
Create a new file named update.sh in the installer directory: Copy the complete script below and paste it into the editor: #!/bin/bash
# ============================================================================
# UTMStack Update Script
# ============================================================================
# Description:
# Automated update script for UTMStack infrastructure. This script handles
# the complete update process including downloading the latest installer,
# managing services, and monitoring the update progress.
#
# Prerequisites:
# - Must be executed in the directory containing the previous UTMStack installer
# - Root/sudo privileges required
# - Active internet connection
# - systemd-based Linux distribution
#
# Usage:
# bash update.sh [OPTIONS]
#
# Options:
# -h, --help Display this help message
# -v, --verbose Enable verbose output
# -d, --dry-run Perform a dry run without making changes
#
# Exit Codes:
# 0 - Success
# 1 - General error
# 2 - Missing prerequisites
# 3 - Download failure
# 4 - Service management failure
# ============================================================================
set -euo pipefail # Exit on error, undefined variables, and pipe failures
IFS = $' \n\t ' # Set Internal Field Separator for better word splitting
# ============================================================================
# Global Variables
# ============================================================================
readonly SCRIPT_VERSION = "1.0.0"
readonly SCRIPT_DIR = "$( cd "$( dirname "${ BASH_SOURCE [0]}")" && pwd )"
readonly INSTALLER_URL = "https://github.com/utmstack/UTMStack/releases/latest/download/installer"
readonly INSTALLER_FILE = "installer"
readonly LOG_FILE = "/utmstack/updates/logs/utmstack-updater.log"
readonly LOG_DIR = "/utmstack/updates/logs"
readonly SERVICE_NAME = "UTMStackComponentsUpdater"
readonly TIMESTAMP = $( date '+%Y-%m-%d %H:%M:%S' )
# Script options
VERBOSE = false
DRY_RUN = false
# Color codes for output
readonly RED = '\033[0;31m'
readonly GREEN = '\033[0;32m'
readonly YELLOW = '\033[1;33m'
readonly BLUE = '\033[0;34m'
readonly NC = '\033[0m' # No Color
# ============================================================================
# Utility Functions
# ============================================================================
# Print formatted messages with timestamp
log_info () {
echo -e "${ BLUE }[INFO]${ NC } [$( date '+%Y-%m-%d %H:%M:%S')] $* "
}
log_success () {
echo -e "${ GREEN }[SUCCESS]${ NC } [$( date '+%Y-%m-%d %H:%M:%S')] $* "
}
log_warning () {
echo -e "${ YELLOW }[WARNING]${ NC } [$( date '+%Y-%m-%d %H:%M:%S')] $* "
}
log_error () {
echo -e "${ RED }[ERROR]${ NC } [$( date '+%Y-%m-%d %H:%M:%S')] $* " >&2
}
log_verbose () {
if [[ "${ VERBOSE }" == true ]]; then
echo -e "${ BLUE }[VERBOSE]${ NC } [$( date '+%Y-%m-%d %H:%M:%S')] $* "
fi
}
# Display help message
show_help () {
sed -n '/^# ===.*UTMStack Update Script/,/^# ===.*$/p' " $0 " | \
sed 's/^# \?//' | \
sed "s/SCRIPT_VERSION/${ SCRIPT_VERSION }/"
}
# Print section header
print_header () {
local message = " $1 "
local width = 60
echo ""
echo "$( printf '=%.0s' $( seq 1 $width ))"
echo " $message "
echo "$( printf '=%.0s' $( seq 1 $width ))"
echo ""
}
# Print step information
print_step () {
local current = " $1 "
local total = " $2 "
local description = " $3 "
echo ""
log_info "Step [ $current / $total ]: $description "
echo "$( printf -- '-%.0s' $( seq 1 60 ))"
}
# ============================================================================
# Validation Functions
# ============================================================================
# Check if script is run with sufficient privileges
check_privileges () {
log_verbose "Checking for sudo privileges..."
if [[ $EUID -ne 0 ]] && ! sudo -n true 2> /dev/null ; then
log_error "This script requires sudo privileges"
log_info "Please run with: sudo bash $0 "
return 2
fi
log_verbose "Privileges check passed"
return 0
}
# Verify required commands are available
check_dependencies () {
log_verbose "Checking required dependencies..."
local missing_deps = ()
for cmd in wget chmod systemctl tail ; do
if ! command -v " $cmd " & > /dev/null; then
missing_deps += ( " $cmd " )
fi
done
if [[ ${ # missing_deps [ @ ]} -gt 0 ]]; then
log_error "Missing required commands: ${ missing_deps [ * ]}"
return 2
fi
log_verbose "All dependencies are available"
return 0
}
# Verify internet connectivity
check_connectivity () {
log_verbose "Checking internet connectivity..."
if ! wget --spider --quiet --timeout=10 "https://github.com" 2> /dev/null ; then
log_error "No internet connectivity detected"
log_info "Please check your network connection and try again"
return 3
fi
log_verbose "Internet connectivity verified"
return 0
}
# Check if systemd service exists
check_service_exists () {
log_verbose "Checking if ${ SERVICE_NAME } service exists..."
if ! systemctl list-unit-files | grep -q "^${ SERVICE_NAME }.service" ; then
log_warning "Service ${ SERVICE_NAME } not found in systemd"
return 1
fi
log_verbose "Service exists"
return 0
}
# Check if script is being executed from installer directory
check_installer_directory () {
log_verbose "Checking if installer exists in current directory..."
if [[ ! -f "${ INSTALLER_FILE }" ]]; then
echo ""
echo "$( printf '=%.0s' $( seq 1 60 ))"
log_error "INSTALLER NOT FOUND IN EXECUTION DIRECTORY"
echo "$( printf '=%.0s' $( seq 1 60 ))"
echo ""
log_info "This script must be executed from the directory where the"
log_info "UTMStack installer is located."
echo ""
log_info "To find your installer location, run:"
log_info " find /root /home -name 'installer' -type f 2>/dev/null"
echo ""
log_info "Then navigate to that directory and run the script:"
log_info " cd /path/to/installer/directory"
log_info " bash update.sh"
echo ""
return 2
fi
log_verbose "Installer file found: ${ INSTALLER_FILE }"
log_info "Installer found in current directory: $( pwd )"
return 0
}
# ============================================================================
# Core Functions
# ============================================================================
# Remove old installer file
remove_old_installer () {
print_step 1 8 "Cleaning up old installer"
if [[ "${ DRY_RUN }" == true ]]; then
log_info "DRY RUN: Would remove ${ INSTALLER_FILE }"
return 0
fi
if [[ -f "${ INSTALLER_FILE }" ]]; then
log_info "Removing existing installer file..."
rm -f "${ INSTALLER_FILE }"
log_success "Old installer removed successfully"
else
log_info "No existing installer found (clean state)"
fi
}
# Download the latest installer
download_installer () {
print_step 2 8 "Downloading latest installer"
if [[ "${ DRY_RUN }" == true ]]; then
log_info "DRY RUN: Would download from ${ INSTALLER_URL }"
return 0
fi
log_info "Fetching installer from: ${ INSTALLER_URL }"
if wget --timeout=300 --tries=3 --progress=bar:force "${ INSTALLER_URL }" -O "${ INSTALLER_FILE }" 2>&1 ; then
log_success "Installer downloaded successfully"
# Verify the downloaded file
if [[ ! -s "${ INSTALLER_FILE }" ]]; then
log_error "Downloaded file is empty"
return 3
fi
else
log_error "Failed to download installer"
log_info "Please check your internet connection and try again"
return 3
fi
}
# Make installer executable
set_executable_permissions () {
print_step 3 8 "Setting executable permissions"
if [[ "${ DRY_RUN }" == true ]]; then
log_info "DRY RUN: Would set executable permissions on ${ INSTALLER_FILE }"
return 0
fi
log_info "Making installer executable..."
chmod +x "${ INSTALLER_FILE }"
log_success "Permissions set successfully"
log_verbose "File permissions: $( ls -lh ${ INSTALLER_FILE })"
}
# Stop the UTMStack service
stop_service () {
print_step 4 8 "Stopping ${ SERVICE_NAME } service"
if [[ "${ DRY_RUN }" == true ]]; then
log_info "DRY RUN: Would stop ${ SERVICE_NAME } service"
return 0
fi
if ! check_service_exists ; then
log_warning "Service not found, skipping stop operation"
return 0
fi
log_info "Stopping service..."
if sudo systemctl stop "${ SERVICE_NAME }" ; then
log_success "Service stopped successfully"
# Wait for service to fully stop
local timeout = 30
local elapsed = 0
while systemctl is-active --quiet "${ SERVICE_NAME }" && [[ $elapsed -lt $timeout ]]; do
sleep 1
(( elapsed ++ ))
log_verbose "Waiting for service to stop... (${ elapsed }s)"
done
if systemctl is-active --quiet "${ SERVICE_NAME }" ; then
log_warning "Service did not stop within ${ timeout } seconds"
return 4
fi
else
log_warning "Failed to stop service (may not be running)"
fi
}
# Clean up old log file
cleanup_log_file () {
print_step 5 8 "Cleaning up old log file"
if [[ "${ DRY_RUN }" == true ]]; then
log_info "DRY RUN: Would remove ${ LOG_FILE }"
return 0
fi
# Ensure log directory exists
if [[ ! -d "${ LOG_DIR }" ]]; then
log_info "Creating log directory: ${ LOG_DIR }"
sudo mkdir -p "${ LOG_DIR }"
fi
if [[ -f "${ LOG_FILE }" ]]; then
# Backup old log before removing
local backup_file = "${ LOG_FILE }.$( date +%Y%m%d_%H%M%S).bak"
log_info "Backing up old log to: ${ backup_file }"
sudo cp "${ LOG_FILE }" "${ backup_file }"
log_info "Removing old log file..."
sudo rm -f "${ LOG_FILE }"
log_success "Log file cleaned up"
else
log_info "No existing log file found"
fi
}
# Start the UTMStack service
start_service () {
print_step 6 8 "Starting ${ SERVICE_NAME } service"
if [[ "${ DRY_RUN }" == true ]]; then
log_info "DRY RUN: Would start ${ SERVICE_NAME } service"
return 0
fi
if ! check_service_exists ; then
log_error "Service not found, cannot start"
return 4
fi
log_info "Starting service..."
if sudo systemctl start "${ SERVICE_NAME }" ; then
log_success "Service started successfully"
# Verify service is running
sleep 2
if systemctl is-active --quiet "${ SERVICE_NAME }" ; then
log_success "Service is running and active"
else
log_error "Service started but is not active"
return 4
fi
else
log_error "Failed to start service"
log_info "Check service status with: sudo systemctl status ${ SERVICE_NAME }"
return 4
fi
}
# Run the installer
run_installer () {
print_step 7 8 "Running UTMStack installer"
if [[ "${ DRY_RUN }" == true ]]; then
log_info "DRY RUN: Would run installer"
return 0
fi
if [[ ! -f "${ INSTALLER_FILE }" ]]; then
log_error "Installer file not found: ${ INSTALLER_FILE }"
return 1
fi
log_info "Executing installer..."
echo "$( printf '=%.0s' $( seq 1 60 ))"
if sudo ./"${ INSTALLER_FILE }" ; then
echo "$( printf '=%.0s' $( seq 1 60 ))"
log_success "Installer completed successfully"
else
local exit_code = $?
echo "$( printf '=%.0s' $( seq 1 60 ))"
log_error "Installer failed with exit code: ${ exit_code }"
return 1
fi
}
# Monitor the update log
monitor_log () {
print_step 8 8 "Monitoring update progress"
if [[ "${ DRY_RUN }" == true ]]; then
log_info "DRY RUN: Would monitor log file"
return 0
fi
log_info "Following log file: ${ LOG_FILE }"
log_info "Press Ctrl+C to exit log monitoring"
echo "$( printf '=%.0s' $( seq 1 60 ))"
# Wait for log file to be created
local max_wait = 10
local wait_count = 0
while [[ ! -f "${ LOG_FILE }" ]] && [[ $wait_count -lt $max_wait ]]; do
log_verbose "Waiting for log file to be created... (${ wait_count }s)"
sleep 1
(( wait_count ++ ))
done
if [[ -f "${ LOG_FILE }" ]]; then
sudo tail -f "${ LOG_FILE }"
else
log_error "Log file was not created after ${ max_wait } seconds"
log_info "Update may have failed. Check service status:"
log_info " sudo systemctl status ${ SERVICE_NAME }"
return 1
fi
}
# ============================================================================
# Main Execution Function
# ============================================================================
main () {
local exit_code = 0
print_header "UTMStack Update Process v${ SCRIPT_VERSION }"
log_info "Started at: ${ TIMESTAMP }"
log_info "Working directory: ${ SCRIPT_DIR }"
# Run pre-flight checks
log_info "Running pre-flight checks..."
check_privileges || exit $?
check_dependencies || exit $?
check_connectivity || exit $?
check_installer_directory || exit $?
log_success "Pre-flight checks completed"
# Execute update steps
remove_old_installer || exit_code = $?
[[ $exit_code -ne 0 ]] && exit $exit_code
download_installer || exit_code = $?
[[ $exit_code -ne 0 ]] && exit $exit_code
set_executable_permissions || exit_code = $?
[[ $exit_code -ne 0 ]] && exit $exit_code
stop_service || exit_code = $?
[[ $exit_code -ne 0 ]] && exit $exit_code
cleanup_log_file || exit_code = $?
[[ $exit_code -ne 0 ]] && exit $exit_code
start_service || exit_code = $?
[[ $exit_code -ne 0 ]] && exit $exit_code
run_installer || exit_code = $?
[[ $exit_code -ne 0 ]] && exit $exit_code
monitor_log || exit_code = $?
if [[ $exit_code -eq 0 ]]; then
print_header "Update Process Completed Successfully"
else
print_header "Update Process Completed with Errors"
fi
log_info "Finished at: $( date '+%Y-%m-%d %H:%M:%S')"
exit $exit_code
}
# ============================================================================
# Script Entry Point
# ============================================================================
# Parse command line arguments
while [[ $# -gt 0 ]]; do
case $1 in
-h | --help )
show_help
exit 0
;;
-v | --verbose )
VERBOSE = true
shift
;;
-d | --dry-run )
DRY_RUN = true
log_info "Running in DRY RUN mode - no changes will be made"
shift
;;
*)
log_error "Unknown option: $1 "
log_info "Use -h or --help for usage information"
exit 1
;;
esac
done
# Trap errors and interrupts
trap 'log_error "Script interrupted"; exit 130' INT TERM
trap 'log_error "Script failed at line $LINENO with exit code $?"' ERR
# Execute main function
main " $@ "
Save the file by pressing Ctrl + X, then Y, and Enter.
Make Script Executable
Grant execution permissions to the script: Verify the script has execute permissions: You should see -rwxr-xr-x at the beginning of the output.
Execute the Update Script
Run the update script with sudo privileges: The script will:
Perform pre-flight checks (privileges, dependencies, connectivity)
Remove the old installer
Download the latest installer from GitHub
Set executable permissions
Stop UTMStack services
Clean up old log files
Start UTMStack services
Run the installer
Monitor the update progress
Do not interrupt the update process. The update may take 10-30 minutes depending on your system specifications and network speed.
Monitor Update Progress
The script automatically monitors the update log. You’ll see real-time output as the update progresses. To exit the log monitoring, press Ctrl + C (this will not stop the update process).
Verification and Post-Update
After the update completes, verify the installation:
Check Update Logs
Review the update logs for any errors or warnings: sudo tail -100 /utmstack/updates/logs/utmstack-updater.log
Verify Service Status
Confirm that all UTMStack services are running: sudo systemctl status UTMStackComponentsUpdater
The service should show “active (running)” status.
Check Application Version
Verify the updated version through the UTMStack web interface:
Log in to your UTMStack instance
Navigate to Settings → About
Confirm the version number matches the latest release
Test Functionality
Perform basic functionality tests:
Verify dashboard loads correctly
Check data ingestion is working
Test alert generation
Confirm integrations are functioning
Troubleshooting
Error: Installer not found in execution directory
Cause: The script is not being executed from the directory containing the UTMStack installer.Solution:
Find your installer location:
find /root /home -name 'installer' -type f 2> /dev/null
Navigate to that directory:
cd /path/to/installer/directory
Run the script again
Error: No internet connectivity detected
Cause: The server cannot reach GitHub to download the installer.Solution:
Check network connectivity:
Verify firewall rules allow outbound HTTPS (port 443)
Check proxy settings if applicable
Error: Failed to stop/start service
Cause: Service management issues with systemd.Solution:
Check service status:
sudo systemctl status UTMStackComponentsUpdater
View service logs:
sudo journalctl -u UTMStackComponentsUpdater -n 50
Restart the service manually:
sudo systemctl restart UTMStackComponentsUpdater
Update process hangs or stalls
Cause: Network issues or resource constraints.Solution:
Check system resources:
Monitor the log file in another terminal:
sudo tail -f /utmstack/updates/logs/utmstack-updater.log
If necessary, stop and restart the update:
sudo systemctl stop UTMStackComponentsUpdater
sudo bash update.sh
Cause: Insufficient privileges to execute the script.Solution:
Always run the script with sudo:
Verify you have root access:
Need Help? If you encounter issues during the update process, please contact UTMStack support or visit our community forums for assistance.