Supported operating systems
Gorelo only supports operating systems that are currently supported by the vendor themselves (Microsoft/Apple).Prerequisite check
Gorelo provides a prerequisite check for Windows and macOS. It confirms the device meets the requirements and can reach Gorelo’s services, and ends with a clear PASS or FAIL. Both scripts ask you to choose your Gorelo region — USW (United States West) or AUE (Australia East) — and then check the matching Gorelo servers, IoT Hub, and download source for that region. When run interactively you’ll be prompted to pick one; to skip the prompt (e.g. for unattended runs), set theGORELO_REGION environment variable to USW or AUE beforehand.
- Windows
- macOS
- Open an elevated PowerShell window on the computer experiencing agent issues.
- Copy the entire script below, paste it into the window, and press Enter:
gorelo-check-windows.ps1
$scriptContent = @'
# Gorelo Agent Pre-Installation Check Script
# Updated: 2026-03-22
# Checks system requirements, connectivity (including Cloudflare R2), TLS, and permissions
function Write-ColorOutput {
param (
[string]$Message,
[string]$Color = "White",
[bool]$IsError = $false
)
if ($IsError) {
Write-Host $Message -ForegroundColor Red
} else {
Write-Host $Message -ForegroundColor $Color
}
}
$hasError = $false
Write-Host ""
Write-Host "======================================" -ForegroundColor Cyan
Write-Host " Gorelo Agent Pre-Installation Check" -ForegroundColor Cyan
Write-Host "======================================" -ForegroundColor Cyan
Write-Host ""
# --- REGION SELECTION ---
# Run via Invoke-Expression, so there are no script parameters. Set $env:GORELO_REGION = "USW" or "AUE"
# beforehand to skip the prompt (e.g. for unattended runs).
$regions = @{
"USW" = "usw"
"AUE" = "aue"
}
$region = $env:GORELO_REGION
if ($region) { $region = $region.Trim().ToUpper() }
while (-not $regions.ContainsKey("$region")) {
Write-Host "Select your Gorelo region:" -ForegroundColor Cyan
Write-Host " 1) USW (United States West)"
Write-Host " 2) AUE (Australia East)"
$choice = (Read-Host "Enter 1 or 2 (or USW / AUE)").Trim().ToUpper()
switch ($choice) {
"1" { $region = "USW" }
"2" { $region = "AUE" }
default { $region = $choice }
}
if (-not $regions.ContainsKey("$region")) {
Write-ColorOutput "Invalid selection '$choice'. Please choose USW or AUE." -Color Yellow
}
}
$regionCode = $regions[$region]
Write-ColorOutput "INFO: Region selected: $region" -Color White
Write-Host ""
# --- SYSTEM CHECKS ---
Write-Host "[System Checks]" -ForegroundColor Cyan
# OS Version
$osInfo = Get-CimInstance Win32_OperatingSystem
Write-ColorOutput "INFO: $($osInfo.Caption) ($($osInfo.Version))" -Color White
# PowerShell version
$requiredVersion = [version]'5.1'
$installedVersion = $PSVersionTable.PSVersion
if ($installedVersion -lt $requiredVersion) {
Write-ColorOutput "FAIL: PowerShell version $($installedVersion) is below required $requiredVersion" -IsError $true
$hasError = $true
} else {
Write-ColorOutput "PASS: PowerShell version $($installedVersion)" -Color Green
}
# 64-bit check
if ($env:PROCESSOR_ARCHITECTURE -eq "AMD64") {
Write-ColorOutput "PASS: 64-bit processor architecture" -Color Green
} else {
Write-ColorOutput "FAIL: Non-64-bit architecture detected: $($env:PROCESSOR_ARCHITECTURE)" -IsError $true
$hasError = $true
}
# 64-bit Program Files
if ($Env:ProgramW6432) {
Write-ColorOutput "PASS: 64-bit Program Files folder exists ($($Env:ProgramW6432))" -Color Green
} else {
Write-ColorOutput "FAIL: 64-bit Program Files folder not found" -IsError $true
$hasError = $true
}
# System drive space
$systemDrive = $env:SystemDrive
if ($systemDrive) {
$driveInfo = Get-PSDrive -PSProvider FileSystem | Where-Object { $_.Name -eq $systemDrive[0] }
if ($driveInfo) {
$freeSpaceMB = [math]::Round($driveInfo.Free / 1MB, 2)
if ($freeSpaceMB -le 300) {
Write-ColorOutput "FAIL: Free space is less than 300 MB (Current: $freeSpaceMB MB)" -IsError $true
$hasError = $true
} else {
Write-ColorOutput "PASS: System drive space ($freeSpaceMB MB free)" -Color Green
}
} else {
Write-ColorOutput "FAIL: Unable to get drive info" -IsError $true
$hasError = $true
}
}
# Administrator check
$currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
if ($currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Write-ColorOutput "PASS: Running as Administrator" -Color Green
} else {
Write-ColorOutput "FAIL: Not running as Administrator (required for installation)" -IsError $true
$hasError = $true
}
Write-Host ""
Write-Host "[TLS / Security Checks]" -ForegroundColor Cyan
# TLS 1.2 check
$tlsProtocols = [Net.ServicePointManager]::SecurityProtocol
if ($tlsProtocols -band [Net.SecurityProtocolType]::Tls12) {
Write-ColorOutput "PASS: TLS 1.2 is enabled in SecurityProtocol ($tlsProtocols)" -Color Green
} else {
Write-ColorOutput "WARN: TLS 1.2 not in default SecurityProtocol ($tlsProtocols). Enabling..." -Color Yellow
try {
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
Write-ColorOutput "PASS: TLS 1.2 enabled successfully" -Color Green
} catch {
Write-ColorOutput "FAIL: Could not enable TLS 1.2. Error: $_" -IsError $true
$hasError = $true
}
}
# Ensure TLS 1.2 is active for all subsequent web requests
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
Write-Host ""
Write-Host "[Connectivity Checks]" -ForegroundColor Cyan
# URL connectivity checks
$urls = @(
@{
Url = "https://www.google.com/"
ExpectedStatus = 200
Description = "Internet connectivity"
},
@{
Url = "https://gw.$regionCode.gorelo.tech/rmm-login/api/login/_health"
ExpectedStatus = 200
Description = "Gorelo Gateway ($region)"
},
@{
Url = "https://sr.rmm.pod1.$regionCode.gorelo.tech/api/_health"
ExpectedStatus = 200
Description = "Gorelo API ($region)"
},
@{
Url = "https://hub.rmm.pod1.$regionCode.gorelo.tech/hc"
ExpectedStatus = 200
Description = "Gorelo Hub ($region)"
}
)
$urlChecksPassed = $true
foreach ($urlCheck in $urls) {
try {
$response = Invoke-WebRequest -Uri $urlCheck.Url -Method Get -UseBasicParsing -TimeoutSec 15
if ($response.StatusCode -eq $urlCheck.ExpectedStatus) {
Write-ColorOutput "PASS: $($urlCheck.Description) ($($urlCheck.Url))" -Color Green
} else {
Write-ColorOutput "WARN: $($urlCheck.Description) returned $($response.StatusCode) (expected $($urlCheck.ExpectedStatus))" -Color Yellow
}
} catch {
Write-ColorOutput "FAIL: $($urlCheck.Description) ($($urlCheck.Url)). Error: $($_.Exception.Message)" -IsError $true
$urlChecksPassed = $false
$hasError = $true
}
}
# Cloudflare R2 connectivity (the installer download source)
Write-Host ""
Write-Host "[Cloudflare R2 Download Check]" -ForegroundColor Cyan
$r2Domain = "600c23d50c6ee4462ecb200a47f6b627.r2.cloudflarestorage.com"
try {
$dnsResult = [System.Net.Dns]::GetHostAddresses($r2Domain)
if ($dnsResult.Count -gt 0) {
Write-ColorOutput "PASS: DNS resolution for Cloudflare R2 ($r2Domain -> $($dnsResult[0]))" -Color Green
} else {
Write-ColorOutput "FAIL: DNS resolution returned no addresses for $r2Domain" -IsError $true
$hasError = $true
}
} catch {
Write-ColorOutput "FAIL: Cannot resolve Cloudflare R2 domain ($r2Domain). Error: $($_.Exception.Message)" -IsError $true
$hasError = $true
}
# Test HTTPS connection to R2 (HEAD request to bucket root - will get 403 which is fine, proves connectivity)
try {
$r2Response = Invoke-WebRequest -Uri "https://$r2Domain/" -Method Head -UseBasicParsing -TimeoutSec 15 -ErrorAction Stop
Write-ColorOutput "PASS: HTTPS connection to Cloudflare R2" -Color Green
} catch [System.Net.WebException] {
$statusCode = $null
if ($_.Exception.Response) {
$statusCode = [int]$_.Exception.Response.StatusCode
}
if ($statusCode -eq 400 -or $statusCode -eq 403 -or $statusCode -eq 404 -or $statusCode -eq 405) {
# 400/403/404/405 means we connected successfully - just not authorized (expected without presigned URL)
Write-ColorOutput "PASS: HTTPS connection to Cloudflare R2 (got HTTP $statusCode - connection works, auth expected to fail without presigned URL)" -Color Green
} else {
Write-ColorOutput "FAIL: HTTPS connection to Cloudflare R2 ($r2Domain). Error: $($_.Exception.Message)" -IsError $true
$hasError = $true
}
} catch {
Write-ColorOutput "FAIL: HTTPS connection to Cloudflare R2 ($r2Domain). Error: $($_.Exception.Message)" -IsError $true
$hasError = $true
}
# Azure IoT Hub connectivity (needed post-install for agent communication)
Write-Host ""
Write-Host "[Post-Install Connectivity (IoT Hub)]" -ForegroundColor Cyan
$iotHubsByRegion = @{
"USW" = "gorelo.azure-devices.net"
"AUE" = "gorelo-aue.azure-devices.net"
}
$iotHubDomains = @(
$iotHubsByRegion[$region]
)
foreach ($domain in $iotHubDomains) {
try {
$dnsResult = [System.Net.Dns]::GetHostAddresses($domain)
if ($dnsResult.Count -gt 0) {
Write-ColorOutput "PASS: DNS resolution for IoT Hub ($domain)" -Color Green
}
} catch {
Write-ColorOutput "WARN: Cannot resolve IoT Hub domain ($domain). Agent may not connect after install." -Color Yellow
}
}
Write-Host ""
Write-Host "[Permission Checks]" -ForegroundColor Cyan
# Registry read/write
try {
$registryPath = "HKLM:\SOFTWARE\Gorelo"
if (-not (Test-Path $registryPath)) {
New-Item -Path $registryPath -Force -ErrorAction Stop | Out-Null
}
Set-ItemProperty -Path $registryPath -Name "PreCheck" -Value "test" -Type String -ErrorAction Stop
$testVal = (Get-ItemProperty -Path $registryPath -Name "PreCheck" -ErrorAction Stop).PreCheck
Remove-ItemProperty -Path $registryPath -Name "PreCheck" -Force -ErrorAction Stop
Write-ColorOutput "PASS: Registry read/write permission" -Color Green
} catch {
Write-ColorOutput "FAIL: Registry read/write permission. Error: $_" -IsError $true
$hasError = $true
}
# Event log
$logName = 'Application'
$sourceName = 'GoreloRmmTest'
try {
if (-not [System.Diagnostics.EventLog]::SourceExists($sourceName)) {
New-EventLog -LogName $logName -Source $sourceName -ErrorAction Stop
}
Write-EventLog -LogName $logName -Source $sourceName -EventId 0 -EntryType Information -Message "Gorelo pre-check test event" -ErrorAction Stop
Write-ColorOutput "PASS: Event log read/write permission" -Color Green
} catch {
Write-ColorOutput "FAIL: Event log read/write permission. Error: $_" -IsError $true
$hasError = $true
}
# PATH check
$path = [System.Environment]::GetEnvironmentVariable("PATH")
$system32Check = $path -like "*system32*"
$psCheck = $path -like "*System32\WindowsPowerShell\v1.0*"
if ($system32Check -and $psCheck) {
Write-ColorOutput "PASS: PATH contains system32 and PowerShell paths" -Color Green
} else {
$missing = @()
if (-not $system32Check) { $missing += "system32" }
if (-not $psCheck) { $missing += "WindowsPowerShell" }
Write-ColorOutput "FAIL: PATH missing: $($missing -join ', ')" -IsError $true
$hasError = $true
}
Write-Host ""
Write-Host "[Time Sync Check]" -ForegroundColor Cyan
# NTP time check
function Get-NTPTime {
try {
$NTPServer = "time.windows.com"
$NTPData = New-Object byte[] 48
$NTPData[0] = 27
$Socket = New-Object Net.Sockets.Socket([Net.Sockets.AddressFamily]::InterNetwork, [Net.Sockets.SocketType]::Dgram, [Net.Sockets.ProtocolType]::Udp)
$Socket.ReceiveTimeout = 5000
$Socket.SendTimeout = 5000
$Socket.Connect($NTPServer, 123)
$null = $Socket.Send($NTPData)
$null = $Socket.Receive($NTPData)
$Socket.Close()
$IntPart = [BitConverter]::ToUInt32($NTPData[43..40], 0)
$FracPart = [BitConverter]::ToUInt32($NTPData[47..44], 0)
$Milliseconds = ($IntPart * 1000) + (($FracPart * 1000) / 0x100000000)
return (New-Object DateTime(1900, 1, 1, 0, 0, 0, [DateTimeKind]::Utc)).AddMilliseconds($Milliseconds)
} catch {
return $null
}
}
$ntpTime = Get-NTPTime
if ($ntpTime) {
$currentTimeZone = Get-TimeZone
$expectedTime = [System.TimeZoneInfo]::ConvertTimeFromUtc($ntpTime, $currentTimeZone)
$currentTime = Get-Date
$timeDifference = ($currentTime - $expectedTime).TotalMinutes
if ([Math]::Abs($timeDifference) -gt 5) {
Write-ColorOutput "FAIL: Time mismatch! System: $($currentTime.ToString('yyyy-MM-dd HH:mm:ss')) | NTP: $($expectedTime.ToString('yyyy-MM-dd HH:mm:ss')) | Diff: $([Math]::Round($timeDifference, 1)) min" -IsError $true
$hasError = $true
} else {
Write-ColorOutput "PASS: Time sync OK (diff: $([Math]::Round($timeDifference, 1)) min) | TZ: $($currentTimeZone.Id)" -Color Green
}
} else {
Write-ColorOutput "WARN: Could not reach NTP server (time.windows.com:123 UDP) - skipping time check" -Color Yellow
}
# --- EXISTING INSTALLATION CHECK ---
Write-Host ""
Write-Host "[Existing Installation]" -ForegroundColor Cyan
$goreloDir = "$Env:ProgramW6432\Gorelo"
if (Test-Path $goreloDir) {
$goreloProcesses = @("Gorelo.Rmm.Installer", "Gorelo.RemoteManagement.Shell", "Gorelo.RemoteManagement.Agent")
$processList = (Get-Process).ProcessName
$runningProcesses = $goreloProcesses | Where-Object { $_ -in $processList }
if ($runningProcesses.Count -gt 0) {
Write-ColorOutput "INFO: Gorelo agent is already installed and running ($($runningProcesses -join ', '))" -Color White
} else {
Write-ColorOutput "INFO: Gorelo directory exists but agent processes are not running" -Color Yellow
}
} else {
Write-ColorOutput "INFO: No existing Gorelo installation found (clean install)" -Color White
}
# --- SUMMARY ---
Write-Host ""
Write-Host "======================================" -ForegroundColor Cyan
if ($hasError) {
Write-ColorOutput "RESULT: FAIL - One or more checks failed" -IsError $true
Write-Host "Fix the issues above and re-run this script." -ForegroundColor Yellow
} else {
Write-ColorOutput "RESULT: PASS - All checks passed. Ready to install." -Color Green
}
Write-Host "======================================" -ForegroundColor Cyan
Write-Host ""
'@
$scriptPath = Join-Path $env:TEMP "gorelo-check-windows.ps1"
Set-Content -Path $scriptPath -Value $scriptContent
& $scriptPath
Remove-Item $scriptPath -Force
- Choose your region (USW or AUE) when prompted.
- Work through resolving any failures, as per below, and make sure this persists across PowerShell sessions and reboots.
| Check | ❌ Failure Message | ✅ Troubleshooting |
|---|---|---|
| PowerShell Version Check | FAIL: PowerShell version X.X is below the required version 5.1 |
|
| System Drive Space Check |
|
|
| Processor Architecture Check | FAIL: Non-64-bit processor architecture detected: X |
|
| Registry Permission Check | FAIL: Registry read/write permission check. Error: [specific error] |
|
| URL Accessibility Checks | FAIL: URL check for [Description] ([URL]). Error: [specific error] | Checks the Gorelo gateway, API, and hub servers for your selected region.
|
| Cloudflare R2 Download Check |
|
|
| Event Log Permission Check | FAIL: Event log read/write permission check. Error: [specific error] |
|
| Environment Variable Check |
|
|
| Time Synchronization Check | FAIL: Time mismatch detected! [time details] |
|
gorelo.azure-devices.net for USW, gorelo-aue.azure-devices.net for AUE). If this can’t resolve, it’s shown as a warning, not a failure — the agent may just fail to connect after install, so it’s worth fixing but won’t block the installer check from passing.- Open Terminal on the Mac experiencing agent issues.
- Copy the entire command below, paste it into the window, and press Enter. You’ll be asked for your password, since the check needs to run as root.
gorelo-check-mac.sh
cat > /tmp/gorelo-check-mac.sh <<'EOF'
#!/bin/bash
# Gorelo Agent Pre-Installation Check Script (macOS)
# Updated: 2026-09-23
# Checks system requirements, connectivity (including Cloudflare R2), TLS, and permissions
#
# Run: curl -fsSL <raw-url>/gorelo-check-mac.sh | sudo bash
# Skip the region prompt: curl -fsSL <raw-url>/gorelo-check-mac.sh | sudo GORELO_REGION=AUE bash
#
# Written for the bash 3.2 that ships with macOS (no associative arrays).
RED=$'\033[31m'; GREEN=$'\033[32m'; YELLOW=$'\033[33m'; CYAN=$'\033[36m'; RESET=$'\033[0m'
has_error=0
pass() { echo "${GREEN}PASS: $*${RESET}"; }
fail() { echo "${RED}FAIL: $*${RESET}"; has_error=1; }
warn() { echo "${YELLOW}WARN: $*${RESET}"; }
info() { echo "INFO: $*"; }
section() { echo; echo "${CYAN}[$*]${RESET}"; }
echo
echo "${CYAN}======================================${RESET}"
echo "${CYAN} Gorelo Agent Pre-Installation Check${RESET}"
echo "${CYAN}======================================${RESET}"
echo
# --- REGION SELECTION ---
# When piped (curl | bash) stdin is the script itself, so the prompt reads from /dev/tty.
region=$(echo "${GORELO_REGION:-}" | tr '[:lower:]' '[:upper:]' | tr -d '[:space:]')
while [ "$region" != "USW" ] && [ "$region" != "AUE" ]; do
if [ ! -r /dev/tty ]; then
echo "${RED}No terminal to prompt on. Set GORELO_REGION=USW or GORELO_REGION=AUE.${RESET}"
exit 2
fi
echo "${CYAN}Select your Gorelo region:${RESET}"
echo " 1) USW (United States West)"
echo " 2) AUE (Australia East)"
printf "Enter 1 or 2 (or USW / AUE): "
read -r choice < /dev/tty
choice=$(echo "$choice" | tr '[:lower:]' '[:upper:]' | tr -d '[:space:]')
case "$choice" in
1) region="USW" ;;
2) region="AUE" ;;
*) region="$choice" ;;
esac
if [ "$region" != "USW" ] && [ "$region" != "AUE" ]; then
echo "${YELLOW}Invalid selection '$choice'. Please choose USW or AUE.${RESET}"
fi
done
if [ "$region" = "USW" ]; then
region_code="usw"
iot_hub="gorelo.azure-devices.net"
else
region_code="aue"
iot_hub="gorelo-aue.azure-devices.net"
fi
info "Region selected: $region"
# --- SYSTEM CHECKS ---
section "System Checks"
info "macOS $(sw_vers -productVersion) (build $(sw_vers -buildVersion))"
arch=$(uname -m)
if [ "$arch" = "arm64" ] || [ "$arch" = "x86_64" ]; then
pass "64-bit processor architecture ($arch)"
else
fail "Unsupported architecture detected: $arch"
fi
# Free space on the system volume (df -k: 1K blocks, column 4 = available)
free_kb=$(df -k / | awk 'NR==2 {print $4}')
if [ -n "$free_kb" ]; then
free_mb=$((free_kb / 1024))
if [ "$free_mb" -le 300 ]; then
fail "Free space is less than 300 MB (Current: $free_mb MB)"
else
pass "System drive space ($free_mb MB free)"
fi
else
fail "Unable to get drive info"
fi
if [ "$(id -u)" -eq 0 ]; then
pass "Running as root (sudo)"
else
fail "Not running as root (required for installation) - re-run with sudo"
fi
# --- TLS / SECURITY CHECKS ---
section "TLS / Security Checks"
if curl -s -o /dev/null --tlsv1.2 --max-time 15 "https://www.google.com/"; then
pass "TLS 1.2 connections work ($(curl --version | head -n 1 | awk '{print $1, $2}'))"
else
fail "Could not make a TLS 1.2 connection"
fi
# --- CONNECTIVITY CHECKS ---
section "Connectivity Checks"
check_url() {
# $1 = url, $2 = description, $3 = expected status
code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 15 "$1")
if [ "$code" = "000" ]; then
fail "$2 ($1). Could not connect"
elif [ "$code" = "$3" ]; then
pass "$2 ($1)"
else
warn "$2 returned $code (expected $3)"
fi
}
check_url "https://www.google.com/" "Internet connectivity" 200
check_url "https://gw.$region_code.gorelo.tech/rmm-login/api/login/_health" "Gorelo Gateway ($region)" 200
check_url "https://sr.rmm.pod1.$region_code.gorelo.tech/api/_health" "Gorelo API ($region)" 200
check_url "https://hub.rmm.pod1.$region_code.gorelo.tech/hc" "Gorelo Hub ($region)" 200
# --- CLOUDFLARE R2 (installer download source, same for all regions) ---
section "Cloudflare R2 Download Check"
r2_domain="600c23d50c6ee4462ecb200a47f6b627.r2.cloudflarestorage.com"
r2_ip=$(dscacheutil -q host -a name "$r2_domain" | awk '/^ip_address:/ {print $2; exit}')
if [ -n "$r2_ip" ]; then
pass "DNS resolution for Cloudflare R2 ($r2_domain -> $r2_ip)"
else
fail "Cannot resolve Cloudflare R2 domain ($r2_domain)"
fi
# HEAD to the bucket root: 400/403/404/405 proves connectivity (no presigned URL, so auth fails)
r2_code=$(curl -s -o /dev/null -I -w "%{http_code}" --max-time 15 "https://$r2_domain/")
case "$r2_code" in
2??) pass "HTTPS connection to Cloudflare R2" ;;
400|403|404|405) pass "HTTPS connection to Cloudflare R2 (got HTTP $r2_code - connection works, auth expected to fail without presigned URL)" ;;
*) fail "HTTPS connection to Cloudflare R2 ($r2_domain). Got: $r2_code" ;;
esac
# --- IOT HUB (needed post-install for agent communication) ---
section "Post-Install Connectivity (IoT Hub)"
if dscacheutil -q host -a name "$iot_hub" | grep -q '^ip_address:'; then
pass "DNS resolution for IoT Hub ($iot_hub)"
else
warn "Cannot resolve IoT Hub domain ($iot_hub). Agent may not connect after install."
fi
# --- PERMISSION CHECKS ---
section "Permission Checks"
test_dir="/Library/Gorelo"
created_dir=0
if [ ! -d "$test_dir" ]; then
mkdir -p "$test_dir" 2>/dev/null && created_dir=1
fi
test_file="$test_dir/.precheck-$$"
if echo "test" > "$test_file" 2>/dev/null && [ "$(cat "$test_file")" = "test" ]; then
pass "Write permission to $test_dir"
else
fail "Write permission to $test_dir"
fi
rm -f "$test_file" 2>/dev/null
[ "$created_dir" -eq 1 ] && rmdir "$test_dir" 2>/dev/null
if [ -w /Library/LaunchDaemons ]; then
pass "Write permission to /Library/LaunchDaemons"
else
fail "Write permission to /Library/LaunchDaemons"
fi
case ":$PATH:" in
*:/usr/bin:*) pass "PATH contains /usr/bin" ;;
*) fail "PATH missing /usr/bin" ;;
esac
# --- TIME SYNC CHECK ---
section "Time Sync Check"
# sntp prints e.g. "+0.012345 +/- 0.0123 time.apple.com 17.253.x.x"; first field = offset in seconds
offset=$(sntp -t 5 time.apple.com 2>/dev/null | awk '$1 ~ /^[+-]?[0-9.]+$/ {print $1; exit}')
if [ -n "$offset" ]; then
abs_min=$(awk -v o="$offset" 'BEGIN { if (o < 0) o = -o; printf "%.1f", o / 60 }')
if awk -v m="$abs_min" 'BEGIN { exit !(m > 5) }'; then
fail "Time mismatch! Offset from NTP: $abs_min min | System: $(date '+%Y-%m-%d %H:%M:%S')"
else
pass "Time sync OK (diff: $abs_min min) | TZ: $(readlink /etc/localtime | sed 's#.*/zoneinfo/##')"
fi
else
warn "Could not reach NTP server (time.apple.com:123 UDP) - skipping time check"
fi
# --- EXISTING INSTALLATION ---
section "Existing Installation"
if [ -d "/Library/Gorelo" ]; then
running=$(pgrep -il gorelo | awk '{print $2}' | sort -u | tr '\n' ' ')
if [ -n "$running" ]; then
info "Gorelo agent is already installed and running ($running)"
else
echo "${YELLOW}INFO: Gorelo directory exists but agent processes are not running${RESET}"
fi
else
info "No existing Gorelo installation found (clean install)"
fi
# --- SUMMARY ---
echo
echo "${CYAN}======================================${RESET}"
if [ "$has_error" -eq 1 ]; then
echo "${RED}RESULT: FAIL - One or more checks failed${RESET}"
echo "${YELLOW}Fix the issues above and re-run this script.${RESET}"
else
echo "${GREEN}RESULT: PASS - All checks passed. Ready to install.${RESET}"
fi
echo "${CYAN}======================================${RESET}"
echo
exit "$has_error"
EOF
chmod +x /tmp/gorelo-check-mac.sh
sudo /tmp/gorelo-check-mac.sh
rm -f /tmp/gorelo-check-mac.sh
- Choose your region (USW or AUE) when prompted.
- Work through resolving any failures, as per below, and make sure this persists across Terminal sessions and reboots.
| Check | ❌ Failure Message | ✅ Troubleshooting |
|---|---|---|
| Processor Architecture Check | FAIL: Unsupported architecture detected: [arch] |
|
| Disk Space Check |
|
|
| Admin Rights Check | FAIL: Not running as root (required for installation) - re-run with sudo |
|
| TLS Check | FAIL: Could not make a TLS 1.2 connection |
|
| Gorelo Server Checks (Gateway / API / Hub) | FAIL: [Description] ([URL]). Could not connect | Checks the Gorelo gateway, API, and hub servers for your selected region.
|
| Cloudflare R2 Download Check |
|
|
| Install Folder Permission Check |
|
|
| PATH Check | FAIL: PATH missing /usr/bin |
|
| Time Synchronization Check | FAIL: Time mismatch! Offset from NTP: X min |
|
gorelo.azure-devices.net for USW, gorelo-aue.azure-devices.net for AUE). If this can’t resolve, it’s shown as a warning, not a failure — the agent may just fail to connect after install, so it’s worth fixing but won’t block the installer check from passing.Logs
- Windows
- macOS
Gorelo logs everything to:As the install progresses, the installer creates additional folders at each stage with log files inside:InstallerHandler > Installer > Shell > AgentFeel free to investigate the following logs — this is where the most common issues will appear:If Gorelo support asks for log files, send the entire LogFiles folder as a .zip.
%programfiles%\Gorelo\LogFiles\
%programfiles%\Gorelo\LogFiles\Installer\diagnostics**.log
%programfiles%\Gorelo\LogFiles\Agent\diagnostics**.log
Gorelo logs everything to:Feel free to investigate the following logs — this is where the most common issues will appear:If Gorelo support asks for log files, send the entire LogFiles folder as a .zip.
/Library/Gorelo/LogFiles/
/Library/Gorelo/LogFiles/ServiceLogs/installer_logs_info.log
/Library/Gorelo/LogFiles/ServiceLogs/installer_logs_error.log
/Library/Gorelo/LogFiles/ServiceLogs/agent_logs_info.log
/Library/Gorelo/LogFiles/ServiceLogs/agent_logs_error.log