SPICE & Graphics Configuration
Complete guide to SPICE protocol setup, graphics port allocation, VNC fallback, and high-resolution graphics
SPICE & Graphics Configuration
Introduction
SPICE protocol for VM remote display. XMLGenerator (backend/app/utils/VirtManager/xmlGenerator.ts) configures SPICE with auto-port allocation, random passwords, optional OpenGL. GraphicPortService retrieves assigned ports from running VMs.
SPICE Protocol
Open-source protocol by Red Hat for VDI. Server runs in QEMU, client on user machine (virt-viewer, remote-viewer, spice-html5). Optimized for VMs with video streaming and adaptive compression.
Features
- Image compression: GLZ, JPEG, zlib (auto-selection)
- Video streaming: Detects/compresses video regions
- Audio: Bidirectional (Opus codec)
- USB redirection, clipboard (bidirectional), file transfer (drag-drop)
- Multi-monitor, OpenGL acceleration
vs VNC: SPICE has better compression, video streaming, audio, file transfer. VNC simpler, wider client support.
SPICE Configuration
addSPICE Method
File: backend/app/utils/VirtManager/xmlGenerator.ts
Parameters: enableAudio (default: true), enableOpenGL (default: true). Returns random alphanumeric password.
Password: Random alphanumeric password (configurable length, recommend 16 characters for production). Stored in MachineConfiguration.graphicPassword.
Graphics init: Clears existing graphics array (ensures SPICE or VNC, not both).
Core Config
<graphics type='spice' autoport='yes' listen='0.0.0.0' passwd='abc12345'>
<listen type='address' address='0.0.0.0'/>
</graphics>
- autoport: libvirt assigns port from 5900-5999
- listen: 0.0.0.0 (all interfaces) or 127.0.0.1 (local only)
Compression
<image compression='auto_glz'/> <!-- GLZ for UI/text -->
<jpeg compression='auto'/> <!-- JPEG for photos -->
<zlib compression='auto'/> <!-- zlib for general data -->
Auto mode adapts to network conditions.
Features
<streaming mode='filter'/> <!-- Auto-detect video regions -->
<clipboard copypaste='yes'/> <!-- Bidirectional clipboard -->
<filetransfer enable='yes'/> <!-- Drag-drop files -->
<mouse mode='server'/> <!-- Server-side cursor (better with GPU) -->
All require SPICE agent in guest.
OpenGL Acceleration
<gl enable='yes' rendernode='/dev/dri/renderD128'/>
Requires host GPU, accessible render node, guest drivers. Provides hardware-accelerated 3D. Path hardcoded (TODO: dynamic detection).
Audio
<channel type='spicevmc'>
<target type='virtio' name='com.redhat.spice.0'/>
<address type='virtio-serial' controller='0' bus='0' port='3'/>
</channel>
Bidirectional audio (Opus codec). Requires SPICE agent, audio device in guest, PulseAudio/PipeWire on host.
Auto-Port Allocation
Libvirt assigns port from 5900-5999 range. GraphicPortService retrieves port from domain XML after VM starts. Configurable via /etc/libvirt/qemu.conf (increase range for >100 VMs).
GraphicPortService
File: backend/app/utils/VirtManager/graphicPortService.ts
Opens libvirt connection, retrieves port from domain XML. Methods: getGraphicPort(domainName, type) → looks up domain → gets XML → parses for graphics port.
VNC Fallback
addVNC (xmlGenerator.ts): Similar to SPICE but simpler (no compression/features). Updates existing VNC or creates new. Returns random alphanumeric password.
Use VNC: Wider client support, simpler, lower overhead. SPICE has more features (audio, file transfer, better compression).
High-Resolution Graphics
enableHighResolutionGraphics (xmlGenerator.ts): Configures video device with VRAM size and driver.
QXL (default): SPICE-optimized, flexible VRAM (ram/vram/vgamem), 2D/3D accel. Best for SPICE.
VirtIO: Experimental, OpenGL passthrough. "Works, but performance is not the best."
VRAM sizing: 512MB for 1080p, 1024MB for 4K, 2048MB for multi-4K.
Storage
Updates MachineConfiguration: graphicProtocol='spice', graphicPassword from addSPICE(), graphicHost from APP_HOST env, graphicPort=-1 (updated after VM starts via GraphicPortService).
Cron job UpdateGraphicsInformation periodically updates ports for running VMs.
Client Connection
Clients: virt-viewer, remote-viewer, GNOME Boxes, virt-manager, spice-html5 (browser).
Connection: remote-viewer spice://HOST:PORT?password=PASSWORD
Security: Password auth required. Enable TLS for production. Restrict port range (5900-5999) with firewall.
Troubleshooting
Port not assigned: Check VM running (virsh list), verify autoport in XML, check libvirt logs.
Cannot connect: Verify port open (netstat), firewall, password, SPICE agent, network (telnet).
Poor performance: Adjust compression, increase VRAM, check QXL driver, test bandwidth.
Audio issues: Check SPICE agent, audio device, client settings, PulseAudio on host.
Clipboard/file transfer: Install SPICE agent (spice-vdagent), restart agent, verify filetransfer enabled.
Environment Variables
| Variable | Description | Default |
|---|---|---|
APP_HOST |
Graphics host address for client connections | '0.0.0.0' |
INFINIBAY_BASE_DIR |
Base directory for UEFI NVRAM, sockets | '/opt/infinibay' |
Mermaid Diagrams
SPICE Configuration Flow
sequenceDiagram
participant XMLGenerator
participant CreateMachineService
participant Database
participant Libvirt
participant CronJob
participant GraphicPortService
XMLGenerator->>XMLGenerator: addSPICE(enableAudio, enableOpenGL)
XMLGenerator->>XMLGenerator: Generate random alphanumeric password
XMLGenerator->>XMLGenerator: Clear existing graphics array
XMLGenerator->>XMLGenerator: Create SPICE config object
XMLGenerator->>XMLGenerator: Set basic attributes (type, autoport, listen, passwd)
XMLGenerator->>XMLGenerator: Add listen element (address: 0.0.0.0)
XMLGenerator->>XMLGenerator: Add compression (image, jpeg, zlib)
XMLGenerator->>XMLGenerator: Add features (video, clipboard, filetransfer, mouse, streaming)
alt enableOpenGL == true
XMLGenerator->>XMLGenerator: Add gl element (enable: yes, rendernode)
end
alt enableAudio == true
XMLGenerator->>XMLGenerator: Add SPICE audio channel (type: spicevmc)
end
XMLGenerator->>XMLGenerator: Push SPICE config to graphics array
XMLGenerator->>CreateMachineService: Return password
CreateMachineService->>Database: Update MachineConfiguration<br/>(graphicProtocol: spice, graphicPassword, graphicPort: -1)
CreateMachineService->>Libvirt: Define and start VM
Libvirt->>Libvirt: Assign port automatically (autoport=yes)
Libvirt->>Libvirt: Update domain XML with assigned port
CronJob->>GraphicPortService: getGraphicPort(domainName, 'spice')
GraphicPortService->>Libvirt: Lookup domain by name
GraphicPortService->>Libvirt: Get domain XML
GraphicPortService->>GraphicPortService: Parse XML, extract port
GraphicPortService->>CronJob: Return port number
CronJob->>Database: Update MachineConfiguration.graphicPort
Port Allocation Process
flowchart TD
Start([VM Definition with autoport=yes]) --> CheckRange[Libvirt: Check port range<br/>5900-5999]
CheckRange --> FindPort[Find first available port]
FindPort --> CheckInUse{Port in use?}
CheckInUse -->|Yes| TryNext[Try next port<br/>5900 → 5901 → 5902...]
TryNext --> CheckInUse
CheckInUse -->|No| AssignPort[Assign port to VM]
AssignPort --> UpdateXML[Update domain XML<br/>with assigned port]
UpdateXML --> StartVM[Start VM with<br/>assigned port]
StartVM --> ListenPort[SPICE server<br/>listens on port]
ListenPort --> QueryXML[GraphicPortService:<br/>Query domain XML]
QueryXML --> ExtractPort[Extract port from<br/>graphics element]
ExtractPort --> ReturnPort[Return port to<br/>application]
ReturnPort --> UpdateDB[Update database<br/>with port]
UpdateDB --> ClientConnect[Client connects<br/>to host:port]
ClientConnect --> End([End])
SPICE Feature Stack
graph TD
SPICE[SPICE Protocol]
SPICE --> Compression[Compression Layer]
Compression --> GLZ[Image Compression<br/>GLZ]
Compression --> JPEG[JPEG Compression]
Compression --> Zlib[Zlib Compression]
SPICE --> Features[Feature Layer]
Features --> Video[Video Streaming]
Features --> Clipboard[Clipboard Sharing]
Features --> FileTransfer[File Transfer]
Features --> Audio[Audio Redirection]
Features --> USB[USB Redirection]
SPICE --> Graphics[Graphics Layer]
Graphics --> QXL[QXL Driver]
Graphics --> OpenGL[OpenGL Acceleration]
Graphics --> HighRes[High-Res Support]
SPICE --> Transport[Transport Layer]
Transport --> TCP[TCP/IP]
Transport --> TLS[TLS<br/>optional]
Transport --> Auth[Authentication<br/>password]