# moonshine

Moonshine is a host-side server for the [Moonlight](https://moonlight-stream.org/) game-streaming clients. You run it on the machine that has the GPU, connect from a phone, tablet, TV box or another PC, and play with keyboard, mouse and controller input sent back to the host. It covers the same role as Sunshine, the established GameStream host, but takes a different approach to how the game gets rendered.

## How it works

Every streamed application gets its own Wayland compositor rather than mirroring an existing desktop. That is the design decision the rest of the project follows from: the host needs no monitor, no HDMI dummy plug and no logged-in graphical session, and whoever is sitting at the host machine can keep using it while somebody else streams. The idea is credited to [magic-mirror](https://github.com/colinmarc/magic-mirror), which pioneered the Vulkan-plus-headless-compositor combination.

Capture and encoding go through Vulkan video encoding on the GPU — H.264, H.265 or AV1, with 10-bit HDR where the game supports it. A Vulkan WSI layer (`libmoonshine_wsi.so`, installed as an implicit layer) is what hooks the game's swapchain into the streaming session. Audio is Opus, stereo or 5.1/7.1. Input devices are synthesized through `uinput` and `uhid`, using the device implementations from [inputtino](https://github.com/games-on-whales/inputtino), so gamepad motion, touchpad and haptics all pass through.

systemd is a hard requirement, not a packaging convenience — it is what launches and supervises the application processes. Running the server for a user who isn't logged in needs lingering enabled:

```bash
sudo loginctl enable-linger $USER
sudo systemctl enable --now moonshine@$USER
```

## Configuration

A single TOML file. Applications are declared as entries with a command and optional hooks that run before and after the session, synchronously:

```toml
[[application]]
title = "Steam"
boxart = "/path/to/steam.png"
command = ["/usr/bin/steam", "steam://open/bigpicture"]
pre_command = [
    ["/usr/bin/systemctl", "stop", "conflicting.service"],
    ["/usr/bin/nvidia-smi", "pstate", "50"],
]
post_command = [
    ["/usr/bin/nvidia-smi", "pstate", "performance"],
]
```

Scanners save you from listing everything by hand. The Steam scanner walks a library directory and generates one entry per installed game; the desktop scanner reads `.desktop` files and can resolve their icons into box art.

```toml
[[application_scanner]]
type = "steam"
library = "$HOME/.local/share/Steam"
command = ["/usr/bin/steam", "-bigpicture", "steam://rungameid/{game_id}"]
```

Pairing happens over HTTP on port 47989. Moonlight shows a PIN, and you either click the host notification or POST it yourself:

```bash
curl -X POST "http://localhost:47989/submit-pin" -d "uniqueid=0123456789ABCDEF&pin=<PIN>"
```

## Limitations

Linux only, tested mainly on Arch. The GPU must support Vulkan video encoding, which in practice means NVIDIA RTX, AMD RDNA2 or newer, or Intel Arc. Clients must be Moonlight 6.0.0 or later; unofficial ports are not guaranteed to work. Streaming to two clients at once is not supported and the author says it isn't a goal.

The security posture is worth reading before opening any ports. GameStream, the protocol Moonlight speaks, does not fully encrypt traffic at the application layer, and the README says plainly that Moonshine is not designed for public networks. Remote play means putting it behind a VPN.

Compared with Sunshine, Moonshine trades breadth for the isolated-session model: Sunshine runs on more platforms and has more features, Moonshine gets headless operation and a host that stays usable during a stream. If the streaming target is emulated retro games rather than a Steam library, [[romm]] solves a different part of the same problem. [[yap]] makes the mirror-image bet on macOS — one vendor's native APIs in exchange for shipping almost no code of its own, where Moonshine leans the same way on Wayland, Vulkan and systemd.

Repo: [github.com/hgaiser/moonshine](https://github.com/hgaiser/moonshine) — ~920 stars, BSD-2-Clause, Rust.
