@@ -1,0 +1,313 @@
# QEMU virtual machines
Sunshine can stream a QEMU virtual machine with no software in the guest. With
[capture](configuration.md#capture) set to `qemu`, the picture, the guest's sound and keyboard, mouse and touch
input go through QEMU's D-Bus display (`-display dbus`). Gamepads still use virtual host devices.
Each VM gets its own Sunshine process with its own configuration file, ports, pairing and name. The files for that
are in `packaging/linux/qemu` in the source tree:
| File | Purpose |
|-------------------------------|--------------------------------------------------------------------------------------|
| `sunshine-qemu@.service` | systemd system unit, one instance per VM, reads `/etc/sunshine-qemu/<vm>.conf` |
| `user/sunshine-qemu@.service` | systemd user unit for rootless setups, reads `~/.config/sunshine-qemu/<vm>.conf` |
| `sunshine-qemu.sysusers` | creates the `sunshine-qemu` user of the system unit |
| `sunshine-qemu-wait-vm` | the units' `ExecStartPre`: waits until the VM's display is reachable |
| `sunshine-qemu-port` | picks non-overlapping base ports for VMs and checks existing configs |
| `libvirt-hook-qemu` | libvirt hook that starts and stops the unit with the domain |
| `example.conf` | a commented per-VM configuration |
## Requirements
- A Sunshine build with the QEMU backend (`-DSUNSHINE_ENABLE_QEMU=ON`, needs GLib/GIO 2.64 and `gdbus-codegen`).
- QEMU 7.0 or newer with the D-Bus display: `qemu-system-x86_64 -display help` lists `dbus`. QEMU 8.2 (Ubuntu 24.04)
and 11.1 were tested. QEMU 8.2 sends the picture as D-Bus messages, newer versions share memory with Sunshine.
- For libvirt: libvirt 8.4.0 or newer (`<graphics type='dbus'>`).
## How Sunshine reaches the VM
[qemu_dbus_address](configuration.md#qemu_dbus_address) takes one of these forms.
| Address | QEMU display | Who can connect |
|--------------------------------------|--------------------------------------|-----------------------------------------------------------------|
| `unix:path=/run/vm/bus.sock` | `-display dbus,addr=...` | Clients allowed by that bus's policy (by default only its owner) |
| `qmp:/run/sunshine-qemu/vm.qmp` | `-display dbus,p2p=on` and `-qmp` | Anyone who can open the QMP socket |
| `libvirt:<domain>` | `<graphics type='dbus' p2p='yes'/>` | Users with libvirt's `open_graphics` permission on the domain |
| `libvirt:<domain>?uri=qemu:///session` | `<graphics type='dbus'/>`, session libvirt | The user running the session libvirt |
- **Bus** (`unix:path=`): QEMU owns `org.qemu` on a D-Bus bus, usually a private `dbus-daemon`. Several clients can
share it.
- **QMP** (`qmp:`): QEMU runs with no bus. Sunshine connects to a QMP socket, hands QEMU one end of a socket pair with
`getfd` and `add_client protocol=@dbus-display`, and talks D-Bus directly on the other end. It reconnects the same
way when the VM restarts. QEMU serves one QMP client at a time, so give Sunshine its own `-qmp` socket.
- **libvirt** (`libvirt:`): Sunshine loads `libvirt.so.0` at run time. For a `p2p='yes'` display it calls
`virDomainOpenGraphicsFD`, which does the same `add_client` through libvirt; libvirt labels the socket for the
domain, so it works with SELinux and AppArmor confinement. For a display without `p2p`, Sunshine reads the bus
address from the running domain's XML and connects to that bus.
QEMU serves one peer-to-peer (`p2p`) control connection at a time. Another client that attaches the same way, for
example virt-viewer through libvirt, takes the VM's display objects away from Sunshine until Sunshine reconnects.
## Raw QEMU
Bus mode, with a private bus:
```bash
mkdir -p /run/sunshine-qemu/win11
dbus-daemon --session --fork --address=unix:path=/run/sunshine-qemu/win11/bus.sock
qemu-system-x86_64 -name win11 -accel kvm -m 8G \
-device virtio-vga \
-display dbus,addr=unix:path=/run/sunshine-qemu/win11/bus.sock,audiodev=snd0 \
-audiodev dbus,id=snd0 -device intel-hda -device hda-output,audiodev=snd0 \
-device virtio-tablet-pci -device virtio-keyboard-pci \
...
```
```
qemu_dbus_address = unix:path=/run/sunshine-qemu/win11/bus.sock
```
Peer to peer through QMP, with no bus:
```bash
qemu-system-x86_64 -name win11 -accel kvm -m 8G \
-device virtio-vga \
-display dbus,p2p=on,audiodev=snd0 \
-qmp unix:/run/sunshine-qemu/win11.qmp,server=on,wait=off \
-audiodev dbus,id=snd0 -device intel-hda -device hda-output,audiodev=snd0 \
-device virtio-tablet-pci -device virtio-keyboard-pci \
...
```
```
qemu_dbus_address = qmp:/run/sunshine-qemu/win11.qmp
```
Options that matter for streaming:
- `audiodev=` on `-display dbus` together with `-audiodev dbus`: without them QEMU exports no audio to Sunshine.
- An absolute pointer (`-device virtio-tablet-pci`, or a USB tablet) makes Moonlight's mouse follow exactly. With
only a PS/2 mouse, Moonlight's absolute positions work only while the guest shows a hardware cursor.
- `-device virtio-multitouch-pci` for native touch; see [native_pen_touch](configuration.md#native_pen_touch).
- `-device virtio-vga-gl -display dbus,gl=on,rendernode=/dev/dri/renderD128` sends GPU buffers (DMABUF) that VAAPI,
NVENC and Vulkan encode without a copy. QEMU must render on the encoder's GPU: set
[adapter_name](configuration.md#adapter_name) to the same render node for VAAPI.
## Several VMs on one host
Every instance needs its own ports, name and state. Nothing else is shared, so configuration files are enough:
- **Ports.** Every Sunshine port is an offset from [port](configuration.md#port), from `port - 5` to `port + 21`,
including the web UI (`port + 1`). Give each VM a base port 100 above the previous one: 48089, 48189, 48289, and
so on (47989 stays free for a desktop Sunshine). `sunshine-qemu-port --dir /etc/sunshine-qemu --write <vm>` adds
the next free base port to `<vm>.conf`, and `sunshine-qemu-port --dir /etc/sunshine-qemu --check` reports
overlapping configs. Open each instance's ports in the firewall.
- **Name.** [sunshine_name](configuration.md#sunshine_name) is what Moonlight shows and the name advertised over
mDNS, so each VM is listed on its own. Keep it unique on the host.
- **State.** [file_state](configuration.md#file_state), [credentials_file](configuration.md#credentials_file),
[pkey](configuration.md#pkey), [cert](configuration.md#cert), [file_apps](configuration.md#file_apps) and
[log_path](configuration.md#log_path) hold pairing, web UI credentials, certificates, apps and the log. Relative
paths are resolved in Sunshine's configuration directory, which the units set per VM with `XDG_CONFIG_HOME`, so
pairing a client with one VM doesn't pair it with another.
- **UPnP.** Set [upnp](configuration.md#upnp) to `disabled`: instances would ask the router for mappings on each
other's behalf.
- **Audio.** With `capture = qemu` Sunshine takes the sound from QEMU and creates no PulseAudio sinks.
## systemd
Install the files (paths as used by the units):
```bash
sudo install -Dm644 packaging/linux/qemu/sunshine-qemu@.service /etc/systemd/system/sunshine-qemu@.service
sudo install -Dm644 packaging/linux/qemu/sunshine-qemu.sysusers /usr/lib/sysusers.d/sunshine-qemu.conf
sudo install -Dm755 packaging/linux/qemu/sunshine-qemu-wait-vm /usr/lib/sunshine-qemu/sunshine-qemu-wait-vm
sudo install -Dm755 packaging/linux/qemu/sunshine-qemu-port /usr/lib/sunshine-qemu/sunshine-qemu-port
sudo systemd-sysusers
sudo install -Dm640 -g sunshine-qemu packaging/linux/qemu/example.conf /etc/sunshine-qemu/win11.conf
# edit /etc/sunshine-qemu/win11.conf, then:
sudo /usr/lib/sunshine-qemu/sunshine-qemu-port --dir /etc/sunshine-qemu --check
sudo -u sunshine-qemu XDG_CONFIG_HOME=/var/lib/sunshine-qemu/win11 sunshine /etc/sunshine-qemu/win11.conf --creds <user> <password>
sudo systemctl daemon-reload
sudo systemctl enable --now sunshine-qemu@win11.service
```
The `--creds` line needs `/var/lib/sunshine-qemu/win11`, which systemd creates on the unit's first start; run it
after starting the unit once, or create the directory owned by `sunshine-qemu` first.
The unit runs `sunshine /etc/sunshine-qemu/<vm>.conf` as `sunshine-qemu` with its state in
`/var/lib/sunshine-qemu/<vm>`, restarts it on failure, and has `After=` on libvirt and Avahi. It uses
`PrivateTmp=yes` and `ProtectHome=yes`, so keep sockets Sunshine connects to under `/run`, not `/tmp` or home
directories.
**Start order.** Sunshine checks QEMU's display once, when it starts. If the VM isn't reachable then, it logs
`Unable to initialize capture method` and keeps running without being able to stream, even after the VM comes up,
until it is restarted. So the unit's `ExecStartPre` runs `sunshine-qemu-wait-vm`, which waits (120 s by default)
until QEMU owns `org.qemu` on the configured bus, the QMP socket exists, or `virsh domstate` reports the libvirt
domain running. When it gives up, the unit fails and `Restart=on-failure` waits again. Start the unit after the VM,
or let the libvirt hook do it. Once Sunshine has found the VM, a guest reboot or a VM restart doesn't need a Sunshine
restart: it reconnects.
**Rootless.** For VMs you run as your own user (raw QEMU, or `qemu:///session`), use the user unit:
```bash
install -Dm644 packaging/linux/qemu/user/sunshine-qemu@.service ~/.config/systemd/user/sunshine-qemu@.service
install -Dm644 packaging/linux/qemu/example.conf ~/.config/sunshine-qemu/win11.conf
systemctl --user daemon-reload
systemctl --user enable --now sunshine-qemu@win11.service
```
It still expects `sunshine-qemu-wait-vm` in `/usr/lib/sunshine-qemu/`; edit the `ExecStartPre` path otherwise.
## libvirt
### Domain XML
For the system libvirt (`qemu:///system`), use a peer-to-peer display:
```xml
<domain type='kvm'>
<name>win11</name>
<devices>
<graphics type='dbus' p2p='yes'>
<audio id='1'/>
</graphics>
<audio id='1' type='dbus'/>
<sound model='ich9'>
<audio id='1'/>
</sound>
<video>
<model type='virtio'/>
</video>
<input type='tablet' bus='virtio'/>
<input type='keyboard' bus='virtio'/>
</devices>
</domain>
```
```
qemu_dbus_address = libvirt:win11
```
For DMABUF zero-copy add `<gl enable='yes' rendernode='/dev/dri/renderD128'/>` inside `<graphics>` and
`<acceleration accel3d='yes'/>` inside the video `<model>`. Without `rendernode`, libvirt picks the first render
node itself, which fails on hosts without `/dev/dri`; use `<gl enable='no'/>` there.
The system unit's user needs libvirt's `domain:open_graphics` permission. The simplest way is the `libvirt` group
(`usermod -aG libvirt sunshine-qemu`), but that group can manage every VM and is effectively root. With
`access_drivers = [ "polkit" ]` in `/etc/libvirt/libvirtd.conf` (or `virtqemud.conf`) a polkit rule can grant only
what Sunshine uses:
```js
// /etc/polkit-1/rules.d/50-sunshine-qemu.rules
polkit.addRule(function(action, subject) {
if (subject.user == "sunshine-qemu" &&
(action.id == "org.libvirt.unix.manage" ||
action.id == "org.libvirt.api.connect.getattr" ||
action.id == "org.libvirt.api.connect.search-domains" ||
action.id == "org.libvirt.api.domain.getattr" ||
action.id == "org.libvirt.api.domain.read" ||
action.id == "org.libvirt.api.domain.open-graphics")) {
return polkit.Result.YES;
}
});
```
Check the exact action names against your libvirt's ACL documentation; this rule hasn't been tested yet.
Why not the bus libvirt starts for a display without `p2p`? For every `<graphics type='dbus'>` without `p2p` or
`address`, libvirt starts a private `dbus-daemon` for the domain under `/run/libvirt/qemu/dbus/` whose path contains
the domain id (so it changes on every start). Its policy only admits the domain's own user (`libvirt-qemu` or `qemu`)
and, from libvirt 11.2, root; being in the socket's group isn't enough. Use that mode only when Sunshine runs as the
same user, as with `qemu:///session`:
```
qemu_dbus_address = libvirt:win11?uri=qemu:///session
```
Sunshine then reads the bus address from the running domain's XML each time it connects.
libvirt 11.2 and newer may start its own display helpers (`qemu-rdp` for `<graphics type='rdp'>`, and from 12.5
`qemu-vnc`) on a bus-mode display; they share the VM with Sunshine.
### Hook
`libvirt-hook-qemu` starts `sunshine-qemu@<domain>.service` when a domain starts (and when libvirt reconnects to a
running domain) and stops it when the domain stops. It only acts on domains that have `/etc/sunshine-qemu/<domain>.conf`,
never waits for Sunshine and never fails the domain operation.
```bash
# libvirt 6.5 and newer: hook directory
sudo install -Dm755 packaging/linux/qemu/libvirt-hook-qemu /etc/libvirt/hooks/qemu.d/sunshine-qemu
# older libvirt, or no other qemu hook: sudo install -Dm755 packaging/linux/qemu/libvirt-hook-qemu /etc/libvirt/hooks/qemu
sudo systemctl restart virtqemud # or libvirtd; libvirt only notices a new hook on restart
```
Don't enable the unit when the hook manages it. A hook must not call libvirt (libvirt holds the domain while hooks
run), so the hook starts the unit asynchronously and Sunshine connects once the domain is up.
### virt-manager
virt-manager has no editor for D-Bus displays, so change the XML:
1. **Edit → Preferences → General**: enable **Enable XML editing**.
2. Shut the VM down and open its details (**Open**, then the light bulb icon).
3. Select **Overview**, open the **XML** tab and, inside `<devices>`, replace the `<graphics type='spice'>` or
`<graphics type='vnc'>` element with `<graphics type='dbus' p2p='yes'><audio id='1'/></graphics>`. Add
`<audio id='1' type='dbus'/>` and make the sound device use it (`<sound model='ich9'><audio id='1'/></sound>`).
Remove SPICE-only devices virt-manager added (`<channel type='spicevmc'>`, `<redirdev type='spicevmc'>`,
`<audio type='spice'>`) if libvirt refuses the XML. Click **Apply**.
4. Under **Add Hardware → Input** add an **EvTouch USB Graphics Tablet** or a virtio tablet if the VM has only a PS/2
mouse.
5. Write `/etc/sunshine-qemu/<domain>.conf` with `qemu_dbus_address = libvirt:<domain>` and install the hook.
6. Start the VM from virt-manager: `systemctl status sunshine-qemu@<domain>` should show Sunshine running, and
Moonlight lists the VM under its `sunshine_name`.
virt-manager's own console can't show a D-Bus display; use Moonlight (or `virt-viewer`, which then takes the
display away from Sunshine, see above).
## Troubleshooting
### "Unable to initialize capture method" or "Unable to find display or encoder during startup"
The VM's display wasn't reachable when Sunshine started. Sunshine doesn't try again by itself: fix the cause and
restart it (the systemd units wait for the VM first). The `qemu:` log line above names the reason:
- `no QEMU owns [org.qemu]`: QEMU isn't running or uses another bus. Start the VM first; the systemd units wait for it.
- `couldn't connect to D-Bus address`: check the path, and that Sunshine's user may connect. A bus started by libvirt
or by another user refuses other users: use `p2p='yes'` or `qmp:`.
- `no QMP greeting`: another client holds the QMP socket; give Sunshine its own `-qmp` socket.
- `QMP add_client failed ... p2p connections not accepted in bus mode`: QEMU runs `-display dbus` without `p2p=on`.
- `couldn't load libvirt.so.0`: install libvirt's client library (`libvirt0` or `libvirt-libs`).
- `virDomainOpenGraphicsFD ... failed` or an access error: Sunshine's user lacks the libvirt permission above, or the
domain's display has no `p2p='yes'`.
- `domain [...] has no <graphics type='dbus'> device`: the domain XML still has a SPICE or VNC display.
### Permission denied on the render node, or "QEMU renders on ..." errors
With `gl=on`, QEMU and the encoder must use the same GPU. Set `rendernode=` in QEMU (or `<gl rendernode=>` in libvirt)
and [adapter_name](configuration.md#adapter_name) to the same `/dev/dri/renderD*` for VAAPI; NVENC needs QEMU on the
NVIDIA GPU's render node. Sunshine's user needs the `render` (and on some systems `video`) group.
### The mouse is offset or doesn't move
Sunshine sends absolute positions when QEMU reports an absolute pointer (`IsAbsolute`). A VM with only a PS/2 mouse is
relative: Moonlight positions then only work while the guest shows a hardware cursor. Add a virtio or USB tablet. If
touches do nothing, the VM lacks `virtio-multitouch-pci`; disable [native_pen_touch](configuration.md#native_pen_touch).
### No sound
QEMU exports audio only with `-audiodev dbus,id=...` plus `-display dbus,audiodev=...` (libvirt:
`<audio type='dbus'>` referenced from `<graphics>`), and the guest's sound card must use that audiodev.
### Two VMs show up as one, or a port is in use
Give every instance its own `port` (100 apart) and `sunshine_name`, and run `sunshine-qemu-port --check`. An
`Address already in use` in the log names the port that collides.
## What was tested
On Ubuntu 24.04 under WSL2 with QEMU 8.2 and 11.1: bus and QMP peer-to-peer streaming with picture, audio, input and
guest reboots, two VMs streamed at the same time by two instances (distinct mDNS names, ports and pairing), the units
with `systemd-analyze verify`, and the hook and helpers with fake `systemctl`, `gdbus` and `virsh`. The libvirt path
is tested against a stand-in for `libvirt.so.0` only. Not tested yet: a real libvirt domain (virt-manager), SELinux or
AppArmor confinement, the polkit rule, and DMABUF on a host with a GPU render node.