# install-mittelstandos-netsnake.ps1 # Netsnake 1-Click-Installer für Windows # Führt aus: WireGuard-Installation → Netsnake-Registration → Heartbeat → Ollama → Modell # Erwartet: slot-config.json im selben Ordner $ErrorActionPreference = "Stop" $Host.UI.RawUI.WindowTitle = "MittelstandOS Netsnake-Installer" $CONFIG_FILE = Join-Path $PSScriptRoot "slot-config.json" $NETSNAKE_DIR = "$env:ProgramData\Netsnake" $MGMT_URL = "https://login.mittelstandos.io" $WG_CONFIG_DIR = "$env:ProgramFiles\WireGuard\Data\Configurations" Write-Host "============================================" -ForegroundColor Cyan Write-Host " MittelstandOS Netsnake-Installer" -ForegroundColor Cyan Write-Host " (Windows)" -ForegroundColor Cyan Write-Host "============================================" -ForegroundColor Cyan Write-Host "" # === Config prüfen === if (-not (Test-Path $CONFIG_FILE)) { Write-Host "❌ slot-config.json nicht gefunden!" -ForegroundColor Red Write-Host " Download unter: https://login.mittelstandos.io/download/" exit 1 } # === Config auslesen === Write-Host "[1/7] Konfiguration lesen..." -ForegroundColor Yellow $config = Get-Content $CONFIG_FILE -Raw | ConvertFrom-Json $setupKey = $config.netsnake.setup_key $endpoint = $config.netsnake.endpoint $serverPubkey = $config.netsnake.server_public_key $subdomain = $config.subdomain_url $ollamaModel = $config.ollama.model $slot = $config.slot Write-Host " Slot: $slot" -ForegroundColor Green Write-Host " Subdomain: $subdomain" -ForegroundColor Green Write-Host " Modell: $ollamaModel" -ForegroundColor Green # === 1. WireGuard installieren === Write-Host "" Write-Host "[2/7] WireGuard installieren..." -ForegroundColor Yellow $wgExe = "$env:ProgramFiles\WireGuard\wg.exe" if (-not (Test-Path $wgExe)) { Write-Host " Lade WireGuard for Windows herunter..." $wgMsiUrl = "https://download.wireguard.com/windows-client/wireguard-installer.exe" $wgInstaller = "$env:TEMP\wireguard-installer.exe" try { Invoke-WebRequest -Uri $wgMsiUrl -OutFile $wgInstaller -UseBasicParsing Write-Host " Installiere WireGuard (stumm)..." Start-Process -Wait -FilePath $wgInstaller -ArgumentList "/S" Write-Host " ✅ WireGuard installiert" -ForegroundColor Green } catch { Write-Host " ⚠️ Download fehlgeschlagen. Bitte WireGuard manuell installieren:" -ForegroundColor Yellow Write-Host " https://www.wireguard.com/install/" Write-Host " Fahre trotzdem fort (Registration + Heartbeat)..." } } else { Write-Host " ✅ WireGuard bereits vorhanden" -ForegroundColor Green } # === 2. WG-Keypair generieren === Write-Host "" Write-Host "[3/7] WireGuard-Keypair generieren..." -ForegroundColor Yellow if (-not (Test-Path $NETSNAKE_DIR)) { New-Item -ItemType Directory -Path $NETSNAKE_DIR -Force | Out-Null } $privateKey = & "$env:ProgramFiles\WireGuard\wg.exe" genkey $publicKey = & "$env:ProgramFiles\WireGuard\wg.exe" pubkey <<< $privateKey $privateKey | Out-File -FilePath "$NETSNAKE_DIR\privatekey" -NoNewline -Force $publicKey | Out-File -FilePath "$NETSNAKE_DIR\publickey" -NoNewline -Force $setupKey | Out-File -FilePath "$NETSNAKE_DIR\setup_key" -NoNewline -Force Write-Host " ✅ Keypair erstellt" -ForegroundColor Green # === 3. Registration === Write-Host "" Write-Host "[4/7] Bei Netsnake registrieren..." -ForegroundColor Yellow $body = @{ setup_key = $setupKey; public_key = $publicKey } | ConvertTo-Json try { $regResp = Invoke-RestMethod -Uri "$MGMT_URL/api/netsnake/register" -Method POST -Body $body -ContentType "application/json" $assignedIp = $regResp.assigned_ip Write-Host " ✅ Registriert! IP: $assignedIp" -ForegroundColor Green } catch { $errMsg = $_.Exception.Message if ($errMsg -match "409") { Write-Host "❌ Setup-Key bereits verwendet (409)." -ForegroundColor Red Write-Host " Bitte kontaktieren Sie uns für einen neuen Key." } else { Write-Host "❌ Registration fehlgeschlagen: $errMsg" -ForegroundColor Red } exit 1 } # === 4. WireGuard-Konfiguration schreiben === Write-Host "" Write-Host "[5/7] WireGuard-Konfiguration schreiben..." -ForegroundColor Yellow if (-not (Test-Path $WG_CONFIG_DIR)) { New-Item -ItemType Directory -Path $WG_CONFIG_DIR -Force | Out-Null } $wgConfig = @" [Interface] PrivateKey = $privateKey Address = $assignedIp/16 ListenPort = 51820 [Peer] PublicKey = $serverPubkey AllowedIPs = 100.64.0.0/16 Endpoint = $endpoint PersistentKeepalive = 25 "@ $wgConfig | Out-File -FilePath "$WG_CONFIG_DIR\netsnake.conf" -Encoding ASCII -Force Write-Host " ✅ netsnake.conf geschrieben" -ForegroundColor Green # Tunnel installieren (als Windows Service) Write-Host " Installiere WireGuard-Tunnel als Dienst..." & "$env:ProgramFiles\WireGuard\wireguard.exe" /installtunnelservice "$WG_CONFIG_DIR\netsnake.conf" 2>$null if ($LASTEXITCODE -eq 0 -or $LASTEXITCODE -eq 2) { Write-Host " ✅ Tunnel aktiv" -ForegroundColor Green } else { Write-Host " ⚠️ Tunnel konnte nicht als Dienst installiert werden" -ForegroundColor Yellow Write-Host " Bitte starten Sie WireGuard und importieren Sie die Config manuell:" Write-Host " $WG_CONFIG_DIR\netsnake.conf" } # === 5. Heartbeat einrichten === Write-Host "" Write-Host "[6/7] Heartbeat einrichten..." -ForegroundColor Yellow $sharedSecret = Get-SHA256Hash $setupKey $heartbeatScript = @" # netsnake-heartbeat.ps1 `$setupKey = Get-Content "$NETSNAKE_DIR\setup_key" -Raw `$pubKey = Get-Content "$NETSNAKE_DIR\publickey" -Raw `$sharedSecret = "$sharedSecret" `$timestamp = [int][double]::Parse((Get-Date -UFormat %s)) `$payload = "`$timestamp`$pubKey" `$hmac = New-Object Security.Cryptography.HMACSHA256 `$hmac.Key = [Text.Encoding]::UTF8.GetBytes(`$sharedSecret) `$sig = [System.BitConverter]::ToString(`$hmac.ComputeHash([Text.Encoding]::UTF8.GetBytes(`$payload))).Replace("-","").ToLower() `$body = @{public_key=`$pubKey; timestamp=`$timestamp; sig=`$sig} | ConvertTo-Json try { Invoke-RestMethod -Uri "$MGMT_URL/api/netsnake/heartbeat" -Method POST -Body `$body -ContentType "application/json" } catch {} "@ $heartbeatScript | Out-File -FilePath "$NETSNAKE_DIR\netsnake-heartbeat.ps1" -Encoding ASCII -Force # Task Scheduler einrichten $taskName = "Netsnake Heartbeat" $action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-NoProfile -WindowStyle Hidden -File `"$NETSNAKE_DIR\netsnake-heartbeat.ps1`"" $trigger = New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval (New-TimeSpan -Minutes 1) -RepetitionDuration ([TimeSpan]::MaxValue) $settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable try { Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -Settings $settings -RunLevel Highest -Force Start-ScheduledTask -TaskName $taskName Write-Host " ✅ Heartbeat läuft (Task Scheduler: $taskName)" -ForegroundColor Green } catch { Write-Host " ⚠️ Heartbeat konnte nicht als Task registriert werden: $_" -ForegroundColor Yellow Write-Host " Führen Sie manuell aus: PowerShell $NETSNAKE_DIR\netsnake-heartbeat.ps1" } # === 6. Ollama + Modell === Write-Host "" Write-Host "[7/7] Ollama + KI-Modell einrichten..." -ForegroundColor Yellow $ollamaExe = "$env:LOCALAPPDATA\Programs\Ollama\ollama.exe" if (-not (Test-Path $ollamaExe)) { Write-Host " Lade Ollama herunter..." try { Invoke-WebRequest -Uri "https://ollama.com/download/OllamaSetup.exe" -OutFile "$env:TEMP\OllamaSetup.exe" -UseBasicParsing Write-Host " Installiere Ollama..." Start-Process -Wait -FilePath "$env:TEMP\OllamaSetup.exe" -ArgumentList "/S" Write-Host " ✅ Ollama installiert" -ForegroundColor Green } catch { Write-Host " ⚠️ Download fehlgeschlagen. Bitte Ollama manuell installieren:" -ForegroundColor Yellow Write-Host " https://ollama.com/download" } } else { Write-Host " ✅ Ollama bereits vorhanden" -ForegroundColor Green } # Ollama starten + Modell laden Write-Host " Lade KI-Modell $ollamaModel (ca. 4.7 GB, Download im Hintergrund)..." try { $ollamaProcess = Start-Process -FilePath $ollamaExe -ArgumentList "pull $ollamaModel" -NoNewWindow -PassThru Write-Host " ⏳ Download läuft im Hintergrund (dauert einige Minuten)" -ForegroundColor Yellow } catch { Write-Host " ⚠️ Modell-Download konnte nicht gestartet werden" -ForegroundColor Yellow Write-Host " Führen Sie später aus: ollama pull $ollamaModel" } # === Fertig === Write-Host "" Write-Host "============================================" -ForegroundColor Cyan Write-Host " ✅ Installation abgeschlossen!" -ForegroundColor Green Write-Host "============================================" -ForegroundColor Cyan Write-Host "" Write-Host " Subdomain: $subdomain" Write-Host " IP: $assignedIp" Write-Host " Status: Heartbeat aktiv (Task Scheduler)" Write-Host "" Write-Host " Browser öffnet sich in Kürze..." Start-Sleep -Seconds 3 Start-Process $subdomain # Helper: SHA256 Hash function Get-SHA256Hash($input) { $sha256 = [System.Security.Cryptography.SHA256]::Create() $bytes = [System.Text.Encoding]::UTF8.GetBytes($input) $hash = $sha256.ComputeHash($bytes) return [System.BitConverter]::ToString($hash).Replace("-","").ToLower() } exit 0