Sunshine Streaming & Tablet Display
Provides a self-hosted Sunshine game and desktop streaming server for use with Moonlight clients (such as Android tablets, phones, handheld consoles, or secondary PCs).
Capabilities & Architecture
- Hardware-Accelerated Encoding: Automatically leverages GPU hardware encoding (VA-API on AMD Radeon GPUs) for ultra-low latency, high-framerate streaming (up to 120 FPS / 4K / HDR).
- Default-Enabled Across Fleet: Registered in common system modules (
outputs.nix) and enabled by default (custom.sunshine.enable = true). - Firewall Integration: Automatically provisions open TCP (
47984, 47989, 47990, 48010) and UDP (47998-48000, 48002, 48010) ports. - Input Emulation & KMS Capture: Configures
uinputrules, grantsvideoandinputpermissions, and assignscap_sys_admin+pcapabilities to the Sunshine binary for direct DRM/KMS frame capture. - Opt-Out Toggle: Can be disabled per-host in
hosts/<hostname>/config.nix:custom.sunshine.enable = false;
Zero-Touch Tablet Extended Display
When custom.sunshine.tabletDisplay.enable = true (default), the module provides an automated, zero-touch virtual second display for tablets:
flowchart TD
subgraph StreamStart["1. Connect & Initialize"]
A["Tablet opens Moonlight"] --> B["Sunshine triggers hypr-virtual-monitor"]
B --> C["Hyprland creates HEADLESS-1 at tablet resolution"]
C --> D["Desktop streams to tablet at 120Hz"]
end
subgraph StreamEnd["2. Teardown Paths"]
D -->|"User Quits Stream"| E["Immediate cleanup: HEADLESS-1 removed"]
D -->|"Tablet Sleep / Connection Drop"| F["Watchdog detects idle stream"]
F --> G["15-minute timeout expires"]
G --> H["Auto-cleanup: HEADLESS-1 removed & session reset"]
end
1. Connection Lifecycle
-
Initiate Stream from Tablet:
- Open Moonlight on the tablet and tap Tablet Display.
- Sunshine executes the
prep-cmdhook:/run/current-system/sw/bin/hypr-virtual-monitor start HEADLESS-1 <scale>. - The script dynamically reads Moonlight’s negotiated resolution and refresh rate (
SUNSHINE_CLIENT_WIDTH,SUNSHINE_CLIENT_HEIGHT,SUNSHINE_CLIENT_FPS) and creates a virtual headless monitor (HEADLESS-1) in Hyprland with exact 1:1 pixel dimensions and 120Hz refresh rate. - Windows and workspaces placed on
HEADLESS-1stream directly to the tablet screen.
-
Graceful Teardown:
- Exiting the stream or tapping Quit Session in Moonlight triggers the
prep-cmdundoaction:hypr-virtual-monitor stop HEADLESS-1. - Hyprland removes
HEADLESS-1and automatically returns active workspaces to your primary monitor.
- Exiting the stream or tapping Quit Session in Moonlight triggers the
-
On-Demand Idle Watchdog (15-Minute Timeout):
- Sunshine treats client disconnects (or tablet screen locks) as “paused” sessions to allow game reconnection, leaving
HEADLESS-1open in Hyprland. - An on-demand systemd service (
sunshine-watchdog.service) is launched byhypr-virtual-monitor startand stopped on explicit quit. - The watchdog periodically polls active Sunshine streaming sockets (
:47989,:48010) usingss. - If the stream remains paused or disconnected continuously for 15 minutes (
custom.sunshine.tabletDisplay.idleTimeout = 900), the watchdog automatically destroysHEADLESS-1, restarts Sunshine to drop stale sessions, and sends a desktop notification. Zero background polling occurs when not streaming.
- Sunshine treats client disconnects (or tablet screen locks) as “paused” sessions to allow game reconnection, leaving
USB Tethering (Zero-Latency / Offline Mode)
To stream with sub-millisecond latency (<0.5ms) and eliminate Wi-Fi jitter completely:
- Connect the tablet to the PC via a USB-C cable.
- Enable USB Tethering in Android settings.
- NetworkManager automatically assigns an IP address on the tethered interface (
usb*oren*u*). - In Moonlight, connect to the PC’s USB IP (or mDNS hostname
<hostname>.local, e.g.mini-pc-k8.localorframework16.local). - Gateway Protection: The module configures NetworkManager with
ipv4.never-default = trueandipv4.route-metric = 1000for all USB tethering interfaces, guaranteeing that the tablet never overrides the PC’s primary internet routing.
Initial Setup & Pairing
- Access Web Configuration: Open
https://localhost:47990in your browser (accept the self-signed TLS certificate warning). - Set Credentials: On first launch, create an administrative username and password.
- Pair Client:
- Open Moonlight on your client device.
- Tap your host machine to display a 4-digit PIN.
- Enter the PIN in the Sunshine Web UI under the PIN tab.