Cloudflare SSH 터널을 통한 EAG Proxmox
Proxmox VE 9.2 서버는 임시 테스트 VM을 호스팅합니다. 이 환경에서 호스트는 eric-pve-ssh.eag.tools입니다. 에이전트는 템플릿을 복제하고, 테스트를 실행한 후, 삭제하기 전에 사용자에게 물어봅니다.
템플릿, 복제 단계, 게스트 로그인은 LAN 환경과 동일합니다. 변경되는 것은 경로입니다: 클라우드 에이전트는 Cloudflare Access를 통해 호스트에 도달하고, 모든 게스트에 접근할 때는 해당 호스트를 통해 점프합니다.
접근
환경 시작 스크립트는 PVE_SSH_PRIVATE_B64와 PVE_SSH_PUBLIC_KEY에서 키 쌍을 작성합니다:
| 파일 | 모드 | 용도 |
|---|---|---|
~/.ssh/pve_ssh | 600 | 개인 키. Proxmox 호스트, Windows Administrator, Ubuntu erolleman. |
~/.ssh/pve_ssh.pub | 644 | 일치하는 공개 키. |
/etc/ssh/ssh_config.d/eric-pve-ssh.conf는 eric-pve-ssh.eag.tools에 대해 이미 User root, IdentityFile ~/.ssh/pve_ssh, IdentitiesOnly yes, ProxyCommand /usr/local/bin/cloudflared access ssh --hostname %h를 설정합니다. 해당 호스트 별칭을 사용하세요. 시스템 파일은 그대로 두십시오.
KEY="$HOME/.ssh/pve_ssh"
test -r "$KEY" || { echo "$KEY 없음; 시작 스크립트가 PVE_SSH_PRIVATE_B64로 생성합니다" >&2; exit 1; }
PVE="ssh -o StrictHostKeyChecking=accept-new eric-pve-ssh.eag.tools"
$PVE 'qm list'
게스트 SSH (10.115.64.x (vmbr0) 및 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"
VMSSH를 확장하기 전에 USER를 Administrator 또는 erolleman으로 설정하고 IP를 게스트 주소로 설정하십시오.
- Windows VM 로그인:
Administrator/Change_me, 또는~/.ssh/pve_ssh. - Ubuntu VM 로그인:
~/.ssh/pve_ssh를 사용하는erolleman.sudo는 암호가 필요 없습니다.docker는sudo가 필요합니다. - Proxmox 웹 UI는 LAN에서
https://10.115.64.44:8006로 수신 대기합니다. 이 터널은 SSH 전용입니다.$PVE를 통해qm및pvesh로 호스트를 관리하십시오. - 키 자료는 위 파일에 보관하십시오.
~/.ssh/pve_ssh나PVE_SSH_PRIVATE_B64를 명령, 로그 또는 답변에 읽어들이지 마십시오. 대체 키를 생성하지 마십시오.
SSH를 통한 PowerShell 리모팅은 동일한 점프를 사용합니다. ~/.ssh/config에 다음을 추가하십시오 (게스트 Host 블록만; 시스템 파일은 이미 터널 호스트를 처리합니다):
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"
엄격한 규칙
- VM 100 (
ubuntu-2404) 또는 VM 101 (ws2025-template)을 시작, 수정, 복제 또는 삭제하지 마십시오. 둘 다 템플릿입니다. - 사용자가 명시적으로 요청하지 않는 한 호스트 구성을 변경하지 마십시오 (스토리지, 네트워크, SDN, 패키지).
- 복제본에서 sysprep,
windows-template/Copy-SysprepFiles.ps1또는ubuntu-template/cloud-init-prepare.sh를 다시 실행하지 마십시오. 해당 스크립트는 템플릿을 준비하며 워크스테이션에 남아 있습니다. 이 환경에는 없습니다. - 생성하는 모든 VM에
ai-test태그를 지정하십시오. - 테스트가 완료되면 사용자에게 생성한 VM을 삭제할지 물어보십시오. 사용자의 응답 없이 VM을 삭제하지 마십시오.
10.115.64.44,10.115.64.x또는10.20.0.x에 직접 SSH 세션을 열지 마십시오. 해당 네트워크는 클라우드 에이전트로 라우팅되지 않습니다. 호스트 명령은eric-pve-ssh.eag.tools를 통해 실행합니다. 게스트 명령은 위의ProxyCommand점프를 사용합니다.
호스트 정보
호스트는 Hyper-V 가상 머신입니다. 중첩 VT-x가 노출됩니다. LAN에서 주소는 10.115.64.44입니다.
| 항목 | 값 |
|---|---|
| 하드웨어 | Intel Xeon Gold 6234 (8코어 / 16스레드), 94 GB RAM. 이에 맞게 VM 예산을 책정하십시오. |
vmbr0 | LAN 브리지, DHCP. 호스트 주소 10.115.64.44/24, 게이트웨이 및 DNS 10.115.64.1, 검색 도메인 eag.lan. 두 템플릿의 NIC는 이 브리지에 있습니다. 게스트 주소는 10.115.64.x입니다. 이 환경에서 SSH는 eric-pve-ssh.eag.tools를 통해 점프합니다. |
nat0 | SDN VNet (단순 영역 nat), 10.20.0.0/24. 게이트웨이 10.20.0.1. DHCP 10.20.0.100–10.20.0.200 (12시간), 호스트의 dnsmasq에서 제공, DNS 10.20.0.1. SNAT 아웃 vmbr0이 10.115.64.44입니다. Proxmox 호스트는 이 서브넷에 도달할 수 있습니다. 이 환경에서 10.20.0.x로의 SSH는 동일한 점프를 사용합니다. |
local-data | LVM-thin on VG vmdata, ~671 GB. VM 디스크, EFI, TPM 및 cloud-init 드라이브. |
local-lvm | 작은 PVE 시스템 VG의 LVM-thin, ~23 GB, 비어 있음. 사용하지 않은 채로 두십시오. |
local | 루트 파일 시스템의 디렉토리. 백업, 컨테이너 템플릿, 가져오기. |
isos | 디렉토리 /mnt/isos. 설치 ISO만 해당. |
템플릿 선택
| 필요 | 복제 |
|---|---|
| Windows, RDP 또는 Windows PowerShell | 101 ws2025-template |
Linux, Docker, pwsh 또는 Nushell | 100 ubuntu-2404 |
사용자가 OS를 지정하지 않으면 복제 전에 물어보십시오.
Windows 복제본은 게스트 내에서 RDP를 활성화합니다. Cloudflare 터널은 SSH를 전달합니다. 게스트에 도달하려면 SSH 또는 PowerShell 리모팅을 사용하십시오.
템플릿: ws2025-template (VMID 101)
Windows Server 2025 Datacenter Evaluation. 4 vCPU (host), 4 GB RAM, UEFI + Secure Boot + TPM 2.0, local-data에 64 GB VirtIO SCSI 디스크, vmbr0의 VirtIO NIC (4 큐), VirtIO 드라이버 및 QEMU 게스트 에이전트 설치됨.
첫 부팅 시 모든 복제본은 자동으로:
- 임의의 컴퓨터 이름, 태평양 시간대, en-US 로캘, Administrator 암호
Change_me를 얻습니다. - 한 번 자동 로그온하고
Initialize-WindowsServer.ps1을 실행합니다. 이 스크립트는 GitHub에서 최신 PowerShell 7을 설치하고,powershell서브시스템으로 OpenSSH 서버를 활성화하고 (SSH를 통한 PS 리모팅), SSH 키를administrators_authorized_keys에 추가하고, RDP를 활성화하고, 공용 네트워크를 개인 네트워크로 설정하고, Ctrl+Alt+Del 요구 사항을 제거합니다. - 자동 로그온 암호와 응답 파일을 제거하고
C:\ProgramData\TemplateSetup\setup-complete를 기록한 다음 다시 시작합니다.
첫 부팅은 몇 분이 소요되며 인터넷이 필요합니다 (PowerShell 7 다운로드). 로그: C:\ProgramData\TemplateSetup\Initialize-WindowsServer.log.
템플릿: ubuntu-2404 (VMID 100)
Ubuntu 24.04.5 LTS. 2 vCPU (x86-64-v2-AES), 4 GB RAM, UEFI (Secure Boot 키 미등록), TPM 없음, local-data에 32 GB VirtIO SCSI 디스크, vmbr0의 VirtIO NIC. QEMU 게스트 에이전트, OpenSSH, PowerShell 7 (pwsh), Nushell (/usr/local/bin의 nu) 및 Docker가 설치되어 있습니다. Podman은 설치되어 있지 않습니다. 시간대는 UTC입니다.
Cloud-init은 정리되었으며 NoCloud 및 ConfigDrive 데이터 소스로 제한되었습니다. 디스크에 netplan이 없으므로 복제본은 Proxmox cloud-init이 실행될 때까지 네트워크가 없습니다. erolleman 계정은 이미 sudo 그룹에 있으며 프로젝트 공개 키도 이미 가지고 있습니다. SSH는 소켓 활성화됩니다. 게스트 에이전트는 virtio 포트가 나타날 때 udev에서 시작됩니다.
Proxmox에서 생성된 user-data는 또한 잠긴 ubuntu 계정을 SSH 키 없이 생성합니다. erolleman으로 로그인하십시오.
워크플로: 테스트 VM 생성
- [ ] 1. 원본 VM이 템플릿인지 확인
- [ ] 2. 복제, 구성, 태그 지정, 시작
- [ ] 3. 게스트 에이전트에서 IP 가져오기
- [ ] 4. 첫 부팅이 완료될 때까지 대기
- [ ] 5. 테스트 실행
- [ ] 6. 사용자에게 VM 삭제 여부 문의
1. 템플릿 확인. 아무것도 출력되지 않으면 중지하고 사용자에게 알리십시오. 템플릿이 아닌 VM을 복제하지 마십시오.
$PVE 'qm config 101 | grep ^template' # Windows
$PVE 'qm config 100 | grep ^template' # Ubuntu
2. 복제, 구성, 태그 지정, 시작. 연결된 복제본이 기본값입니다. VM이 템플릿보다 오래 지속되어야 하는 경우에만 --full --storage local-data를 추가하십시오.
복제본은 4 vCPU / 4 GB (Windows) 또는 2 vCPU / 4 GB (Ubuntu)를 상속합니다. 테스트에 더 많은 것이 필요하면 시작하기 전에 qm set으로 복제본을 설정하십시오. 템플릿은 변경하지 않은 채로 두십시오.
Windows:
ID=$($PVE 'pvesh get /cluster/nextid')
$PVE "qm clone 101 $ID --name test-<목적> && qm set $ID --tags ai-test && qm start $ID"
Ubuntu: 첫 번째 시작 전에 cloud-init 드라이브를 연결하십시오. 템플릿의 ide2는 빈 CD입니다. 교체하십시오. --ciupgrade 0은 기본 전체 패키지 업그레이드를 건너뜁니다. --ipconfig0 ip=dhcp가 없으면 복제본이 주소를 전혀 얻지 못합니다.
ID=$($PVE 'pvesh get /cluster/nextid')
$PVE "qm clone 100 $ID --name test-<목적> && qm set $ID --tags ai-test --ide2 local-data:cloudinit --citype nocloud --ipconfig0 ip=dhcp --ciupgrade 0 --boot order=scsi0 && qm start $ID"
격리된 네트워크, 모든 OS: 시작 전에 NIC를 nat0에 배치하십시오. 사용자가 VM을 LAN에서 분리하려는 경우에만 이 옵션을 유지하십시오. 게스트 주소는 10.20.0.x가 됩니다. 이 환경에서 SSH는 여전히 접근의 점프를 사용합니다. Proxmox 호스트가 nat0에 도달할 수 있는 호스트입니다.
$PVE "qm set $ID --net0 virtio,bridge=nat0"
# Ubuntu 전용. Windows는 자체 DHCP를 사용합니다. Ubuntu DNS를 NAT 게이트웨이의 dnsmasq로 지정합니다.
$PVE "qm set $ID --ipconfig0 ip=dhcp --nameserver 10.20.0.1"
3. IP 가져오기. OS가 실행되면 게스트 에이전트가 응답합니다. 약 15초마다 재시도하십시오. vmbr0 NIC의 경우 10.115.64.x 주소를 사용하고, nat0의 경우 10.20.0.x 주소를 사용하십시오.
$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. 첫 부팅 대기. 복제본은 새 호스트 키를 얻고 주소는 재사용되므로 게스트 SSH는 호스트 키 확인을 건너뜁니다. 점프 호스트 키는 accept-new로 저장됩니다.
Windows: SSH는 설정 중에 나타나고 스크립트는 완료되면 VM을 다시 시작합니다. setup-complete 파일이 존재하고 Windows가 해당 파일이 작성된 이후 다시 부팅되면 VM이 준비된 것입니다.
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)는 중첩된 bash/cmd/PowerShell 인용을 피합니다.
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는 설정이 완료되고 VM이 다시 시작되었음을 의미합니다. READY failed가 출력되면 로그를 읽고 보고하십시오:
$VMSSH 'powershell -NoProfile -Command "Get-Content C:\ProgramData\TemplateSetup\Initialize-WindowsServer.log -Tail 30"'
Ubuntu: cloud-init가 status: done을 보고할 때까지 기다리십시오. status: error는 중지하고 /var/log/cloud-init-output.log를 읽으십시오.
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. 테스트 실행.
Windows: 기본 SSH 셸은 cmd.exe입니다.
$VMSSH 'pwsh -NoProfile -Command "Get-ComputerInfo | Select-Object OsName, CsName"'
SSH를 통한 PowerShell 리모팅 (클라우드 에이전트의 pwsh에서)은 접근의 ~/.ssh/config 게스트 블록을 사용합니다:
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. 정리 전 문의. 테스트 결과를 보고하고 생성한 VM (VMID, 이름, IP)을 나열한 후 사용자에게 삭제할지 물어보십시오. 가능한 경우 AskQuestion 도구를 사용하고 옵션으로 "Destroy", "Keep running", "Shut down but keep"을 제공하십시오 (여러 개를 생성한 경우 VM별 선택도 포함).
사용자가 삭제를 선택한 경우:
$PVE "qm stop $ID && qm destroy $ID --purge"
사용자가 유지하지만 종료를 선택한 경우:
$PVE "qm shutdown $ID --timeout 120 || qm stop $ID"
VM이 유지되는 경우 사용자에게 VMID를 알려 나중에 찾을 수 있도록 하십시오 (ai-test 태그가 유지됨).
스냅샷
두 템플릿의 디스크는 LVM-thin에 있으므로 복제본은 스냅샷을 지원합니다:
$PVE "qm snapshot $ID before-test"
$PVE "qm rollback $ID before-test"
$PVE "qm delsnapshot $ID before-test"
정리 및 인벤토리
$PVE 'pvesh get /cluster/resources --type vm --output-format json' \
| jq -r '.[] | select((.tags // "") | split(";") | index("ai-test")) | "\(.vmid)\t\(.name)\t\(.status)"'
사용자가 더 광범위한 정리를 요청하지 않는 한, 이 세션에서 생성한 ai-test VM만 삭제를 제안하십시오. 항상 사용자의 확인을 먼저 받으십시오.
주의사항
- Windows는 180일 라이선스가 있는 평가판입니다. 수명이 짧은 VM에 사용하십시오.
- cloud-init 드라이브 없이 한 번 부팅된 Ubuntu 복제본은 네트워크 없이 시작되며 cloud-init이 깔끔하게 재시도되지 않습니다. 삭제하고 다시 복제하십시오.
- Windows 복제본에서
sysprep을 실행하지 말고, 두 템플릿의 복제본을 템플릿으로 변환하지 마십시오. - 호스트 주소는 DHCP 임대입니다.
nat0SNAT는10.115.64.44에 고정되어 있습니다. 해당 주소가 변경되면 알리십시오. 사용자가 요청하지 않는 한 SDN을 편집하지 마십시오. cloudflared는 시스템 SSH 구성에 의해/usr/local/bin/cloudflared로 호출됩니다. 키 파일이 없으면 시작 스크립트가 실행되지 않은 것입니다. 비밀은 건드리지 말고 보고하십시오.- 게스트 호스트 키는 복제할 때마다 변경됩니다.
UserKnownHostsFile=/dev/null은 게스트 세션에 적용됩니다. 터널 호스트 키는~/.ssh/known_hosts에 남아 있습니다.