EAG Proxmox über den Cloudflare SSH-Tunnel
Der Proxmox VE 9.2 Server hostet kurzlebige Test-VMs. Von dieser Umgebung aus lautet der Host eric-pve-ssh.eag.tools. Agenten klonen eine Vorlage, führen den Test durch und fragen dann, bevor sie etwas löschen.
Die Vorlagen, Klonschritte und Gast-Logins entsprechen der LAN-Umgebung. Was sich ändert, ist der Pfad: Der Cloud-Agent erreicht den Host über Cloudflare Access und erreicht jeden Gast über einen Sprung (Jump) durch diesen Host.
Zugriff
Das Startskript schreibt das Schlüsselpaar aus PVE_SSH_PRIVATE_B64 und PVE_SSH_PUBLIC_KEY:
| Datei | Modus | Verwendung |
|---|---|---|
~/.ssh/pve_ssh | 600 | Privater Schlüssel. Proxmox-Host, Windows Administrator, Ubuntu erolleman. |
~/.ssh/pve_ssh.pub | 644 | Zugehöriger öffentlicher Schlüssel. |
/etc/ssh/ssh_config.d/eric-pve-ssh.conf setzt bereits User root, IdentityFile ~/.ssh/pve_ssh, IdentitiesOnly yes und ProxyCommand /usr/local/bin/cloudflared access ssh --hostname %h für eric-pve-ssh.eag.tools. Verwende diesen Host-Alias. Lasse die Systemdatei an Ort und Stelle.
KEY="$HOME/.ssh/pve_ssh"
test -r "$KEY" || { echo "$KEY fehlt; das Startskript erstellt ihn aus PVE_SSH_PRIVATE_B64" >&2; exit 1; }
PVE="ssh -o StrictHostKeyChecking=accept-new eric-pve-ssh.eag.tools"
$PVE 'qm list'
Gast-SSH, sowohl für 10.115.64.x (vmbr0) als auch 10.20.0.x (nat0):
JUMP='ssh -o StrictHostKeyChecking=accept-new -W %h:%p eric-pve-ssh.eag.tools'
VMSSH="ssh -i $KEY -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=5 -o ProxyCommand=\"$JUMP\" USER@$IP"
Setze USER auf Administrator oder erolleman und IP auf die Gastadresse, bevor du VMSSH expandierst.
- Windows VM-Login:
Administrator/Change_meoder~/.ssh/pve_ssh. - Ubuntu VM-Login:
erollemanmit~/.ssh/pve_ssh.sudoist ohne Passwort.dockerbenötigtsudo. - Die Proxmox-Web-Oberfläche lauscht im LAN unter
https://10.115.64.44:8006. Dieser Tunnel ist nur für SSH. Verwalte den Host mitqmundpveshüber$PVE. - Halte das Schlüsselmaterial in den obigen Dateien. Lies weder
~/.ssh/pve_sshnochPVE_SSH_PRIVATE_B64in einen Befehl, ein Log oder eine Antwort ein. Generiere keinen Ersatzschlüssel.
PowerShell-Remoting über SSH verwendet den gleichen Sprung. Füge dies zu ~/.ssh/config hinzu (nur der Host-Block für den Gast; die Systemdatei deckt bereits den Tunnelhost ab):
Host 10.115.64.* 10.20.0.*
IdentityFile ~/.ssh/pve_ssh
IdentitiesOnly yes
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
ProxyCommand ssh -o StrictHostKeyChecking=accept-new -W %h:%p eric-pve-ssh.eag.tools
Enter-PSSession -HostName <ip> -UserName Administrator -KeyFilePath "$HOME/.ssh/pve_ssh"
Harte Regeln
- Starte, ändere, klone oder lösche NIEMALS VM 100 (
ubuntu-2404) oder VM 101 (ws2025-template). Beide sind Vorlagen. - Ändere die Hostkonfiguration (Speicher, Netzwerk, SDN, Pakete) nur, wenn der Benutzer explizit darum bittet.
- Führe
sysprep,windows-template/Copy-SysprepFiles.ps1oderubuntu-template/cloud-init-prepare.shnicht auf einem Klon erneut aus. Diese Skripte bereiten die Vorlagen vor und verbleiben auf der Workstation. Sie sind nicht in dieser Umgebung. - Tagge jede von dir erstellte VM mit
ai-test. - Wenn der Test abgeschlossen ist, frage den Benutzer, ob die von dir erstellten VMs gelöscht werden sollen. Lösche niemals eine VM ohne die Antwort des Benutzers.
- Öffne keine direkte SSH-Sitzung zu
10.115.64.44,10.115.64.xoder10.20.0.x. Diese Netzwerke sind nicht zum Cloud-Agenten geroutet. Host-Befehle werden übereric-pve-ssh.eag.toolsausgeführt. Gast-Befehle verwenden den obigenProxyCommand-Sprung.
Host-Fakten
Der Host ist eine Hyper-V virtuelle Maschine. Geschachteltes VT-x ist verfügbar gemacht. Seine Adresse im LAN ist 10.115.64.44.
| Element | Wert |
|---|---|
| Hardware | Intel Xeon Gold 6234 (8 Kerne / 16 Threads), 94 GB RAM. Budgetiere VMs entsprechend. |
vmbr0 | LAN-Brücke, DHCP. Host-Adresse 10.115.64.44/24, Gateway und DNS 10.115.64.1, Suchdomäne eag.lan. Die Netzwerkkarten beider Vorlagen sind an dieser Brücke. Gast-Adressen sind 10.115.64.x. Von dieser Umgebung aus erfolgt der SSH-Zugriff zu ihnen über einen Sprung durch eric-pve-ssh.eag.tools. |
nat0 | SDN VNet (einfache Zone nat), 10.20.0.0/24. Gateway 10.20.0.1. DHCP 10.20.0.100–10.20.0.200 (12 h) von dnsmasq auf dem Host, DNS 10.20.0.1. SNAT ausgehend über vmbr0 als 10.115.64.44. Der Proxmox-Host kann dieses Subnetz erreichen. Von dieser Umgebung aus verwendet SSH zu 10.20.0.x den gleichen Sprung. |
local-data | LVM-thin auf VG vmdata, ~671 GB. VM-Festplatten, EFI, TPM und Cloud-Init-Laufwerke. |
local-lvm | LVM-thin auf der kleinen PVE-System-VG, ~23 GB, leer. Lasse es ungenutzt. |
local | Verzeichnis auf dem Root-Dateisystem. Backups, Container-Vorlagen, Importe. |
isos | Verzeichnis /mnt/isos. Nur Installations-ISOs. |
Welche Vorlage
| Bedarf | Klon |
|---|---|
| Windows, RDP oder Windows PowerShell | 101 ws2025-template |
Linux, Docker, pwsh oder Nushell | 100 ubuntu-2404 |
Wenn der Benutzer nicht angibt, welches Betriebssystem, frage vor dem Klonen nach.
Windows-Klone aktivieren RDP innerhalb des Gasts. Der Cloudflare-Tunnel überträgt SSH. Verwende SSH oder PowerShell-Remoting, um den Gast zu erreichen.
Vorlage: ws2025-template (VMID 101)
Windows Server 2025 Datacenter Evaluation. 4 vCPU (host), 4 GB RAM, UEFI + Secure Boot + TPM 2.0, 64 GB VirtIO SCSI-Festplatte auf local-data, VirtIO-NIC auf vmbr0 (4 Warteschlangen), VirtIO-Treiber und QEMU-Gastagent installiert.
Beim ersten Start führt jeder Klon automatisch folgende Schritte aus:
- Erhält einen zufälligen Computernamen, Zeitzone Pazifik, Gebietsschema en-US und Administrator-Passwort
Change_me. - Meldet sich einmal automatisch an und führt
Initialize-WindowsServer.ps1aus, das die neueste PowerShell 7 von GitHub installiert, den OpenSSH-Server mit einempowershell-Subsystem aktiviert (PS-Remoting über SSH), den SSH-Schlüssel zuadministrators_authorized_keyshinzufügt, RDP aktiviert, öffentliche Netzwerke auf Privat setzt und die Strg+Alt+Entf-Anforderung entfernt. - Entfernt das Auto-Logon-Passwort und die Antwortdatei, schreibt
C:\ProgramData\TemplateSetup\setup-completeund startet dann neu.
Der erste Start dauert mehrere Minuten und benötigt Internet (PowerShell 7 Download). Log: C:\ProgramData\TemplateSetup\Initialize-WindowsServer.log.
Vorlage: ubuntu-2404 (VMID 100)
Ubuntu 24.04.5 LTS. 2 vCPU (x86-64-v2-AES), 4 GB RAM, UEFI (Secure Boot-Schlüssel nicht eingetragen), kein TPM, 32 GB VirtIO SCSI-Festplatte auf local-data, VirtIO-NIC auf vmbr0. QEMU-Gastagent, OpenSSH, PowerShell 7 (pwsh), Nushell (nu in /usr/local/bin) und Docker sind installiert. Podman ist nicht installiert. Zeitzone ist UTC.
Cloud-Init wurde bereinigt und auf die Datenquellen NoCloud und ConfigDrive beschränkt. Die Festplatte hat kein Netplan, daher hat ein Klon kein Netzwerk, bis Proxmox Cloud-Init ausgeführt wird. Das Konto erolleman ist bereits in sudo und hat bereits den öffentlichen Projektschlüssel. SSH ist socket-aktiviert. Der Gastagent startet von udev, wenn der VirtIO-Port erscheint.
Proxmoxs generierte Benutzerdaten erstellt auch ein gesperrtes ubuntu-Konto ohne SSH-Schlüssel. Melde dich als erolleman an.
Arbeitsablauf: Eine Test-VM erstellen
- [ ] 1. Bestätige, dass die Quell-VM eine Vorlage ist
- [ ] 2. Klonen, konfigurieren, taggen, starten
- [ ] 3. IP vom Gastagenten abrufen
- [ ] 4. Warten, bis der erste Start abgeschlossen ist
- [ ] 5. Den Test durchführen
- [ ] 6. Den Benutzer fragen, ob die VM gelöscht werden soll
1. Bestätige die Vorlage. Wenn dies nichts ausgibt, brich ab und informiere den Benutzer. Klone keine VM, die keine Vorlage ist.
$PVE 'qm config 101 | grep ^template' # Windows
$PVE 'qm config 100 | grep ^template' # Ubuntu
2. Klonen, konfigurieren, taggen, starten. Verknüpfte Klone sind die Standardeinstellung. Füge --full --storage local-data nur hinzu, wenn die VM die Vorlage überleben muss.
Klone erben 4 vCPU / 4 GB (Windows) oder 2 vCPU / 4 GB (Ubuntu). Wenn der Test mehr benötigt, setze qm set auf den Klon, bevor du ihn startest. Lasse die Vorlagen unverändert.
Windows:
ID=$($PVE 'pvesh get /cluster/nextid')
$PVE "qm clone 101 $ID --name test-<zweck> && qm set $ID --tags ai-test && qm start $ID"
Ubuntu: Hänge das Cloud-Init-Laufwerk vor dem ersten Start an. ide2 auf der Vorlage ist eine leere CD; ersetze sie. --ciupgrade 0 überspringt das standardmäßige vollständige Paket-Upgrade. Ohne --ipconfig0 ip=dhcp erhält der Klon niemals eine Adresse.
ID=$($PVE 'pvesh get /cluster/nextid')
$PVE "qm clone 100 $ID --name test-<zweck> && qm set $ID --tags ai-test --ide2 local-data:cloudinit --citype nocloud --ipconfig0 ip=dhcp --ciupgrade 0 --boot order=scsi0 && qm start $ID"
Isoliertes Netzwerk, für beide Betriebssysteme: Platziere die NIC vor dem Start auf nat0. Behalte dies nur bei, wenn der Benutzer die VM vom LAN fernhalten möchte. Die Gastadresse wird 10.20.0.x sein. SSH aus dieser Umgebung verwendet immer noch den Sprung in Zugriff; der Proxmox-Host ist derjenige, der nat0 erreichen kann.
$PVE "qm set $ID --net0 virtio,bridge=nat0"
# Nur Ubuntu. Windows macht DHCP selbst. Weisen Sie Ubuntu-DNS auf dnsmasq am NAT-Gateway.
$PVE "qm set $ID --ipconfig0 ip=dhcp --nameserver 10.20.0.1"
3. IP abrufen. Der Gastagent antwortet, sobald das Betriebssystem läuft. Wiederhole alle ~15 s. Verwende die 10.115.64.x-Adresse für eine vmbr0-NIC oder die 10.20.0.x-Adresse für nat0.
$PVE "qm guest cmd $ID network-get-interfaces" \
| jq -r '.[]."ip-addresses"[]? | select(."ip-address-type"=="ipv4") | ."ip-address"' \
| grep -vE '^(127\.|169\.254\.)'
4. Auf den ersten Start warten. Klone erhalten neue Hostschlüssel und Adressen werden wiederverwendet, daher überspringt Gast-SSH die Hostschlüsselprüfung. Der Sprung-Hostschlüssel wird mit accept-new gespeichert.
Windows: SSH wird während der Einrichtung gestartet, und das Skript startet die VM neu, wenn es abgeschlossen ist. Die VM ist bereit, sobald setup-complete vorhanden ist und Windows seit dem Schreiben erneut gebootet hat.
VMSSH="ssh -i $KEY -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=5 -o ProxyCommand=\"$JUMP\" Administrator@$IP"
# -EncodedCommand (base64 UTF-16LE) vermeidet verschachteltes bash/cmd/PowerShell-Quoting.
PS_CHECK=$(cat <<'EOF'
$m = Get-Item C:\ProgramData\TemplateSetup\setup-complete -ErrorAction SilentlyContinue
if ($m -and (Get-CimInstance Win32_OperatingSystem).LastBootUpTime -gt $m.LastWriteTime) { 'READY ' + (Get-Content $m.FullName) } else { 'WAITING' }
EOF
)
CHECK="powershell -NoProfile -EncodedCommand $(printf '%s' "$PS_CHECK" | iconv -t UTF-16LE | base64 -w0)"
until STATUS=$($VMSSH "$CHECK" 2>/dev/null | tr -d '\r'); [[ $STATUS == READY* ]]; do sleep 15; done
echo "$STATUS"
READY succeeded bedeutet, dass die Einrichtung abgeschlossen ist und die VM neu gestartet wurde. Wenn READY failed ausgegeben wird, lies das Log und melde es:
$VMSSH 'powershell -NoProfile -Command "Get-Content C:\ProgramData\TemplateSetup\Initialize-WindowsServer.log -Tail 30"'
Ubuntu: Warte, bis Cloud-Init status: done meldet. status: error bedeutet anhalten und /var/log/cloud-init-output.log lesen.
VMSSH="ssh -i $KEY -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=5 -o ProxyCommand=\"$JUMP\" erolleman@$IP"
until STATUS=$($VMSSH 'cloud-init status 2>/dev/null' | tr -d '\r'); [[ $STATUS == status:\ done || $STATUS == status:\ error ]]; do sleep 10; done
echo "$STATUS"
5. Test durchführen.
Windows: Die Standard-SSH-Shell ist cmd.exe.
$VMSSH 'pwsh -NoProfile -Command "Get-ComputerInfo | Select-Object OsName, CsName"'
PowerShell-Remoting über SSH (von pwsh auf dem Cloud-Agenten) verwendet den ~/.ssh/config-Gast-Block unter Zugriff:
Enter-PSSession -HostName <ip> -UserName Administrator -KeyFilePath "$HOME/.ssh/pve_ssh"
Ubuntu:
$VMSSH 'pwsh -NoLogo -Command "$PSVersionTable.PSVersion.ToString()"'
$VMSSH 'sudo docker info --format "{{.ServerVersion}}"'
6. Vor der Bereinigung fragen. Melde die Testergebnisse, liste die von dir erstellten VMs auf (VMID, Name, IP) und frage den Benutzer, ob sie gelöscht werden sollen. Verwende das AskQuestion-Tool, wenn verfügbar, mit den Optionen "Löschen", "Weiterlaufen lassen" und "Herunterfahren, aber behalten" (plus pro-VM-Auswahl, wenn du mehrere erstellt hast).
Wenn der Benutzer sich für das Löschen entscheidet:
$PVE "qm stop $ID && qm destroy $ID --purge"
Wenn der Benutzer sich dafür entscheidet, die VM zu behalten, aber herunterzufahren:
$PVE "qm shutdown $ID --timeout 120 || qm stop $ID"
Wenn VMs behalten werden, teile dem Benutzer ihre VMIDs mit, damit sie später gefunden werden können (sie behalten das ai-test-Tag).
Snapshots
Die Festplatten beider Vorlagen befinden sich auf LVM-thin, daher unterstützen Klone Snapshots:
$PVE "qm snapshot $ID before-test"
$PVE "qm rollback $ID before-test"
$PVE "qm delsnapshot $ID before-test"
Bereinigung und Inventar
$PVE 'pvesh get /cluster/resources --type vm --output-format json' \
| jq -r '.[] | select((.tags // "") | split(";") | index("ai-test")) | "\(.vmid)\t\(.name)\t\(.status)"'
Biete nur an, ai-test-VMs zu löschen, die du in dieser Sitzung erstellt hast, es sei denn, der Benutzer bittet um eine breitere Bereinigung. Hole immer zuerst die Bestätigung des Benutzers ein.
Fallstricke
- Windows ist eine Evaluierungsedition mit einer 180-Tage-Lizenz. Verwende sie für kurzlebige VMs.
- Ein Ubuntu-Klon, der einmal ohne das Cloud-Init-Laufwerk bootet, startet ohne Netzwerk, und Cloud-Init wird nicht sauber wiederholen. Lösche ihn und klone erneut.
- Führe
sysprepnicht auf Windows-Klonen durch und konvertiere keine Klone beider Vorlagen in Vorlagen. - Die Hostadresse ist ein DHCP-Lease.
nat0SNAT ist an10.115.64.44gebunden. Wenn sich diese Adresse ändert, sage dies; bearbeite SDN nicht, es sei denn, der Benutzer bittet darum. cloudflaredwird von der System-SSH-Konfiguration als/usr/local/bin/cloudflaredaufgerufen. Eine fehlende Schlüsseldatei bedeutet, dass das Startskript nicht ausgeführt wurde; lasse die Geheimnisse unberührt und melde dies.- Gast-Hostschlüssel ändern sich bei jedem Klon.
UserKnownHostsFile=/dev/nullgilt für die Gastsitzung. Der Tunnel-Hostschlüssel bleibt in~/.ssh/known_hosts.