Desktop Access for KVM on Podman: VNC First, SPICE Next
Quick one-liner: Your VM works over SSH, but some tasks need a real desktop. In this post, we add a QEMU VNC console first, then show the same VM through SPICE and remote-viewer.
🤔 Why This Matters
In Post #5, we made the VM reachable over SSH. In Post #6, we fixed the tiny SLES cloud image so it finally had room to install real packages.
That gives us a working server-style VM — but it's still terminal-only.
That's fine for many tasks, until you need:
- GUI installers
- visual tools
- browser-based checks inside the guest
- desktop workflows for testing
This post is the step from "I can SSH into it" to "I can actually see and operate the desktop."
The important distinction is that we're not starting with a guest-native remote desktop service yet. We first want a VM access path that proves the display layer works, even before SLES-specific RDP configuration enters the picture.
🏗️ What We Are Building
We're not rebuilding everything from scratch. We keep the same resized VM disk from Post #6, the same SSH management path from Post #5, and add desktop access in two layers:
-
QEMU VNC console
- VM console path
- useful when the guest stops at GRUB, installer screens, first boot, or recovery
- does not depend on a working guest-native remote desktop service
-
GNOME inside the guest
- full desktop environment
- visible through the VM console
- Firefox and Cockpit for a useful first desktop/admin workflow
- prepares the VM for guest-native remote desktop in the next post
-
SPICE from QEMU
- alternate VM console path
- works with
remote-viewer
VNC is first because QEMU can expose the VM console directly. Once GNOME is installed, the same console shows the graphical desktop.
SPICE is the alternate path we add next so the same VM can be opened with remote-viewer too.
✅ Prerequisites
- Posts #1 to #6 completed
- Existing VM disk in
~/vm -
qemu:baseimage available - Podman network
mynetavailable - Host port
5900free - SLES 16 full ISO available in
~/vmfor non-subscribed installs - The
/datadisk from Post #6 available as~/vm/extra-disk.qcow2
Examples below assume:
- VM disk:
~/vm/SLES-16.0-Minimal-VM.x86_64-Cloud-GM.qcow2 - SLES ISO:
~/vm/SLES-16.0-Full-x86_64-GM.install.iso - Data disk:
~/vm/extra-disk.qcow2 - Guest user:
sysadmin
If you are using another distro image, keep the same flow and swap only the package commands for that distro.
🖥️ Step 1: Boot the VM with a QEMU VNC Console
First, boot the VM with the QEMU VNC console exposed on host port 5900.
The QEMU console matters before the guest desktop is ready. If the VM stops at GRUB or needs boot interaction, SSH will not help yet. You need to see the VM console first.
One important carry-over from Post #6: we continue with the same VM state, including the /data disk.
If extra-disk.qcow2 is missing but /etc/fstab still expects it, the VM may sit at a boot wait for a missing UUID and SSH will never become usable.
cd ~/vm
# Download your SLES 16 full ISO manually from SUSE Customer Center if needed.
podman network exists mynet || podman network create mynet
podman run --rm -it \
--name kvm-gui \
--network=mynet \
--device /dev/kvm \
-p 2222:22 \
-p 5900:5900 \
-v ~/vm:/vm:z \
qemu:base \
qemu-system-x86_64 \
-enable-kvm -cpu host \
-m 2048 \
-drive file=/vm/SLES-16.0-Minimal-VM.x86_64-Cloud-GM.qcow2,format=qcow2,if=virtio \
-drive file=/vm/extra-disk.qcow2,format=qcow2,if=virtio \
-drive file=/vm/SLES-16.0-Full-x86_64-GM.install.iso,media=cdrom,readonly=on \
-boot order=c \
-netdev user,id=net0,hostfwd=tcp::22-:22 \
-device virtio-net-pci,netdev=net0 \
-vga virtio \
-display vnc=0.0.0.0:0
After you run this, the terminal may look quiet — that's expected. QEMU isn't opening a local GTK window or printing the graphical boot console to your shell. The VM console is being served over VNC on 5900.
Quick notes:
-
-p 5900:5900exposes the QEMU VM console to your host - keep
-p 2222:22for SSH control - ISO is attached as a virtual CD-ROM so the guest can mount it as
/dev/sr0 -
extra-disk.qcow2keeps the/datamount from Post #6 available during boot -
-boot order=ckeeps the resized cloud disk as the boot target even with the ISO attached -
-vga virtiogives the guest a proper virtual display adapter for the graphical desktop -
-display vnc=0.0.0.0:0exposes QEMU's console on port5900
Now connect a VNC client to the QEMU console right away:
localhost:5900
Use this console to watch boot progress and confirm the VM gets past GRUB and reaches the guest OS. After the guest is up, SSH should work again:
ssh -p 2222 sysadmin@localhost
🎨 Step 2: Install GNOME 48
Once the VM is up, SSH in if you're not already using the QEMU console:
ssh -p 2222 sysadmin@localhost
We'll install GNOME, the default desktop environment on SLES 16.
There are two practical install paths:
- subscribed system: install directly from online repos
- non-subscribed system: mount the SLES 16 ISO and use it as a local repo
Option A: Subscribed SLES (online repos)
sudo zypper refresh
sudo zypper patterns | grep -i gnome
sudo zypper in -t pattern gnome
sudo zypper install -y MozillaFirefox cockpit
sudo systemctl start cockpit.socket
sudo systemctl enable cockpit.socket
Option B: Non-Subscribed SLES (ISO repo)
Mount the attached SLES 16 ISO inside the guest and register it as a local repository:
sudo mkdir -p /mnt/sles16-iso
lsblk
sudo mount /dev/sr0 /mnt/sles16-iso
sudo zypper ar -f file:///mnt/sles16-iso sles16-iso
sudo zypper refresh
sudo zypper patterns | grep -i gnome
sudo zypper in -t pattern gnome
sudo zypper install -y MozillaFirefox cockpit
sudo systemctl start cockpit.socket
sudo systemctl enable cockpit.socket
Firefox gives the desktop something useful to open immediately.
Cockpit gives you a browser-based admin interface at:
https://localhost:9090
From inside the VM desktop, open Firefox and browse to that address.
Cockpit also gives you a decent terminal, so you don't need to add a separate desktop terminal package for this lab.
Set graphical mode as the default boot target:
sudo systemctl set-default graphical.target
Then reboot so SLES starts into the graphical target:
sudo reboot
🔌 Step 3: Connect to the Desktop Console
From your host, keep your VNC client connected to the QEMU console:
localhost:5900
After the reboot, the same QEMU VNC console should show the SLES graphical login screen. This is still not guest-native RDP — it's the VM console showing the guest desktop.
⚡ Step 4: Where SPICE Fits
QEMU VNC proves the VM console and desktop path work. SPICE is the alternate client path — same VM, different protocol.
Use the same VM, but switch the display side of the QEMU command to SPICE:
podman run --rm -it \
--name kvm-spice \
--network=mynet \
--device /dev/kvm \
-p 2222:22 \
-p 5930:5930 \
-v ~/vm:/vm:z \
qemu:base \
qemu-system-x86_64 \
-enable-kvm -cpu host \
-m 2048 \
-drive file=/vm/SLES-16.0-Minimal-VM.x86_64-Cloud-GM.qcow2,format=qcow2,if=virtio \
-drive file=/vm/extra-disk.qcow2,format=qcow2,if=virtio \
-drive file=/vm/SLES-16.0-Full-x86_64-GM.install.iso,media=cdrom,readonly=on \
-boot order=c \
-netdev user,id=net0,hostfwd=tcp::22-:22 \
-device virtio-net-pci,netdev=net0 \
-spice port=5930,addr=0.0.0.0,disable-ticketing=on \
-device virtio-vga \
-device virtio-keyboard-pci \
-device virtio-mouse-pci
Then connect with:
remote-viewer spice://localhost:5930
At this point, you have two access paths:
- SSH: command-line management on
2222 - QEMU VNC console or SPICE console: boot, recovery, and desktop console
💡 Why Not Start with RDP?
SLES 16 has a GNOME Remote Desktop path that uses RDP. That's probably the more familiar protocol for many users, and it's worth covering.
But it's also a guest OS feature. You configure it inside SLES with GNOME, GDM, TLS credentials, and grdctl — that's a different layer from the VM console.
VNC is the generic first step because it works across guest operating systems. SPICE is another QEMU/KVM console protocol and a valid alternate client path.
So the order is deliberate:
- QEMU VNC proves generic console and desktop visibility.
- SPICE gives you another way to open the same console from
remote-viewer. - GNOME Remote Desktop over RDP becomes the SLES-native day-to-day access path once the guest is healthy.
🎉 Wrap Up
At this point, your KVM-on-Podman VM is not only reachable and resized — it's also visible. VNC gives you the generic desktop baseline, and SPICE is an alternate console path for remote-viewer.
In the next post, we'll switch from console access to guest-native access and use the SLES 16 path: GNOME Remote Desktop over RDP.
Top comments (0)