quickemu-project / quickemu

Quickly create and run optimised Windows, macOS and Linux virtual machines
MIT License
10.88k stars 478 forks source link

bug: can start but cannot ssh into linux VMs #1455

Closed StoicDeveloper closed 2 months ago

StoicDeveloper commented 2 months ago

Describe the bug From a headless NixOS host linux VMs can be started but cannot be accessed by SSH. The nixos config includes:

{
networking.firewall = { enable = false; };
    environment.systemPackages = with pkgs;
      [
        qemu
        quickemu
        spice-vdagent

}

To Reproduce Steps to reproduce the behavior:

quickget ubuntu 22.04
quickemu --vm ubuntu-22.04.conf --display none

The latter command results in a running vm process and produces this output:

Error: unable to open display 
Quickemu 4.9.6 using /nix/store/s491i7900vfk4gfz85brdsk0093syzmh-qemu-9.0.2/bin/qemu-system-x86_64 v9.0.2
 - Host:     NixOS 24.11 (Vicuna) running Linux 6.6.47 commie
 - CPU:      Intel(R) Core(TM) i5-2435M CPU @ 2.40GHz 
 - CPU VM:   host, 1 Socket(s), 1 Core(s), 2 Thread(s)
 - RAM VM:   4G RAM
 - BOOT:     EFI (Linux), OVMF (/nix/store/3lpyl0mhzz9r9r58h1817rpk89njx29a-OVMF-202402-fd/FV/OVMF_CODE.fd), SecureBoot (off).
 - Disk:     ubuntu-22.04/disk.qcow2 (16G)
             Looks unused, booting from ubuntu-22.04/ubuntu-22.04.5-desktop-amd64.iso
 - Boot ISO: ubuntu-22.04/ubuntu-22.04.5-desktop-amd64.iso
 - Display:  NONE, virtio-gpu, GL (on), VirGL (off) @ (1280 x 800)
 - Sound:    intel-hda (hda-micro)
 - ssh:      On host:  ssh user@localhost -p 22220
 - SPICE:    On host:  spicy --title "ubuntu-22.04" --port 5930 --spice-shared-dir /home/<name>
 - WebDAV:   On guest: dav://localhost:9843/
 - 9P:       On guest: sudo mount -t 9p -o trans=virtio,version=9p2000.L,msize=104857600 Public-<name> ~/<name>
 - smbd:     On guest: smb://10.0.2.4/qemu
 - Network:  User (virtio-net)
 - Monitor:  On host:  socat -,echo=0,icanon=0 unix-connect:ubuntu-22.04/ubuntu-22.04-monitor.socket
 - Serial:   On host:  socat -,echo=0,icanon=0 unix-connect:ubuntu-22.04/ubuntu-22.04-serial.socket
 - Process:  Started ubuntu-22.04.conf as ubuntu-22.04 (11590)

The ssh command ssh user@localhost -p 22220 -v results in

OpenSSH_9.8p1, OpenSSL 3.0.14 4 Jun 2024
debug1: Reading configuration data /home/xian/.ssh/config
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 5: Applying options for *
debug1: Connecting to localhost [::1] port 22220.
debug1: connect to address ::1 port 22220: Connection refused
debug1: Connecting to localhost [127.0.0.1] port 22220.
debug1: Connection established.
debug1: identity file /home/xian/.ssh/id_rsa type 0
debug1: identity file /home/xian/.ssh/id_rsa-cert type -1
debug1: identity file /home/xian/.ssh/id_ecdsa type -1
debug1: identity file /home/xian/.ssh/id_ecdsa-cert type -1
debug1: identity file /home/xian/.ssh/id_ecdsa_sk type -1
debug1: identity file /home/xian/.ssh/id_ecdsa_sk-cert type -1
debug1: identity file /home/xian/.ssh/id_ed25519 type 3
debug1: identity file /home/xian/.ssh/id_ed25519-cert type -1
debug1: identity file /home/xian/.ssh/id_ed25519_sk type -1
debug1: identity file /home/xian/.ssh/id_ed25519_sk-cert type -1
debug1: identity file /home/xian/.ssh/id_xmss type -1
debug1: identity file /home/xian/.ssh/id_xmss-cert type -1
debug1: Local version string SSH-2.0-OpenSSH_9.8
kex_exchange_identification: Connection closed by remote host
Connection closed by 127.0.0.1 port 22220

Expected behavior SSH should allow access to linux VMs

System information Run quickreport and include the output here; if you can't run quickreport, please provide the output of the following:

Quickreport output ```text ---------------------------------- Quickemu 4.9.6 ---------------------------------- Distro: NixOS 24.11 (Vicuna) Kernel: Linux 6.6.47 x86_64 Memory: 7.9G GPU: - Intel Corporation 2nd Generation Core Processor Family Integrated Graphics Controller (rev 09) ---------------------------------- curl 8.9.0 ---------------------------------- Libraries: libcurl/8.9.0 OpenSSL/3.0.14 zlib/1.3.1 brotli/1.1.0 zstd/1.5.6 libidn2/2.3.7 libpsl/0.21.5 libssh2/1.11.0 nghttp2/1.62.1 Protocols: dict file ftp ftps gopher gophers http https imap imaps ipfs ipns mqtt pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp Features: alt-svc AsynchDNS brotli GSS-API HSTS HTTP2 HTTPS-proxy IDN IPv6 Kerberos Largefile libz NTLM PSL SPNEGO SSL threadsafe TLS-SRP UnixSockets zstd ---------------------------------- QEMU 9.0.2 ---------------------------------- Available CPUs: x86 486 (alias configured by machine type) x86 486-v1 x86 Broadwell (alias configured by machine type) x86 Broadwell-IBRS (alias of Broadwell-v3) x86 Broadwell-noTSX (alias of Broadwell-v2) x86 Broadwell-noTSX-IBRS (alias of Broadwell-v4) x86 Broadwell-v1 Intel Core Processor (Broadwell) x86 Broadwell-v2 Intel Core Processor (Broadwell, no TSX) x86 Broadwell-v3 Intel Core Processor (Broadwell, IBRS) x86 Broadwell-v4 Intel Core Processor (Broadwell, no TSX, IBRS) x86 Cascadelake-Server (alias configured by machine type) x86 Cascadelake-Server-noTSX (alias of Cascadelake-Server-v3) x86 Cascadelake-Server-v1 Intel Xeon Processor (Cascadelake) x86 Cascadelake-Server-v2 Intel Xeon Processor (Cascadelake) [ARCH_CAPABILITIES] x86 Cascadelake-Server-v3 Intel Xeon Processor (Cascadelake) [ARCH_CAPABILITIES, no TSX] x86 Cascadelake-Server-v4 Intel Xeon Processor (Cascadelake) [ARCH_CAPABILITIES, no TSX] x86 Cascadelake-Server-v5 Intel Xeon Processor (Cascadelake) [ARCH_CAPABILITIES, EPT switching, XSAVES, no TSX] x86 Conroe (alias configured by machine type) x86 Conroe-v1 Intel Celeron_4x0 (Conroe/Merom Class Core 2) x86 Cooperlake (alias configured by machine type) x86 Cooperlake-v1 Intel Xeon Processor (Cooperlake) x86 Cooperlake-v2 Intel Xeon Processor (Cooperlake) [XSAVES] x86 Denverton (alias configured by machine type) x86 Denverton-v1 Intel Atom Processor (Denverton) x86 Denverton-v2 Intel Atom Processor (Denverton) [no MPX, no MONITOR] x86 Denverton-v3 Intel Atom Processor (Denverton) [XSAVES, no MPX, no MONITOR] x86 Dhyana (alias configured by machine type) x86 Dhyana-v1 Hygon Dhyana Processor x86 Dhyana-v2 Hygon Dhyana Processor [XSAVES] x86 EPYC (alias configured by machine type) x86 EPYC-Genoa (alias configured by machine type) x86 EPYC-Genoa-v1 AMD EPYC-Genoa Processor x86 EPYC-IBPB (alias of EPYC-v2) x86 EPYC-Milan (alias configured by machine type) x86 EPYC-Milan-v1 AMD EPYC-Milan Processor x86 EPYC-Milan-v2 AMD EPYC-Milan-v2 Processor x86 EPYC-Rome (alias configured by machine type) x86 EPYC-Rome-v1 AMD EPYC-Rome Processor x86 EPYC-Rome-v2 AMD EPYC-Rome Processor x86 EPYC-Rome-v3 AMD EPYC-Rome-v3 Processor x86 EPYC-Rome-v4 AMD EPYC-Rome-v4 Processor (no XSAVES) x86 EPYC-v1 AMD EPYC Processor x86 EPYC-v2 AMD EPYC Processor (with IBPB) x86 EPYC-v3 AMD EPYC Processor x86 EPYC-v4 AMD EPYC-v4 Processor x86 GraniteRapids (alias configured by machine type) x86 GraniteRapids-v1 Intel Xeon Processor (GraniteRapids) x86 Haswell (alias configured by machine type) x86 Haswell-IBRS (alias of Haswell-v3) x86 Haswell-noTSX (alias of Haswell-v2) x86 Haswell-noTSX-IBRS (alias of Haswell-v4) x86 Haswell-v1 Intel Core Processor (Haswell) x86 Haswell-v2 Intel Core Processor (Haswell, no TSX) x86 Haswell-v3 Intel Core Processor (Haswell, IBRS) x86 Haswell-v4 Intel Core Processor (Haswell, no TSX, IBRS) x86 Icelake-Server (alias configured by machine type) x86 Icelake-Server-noTSX (alias of Icelake-Server-v2) x86 Icelake-Server-v1 Intel Xeon Processor (Icelake) x86 Icelake-Server-v2 Intel Xeon Processor (Icelake) [no TSX] x86 Icelake-Server-v3 Intel Xeon Processor (Icelake) x86 Icelake-Server-v4 Intel Xeon Processor (Icelake) x86 Icelake-Server-v5 Intel Xeon Processor (Icelake) [XSAVES] x86 Icelake-Server-v6 Intel Xeon Processor (Icelake) [5-level EPT] x86 IvyBridge (alias configured by machine type) x86 IvyBridge-IBRS (alias of IvyBridge-v2) x86 IvyBridge-v1 Intel Xeon E3-12xx v2 (Ivy Bridge) x86 IvyBridge-v2 Intel Xeon E3-12xx v2 (Ivy Bridge, IBRS) x86 KnightsMill (alias configured by machine type) x86 KnightsMill-v1 Intel Xeon Phi Processor (Knights Mill) x86 Nehalem (alias configured by machine type) x86 Nehalem-IBRS (alias of Nehalem-v2) x86 Nehalem-v1 Intel Core i7 9xx (Nehalem Class Core i7) x86 Nehalem-v2 Intel Core i7 9xx (Nehalem Core i7, IBRS update) x86 Opteron_G1 (alias configured by machine type) x86 Opteron_G1-v1 AMD Opteron 240 (Gen 1 Class Opteron) x86 Opteron_G2 (alias configured by machine type) x86 Opteron_G2-v1 AMD Opteron 22xx (Gen 2 Class Opteron) x86 Opteron_G3 (alias configured by machine type) x86 Opteron_G3-v1 AMD Opteron 23xx (Gen 3 Class Opteron) x86 Opteron_G4 (alias configured by machine type) x86 Opteron_G4-v1 AMD Opteron 62xx class CPU x86 Opteron_G5 (alias configured by machine type) x86 Opteron_G5-v1 AMD Opteron 63xx class CPU x86 Penryn (alias configured by machine type) x86 Penryn-v1 Intel Core 2 Duo P9xxx (Penryn Class Core 2) x86 SandyBridge (alias configured by machine type) x86 SandyBridge-IBRS (alias of SandyBridge-v2) x86 SandyBridge-v1 Intel Xeon E312xx (Sandy Bridge) x86 SandyBridge-v2 Intel Xeon E312xx (Sandy Bridge, IBRS update) x86 SapphireRapids (alias configured by machine type) x86 SapphireRapids-v1 Intel Xeon Processor (SapphireRapids) x86 SapphireRapids-v2 Intel Xeon Processor (SapphireRapids) x86 Skylake-Client (alias configured by machine type) x86 Skylake-Client-IBRS (alias of Skylake-Client-v2) x86 Skylake-Client-noTSX-IBRS (alias of Skylake-Client-v3) x86 Skylake-Client-v1 Intel Core Processor (Skylake) x86 Skylake-Client-v2 Intel Core Processor (Skylake, IBRS) x86 Skylake-Client-v3 Intel Core Processor (Skylake, IBRS, no TSX) x86 Skylake-Client-v4 Intel Core Processor (Skylake, IBRS, no TSX) [IBRS, XSAVES, no TSX] x86 Skylake-Server (alias configured by machine type) x86 Skylake-Server-IBRS (alias of Skylake-Server-v2) x86 Skylake-Server-noTSX-IBRS (alias of Skylake-Server-v3) x86 Skylake-Server-v1 Intel Xeon Processor (Skylake) x86 Skylake-Server-v2 Intel Xeon Processor (Skylake, IBRS) x86 Skylake-Server-v3 Intel Xeon Processor (Skylake, IBRS, no TSX) x86 Skylake-Server-v4 Intel Xeon Processor (Skylake, IBRS, no TSX) x86 Skylake-Server-v5 Intel Xeon Processor (Skylake, IBRS, no TSX) [IBRS, XSAVES, EPT switching, no TSX] x86 Snowridge (alias configured by machine type) x86 Snowridge-v1 Intel Atom Processor (SnowRidge) x86 Snowridge-v2 Intel Atom Processor (Snowridge, no MPX) x86 Snowridge-v3 Intel Atom Processor (Snowridge, no MPX) [XSAVES, no MPX] x86 Snowridge-v4 Intel Atom Processor (Snowridge, no MPX) [no split lock detect, no core-capability] x86 Westmere (alias configured by machine type) x86 Westmere-IBRS (alias of Westmere-v2) x86 Westmere-v1 Westmere E56xx/L56xx/X56xx (Nehalem-C) x86 Westmere-v2 Westmere E56xx/L56xx/X56xx (IBRS update) x86 athlon (alias configured by machine type) x86 athlon-v1 QEMU Virtual CPU version 2.5+ x86 core2duo (alias configured by machine type) x86 core2duo-v1 Intel(R) Core(TM)2 Duo CPU T7700 @ 2.40GHz x86 coreduo (alias configured by machine type) x86 coreduo-v1 Genuine Intel(R) CPU T2600 @ 2.16GHz x86 kvm32 (alias configured by machine type) x86 kvm32-v1 Common 32-bit KVM processor x86 kvm64 (alias configured by machine type) x86 kvm64-v1 Common KVM processor x86 n270 (alias configured by machine type) x86 n270-v1 Intel(R) Atom(TM) CPU N270 @ 1.60GHz x86 pentium (alias configured by machine type) x86 pentium-v1 x86 pentium2 (alias configured by machine type) x86 pentium2-v1 x86 pentium3 (alias configured by machine type) x86 pentium3-v1 x86 phenom (alias configured by machine type) x86 phenom-v1 AMD Phenom(tm) 9550 Quad-Core Processor x86 qemu32 (alias configured by machine type) x86 qemu32-v1 QEMU Virtual CPU version 2.5+ x86 qemu64 (alias configured by machine type) x86 qemu64-v1 QEMU Virtual CPU version 2.5+ x86 base base CPU model type with no features enabled x86 host processor with all supported host features x86 max Enables all features supported by the accelerator in the current host Recognized CPUID flags: 3dnow 3dnowext 3dnowprefetch abm ace2 ace2-en acpi adx aes amd-no-ssb amd-psfd amd-ssbd amd-stibp amx-bf16 amx-complex amx-fp16 amx-int8 amx-tile apic arat arch-capabilities arch-lbr auto-ibrs avic avx avx-ifma avx-ne-convert avx-vnni avx-vnni-int8 avx2 avx512-4fmaps avx512-4vnniw avx512-bf16 avx512-fp16 avx512-vp2intersect avx512-vpopcntdq avx512bitalg avx512bw avx512cd avx512dq avx512er avx512f avx512ifma avx512pf avx512vbmi avx512vbmi2 avx512vl avx512vnni bmi1 bmi2 bus-lock-detect cid cldemote clflush clflushopt clwb clzero cmov cmp-legacy cmpccxadd core-capability cr8legacy cx16 cx8 dca de decodeassists ds ds-cpl dtes64 erms est extapic f16c fb-clear fbsdp-no flush-l1d flushbyasid fma fma4 fpu fsgsbase fsrc fsrm fsrs full-width-write fxsr fxsr-opt fzrm gds-no gfni hle ht hypervisor ia64 ibpb ibrs ibrs-all ibs intel-pt intel-pt-lip invpcid invtsc kvm-asyncpf kvm-asyncpf-int kvm-asyncpf-vmexit kvm-hint-dedicated kvm-mmu kvm-msi-ext-dest-id kvm-nopiodelay kvm-poll-control kvm-pv-eoi kvm-pv-ipi kvm-pv-sched-yield kvm-pv-tlb-flush kvm-pv-unhalt kvm-steal-time kvmclock kvmclock kvmclock-stable-bit la57 lahf-lm lbrv lfence-always-serializing lm lwp mca mcdt-no mce md-clear mds-no misalignsse mmx mmxext monitor movbe movdir64b movdiri mpx msr mtrr no-nested-data-bp nodeid-msr npt nrip-save null-sel-clr-base nx osvw pae pat pause-filter pbe pbrsb-no pcid pclmulqdq pcommit pdcm pdpe1gb perfctr-core perfctr-nb pfthreshold pge phe phe-en pks pku pmm pmm-en pn pni popcnt prefetchiti pschange-mc-no psdp-no pse pse36 rdctl-no rdpid rdrand rdseed rdtscp rsba rtm sbdr-ssdp-no sep serialize sgx sgx-aex-notify sgx-debug sgx-edeccssa sgx-exinfo sgx-kss sgx-mode64 sgx-provisionkey sgx-tokenkey sgx1 sgx2 sgxlc sha-ni skinit skip-l1dfl-vmentry smap smep smx spec-ctrl split-lock-detect ss ssb-no ssbd sse sse2 sse4.1 sse4.2 sse4a ssse3 stibp stibp-always-on svm svm-lock svme-addr-chk syscall taa-no tbm tce tm tm2 topoext tsc tsc-adjust tsc-deadline tsc-scale tsx-ctrl tsx-ldtrk umip v-vmsave-vmload vaes vgif virt-ssbd vmcb-clean vme vmx vmx-activity-hlt vmx-activity-shutdown vmx-activity-wait-sipi vmx-any-errcode vmx-apicv-register vmx-apicv-vid vmx-apicv-x2apic vmx-apicv-xapic vmx-cr3-load-noexit vmx-cr3-store-noexit vmx-cr8-load-exit vmx-cr8-store-exit vmx-desc-exit vmx-enable-user-wait-pause vmx-encls-exit vmx-entry-ia32e-mode vmx-entry-load-bndcfgs vmx-entry-load-efer vmx-entry-load-pat vmx-entry-load-perf-global-ctrl vmx-entry-load-pkrs vmx-entry-load-rtit-ctl vmx-entry-noload-debugctl vmx-ept vmx-ept-1gb vmx-ept-2mb vmx-ept-advanced-exitinfo vmx-ept-execonly vmx-eptad vmx-eptp-switching vmx-exit-ack-intr vmx-exit-clear-bndcfgs vmx-exit-clear-rtit-ctl vmx-exit-load-efer vmx-exit-load-pat vmx-exit-load-perf-global-ctrl vmx-exit-load-pkrs vmx-exit-nosave-debugctl vmx-exit-save-efer vmx-exit-save-pat vmx-exit-save-preemption-timer vmx-flexpriority vmx-hlt-exit vmx-ins-outs vmx-intr-exit vmx-invept vmx-invept-all-context vmx-invept-single-context vmx-invept-single-context vmx-invept-single-context-noglobals vmx-invlpg-exit vmx-invpcid-exit vmx-invvpid vmx-invvpid-all-context vmx-invvpid-single-addr vmx-io-bitmap vmx-io-exit vmx-monitor-exit vmx-movdr-exit vmx-msr-bitmap vmx-mtf vmx-mwait-exit vmx-nmi-exit vmx-page-walk-4 vmx-page-walk-5 vmx-pause-exit vmx-ple vmx-pml vmx-posted-intr vmx-preemption-timer vmx-rdpmc-exit vmx-rdrand-exit vmx-rdseed-exit vmx-rdtsc-exit vmx-rdtscp-exit vmx-secondary-ctls vmx-shadow-vmcs vmx-store-lma vmx-true-ctls vmx-tsc-offset vmx-tsc-scaling vmx-unrestricted-guest vmx-vintr-pending vmx-vmfunc vmx-vmwrite-vmexit-fields vmx-vnmi vmx-vnmi-pending vmx-vpid vmx-wbinvd-exit vmx-xsaves vmx-zero-len-inject vnmi vpclmulqdq waitpkg wbnoinvd wdt x2apic xcrypt xcrypt-en xfd xgetbv1 xop xsave xsavec xsaveerptr xsaveopt xsaves xstore xstore-en xtpr ---------------------------------- CPU ---------------------------------- Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Address sizes: 36 bits physical, 48 bits virtual Byte Order: Little Endian CPU(s): 4 On-line CPU(s) list: 0-3 Vendor ID: GenuineIntel Model name: Intel(R) Core(TM) i5-2435M CPU @ 2.40GHz CPU family: 6 Model: 42 Thread(s) per core: 2 Core(s) per socket: 2 Socket(s): 1 Stepping: 7 CPU(s) scaling MHz: 70% CPU max MHz: 3000.0000 CPU min MHz: 800.0000 BogoMIPS: 4789.45 Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ht tm pbe syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic popcnt tsc_deadline_timer aes xsave avx lahf_lm pti ssbd ibrs ibpb stibp tpr_shadow flexpriority ept vpid xsaveopt dtherm ida arat pln pts vnmi md_clear flush_l1d Virtualization: VT-x L1d cache: 64 KiB (2 instances) L1i cache: 64 KiB (2 instances) L2 cache: 512 KiB (2 instances) L3 cache: 3 MiB (1 instance) NUMA node(s): 1 NUMA node0 CPU(s): 0-3 Vulnerability Gather data sampling: Not affected Vulnerability Itlb multihit: KVM: Mitigation: Split huge pages Vulnerability L1tf: Mitigation; PTE Inversion; VMX conditional cache flushes, SMT vulnerable Vulnerability Mds: Mitigation; Clear CPU buffers; SMT vulnerable Vulnerability Meltdown: Mitigation; PTI Vulnerability Mmio stale data: Unknown: No mitigations Vulnerability Reg file data sampling: Not affected Vulnerability Retbleed: Not affected Vulnerability Spec rstack overflow: Not affected Vulnerability Spec store bypass: Mitigation; Speculative Store Bypass disabled via prctl Vulnerability Spectre v1: Mitigation; usercopy/swapgs barriers and __user pointer sanitization Vulnerability Spectre v2: Mitigation; Retpolines; IBPB conditional; IBRS_FW; STIBP conditional; RSB filling; PBRSB-eIBRS Not affected; BHI Not affected Vulnerability Srbds: Not affected Vulnerability Tsx async abort: Not affected ```
philclifford commented 2 months ago

You need to have enabled ssh on the VM. On Ubuntu it is not installed/enabled by default. We set up the port forwarding but until there is an sshd running you cannot connect using ssh.

StoicDeveloper commented 2 months ago

forgive me if this is a stupid question, but from what I can tell this is a catch 22. Most VMs don't come with sshd enabled, but how could I get into the VM to enable ssh if there is not ssh access? I aim to run this on a headless server, and so it seems the spice access isn't useful here. Does quickemu provide some other method of getting a cli prompt in the VM other than SSH?

philclifford commented 2 months ago

Spice will make the VM display available on a port on localhost on the "headless server" - you can then ssh to the headless server and use port forwarding to connect a spice viewer on your workstation/laptop through to the local port on the headless server. I set up a bunch of forwards in my .ssh/config so that when I ssh to a VM host I automatically tunnel a few spice ports, ssh ports and so on such that I can spin up VMs there with localhost ports already in place for ssh access and spicy display access. You can get by for a short while using a small range per headless server but it pays to take the time to configure specific ports for the remote VMs and tie these down in your ssh config.

For example if your Quickemu VM with spice display reports

 - ssh:      On host:  ssh user@localhost -p 22220
 - SPICE:    On host:  spicy --title "haiku-r1beta4-x86_64" --port 5930 --spice-shared-dir /home/testuser/Public

then you could set up forwarding in your ssh config with something like

Host headlessVMServer
  LocalForward 5940 localhost:5930
  LocalForward 5941 localhost:5931
  LocalForward 5942 localhost:5932
  LocalForward 23220 localhost:22220
  LocalForward 23221 localhost:22221

 #################
Host haikuVM
  port 23220

Then so long as you open ssh to headlessVMServer you can use spice://localhost:5940 as the address from your workstation to access the spice display of the VM ...

You could also go down the path of using installation automation options to get a base system with ssh enabled installed and maybe some users and services in place - this will often be different for many distros and not possible for many - for example take a look at cloud-init ( https://documentation.ubuntu.com/lxd/en/latest/cloud-init/ ) .

You could also provide a remote desktop to your "headless server" to give you access to a desktop on which to access the installation GUI of the VM ( using vnc or nx nomachine or x2go or the like ... ) .. all the way to running the "headless server"'s X display on the X server on your client ....