Skip to content

Instantly share code, notes, and snippets.

@BananaAcid
Last active August 6, 2026 22:46
Show Gist options
  • Select an option

  • Save BananaAcid/7667882d80f565dc8319640117f4fedf to your computer and use it in GitHub Desktop.

Select an option

Save BananaAcid/7667882d80f565dc8319640117f4fedf to your computer and use it in GitHub Desktop.
Gaming and AI in **ALL** VMs with shared GPU

Gaming and AI in ALL VMs with shared GPU

Important

Curent state of infos: 2026-08

Distinction

  1. LXC + (/dev/dri/renderD128 + ZLUDA || nvidia nodes) --> "just works"
  2. In isolated VMs ... the following:

Venus?

Mesa Venus (Vulkan virtualization driver), successor to: VirGL (OpenGL virtualization driver)

A driver for the host to accept Vulkan GPU and Vulkan Compute (ALUs - arithmetic logic units, like "CUDA" cores) commands and Vulkan SPIR-V shaders from the guest

Host: Proxmox/QUEMU - Venus GPU for Guest

  • Requires Host GPU with Vulkan support
  • Venus Host calls: Vulkan GPU and Vulkan Compute
  • Venus Guest GPU accepts: Vulkan GPU and Vulkan Compute

Windows Guest VM - Venus GPU

Linux Guest VM - Venus GPU

  • YES: GPU and ALUs supported

  • AI: Text

    • llama.cpp supports Vulkan backend (ggml-virtgpu)
      • Ollama works as well because it uses llama.cpp
    • vLLM does not: uses CUDA and ROCm directly
  • AI: Image

    • YES: Native C++ (stable-diffusion.cpp)
      • native, highly optimized Vulkan backend
    • NO: PyTorch-Based (ComfyUI / AUTOMATIC1111)
      • PyTorch’s Vulkan backend is experimental
        • Nvidia CUDA, AMD ROCm, Intel XPU, Microsoft DirectML
  • WINDOWS GAMES, using Proton

    1. game requests DirectX
    2. Proton (DXVK/VKD3D) translates those DirectX calls into Vulkan in real-time.
    • DXVK (for DX9/10/11) or VKD3D-Proton (for DX12)
    • proprietary DirectML is not supported
    1. Those Vulkan (GPU + ALU) commands are sent to the guest VM's Venus driver
    2. Venus serializes the Vulkan commands and passes them directly to the host's native Linux GPU driver (which executes them on the physical hardware

Linux Guest VM - no GPU (Remote host)

  • YES: ALUs supported on Host

  • AI: Image

    • DIY: PyTorch-Based
      • CUDA-over-IP ("LUPINE") (https://github.com/lupinemachines/lupine)
        • ... not sure it supports full graphics, they claim to do GPU-over-IP
        • server on proxmox host and client in VM or container
        • Multi-GPU Across Multiple Servers (inspired by "Juice")
        • developers publish pre-configured Docker images
        • nvidia-smi works
      • GPU-over-IP ("Juice") (https://docs.juicelabs.co/docs/juice/intro)
        • juice server on Proxmox host, juice client in VM or container (Linux AND Windows)
        • Multi-GPU Across Multiple Servers
        • ... not free, except you compile the project yourself from source
      • mycelya-torch (https://github.com/alyxya/mycelya-torch)
        • modify python script to redirect any pytorch call to a server on the host
        • needs an account on Modal (free tier available)
          • Supported GPUs: T4, L4, A10G, A100, L40S, H100, H200, B200

Note

Very minor translation delays by Proton and Vulkan, but pusing to VRAM within the VM and using it by the host Vulkan is optimized for minimal losses.

But as we know, gaming in Proton is absolutely possible.

Docker containers

Since linux containers directly use the host's kernel, the gpu and alus path can be passed through ...

NVIDIA GPUs

  • Host: Install the NVIDIA Container Toolkit
    • GPU flag and enable the graphics driver capability
    • docker run --gpus all -e NVIDIA_DRIVER_CAPABILITIES=compute,graphics,utility -it ubuntu:latest
  • Guest:
    • run nvidia-smi

AMD or Intel GPUs (using open-source Mesa drivers)

  • Host: pass rendering device node (/dev/dri/renderD128) into the container
    • docker run -it --device=/dev/dri/renderD128 --device=/dev/dri/card0 ubuntu:latest
  • Guest: install the standard Vulkan loader (libvulkan1) and your distribution's Vulkan/Mesa drivers
    • apt-get update && apt-get install -y libvulkan1 mesa-vulkan-drivers vulkan-tools && vulkaninfo

Docker inside a VM

  • Host VM: Venus
  • Guest VM Docker using Venus
    • pass the render device
    • docker run -it --device=/dev/dri/renderD128 your-container-image
  • Conainer
    • should be using Vulkan tools

Why not XY

Why not PCIe GPU Passthrough?

  • The graphics card is disconnected from the host and passed through to only one VM
  • Setup doable

Why not SR-IOV?

  • Fixed Splitting of VRAM for each GPU-Function (like up to 16 connections for VMs)
  • Must be supported by a specific GPU driver (Nvidia is expensive, AMD and Intel are integrated into the Linux Kernel)
  • Do not support all GPUs (Vulkan has way broader GPU support)
  • Setup is a pain (depends on motherboard support)

ZLUDA ?

  • No: it only translates CUDA to ROCm etc, not Vulkan - not usable for Venus

Output: Final Best Setup

Stream to Remote

  1. Parsec (Free) - https://parsec.app/
  2. Moonlight - https://moonlight-stream.org/

Local - Direct hyper-converged desktop

The Proxmox host itself gets a desktop and is able to switch to different running vms.

The Desktop on the host handles VM switching and audio mixing

  • you could add a simple interface that shows VM on/off and a button to start or stop.

Host:

  • Proxmox, for VMs
  • Rutabaga, with Venus compat, for sharing GPU on host
  • Wayland + HyprLand
  • PipeWire
  • LUPINE host for sharing CUDA on host

Guests

LXC

(Shared GPU, RAM, ...)

  • passthrough of GPU, draws output directly to host wayland

VM

(Isolation, fixed Ressources)

  • Proton for games (get Direct3D to Vulcan)
  • Vulcan Compute works and gets forwarded to host(for AI)
  • LUPINE client for CUDA forwarding
  • Non-Linux
    • Windows: no GPU acceleration, but LUPINE
    • MacOS: no GPU acceleration, but LUPINE

Output: Local - Direct hyper-converged desktop

Structure:

  1. Proxmox gets Desktop
  • to switch output from VM to VM
  • REQUIRES PipeWire on the host to mix VM outputs (not ALSA or PulseAudio)
  1. VMs need Display set to SPICE (qxl) for Linux/Win VMs
  2. host needs to get keycombination setup to switch between VMs

Desktop

  • egl-headless, local X11 layout buffer

    • VM 101.conf

      vga: none
      args: -device virtio-vga-gl,blob=on,hostmem=4G,venus=on -display egl-headless,gl=on
      

      and VM should autostart

    • install: xinit openbox meas-utils xterm

      • host must have persmission to renderD128 node (service needs exec perms)
    • no need for SPICE (remote-viewer), EGL surface to OpenBox in X11 directly (-display egl-headless grabs X11 context)

    • Keycombinations in openbox config (Alt+1,..) <keybind key="A-1"><action name="GoToDesktop"><to>1</to></action></keybind> ...

    • Systemd to start graphics as kiosk without manual terminal logging (set env to Display=:0)

    • /etc/systemd/system/local-accelerated-display.service

      [Unit]
      Description=Local Proxmox Venus Accelerated Kiosk
      After=pve-cluster.service qemu-server.service
      
      [Service]
      Type=simple
      User=root
      Environment=DISPLAY=:0
      ExecStart=/usr/bin/xinit /usr/bin/openbox-session -- :0 -nolisten tcp
      Restart=always
      
      [Install]
      WantedBy=multi-user.target

      systemctl enable --now /etc/systemd/system/local-accelerated-display.service

  • Wayland, egl

    • install cage virt-viewer seatd

    • requires SPICE (virt-viewer)

      • beacuse wayland isolates apps and QEMU is not native to wayland client
      • egl copies the Venus-accelerated frame rendering from GPU into shared memory buffer -> SPICE captures that local buffer and passes it directly to remote-viwer
        • (should NOT impact performance)
    • /etc/pve/qemu-server/101.conf

      vga: none
      args: -device virtio-vga-gl,blob=on,hostmem=4G,venus=on -display egl-headless,gl=on
      tablet: 1
      
    • requires Tablet Pointer option to be able to react to key combinations (tablet:1 in 101.conf)

    • service 1 /usr/local/bin/launch-1.sh

      #!/bin/bash
      sleep 4
      qm start 101
      GDK_BACKEND=wayland remote-viewer spice://127.0.0.1:5900 --full-screen --spice-gl=on
      

      ... Spice ports: 5900, 5901 ... then chmod +x /usr/local/bin/launch-1.sh

      Bind each desktop to a TTY /etc/systemd/system/wayland-vm1.service

      [Unit]
      Description=Wayland Video Output Kiosk 1
      After=pve-cluster.service qemu-server.service seatd.service
      Conflicts=getty@tty7.service
      
      [Service]
      Type=simple
      User=root
      Environment=XDG_RUNTIME_DIR=/run/user/0
      ExecStart=/usr/bin/cage -s -- /usr/local/bin/launch-1.sh
      StandardInput=tty
      StandardOutput=tty
      TTYPath=/dev/tty7
      Restart=always
      
      [Install]
      WantedBy=multi-user.target
      

      systemctl enable --now wayland-vm1.service ... CTRL+ALT+F7

    • Proxmox boot boot flag in case of Nvidia: nvidia-drm.modset=1 in for cage, in case of blank display init error

    • maybe add an interface on TTY1 to start/stop VMs and show running status

multi monitor

instead of cage

  • install sway
  • 101.conf ... ,venus=on,max_outputs=2 ...
  • remote-viewer opens 2 windows automatically
  • sway config to distribute these
    # Disable default bar and window decorations for a clean look
    default_border none
    default_floating_border none
    font pango:monospace 8
    floating_modifier Mod4
    
    # Automatically assign monitors (adjust HDMI-A-1 / DP-1 to match your 'swaymsg -t get_outputs')
    workspace 1 output HDMI-A-1
    workspace 2 output DP-1
    
    # Force the two SPICE display windows onto their respective workspaces/monitors
    for_window [title="*Display 1*"] move to workspace 1; fullscreen enable
    for_window [title="*Display 2*"] move to workspace 2; fullscreen enable
    
    # Keybindings to easily kill or reload if something gets stuck (Mod4 = Windows key)
    bindsym Mod4+Shift+c reload
    bindsym Mod4+Shift+q exec swaymsg exit
    
  • service to run sway for VM 1
    [Service]
    Type=simple
    User=root
    Environment=XDG_RUNTIME_DIR=/run/user/0
    ExecStart=/usr/bin/sway --config /etc/sway/config.vm
    StandardInput=tty
    StandardOutput=tty
    TTYPath=/dev/tty7
    

additionally

On host: gamescope -f -w 3840 -h 2160 --fsr -- remote-viewer spice://127.0.0.1:5900

Using gamescope, FSR, HDR and more become possible.

virtio-gpu-rutabaga instead of spice for low-latency?

Spice supports linux + Windows, but is FPS capped and performance is lower

virtio-gpu-rutabaga + Venus + PipeWire + Evdev -> directly renders to wayland, low-latency, HDR etc

Venus in client, rendered by rutqabaga on the host

Rutabaga fully forwards Vulkan Compute workloads for AI when running with the Venus capability set (rutabaga_capsets=venus).

Notes ...

-device virtio-gpu-rutabaga,cross-domain=on,hostmem=8G -display ...

PipeWire + virtio-snd

  # 1. GPU & Display: Rutabaga + Venus + Native Wayland (NO SPICE)
  -device virtio-gpu-rutabaga,rutabaga_capsets=venus:cross_domain,hostmem=8G \
  -display wayland,gl=on \
  
  # 2. Audio: Native PipeWire via VirtIO Sound
  -audiodev pipewire,id=snd0 \
  -device virtio-sound-pci,audiodev=snd0 \

Note

Infos are AI GENERATED

In the original Gist’s "Wayland, egl" section (README_1_OUTPUT.md), the architecture relied on a multi-step chain:

Gist's Original Chain: Proxmox Host $\rightarrow$ QEMU (-display egl-headless) $\rightarrow$ SPICE Server $\rightarrow$ Local remote-viewer Client $\rightarrow$ Cage / Openbox Compositor $\rightarrow$ Physical Monitor.

While this allowed you to run Proxmox as a hyper-converged desktop host, it required running remote-viewer processes inside Cage/Sway to display the VMs, adding SPICE encoding overhead and latency.


The New Architecture: Proxmox + virtio-gpu-rutabaga + Venus

With virtio-gpu-rutabaga + Venus, you bypass SPICE, remote-viewer, and egl-headless entirely. The VM outputs its Vulkan/Wayland frames directly into the Proxmox host's Wayland compositor via shared GPU memory (DMA-BUF).

New Rutabaga + Venus Chain: Proxmox Host $\rightarrow$ QEMU (virtio-gpu-rutabaga) $\rightarrow$ Host Sway / Hyprland Compositor $\rightarrow$ Physical Monitor.


How it Looks & Works Step-by-Step

1. Proxmox Host Layer (Bare Metal)

On the Proxmox VE host (which is Debian-based), you install a lightweight Wayland tiling compositor like Sway or Hyprland instead of Cage/Openbox.

  • PipeWire runs on the Proxmox host to mix audio from all running VMs simultaneously.
  • Sway/Hyprland runs on TTY1 when the Proxmox host boots.

2. Proxmox VM Configuration (/etc/pve/qemu-server/<vmid>.conf)

In Proxmox, custom QEMU arguments are passed using the args: parameter. For each VM, you configure Rutabaga, Venus, and direct Wayland display output:

# /etc/pve/qemu-server/100.conf (Fedora Gaming VM)
name: Fedora-Gaming-VM
memory: 16384
cores: 8
vga: none
# Direct Rutabaga + Venus + Wayland socket connection:
args: -device virtio-gpu-rutabaga,rutabaga_capsets=venus:cross_domain,hostmem=8G -display wayland,gl=on -audiodev pipewire,id=snd0 -device virtio-sound-pci,audiodev=snd0

3. Desktop Switching (The "KVM Switch" Experience)

Instead of managing remote-viewer windows inside Cage as proposed in the Gist, Sway or Hyprland on the Proxmox host acts as your hardware desktop switcher:

  • Workspace 1 (Super + 1): Fedora Gaming VM (Full screen, 144Hz/VRR, Venus Vulkan acceleration via Rutabaga).
  • Workspace 2 (Super + 2): Ubuntu Work VM (Full screen, seamless Wayland application forwarding via Rutabaga cross-domain).
  • Workspace 3 (Super + 3): Proxmox Host Web GUI (Running in a lightweight host browser like Firefox/Chromium to manage VMs, storage, and backups).
 ┌────────────────────────────────────────────────────────────────────────┐
 │ Proxmox Host (Running Sway / Hyprland)                                 │
 │                                                                        │
 │  [ Workspace 1: Super+1 ]    [ Workspace 2: Super+2 ]    [ Workspace 3 ]│
 │  ┌──────────────────────┐    ┌──────────────────────┐    ┌───────────┐ │
 │  │ Fedora VM            │    │ Ubuntu VM            │    │ Proxmox   │ │
 │  │ (Rutabaga + Venus)   │    │ (Rutabaga)           │    │ Web UI    │ │
 │  │ 144Hz Gaming / Proton│    │ Development / Apps   │    │ Dashboard │ │
 │  └──────────────────────┘    └──────────────────────┘    └───────────┘ │
 └────────────────────────────────────────────────────────────────────────┘

Key Upgrades Over the Gist's "Wayland, egl" Setup

Feature Gist Original Setup (egl-headless / SPICE / Cage) New Setup (virtio-gpu-rutabaga + Venus + Sway)
VM Display Pipeline QEMU $\rightarrow$ SPICE $\rightarrow$ remote-viewer $\rightarrow$ Cage QEMU $\rightarrow$ Rutabaga DMA-BUF $\rightarrow$ Sway Host
Vulkan Support Limited / Wrapped inside virgl Native Zero-Copy Vulkan (Mesa Venus)
Switching Latency Slow (SPICE socket buffer reconnections) Instant (<1ms) via Sway workspace hotkeys
High Refresh Rate & VRR Capped by SPICE client rendering Native 144Hz+ / FreeSync / G-Sync
Clipboard Sharing Requires spice-vdagent inside guest Native Wayland Clipboard via Rutabaga cross-domain
Audio PipeWire via SPICE audio channel Direct VirtIO Sound (virtio-snd) to PipeWire

Practical Implementation Note for Proxmox

By default, Proxmox's packaged QEMU binary (pve-qemu) may not have the Rust rutabaga_gfx feature enabled at compile time. To achieve this setup on Proxmox, you either:

  1. Compile a custom pve-qemu package with rutabaga support enabled, or
  2. Point Proxmox's VM config to a custom QEMU binary compiled with Rutabaga/Venus enabled (args: -exec /usr/local/bin/qemu-system-x86_64 ...).

1. Are there pre-compiled binaries for pve-qemu with Rutabaga support?

Official Proxmox Repositories:

  • Official PVE Status: Official Proxmox VE packages (pve-qemu-kvm 9.2 / 10.0 / 11.0) do not enable Rutabaga by default. This is because Rutabaga requires Rust C-bindings (librutabaga_gfx_ffi) that are not part of standard Debian base repositories.
  • Native Venus Alternative (QEMU 9.2+ / Proxmox 9+): Starting with QEMU 9.2, upstream QEMU merged native Venus Vulkan support into virtio-gpu-gl via virglrenderer 1.0+. This means on modern Proxmox, you can run Venus Vulkan acceleration directly using -device virtio-gpu-gl,venus=on,hostmem=8G without needing custom Rutabaga binaries!

If you specifically need Rutabaga (for cross-domain Wayland socket forwarding):

  1. Community Builds: There are community GitHub repositories (e.g., qemu-kvm-wayland-rutabaga) that provide .deb packages or build scripts compiling QEMU with rutabaga_gfx enabled.
  2. Build from Source: You can pull the pve-qemu package source using apt source pve-qemu, add --enable-rutabaga_gfx to debian/rules, build librutabaga_gfx_ffi, and compile your custom .deb package.

2. Systemd & Sway Setup for the Hyper-Converged Proxmox Desktop

To run a bare-metal Proxmox host that boots directly into a Wayland compositor (Sway) and automatically maps each VM to a dedicated workspace, you set up a systemd service on the Proxmox host.

A. Host Systemd Service (/etc/systemd/system/wayland-desktop.service)

This service boots Sway automatically on TTY1 as a non-root desktop user (e.g., pve-desktop):

[Unit]
Description=Proxmox Host Wayland Desktop (Sway)
After=systemd-user-sessions.service plymouth-quit-active.service pve-guests.service
Wants=pve-guests.service

[Service]
Type=simple
User=pve-desktop
PAMName=login
WorkingDirectory=/home/pve-desktop
Environment=XDG_SESSION_TYPE=wayland
Environment=XDG_CURRENT_DESKTOP=sway
Environment=XDG_RUNTIME_DIR=/run/user/1000
Environment=WAYLAND_DISPLAY=wayland-0
Environment=PIPEWIRE_RUNTIME_DIR=/run/user/1000
TTYPath=/dev/tty1
ExecStart=/usr/bin/sway
Restart=on-failure

[Install]
WantedBy=graphical.target

Enable it on Proxmox:

systemctl set-default graphical.target
systemctl enable wayland-desktop.service

B. Sway Config (/home/pve-desktop/.config/sway/config)

Sway handles mapping each VM's QEMU display window to a specific workspace automatically based on the VM name/ID:

# Automatically route QEMU windows to specific Workspaces
assign [app_id="qemu" title=".*VM 100.*"] workspace number 1
assign [app_id="qemu" title=".*VM 101.*"] workspace number 2
assign [app_id="qemu" title=".*VM 102.*"] workspace number 3
assign [app_id="qemu" title=".*VM 103.*"] workspace number 4
assign [app_id="qemu" title=".*VM 104.*"] workspace number 5

# Auto-start Proxmox Web UI browser on Workspace 3
exec_always swaymsg "workspace number 3; exec firefox --kiosk https://127.0.0.1:8006"

# Hotkeys for switching between VMs (Super + 1..5)
bindsym $mod+1 workspace number 1
bindsym $mod+2 workspace number 2
bindsym $mod+3 workspace number 3
bindsym $mod+4 workspace number 4
bindsym $mod+5 workspace number 5

3. Adding macOS and Windows 11 VMs to the Mix

Neither Windows nor macOS supports Mesa Venus or virtio-gpu-rutabaga natively because Venus is a Linux-only Mesa driver. However, they integrate cleanly into the Sway workspace setup.

 ┌─────────────────────────────────────────────────────────────────────────┐
 │ Proxmox Host Wayland Desktop (Sway)                                     │
 │                                                                         │
 │  Workspace 1: Linux Gaming VM   ───> (Mesa Venus / Rutabaga Vulkan 3D)  │
 │  Workspace 2: Linux Work VM     ───> (Mesa Venus / Wayland Forwarding)  │
 │  Workspace 3: Proxmox Web GUI   ───> (Host Browser)                     │
 │  Workspace 4: Windows 11 VM     ───> (VirtIO 2D or VFIO GPU Passthrough)│
 │  Workspace 5: macOS VM          ───> (OSX-KVM VirtIO or AMD Passthrough)│
 └─────────────────────────────────────────────────────────────────────────┘

How Windows 11 Fits In (Workspace 4)

  • Graphics Acceleration Options:
    1. Standard 2D / Office Use: Use virtio-gpu-pci with official Red Hat virtio-win drivers. Windows renders in 2D, and QEMU outputs the desktop directly onto Sway Workspace 4.
    2. 3D Gaming / CAD: Pass a secondary physical GPU (NVIDIA/AMD) to Windows via PCIe Passthrough (VFIO) or use SR-IOV vGPU. You can then display Windows using Looking Glass inside Sway.
  • Proxmox Config (/etc/pve/qemu-server/103.conf):
    name: Windows11-VM
    bios: ovmf
    efidisk0: local-lvm:vm-103-disk-0,efitype=4m,pre-enrolled-keys=1
    tpmstate0: local-lvm:vm-103-disk-1,version=v2.0
    vga: virtio
    args: -display wayland,gl=on -audiodev pipewire,id=snd0 -device virtio-sound-pci,audiodev=snd0

How macOS Fits In (Workspace 5)

  • Graphics Acceleration Options:
    1. Software Rendering (Standard OSX-KVM): macOS has zero VirtIO-GPU 3D driver support. OSX-KVM runs using software rendering (LLVMpipe). QEMU displays the macOS desktop directly onto Sway Workspace 5.
    2. Hardware Acceleration: Pass a compatible AMD GPU (e.g., RX 6600 / RX 6800) directly to macOS via PCIe Passthrough (VFIO).
  • Proxmox Config (/etc/pve/qemu-server/104.conf):
    name: macOS-Sonoma-VM
    bios: ovmf
    args: -device isa-applesmc,osk="..." -smbios type=2 -display wayland -audiodev pipewire,id=snd0 -device virtio-sound-pci,audiodev=snd0

Summary of the Complete Desktop Workflow

  1. Host Boot: Proxmox boots, starts wayland-desktop.service, launching Sway on TTY1.
  2. Auto-Start VMs: Proxmox auto-starts VMs 100 through 104.
  3. Workspace Mapping:
    • Super + 1: Linux Gaming VM (Fedora + Venus Vulkan 3D).
    • Super + 2: Linux Work VM (Ubuntu + Venus Vulkan).
    • Super + 3: Proxmox Admin GUI (Firefox in kiosk mode).
    • Super + 4: Windows 11 VM (VirtIO-GPU 2D or Looking Glass).
    • Super + 5: macOS VM (OSX-KVM).
  4. Audio & Input: PipeWire mixes audio from Linux, Windows, macOS, and Host simultaneously. Hotkeys instantly switch display focus across all 5 systems in <1 millisecond.

Note: Mesa Venus / Wayland Forwarding


The difference highlights the two distinct ways Rutabaga + Venus can display virtual machines on your host desktop, depending on what you are using the VM for:


Workspace 1: Full-Screen 3D Rendering Mode (Gaming VM)

(Mesa Venus / Rutabaga Vulkan 3D)

  • How it works: The VM acts as a complete, self-contained desktop system.
  • The Pipeline: The game running in the VM renders full 3D frames (using Mesa Venus Vulkan / Proton). Rutabaga takes that entire 3D frame buffer and displays the VM as one single, unified full-screen window on your host display.
  • Why use this for Gaming?
    • Games need exclusive full-screen control for resolution scaling, aspect ratios, and mouse pointer grabbing.
    • You run a full desktop or Steam Big Picture mode inside the VM.
    • Best for: Steam games, Cyberpunk, Proton, Blender, or CAD software.

Workspace 2: Wayland Forwarding / Seamless Window Mode (Work VM)

(Mesa Venus / Wayland Forwarding / Cross-Domain)

  • How it works: The VM does NOT render a full desktop environment (no guest taskbar, no desktop wallpaper, no nested window manager).
  • The Pipeline: Utilizing Rutabaga’s cross-domain feature (virtio-wayland), the guest VM proxies individual Wayland application sockets directly to your host Sway compositor.
  • Why use this for Work?
    • Applications inside the VM (like VS Code, Firefox, or a Terminal) open as individual, floating windows directly on your host desktop.
    • They tile, resize, and integrate seamlessly alongside native host apps without looking like a "box inside a box."
    • Best for: Development, web browsing, coding, and day-to-day productivity where you want seamless app integration without the memory overhead of a guest desktop environment.

Summary Comparison

Feature Workspace 1: Gaming VM (Full 3D Mode) Workspace 2: Work VM (Wayland Forwarding Mode)
Visual Output One large window displaying the entire VM desktop / game. Individual app windows floating directly on host Sway.
Guest Desktop Environment Required (e.g., KDE, GNOME, or Steam Big Picture). Not required (App windows pass directly to host compositor).
Rutabaga Feature Used venus (Vulkan 3D GPU acceleration) cross-domain (Wayland socket proxying) + venus
Ideal Workloads Full-screen AAA games, 3D rendering, video editing. Coding (VS Code), Terminal, Web browsing, Slack.

Using Hyprland instead of Sway on your Proxmox host is a popular choice for gaming and multimedia hypervisors.

While Sway focuses on strict i3-like minimalism, Hyprland offers three distinct advantages for a hyper-converged desktop:

  1. Direct Scanout: Bypasses the host compositor's rendering pipeline when a VM goes full-screen, delivering absolute zero-latency display performance (identical to bare metal).
  2. Native VRR / FreeSync Support: Flawless Variable Refresh Rate handling per-window and per-monitor.
  3. Fluid Workspace Animations: Sliding seamlessly between VM workspaces feels like switching spaces on macOS or SteamOS.

1. Updated Systemd Service (/etc/systemd/system/wayland-desktop.service)

The systemd service remains almost identical, with minor changes to launch Hyprland:

[Unit]
Description=Proxmox Host Wayland Desktop (Hyprland)
After=systemd-user-sessions.service plymouth-quit-active.service pve-guests.service
Wants=pve-guests.service

[Service]
Type=simple
User=pve-desktop
PAMName=login
WorkingDirectory=/home/pve-desktop
Environment=XDG_SESSION_TYPE=wayland
Environment=XDG_CURRENT_DESKTOP=Hyprland
Environment=XDG_RUNTIME_DIR=/run/user/1000
Environment=WAYLAND_DISPLAY=wayland-0
Environment=PIPEWIRE_RUNTIME_DIR=/run/user/1000
TTYPath=/dev/tty1
ExecStart=/usr/bin/Hyprland
Restart=on-failure

[Install]
WantedBy=graphical.target

2. Hyprland Configuration (/home/pve-desktop/.config/hypr/hyprland.conf)

Hyprland uses a powerful rule system called windowrulev2 to route VM windows, enable zero-latency scanouts, and handle hotkeys.

# ==========================================
# 1. Performance & Display Settings
# ==========================================
misc {
    # Direct Scanout bypasses host compositing for full-screen VMs (Zero-latency!)
    direct_scanout = true
    # VRR (Variable Refresh Rate / FreeSync / G-Sync)
    vrr = 1 # 1 = always on, 2 = fullscreen only
}

# General Layout
general {
    gaps_in = 5
    gaps_out = 10
    border_size = 2
    layout = master
}

# ==========================================
# 2. VM Window Routing Rules (windowrulev2)
# ==========================================
# Assign VM windows to dedicated workspaces based on title/ID
windowrulev2 = workspace 1, class:^(qemu|qemu-system-x86_64)$, title:(.*VM 100.*)
windowrulev2 = workspace 2, class:^(qemu|qemu-system-x86_64)$, title:(.*VM 101.*)
windowrulev2 = workspace 3, class:^(qemu|qemu-system-x86_64)$, title:(.*VM 102.*)
windowrulev2 = workspace 4, class:^(qemu|qemu-system-x86_64)$, title:(.*VM 103.*)
windowrulev2 = workspace 5, class:^(qemu|qemu-system-x86_64)$, title:(.*VM 104.*)

# Force Gaming VM (Workspace 1) to open Fullscreen
windowrulev2 = fullscreen, class:^(qemu|qemu-system-x86_64)$, title:(.*VM 100.*)

# ==========================================
# 3. Workspace Hotkeys (Super + 1..5)
# ==========================================
$mainMod = SUPER

bind = $mainMod, 1, workspace, 1
bind = $mainMod, 2, workspace, 2
bind = $mainMod, 3, workspace, 3
bind = $mainMod, 4, workspace, 4
bind = $mainMod, 5, workspace, 5

# Move active window to workspace
bind = $mainMod SHIFT, 1, movetoworkspace, 1
bind = $mainMod SHIFT, 2, movetoworkspace, 2

# ==========================================
# 4. Auto-Start Proxmox Dashboard
# ==========================================
# Launch Firefox kiosk mode with Proxmox Web GUI on Workspace 3
exec-once = hyprctl dispatch workspace 3 && firefox --kiosk https://127.0.0.1:8006

3. Visual & Interactive Behavior in Hyprland

 ┌─────────────────────────────────────────────────────────────────────────┐
 │ Hyprland Host Desktop (Proxmox VE)                                     │
 │                                                                         │
 │  ┌────────────────────────┐  Slide Right ┌──────────────────────────┐   │
 │  │ Workspace 1: Gaming VM │ ────────────>│ Workspace 2: Work Apps   │   │
 │  │ (144Hz, Direct Scanout)│ (Super + 2)  │ (Seamless App Windows)   │   │
 │  └────────────────────────┘              └──────────────────────────┘   │
 └─────────────────────────────────────────────────────────────────────────┘

Workspace 1: Gaming VM (Full-Screen Direct Scanout)

  • When you press Super + 1, Hyprland smoothly slides to Workspace 1.
  • Hyprland detects the full-screen QEMU window and triggers Direct Scanout. The host compositor stops processing that window entirely, handing direct control of the monitor's display buffer to the VM via virtio-gpu-rutabaga / Venus.
  • Latency: Exactly identical to native bare-metal gaming.

Workspace 2: Linux Work VM (Rutabaga Wayland Forwarding)

  • When you press Super + 2, you enter Workspace 2.
  • Guest Wayland applications (VS Code, Terminal, Slack) proxy their Wayland sockets using Rutabaga cross-domain.
  • Hyprland's dynamic tiling manager automatically tiles and snaps these guest windows alongside native host windows with smooth opening/closing animations.

Workspace 3: Proxmox Web GUI

  • Pressing Super + 3 slides over to a browser displaying your local Proxmox management dashboard, allowing you to monitor node stats, temperature, CPU usage, and manage VM snapshots.

Sway vs. Hyprland for Proxmox Host

Feature Sway Host Hyprland Host
Philosophy Minimal, strict i3-compatible tiling Modern, fluid, animated
Latency for Fullscreen VMs Very low Lowest possible (via Direct Scanout)
Animations None (instant hard cuts) Smooth spatial transitions between VMs
VRR / FreeSync Basic Per-window / Per-monitor advanced VRR
Window Rules Standard Sway criteria Advanced windowrulev2 regex filtering

LXC Containers for Linux - instead of Linux VMs

In fact, for Linux workloads, LXC containers work even better, faster, and simpler than Virtual Machines.

While VMs require paravirtualized GPU drivers (like Mesa Venus over virtio-gpu) to bridge guest and host, LXC containers share the host Linux kernel directly.

This means LXC containers can bypass Venus entirely and use your physical GPU and Wayland compositor at 100% native bare-metal speed with zero virtualization overhead.


Why LXCs are Superior for Linux Workloads on Proxmox

Feature KVM Virtual Machines (VMs) LXC Containers
GPU Performance Near-native (~95–98%) via Venus 100% Native Bare Metal (Direct GPU hardware access)
Display Sharing Requires virtio-gpu-rutabaga or SPICE Direct Wayland Socket Mount (/run/user/1000/wayland-0)
RAM Usage Fixed pre-allocated memory (e.g., locks 16GB) Dynamic Shared RAM (Uses only what it needs on-demand)
Boot Time 5 – 15 seconds Sub-second (<0.5 seconds)
OS Support Linux, Windows, macOS, BSD Linux Only (Fedora, Arch, Ubuntu, Alpine)

How to Set Up LXC Display & GPU in Proxmox

Instead of using virtio-gpu-rutabaga, you pass two things from the Proxmox host into the LXC container:

  1. The GPU Render Node (/dev/dri/renderD128) for native Vulkan/OpenGL 3D acceleration.
  2. The Host Wayland Socket (/run/user/1000/wayland-0) so container apps render directly onto the host Hyprland desktop.

Step 1: Proxmox LXC Configuration (/etc/pve/lxc/<CTID>.conf)

Add these lines to your LXC config file on the Proxmox host (e.g., container ID 200):

# /etc/pve/lxc/200.conf (Ubuntu Work LXC)
arch: amd64
cores: 8
memory: 8192
ostype: ubuntu

# 1. Pass host GPU render node directly for native 3D/Vulkan (AMD / Intel / NVIDIA)
lxc.cgroup2.devices.allow: c 226:128 rwm
lxc.mount.entry: /dev/dri/renderD128 dev/dri/renderD128 none bind,optional,create=file

# 2. Pass host Wayland socket directly into the container
lxc.mount.entry: /run/user/1000/wayland-0 run/user/1000/wayland-0 none bind,optional,create=file

# 3. Share audio socket (PipeWire)
lxc.mount.entry: /run/user/1000/pipewire-0 run/user/1000/pipewire-0 none bind,optional,create=file

Step 2: Environment Inside the LXC Container

Inside the LXC container's /etc/environment or user .bashrc, tell applications where to find the Wayland socket:

WAYLAND_DISPLAY=wayland-0
XDG_RUNTIME_DIR=/run/user/1000
PIPEWIRE_RUNTIME_DIR=/run/user/1000

Now, whenever you launch an app inside the LXC container (e.g., code, firefox, or steam), its window appears instantly on your host Hyprland desktop as if it were a native host application!


Step 3: Hyprland Window Routing for LXC (hyprland.conf)

Hyprland sees LXC applications just like native host windows. You map them to workspaces using window rules:

# Route LXC Application windows to Workspace 2 (Work)
windowrulev2 = workspace 2, class:^(code-url-handler|code|firefox)$

# Route LXC Steam / Games to Workspace 1 (Gaming)
windowrulev2 = workspace 1, class:^(steam|gamescope)$

The Ultimate Hybrid Proxmox Desktop Architecture

You combine LXCs for Linux and KVM VMs for Windows/macOS:

 ┌─────────────────────────────────────────────────────────────────────────┐
 │ Proxmox Host Desktop (Hyprland)                                         │
 │                                                                         │
 │  Workspace 1: Gaming LXC Container ───> (Direct /dev/dri GPU Access)    │
 │  Workspace 2: Work LXC Container   ───> (Direct Wayland Socket Mount)  │
 │  Workspace 3: Proxmox Web GUI     ───> (Host Firefox Kiosk)             │
 │  Workspace 4: Windows 11 VM       ───> (KVM + VirtIO-GPU / VFIO)       │
 │  Workspace 5: macOS VM            ───> (OSX-KVM + VFIO)                │
 └─────────────────────────────────────────────────────────────────────────┘

Summary

  • Use LXCs for: Linux gaming, Linux development, containers, and web browsers. You get sub-second boots, dynamic RAM usage, zero CPU/memory overhead, and 100% native GPU performance.
  • Use KVM VMs for: Windows 11 and macOS, because they require full OS kernel virtualization and cannot run inside a Linux LXC container.

Direct hyper-converged desktop - Alternatives

  • XBOX One ... based on HyperV - games are started in VMs and resized to fullscreen
  • Windows + VirtualBox, Different windows for the VMs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment