@@ -31,8 +31,8 @@
| 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 |
| `qmp:/run/sunshine-qemu/vm.qmp` | `-display dbus,p2p=on` and `-qmp` | Anyone who can open the QMP socket (full control of QEMU) |
| `libvirt:<domain>` | `<graphics type='dbus' p2p='yes'/>`, system libvirt | 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
@@ -40,7 +40,13 @@
- **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.
**QMP access is full control of QEMU**: whoever can open the socket can run commands as QEMU's user (for example
- **libvirt** (`libvirt:`): Sunshine loads `libvirt.so.0` at run time. For a `p2p='yes'` display it calls
`human-monitor-command` with `migrate exec:`) and read host files through `blockdev-add`. Sunshine is a network
service, so a flaw in it would hand that over. Run such a QEMU as an unprivileged user, never as root, and prefer
libvirt's `p2p='yes'` (which gives Sunshine only the display) or a bus.
- **libvirt** (`libvirt:`): Sunshine loads `libvirt.so.0` at run time. `libvirt:<domain>` uses the system libvirt
(`qemu:///system`), also when Sunshine runs as an unprivileged user whose own default would be `qemu:///session`;
`?uri=` picks another connection (an empty `?uri=` leaves the choice to libvirt). 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.
@@ -50,11 +56,15 @@
## Raw QEMU
The examples run QEMU as an unprivileged user (`vmuser` here) and let the system unit's `sunshine-qemu` user in; for
the user unit, run everything as yourself and skip the ownership steps.
Bus mode, with a private bus:
```bash
install -d -o vmuser -g sunshine-qemu -m 2750 /run/sunshine-qemu/win11
# run as vmuser; a --session bus admits only its owner, so use a policy that also admits sunshine-qemu (below)
dbus-daemon --config-file=/etc/sunshine-qemu/win11-bus.conf --fork --address=unix:path=/run/sunshine-qemu/win11/bus.sock
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 \
@@ -66,10 +76,17 @@
```
qemu_dbus_address = unix:path=/run/sunshine-qemu/win11/bus.sock
```
`/etc/sunshine-qemu/win11-bus.conf` is a copy of `/usr/share/dbus-1/session.conf` whose `<policy context="default">`
also has `<allow user="sunshine-qemu"/>` (without such a rule dbus-daemon admits only its owner's uid).
Peer to peer through QMP, with no bus:
Peer to peer through QMP, with no bus (see the warning above: the socket gives full control of QEMU):
```bash
# setgid directory: the socket QEMU creates belongs to the sunshine-qemu group
install -d -o vmuser -g sunshine-qemu -m 2750 /run/sunshine-qemu
# run as vmuser; umask 0007 makes the socket group-writable, so the sunshine-qemu group can connect
umask 0007
qemu-system-x86_64 -name win11 -accel kvm -m 8G \
-device virtio-vga \
-display dbus,p2p=on,audiodev=snd0 \
@@ -103,12 +120,14 @@
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.
mDNS, so each VM is listed on its own. Any text works (up to 63 bytes); keep it unique on the host, ignoring case.
`sunshine-qemu-port --check` reports configs with the same name.
- **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.
paths are resolved in Sunshine's configuration directory, which the units set per VM with
`CONFIGURATION_DIRECTORY` (Sunshine then uses `<dir>/sunshine`), so pairing a client with one VM doesn't pair it
with another. Unlike `XDG_CONFIG_HOME`, it doesn't move the configuration of libvirt, `virsh` or other libraries.
- **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.
@@ -123,16 +142,30 @@
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
```
Then for each VM, with `vm` set to its name (the libvirt domain name when the hook starts the unit):
sudo install -Dm640 -g sunshine-qemu packaging/linux/qemu/example.conf /etc/sunshine-qemu/win11.conf
# edit /etc/sunshine-qemu/win11.conf, then:
```bash
vm=win11
instance="$(systemd-escape "${vm}")" # names with '-' or spaces are escaped in unit names and state paths
sudo install -Dm640 -g sunshine-qemu packaging/linux/qemu/example.conf "/etc/sunshine-qemu/${vm}.conf"
# edit /etc/sunshine-qemu/${vm}.conf (qemu_dbus_address, sunshine_name), then pick its base port and check:
sudo /usr/lib/sunshine-qemu/sunshine-qemu-port --dir /etc/sunshine-qemu --write "${vm}"
sudo /usr/lib/sunshine-qemu/sunshine-qemu-port --dir /etc/sunshine-qemu --check
# the state directory the unit uses, created now so the web UI credentials can be set before the first start
sudo -u sunshine-qemu XDG_CONFIG_HOME=/var/lib/sunshine-qemu/win11 sunshine /etc/sunshine-qemu/win11.conf --creds <user> <password>
sudo install -d -o sunshine-qemu -g sunshine-qemu -m 0750 /var/lib/sunshine-qemu "/var/lib/sunshine-qemu/${instance}"
sudo -u sunshine-qemu CONFIGURATION_DIRECTORY="/var/lib/sunshine-qemu/${instance}" \
sunshine "/etc/sunshine-qemu/${vm}.conf" --creds <user> <password>
sudo systemctl daemon-reload
sudo systemctl enable --now sunshine-qemu@win11.service
sudo systemctl enable --now "$(systemd-escape --template sunshine-qemu@.service "${vm}")"
```
Set the credentials before the unit first starts: until then the web UI (on `port + 1`) accepts whoever sets them
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.
first, and anyone who does can pair clients and control the VM. Skip `enable` when the libvirt hook starts the unit.
The configuration file is read-only for the unit (root-owned, and `ProtectSystem=strict`), so saving settings in the
web UI fails; edit `/etc/sunshine-qemu/<vm>.conf` as root and restart the unit.
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
@@ -142,7 +175,9 @@
**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
until QEMU owns `org.qemu` on the configured bus, QEMU answers on the QMP socket, or `virsh domstate` reports the libvirt
domain running (on `qemu:///system` unless the address has `?uri=`). For QMP it waits for QEMU's greeting, not just
the socket file, which a killed QEMU leaves behind. When it gives up, the unit fails and `Restart=on-failure` waits
again. Start the unit after the VM,
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.
@@ -152,8 +187,13 @@
```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
# edit it: for session libvirt use qemu_dbus_address = libvirt:win11?uri=qemu:///session
mkdir -p ~/.local/state/sunshine-qemu/win11
CONFIGURATION_DIRECTORY=~/.local/state/sunshine-qemu/win11 sunshine ~/.config/sunshine-qemu/win11.conf --creds <user> <password>
systemctl --user daemon-reload
systemctl --user enable --now sunshine-qemu@win11.service
```
For VM names with `-` or spaces, use `systemd-escape` as for the system unit.
It still expects `sunshine-qemu-wait-vm` in `/usr/lib/sunshine-qemu/`; edit the `ExecStartPre` path otherwise.
@@ -231,8 +271,9 @@
### 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`,
`libvirt-hook-qemu` starts `sunshine-qemu@<domain>.service` (the domain name escaped with `systemd-escape`, so its
state is in `/var/lib/sunshine-qemu/$(systemd-escape <domain>)`) 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
@@ -291,7 +332,11 @@
### 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.
QEMU offers native touch on every VM, but only a VM with `-device virtio-multitouch-pci` receives the touches, and
Sunshine can't tell the difference. So `example.conf` disables [native_pen_touch](configuration.md#native_pen_touch)
and Moonlight sends touches as mouse input; enable it for VMs with a multi-touch device. If touches do nothing, the
VM lacks that device and `native_pen_touch` is enabled.
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
@@ -310,4 +355,5 @@
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, the bus policy and socket ownership in the raw QEMU examples, and DMABUF (VAAPI,
AppArmor confinement, the polkit rule, and DMABUF on a host with a GPU render node.
NVENC or Vulkan zero-copy) on a host with a GPU render node.