Remove Cloudflare tunnel; shorten generated admin password to 8 chars.
The tunnel setup is being handled externally. Removed all cloudflared install/watchdog scripts and config from LAUNCH.bat and usb\. LAUNCH.bat now shows LAN IP directly. Admin password generator changed from 20-char hex to 8-char hex for easier first login.
This commit is contained in:
@@ -170,35 +170,19 @@ if not exist "%ROOT%\data\blueprints" mkdir "%ROOT%\data\blueprints"
|
||||
if not exist "%ROOT%\data\preps" mkdir "%ROOT%\data\preps"
|
||||
|
||||
:: ----------------------------------------------------------------
|
||||
:: 5. Cloudflare Tunnel - start in background window + 60s watchdog
|
||||
:: 5. Detect LAN IP for display
|
||||
:: ----------------------------------------------------------------
|
||||
set "SERVER_PORT=8989"
|
||||
set "CF_HOSTNAME=aether.thetempleofdoom.com"
|
||||
set "CF_READY=0"
|
||||
|
||||
if not exist "%ROOT%\cloudflare\start-tunnel.ps1" (
|
||||
echo [CF] WARNING: cloudflare\start-tunnel.ps1 missing - tunnel skipped.
|
||||
goto cf_done
|
||||
for /f "tokens=2 delims=:" %%I in ('ipconfig ^| findstr /i "IPv4" ^| findstr /v "127.0.0.1"') do (
|
||||
set "LAN_IP=%%I"
|
||||
goto lan_done
|
||||
)
|
||||
|
||||
echo.
|
||||
echo [CF] Starting Cloudflare tunnel for https://%CF_HOSTNAME% ...
|
||||
echo [CF] Log: %ROOT%\data\logs\tunnel.log
|
||||
start "AetherForge Tunnel" powershell -NoProfile -ExecutionPolicy Bypass -File "%ROOT%\cloudflare\start-tunnel.ps1" -Root "%ROOT%"
|
||||
|
||||
:: Give the tunnel script 8 seconds to start before we open the server
|
||||
ping -n 9 127.0.0.1 >nul
|
||||
set "CF_READY=1"
|
||||
|
||||
:cf_done
|
||||
|
||||
:: ----------------------------------------------------------------
|
||||
:: 6. Detect LAN IP for display
|
||||
:: ----------------------------------------------------------------
|
||||
set "LAN_IP=localhost"
|
||||
:lan_done
|
||||
set "LAN_IP=%LAN_IP: =%"
|
||||
|
||||
:: ----------------------------------------------------------------
|
||||
:: 7. Kill any stale server process
|
||||
:: 6. Kill any stale server process
|
||||
:: ----------------------------------------------------------------
|
||||
taskkill /F /IM AetherForge.exe >nul 2>nul
|
||||
ping -n 2 127.0.0.1 >nul
|
||||
@@ -207,15 +191,11 @@ echo.
|
||||
echo ================================================================
|
||||
echo STARTING CONTROL DECK
|
||||
echo ================================================================
|
||||
echo Local: http://localhost:%SERVER_PORT%
|
||||
echo LAN: http://%LAN_IP%:%SERVER_PORT%
|
||||
if "!CF_READY!"=="1" (
|
||||
echo Public: https://!CF_HOSTNAME!
|
||||
echo Dropper PS: iex -irm https://!CF_HOSTNAME!/install.ps1
|
||||
)
|
||||
echo Data: %ROOT%\data\
|
||||
echo Local: http://localhost:%SERVER_PORT%
|
||||
echo LAN: http://%LAN_IP%:%SERVER_PORT%
|
||||
echo Data: %ROOT%\data\
|
||||
echo.
|
||||
echo Dashboard login printed below each start.
|
||||
echo Login credentials printed below.
|
||||
echo Press Ctrl+C to stop.
|
||||
echo ================================================================
|
||||
echo.
|
||||
@@ -235,8 +215,6 @@ if "!EC!"=="0" (
|
||||
echo If port %SERVER_PORT% is in use, close other AetherForge windows and retry.
|
||||
)
|
||||
|
||||
:: Cloudflare tunnel runs as a Windows service — stays up after LAUNCH.bat exits
|
||||
|
||||
echo.
|
||||
pause
|
||||
endlocal
|
||||
|
||||
@@ -1,302 +0,0 @@
|
||||
#Requires -Version 5
|
||||
param([string]$Root)
|
||||
$ErrorActionPreference = 'Continue'
|
||||
$Root = ($Root -replace '\\$','')
|
||||
|
||||
# --- Config (overridden by tunnel-config.json if present) --------------------
|
||||
$TOKEN = 'eyJhIjoiODk1NDc5YWIzNTQwZGFhNmQ2MWFlNzAyYTUxNjQ0NzUiLCJ0IjoiYWFhYzYzMTctMzgyYS00OTM3LTgxY2YtYjM2ZjVkNjZjYTU4IiwicyI6Ik1XRXlaV0ZqTlRndE5XTTRPUzAwT0RCa0xXRTNaR010WkdRNU56UTJZMlJoTmpNMiJ9'
|
||||
$HOSTNAME = 'aether.thetempleofdoom.com'
|
||||
$ORIGIN = 'http://127.0.0.1:8989'
|
||||
$SVC = 'cloudflared'
|
||||
$DESTDIR = "$env:ProgramData\AetherForge\bin"
|
||||
$LOGDIR = "$Root\data\logs"
|
||||
$LOGFILE = "$LOGDIR\tunnel.log"
|
||||
$PIDFILE = "$env:ProgramData\AetherForge\tunnel.pid"
|
||||
$INTERVAL = 60
|
||||
|
||||
$cfgPath = Join-Path $PSScriptRoot 'tunnel-config.json'
|
||||
if (Test-Path $cfgPath) {
|
||||
try {
|
||||
$c = Get-Content $cfgPath -Raw | ConvertFrom-Json
|
||||
if ($c.tunnel_token) { $TOKEN = $c.tunnel_token }
|
||||
if ($c.hostname) { $HOSTNAME = $c.hostname }
|
||||
if ($c.origin) { $ORIGIN = $c.origin }
|
||||
if ($c.watch_interval_seconds){ $INTERVAL = [int]$c.watch_interval_seconds }
|
||||
} catch {}
|
||||
}
|
||||
|
||||
# --- Helpers -----------------------------------------------------------------
|
||||
function Log([string]$msg, [string]$tag = 'INFO') {
|
||||
$line = '{0} [TUNNEL][{1}] {2}' -f (Get-Date -Format 'HH:mm:ss'), $tag, $msg
|
||||
Write-Host $line
|
||||
try { Add-Content -LiteralPath $LOGFILE -Value $line -Encoding UTF8 } catch {}
|
||||
}
|
||||
|
||||
function SvcState {
|
||||
$q = (& sc.exe query $SVC 2>&1) -join ' '
|
||||
if ($q -match '1060|does not exist') { return 'MISSING' }
|
||||
if ($q -match 'RUNNING') { return 'RUNNING' }
|
||||
if ($q -match 'STOPPED') { return 'STOPPED' }
|
||||
return 'UNKNOWN'
|
||||
}
|
||||
|
||||
function IsAdmin {
|
||||
([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()
|
||||
).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||
}
|
||||
|
||||
function HttpGet([string]$url, [int]$sec = 10) {
|
||||
try {
|
||||
$r = Invoke-WebRequest -Uri $url -UseBasicParsing -TimeoutSec $sec
|
||||
return [pscustomobject]@{ Ok=$true; Code=[int]$r.StatusCode; Err=$null }
|
||||
} catch {
|
||||
$code = $null
|
||||
if ($_.Exception.Response) { $code = [int]$_.Exception.Response.StatusCode }
|
||||
return [pscustomobject]@{ Ok=$false; Code=$code; Err=$_.Exception.Message }
|
||||
}
|
||||
}
|
||||
|
||||
# --- Locate cloudflared -------------------------------------------------------
|
||||
function FindCloudflared {
|
||||
# 1. Already staged in ProgramData
|
||||
if (Test-Path "$DESTDIR\cloudflared.exe") { return "$DESTDIR\cloudflared.exe" }
|
||||
|
||||
New-Item -ItemType Directory -Force -Path $DESTDIR | Out-Null
|
||||
|
||||
# 2. Bundled next to this script on the USB
|
||||
$bundled = Join-Path $PSScriptRoot 'cloudflared.exe'
|
||||
if (Test-Path $bundled) {
|
||||
Copy-Item $bundled "$DESTDIR\cloudflared.exe" -Force
|
||||
return "$DESTDIR\cloudflared.exe"
|
||||
}
|
||||
|
||||
# 3. MSI-installed on this PC
|
||||
foreach ($dir in @("$env:ProgramFiles\cloudflare\cloudflared",
|
||||
"${env:ProgramFiles(x86)}\cloudflare\cloudflared")) {
|
||||
if (Test-Path "$dir\cloudflared.exe") {
|
||||
Copy-Item "$dir\cloudflared.exe" "$DESTDIR\cloudflared.exe" -Force
|
||||
return "$DESTDIR\cloudflared.exe"
|
||||
}
|
||||
}
|
||||
|
||||
# 4. Run the MSI if bundled
|
||||
$msi = Join-Path $PSScriptRoot 'cloudflared-windows-amd64.msi'
|
||||
if (Test-Path $msi) {
|
||||
Log 'Installing cloudflared MSI...' 'SETUP'
|
||||
Start-Process msiexec -ArgumentList "/i `"$msi`" /quiet /norestart" -Wait
|
||||
Start-Sleep -Seconds 6
|
||||
if (Test-Path "$env:ProgramFiles\cloudflare\cloudflared\cloudflared.exe") {
|
||||
Copy-Item "$env:ProgramFiles\cloudflare\cloudflared\cloudflared.exe" "$DESTDIR\cloudflared.exe" -Force
|
||||
return "$DESTDIR\cloudflared.exe"
|
||||
}
|
||||
}
|
||||
|
||||
# 5. Download from GitHub as last resort
|
||||
Log 'Downloading cloudflared from GitHub...' 'SETUP'
|
||||
try {
|
||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||
$url = 'https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-windows-amd64.exe'
|
||||
Invoke-WebRequest -Uri $url -OutFile "$DESTDIR\cloudflared.exe" -UseBasicParsing
|
||||
if (Test-Path "$DESTDIR\cloudflared.exe") { return "$DESTDIR\cloudflared.exe" }
|
||||
} catch { Log "Download failed: $_" 'ERROR' }
|
||||
|
||||
return $null
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# MAIN
|
||||
# =============================================================================
|
||||
New-Item -ItemType Directory -Force -Path $LOGDIR | Out-Null
|
||||
New-Item -ItemType Directory -Force -Path $DESTDIR | Out-Null
|
||||
|
||||
Log "Tunnel setup hostname=$HOSTNAME origin=$ORIGIN" 'SETUP'
|
||||
|
||||
$CF = FindCloudflared
|
||||
if (-not $CF) {
|
||||
Log 'Cannot locate cloudflared.exe - tunnel skipped.' 'ERROR'
|
||||
exit 1
|
||||
}
|
||||
Log "Using: $CF" 'SETUP'
|
||||
|
||||
# --- Install + start as Windows service (admin path) -------------------------
|
||||
$asService = $false
|
||||
|
||||
if (IsAdmin) {
|
||||
# Stop and remove any existing service
|
||||
if ((SvcState) -ne 'MISSING') {
|
||||
Log 'Removing existing cloudflared service...' 'SETUP'
|
||||
& net.exe stop $SVC 2>&1 | Out-Null
|
||||
Start-Sleep -Seconds 2
|
||||
& sc.exe delete $SVC 2>&1 | Out-Null
|
||||
Start-Sleep -Seconds 2
|
||||
}
|
||||
|
||||
# Clear stale EventLog registry key left by previous installs.
|
||||
# cloudflared rolls back the entire service install if this key already exists.
|
||||
$evtKey = 'HKLM:\SYSTEM\CurrentControlSet\Services\EventLog\Application\Cloudflared'
|
||||
if (Test-Path $evtKey) {
|
||||
Log 'Removing stale EventLog registry key...' 'SETUP'
|
||||
Remove-Item -LiteralPath $evtKey -Force -ErrorAction SilentlyContinue
|
||||
Start-Sleep -Seconds 1
|
||||
}
|
||||
|
||||
Log 'Installing cloudflared Windows service...' 'SETUP'
|
||||
# Capture output without triggering PS NativeCommandError decorations
|
||||
$installOut = (& $CF service install $TOKEN 2>&1) -join "`n"
|
||||
Log $installOut.Trim() 'SETUP'
|
||||
Start-Sleep -Seconds 3
|
||||
|
||||
Log 'Starting service...' 'SETUP'
|
||||
& net.exe start $SVC 2>&1 | Out-Null
|
||||
Start-Sleep -Seconds 6
|
||||
|
||||
if ((SvcState) -eq 'RUNNING') {
|
||||
Log 'Service RUNNING' 'OK'
|
||||
$asService = $true
|
||||
} else {
|
||||
Log "Service not RUNNING after install (state=$(SvcState)) - falling back to background process." 'WARN'
|
||||
}
|
||||
} else {
|
||||
Log 'Not running as Administrator.' 'WARN'
|
||||
Log 'For a persistent Windows service: right-click LAUNCH.bat > Run as administrator.' 'WARN'
|
||||
if ((SvcState) -eq 'RUNNING') {
|
||||
Log 'Existing cloudflared service is RUNNING - using it.' 'OK'
|
||||
$asService = $true
|
||||
}
|
||||
}
|
||||
|
||||
# --- Run directly as background process (non-admin fallback) -----------------
|
||||
$bgProc = $null
|
||||
if (-not $asService) {
|
||||
Log 'Starting cloudflared as background process...' 'SETUP'
|
||||
|
||||
# Kill leftover from previous run
|
||||
if (Test-Path $PIDFILE) {
|
||||
$oldpid = [int](Get-Content $PIDFILE -Raw -ErrorAction SilentlyContinue)
|
||||
if ($oldpid) { Stop-Process -Id $oldpid -Force -ErrorAction SilentlyContinue }
|
||||
}
|
||||
|
||||
$si = New-Object System.Diagnostics.ProcessStartInfo
|
||||
$si.FileName = $CF
|
||||
$si.Arguments = "tunnel run --token $TOKEN"
|
||||
$si.UseShellExecute = $false
|
||||
$si.CreateNoWindow = $true
|
||||
|
||||
$bgProc = [System.Diagnostics.Process]::Start($si)
|
||||
Set-Content -LiteralPath $PIDFILE -Value $bgProc.Id -Encoding ASCII
|
||||
Log "cloudflared running (PID $($bgProc.Id))" 'SETUP'
|
||||
Start-Sleep -Seconds 5
|
||||
}
|
||||
|
||||
# --- Wait up to 20s for cloudflared to establish connection ------------------
|
||||
# NOTE: We do NOT check the public URL here because AetherForge hasn't started
|
||||
# yet (LAUNCH.bat starts it after this script returns). A 502 at this stage is
|
||||
# normal - it just means the tunnel is connected but origin isn't up yet.
|
||||
# The watchdog (below) will report OK once AetherForge is running.
|
||||
Log "Giving cloudflared 20s to connect to Cloudflare..." 'SETUP'
|
||||
Start-Sleep -Seconds 20
|
||||
$finalState = SvcState
|
||||
if ($asService) {
|
||||
if ($finalState -eq 'RUNNING') {
|
||||
Log "Tunnel connector ready (service=$finalState). AetherForge starting next." 'OK'
|
||||
} else {
|
||||
Log "Service state=$finalState after 20s - may still be connecting." 'WARN'
|
||||
}
|
||||
} else {
|
||||
if ($bgProc -and -not $bgProc.HasExited) {
|
||||
Log "Tunnel connector ready (background PID $($bgProc.Id)). AetherForge starting next." 'OK'
|
||||
} else {
|
||||
Log "cloudflared process exited unexpectedly." 'ERROR'
|
||||
}
|
||||
}
|
||||
Log "Public URL will be live once AetherForge starts: https://$HOSTNAME" 'SETUP'
|
||||
|
||||
# =============================================================================
|
||||
# WATCHDOG - runs forever; auto-restarts cloudflared if it goes down
|
||||
# =============================================================================
|
||||
Log "Watchdog started: checking every ${INTERVAL}s. Log: $LOGFILE" 'WATCH'
|
||||
$fails = 0
|
||||
|
||||
while ($true) {
|
||||
Start-Sleep -Seconds $INTERVAL
|
||||
|
||||
$svc = SvcState
|
||||
$pub = HttpGet "https://$HOSTNAME/" 12
|
||||
$procOk = ($bgProc -ne $null) -and (-not $bgProc.HasExited)
|
||||
|
||||
# In background-process mode the service will always be MISSING - that is fine.
|
||||
$connectorOk = ($asService -and $svc -eq 'RUNNING') -or (-not $asService -and $procOk)
|
||||
$ok = $pub.Ok -and $connectorOk
|
||||
|
||||
if ($ok) {
|
||||
if ($fails -gt 0) { Log "Recovered after $fails failure(s)." 'OK' }
|
||||
else { Log "OK svc=$svc public=HTTP $($pub.Code)" 'WATCH' }
|
||||
$fails = 0
|
||||
continue
|
||||
}
|
||||
|
||||
$fails++
|
||||
$pubLabel = if ($pub.Ok) { "HTTP $($pub.Code)" } else { $pub.Err }
|
||||
$connLabel = if ($asService) { "svc=$svc" } else { "proc=$(if($procOk){'alive'}else{'dead'})" }
|
||||
Log "DEGRADED #$fails $connLabel public=$pubLabel" 'WARN'
|
||||
|
||||
if ($asService) {
|
||||
# --- Service mode healing ---
|
||||
if ($svc -ne 'RUNNING') {
|
||||
Log 'Restart: net start cloudflared' 'HEAL'
|
||||
& net.exe start $SVC 2>&1 | Out-Null
|
||||
Start-Sleep -Seconds 5
|
||||
if ((SvcState) -eq 'RUNNING') {
|
||||
Log 'Service restarted OK.' 'HEAL'
|
||||
$fails = 0
|
||||
} elseif ($fails -ge 3 -and (IsAdmin)) {
|
||||
Log 'Reinstalling cloudflared service after 3 failures...' 'HEAL'
|
||||
& net.exe stop $SVC 2>&1 | Out-Null
|
||||
& sc.exe delete $SVC 2>&1 | Out-Null
|
||||
Start-Sleep -Seconds 2
|
||||
& $CF service install $TOKEN 2>&1 | Out-Null
|
||||
Start-Sleep -Seconds 2
|
||||
& net.exe start $SVC 2>&1 | Out-Null
|
||||
Start-Sleep -Seconds 5
|
||||
if ((SvcState) -eq 'RUNNING') {
|
||||
Log 'Service reinstalled and RUNNING.' 'HEAL'
|
||||
$fails = 0
|
||||
} else {
|
||||
Log 'Reinstall failed.' 'ERROR'
|
||||
}
|
||||
}
|
||||
} else {
|
||||
# Service running but public URL unreachable
|
||||
Log "Service OK but public URL unreachable. Check Cloudflare dashboard route and that AetherForge is on port 8989." 'WARN'
|
||||
}
|
||||
} else {
|
||||
# --- Background process mode healing ---
|
||||
if ($bgProc -and $bgProc.HasExited) {
|
||||
Log "cloudflared process exited - restarting..." 'HEAL'
|
||||
$si2 = New-Object System.Diagnostics.ProcessStartInfo
|
||||
$si2.FileName = $CF
|
||||
$si2.Arguments = "tunnel run --token $TOKEN"
|
||||
$si2.UseShellExecute = $false
|
||||
$si2.CreateNoWindow = $true
|
||||
$bgProc = [System.Diagnostics.Process]::Start($si2)
|
||||
Set-Content -LiteralPath $PIDFILE -Value $bgProc.Id -Encoding ASCII
|
||||
Log "cloudflared restarted (PID $($bgProc.Id))" 'HEAL'
|
||||
$fails = 0
|
||||
Start-Sleep -Seconds 8
|
||||
} elseif ($fails -ge 3) {
|
||||
Log "3 failures, killing and restarting cloudflared..." 'HEAL'
|
||||
if ($bgProc -and -not $bgProc.HasExited) { $bgProc.Kill() }
|
||||
Start-Sleep -Seconds 2
|
||||
$si3 = New-Object System.Diagnostics.ProcessStartInfo
|
||||
$si3.FileName = $CF
|
||||
$si3.Arguments = "tunnel run --token $TOKEN"
|
||||
$si3.UseShellExecute = $false
|
||||
$si3.CreateNoWindow = $true
|
||||
$bgProc = [System.Diagnostics.Process]::Start($si3)
|
||||
Set-Content -LiteralPath $PIDFILE -Value $bgProc.Id -Encoding ASCII
|
||||
Log "cloudflared restarted (PID $($bgProc.Id))" 'HEAL'
|
||||
$fails = 0
|
||||
Start-Sleep -Seconds 8
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"tunnel_token": "eyJhIjoiODk1NDc5YWIzNTQwZGFhNmQ2MWFlNzAyYTUxNjQ0NzUiLCJ0IjoiYWFhYzYzMTctMzgyYS00OTM3LTgxY2YtYjM2ZjVkNjZjYTU4IiwicyI6Ik1XRXlaV0ZqTlRndE5XTTRPUzAwT0RCa0xXRTNaR010WkdRNU56UTJZMlJoTmpNMiJ9",
|
||||
"hostname": "aether.thetempleofdoom.com",
|
||||
"origin": "http://127.0.0.1:8989",
|
||||
"watch_interval_seconds": 60
|
||||
}
|
||||
Reference in New Issue
Block a user