feat: [US-004] Add SSH tunnel auto-start for Windows services

- Add ssh-tunnel.ps1: Windows SSH tunnel manager (equivalent to ssh-tunnel.sh)
  - Supports password auth via plink.exe (PuTTY)
  - Supports ssh_hostkey for non-interactive batch mode
  - Commands: start, stop, restart, status

- Add start-backend-service.ps1: NSSM service wrapper
  - Starts SSH tunnels before uvicorn
  - Waits for tunnel ports to be accessible (30s timeout)
  - Configured by Install-ROA2WEB.ps1

- Add start.ps1: Windows equivalent of start.sh
  - Orchestrates SSH tunnel + backend + frontend startup

- Add backend/shared/ssh_tunnel_manager.py: Python monitoring
  - Background asyncio task monitors tunnel health every 30s
  - Auto-restarts tunnels after 2 consecutive failures
  - Exposes status to /health endpoint

- Update ROA2WEB-Console.ps1:
  - Add Deploy-Scripts function
  - Update Update-ServiceToUseVenv to use wrapper script

- Fix PowerShell reserved variable ($PID -> $tunnelPid)
- Fix script path detection (scripts/ vs deployment/windows/scripts/)
- Update README.md with ssh_hostkey documentation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-01-28 19:04:26 +00:00
parent dc1711acd0
commit 6718c956f7
9 changed files with 1766 additions and 26 deletions

View File

@@ -383,21 +383,24 @@ function New-WindowsService {
Write-Success "Existing service removed"
}
# Get Python path from venv
# Verify venv exists (wrapper script needs it)
$venvPython = Join-Path $Config.VenvPath "Scripts\python.exe"
if (-not (Test-Path $venvPython)) {
throw "Virtual environment Python not found at $venvPython. Run Install-PythonDependencies first."
}
$uvicornModule = "uvicorn"
$appModule = "main:app"
# NSSM service creation
# NSSM service creation using wrapper script
# The wrapper script (start-backend-service.ps1) handles:
# 1. Starting SSH tunnels before backend
# 2. Waiting for tunnel ports to be accessible
# 3. Starting uvicorn
try {
# Install service using venv Python
# NOTE: Using --workers 1 because Telegram bot requires single instance (polling conflict)
& nssm install $Config.ServiceName $venvPython "-m" $uvicornModule $appModule "--host" "127.0.0.1" "--port" $Config.ServicePort.ToString() "--workers" "1"
$wrapperScript = Join-Path $PSScriptRoot "start-backend-service.ps1"
# Install service using PowerShell wrapper
# NOTE: Using wrapper to ensure SSH tunnels start before uvicorn
& nssm install $Config.ServiceName "powershell.exe" "-ExecutionPolicy" "Bypass" "-File" "`"$wrapperScript`""
# Set service configuration
& nssm set $Config.ServiceName DisplayName $Config.ServiceDisplayName
@@ -423,7 +426,8 @@ function New-WindowsService {
& nssm set $Config.ServiceName AppExit Default Restart
& nssm set $Config.ServiceName AppRestartDelay 5000
Write-Success "Windows Service created successfully"
Write-Success "Windows Service created successfully (using wrapper script)"
Write-Success " Wrapper: $wrapperScript"
} catch {
throw "Failed to create Windows Service: $_"
}