Phase 4: Updated doc with current progress and native install instructions
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
This commit is contained in:
@@ -1,15 +1,45 @@
|
||||
# Phase 4: Remote Gaming (Sunshine + Moonlight)
|
||||
|
||||
## Goal
|
||||
Enable low-latency 60FPS game streaming from Nobara Linux (AMD GPU) to MacBook and Android devices, using Tailscale for optimal network pathing.
|
||||
## Status: 🔄 IN PROGRESS
|
||||
|
||||
**Last Updated:** 2026-01-19
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
## Current Progress
|
||||
|
||||
- **Gaming PC:** Nobara Linux with AMD GPU (VA-API support)
|
||||
- **Tailscale:** Installed on gaming PC (from Phase 1)
|
||||
- **Clients:** MacBook and Android devices with Tailscale
|
||||
| Task | Status | Notes |
|
||||
|------|--------|-------|
|
||||
| Tailscale on Nobara | ✅ Complete | IP: 100.98.57.73 |
|
||||
| VA-API verification | ✅ Complete | RX 6600 H.264/HEVC encoding working |
|
||||
| Sunshine Flatpak | ❌ Failed | Capture methods incompatible |
|
||||
| Native Sunshine | ⏳ Pending | Recommended installation method |
|
||||
| Moonlight pairing | ⏳ Pending | Awaiting Sunshine setup |
|
||||
|
||||
### Verified Hardware
|
||||
- **GPU:** AMD Radeon RX 6600M (Navi 23) + AMD Radeon 680M (integrated)
|
||||
- **Driver:** Mesa Gallium 25.3.2 (radeonsi, navi23, LLVM 21.1.7)
|
||||
- **VA-API:** v1.22 with H.264 and HEVC encode support
|
||||
|
||||
### Tailscale Network
|
||||
| Device | Tailscale IP | Status |
|
||||
|--------|--------------|--------|
|
||||
| xtrm-pc (Nobara) | 100.98.57.73 | Online |
|
||||
| kaloyans-macbook-air | 100.68.118.59 | Online |
|
||||
| xtrm-unraid | 100.100.208.70 | Online |
|
||||
|
||||
### Flatpak Issues Encountered
|
||||
The Flatpak version of Sunshine failed due to:
|
||||
1. **wlr capture:** Missing wlr-export-dmabuf protocol (KDE Plasma incompatible)
|
||||
2. **PipeWire capture:** XDG portal permissions blocked in sandbox
|
||||
3. **KMS capture:** Cannot apply setcap to sandboxed binaries
|
||||
|
||||
**Solution:** Use native DNF installation instead.
|
||||
|
||||
---
|
||||
|
||||
## Goal
|
||||
Enable low-latency 60FPS game streaming from Nobara Linux (AMD GPU) to MacBook and Android devices, using Tailscale for optimal network pathing.
|
||||
|
||||
---
|
||||
|
||||
@@ -26,250 +56,89 @@ Enable low-latency 60FPS game streaming from Nobara Linux (AMD GPU) to MacBook a
|
||||
▼ ▼ ▼
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ Nobara Gaming PC│ │ MacBook │ │ Android Device │
|
||||
│ Sunshine Host │ │ Moonlight Client│ │ Moonlight Client│
|
||||
│ 100.x.x.x (TS) │ │ 100.x.x.x (TS) │ │ 100.x.x.x (TS) │
|
||||
│ AMD VA-API │ │ │ │ │
|
||||
│ xtrm-pc │ │ Moonlight Client│ │ Moonlight Client│
|
||||
│ 100.98.57.73 │ │ 100.68.118.59 │ │ │
|
||||
│ AMD RX 6600 │ │ │ │ │
|
||||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||
```
|
||||
|
||||
**Why Tailscale for Gaming?**
|
||||
- Automatic P2P connection when on same LAN
|
||||
- Encrypted tunnel when remote
|
||||
- No manual port forwarding required
|
||||
- MagicDNS for easy hostname resolution
|
||||
- NAT traversal handled automatically
|
||||
---
|
||||
|
||||
## Installation (Native - Recommended)
|
||||
|
||||
### Step 1: Remove Flatpak (if installed)
|
||||
```bash
|
||||
flatpak remove dev.lizardbyte.app.Sunshine -y
|
||||
```
|
||||
|
||||
### Step 2: Install Native Sunshine
|
||||
```bash
|
||||
sudo dnf copr enable lizardbyte/stable -y
|
||||
sudo dnf install sunshine -y
|
||||
```
|
||||
|
||||
### Step 3: Set KMS Capture Permission
|
||||
```bash
|
||||
sudo setcap cap_sys_admin+p $(readlink -f $(which sunshine))
|
||||
```
|
||||
|
||||
### Step 4: Enable Service
|
||||
```bash
|
||||
systemctl --user enable --now sunshine
|
||||
```
|
||||
|
||||
### Step 5: Configure Sunshine
|
||||
1. Open https://localhost:47990
|
||||
2. Set admin password
|
||||
3. Go to Configuration → Video:
|
||||
- Encoder: vaapi
|
||||
- Adapter: /dev/dri/renderD128
|
||||
|
||||
---
|
||||
|
||||
## Implementation Steps
|
||||
## Moonlight Client Setup
|
||||
|
||||
### Step 4.1: Install Sunshine on Nobara
|
||||
### MacBook
|
||||
Moonlight already installed. Add PC:
|
||||
- Host: 100.98.57.73 (Tailscale IP)
|
||||
- Or hostname: xtrm-pc (if MagicDNS enabled)
|
||||
|
||||
**Method A: Flatpak (Recommended for Nobara)**
|
||||
```bash
|
||||
# Install via Flatpak
|
||||
flatpak install flathub dev.lizardbyte.app.Sunshine
|
||||
|
||||
# Enable autostart
|
||||
flatpak run --command=sunshine dev.lizardbyte.app.Sunshine &
|
||||
```
|
||||
|
||||
**Method B: Native Package**
|
||||
```bash
|
||||
# Add Sunshine repository
|
||||
sudo dnf copr enable lizardbyte/stable
|
||||
sudo dnf install sunshine
|
||||
|
||||
# Enable service
|
||||
sudo systemctl enable --now sunshine
|
||||
```
|
||||
|
||||
**Post-Install:**
|
||||
1. Access Sunshine web UI: `https://localhost:47990`
|
||||
2. Set initial admin password
|
||||
3. Complete setup wizard
|
||||
### Pairing
|
||||
1. Open Moonlight, add xtrm-pc
|
||||
2. Enter 4-digit PIN shown in Moonlight
|
||||
3. Input PIN in Sunshine Web UI → PIN Pairing
|
||||
|
||||
---
|
||||
|
||||
### Step 4.2: Configure AMD VA-API Hardware Encoding
|
||||
## VA-API Verification Output
|
||||
|
||||
**Verify AMD GPU:**
|
||||
```bash
|
||||
# Check for AMD GPU
|
||||
lspci | grep -i vga
|
||||
|
||||
# Verify VA-API support
|
||||
vainfo
|
||||
```
|
||||
|
||||
**Expected output:**
|
||||
```
|
||||
vainfo: VA-API version: 1.x
|
||||
vainfo: Driver version: Mesa Gallium driver ...
|
||||
vainfo: Supported profile and entrypoints:
|
||||
VAProfileH264Main : VAEntrypointEncSlice
|
||||
VAProfileHEVCMain : VAEntrypointEncSlice
|
||||
```
|
||||
|
||||
**Configure Sunshine for VA-API:**
|
||||
|
||||
1. Open Sunshine Web UI → Configuration → Video
|
||||
2. Set:
|
||||
- **Encoder:** `vaapi`
|
||||
- **Adapter:** `/dev/dri/renderD128` (default AMD)
|
||||
- **Codec:** `H.265/HEVC` (better compression, lower latency)
|
||||
|
||||
**Sunshine config file** (`~/.config/sunshine/sunshine.conf`):
|
||||
```ini
|
||||
[video]
|
||||
encoder = vaapi
|
||||
adapter_name = /dev/dri/renderD128
|
||||
hevc_mode = 2 # Always use HEVC when client supports
|
||||
|
||||
[stream]
|
||||
fps = [30, 60, 120]
|
||||
resolutions = [
|
||||
1920x1080,
|
||||
2560x1440,
|
||||
3840x2160
|
||||
]
|
||||
vainfo: VA-API version: 1.22 (libva 2.22.0)
|
||||
vainfo: Driver version: Mesa Gallium driver 25.3.2 for AMD Radeon RX 6600M
|
||||
vainfo: Supported profile and entrypoints
|
||||
VAProfileH264ConstrainedBaseline: VAEntrypointEncSlice
|
||||
VAProfileH264Main : VAEntrypointEncSlice
|
||||
VAProfileH264High : VAEntrypointEncSlice
|
||||
VAProfileHEVCMain : VAEntrypointEncSlice
|
||||
VAProfileHEVCMain10 : VAEntrypointEncSlice
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Step 4.3: Add Applications to Sunshine
|
||||
|
||||
**Access:** Sunshine Web UI → Applications
|
||||
|
||||
**Recommended Applications:**
|
||||
|
||||
| Name | Command | Working Directory |
|
||||
|------|---------|-------------------|
|
||||
| Desktop | - | - |
|
||||
| Steam Big Picture | `steam -bigpicture` | - |
|
||||
| Lutris | `lutris` | - |
|
||||
| Heroic Games | `heroic` | - |
|
||||
|
||||
**For specific games:**
|
||||
```
|
||||
Name: Cyberpunk 2077
|
||||
Command: steam steam://rungameid/1091500
|
||||
Detached: ["steam"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Step 4.4: Install Tailscale on Nobara
|
||||
## Firewall Configuration (Optional)
|
||||
|
||||
Restrict Sunshine to Tailscale network only:
|
||||
```bash
|
||||
# Install Tailscale
|
||||
curl -fsSL https://tailscale.com/install.sh | sh
|
||||
|
||||
# Authenticate
|
||||
sudo tailscale up
|
||||
|
||||
# Get Tailscale IP
|
||||
tailscale ip -4
|
||||
```
|
||||
|
||||
**Note the Tailscale IP** (e.g., `100.64.x.x`) - clients will connect to this.
|
||||
|
||||
---
|
||||
|
||||
### Step 4.5: Configure Sunshine for Tailscale
|
||||
|
||||
**Sunshine listens on all interfaces by default.** For security, restrict to Tailscale:
|
||||
|
||||
**Option A: Bind to Tailscale interface only**
|
||||
```ini
|
||||
# ~/.config/sunshine/sunshine.conf
|
||||
[network]
|
||||
address_family = both
|
||||
origin_address = 100.64.x.x # Your Tailscale IP
|
||||
```
|
||||
|
||||
**Option B: Firewall rules (recommended)**
|
||||
```bash
|
||||
# Allow Sunshine ports only from Tailscale
|
||||
sudo firewall-cmd --permanent --zone=trusted --add-source=100.64.0.0/10
|
||||
sudo firewall-cmd --permanent --zone=trusted --add-port=47984-48010/tcp
|
||||
sudo firewall-cmd --permanent --zone=trusted --add-port=47998-48010/udp
|
||||
sudo firewall-cmd --permanent --zone=trusted --add-port=47989/tcp # Web UI
|
||||
sudo firewall-cmd --permanent --zone=trusted --add-port=47990/tcp # Web UI HTTPS
|
||||
sudo firewall-cmd --permanent --zone=trusted --add-port=47989-47990/tcp
|
||||
sudo firewall-cmd --reload
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Step 4.6: Install Moonlight Clients
|
||||
|
||||
#### MacBook
|
||||
```bash
|
||||
# Homebrew
|
||||
brew install --cask moonlight
|
||||
|
||||
# Or download from: https://moonlight-stream.org/
|
||||
```
|
||||
|
||||
#### Android
|
||||
- Install "Moonlight Game Streaming" from Google Play Store
|
||||
|
||||
---
|
||||
|
||||
### Step 4.7: Pair Moonlight with Sunshine
|
||||
|
||||
1. **On Moonlight client:**
|
||||
- Add PC manually: Enter Tailscale IP (e.g., `100.64.x.x`)
|
||||
- Or use MagicDNS hostname: `nobara-pc` (if enabled in Tailscale)
|
||||
|
||||
2. **Enter PIN:**
|
||||
- Moonlight displays a 4-digit PIN
|
||||
- Enter in Sunshine Web UI → PIN Pairing
|
||||
|
||||
3. **Verify connection:**
|
||||
- Moonlight should show your configured applications
|
||||
|
||||
---
|
||||
|
||||
### Step 4.8: MikroTik QoS for Gaming (Optional but Recommended)
|
||||
|
||||
**Goal:** Prioritize Nobara PC traffic to prevent bufferbloat during gaming sessions.
|
||||
|
||||
**SSH to MikroTik:**
|
||||
```bash
|
||||
ssh -i /root/.ssh/mikrotik_key -p 2222 unraid@192.168.31.1
|
||||
```
|
||||
|
||||
**Create Simple Queue for Gaming PC:**
|
||||
```routeros
|
||||
# First, find Nobara's IP (replace with actual)
|
||||
# Assuming Nobara is at 192.168.31.50
|
||||
|
||||
# Create queue for gaming priority
|
||||
/queue simple add \
|
||||
name="Gaming-Priority" \
|
||||
target=192.168.31.50 \
|
||||
max-limit=0/0 \
|
||||
priority=1/1 \
|
||||
queue=default-small/default-small \
|
||||
comment="Nobara Gaming PC Priority"
|
||||
|
||||
# Alternative: Use queue tree for more control
|
||||
/queue tree add \
|
||||
name="Gaming-Upload" \
|
||||
parent=global \
|
||||
packet-mark=gaming-upload \
|
||||
priority=1 \
|
||||
max-limit=50M
|
||||
|
||||
/queue tree add \
|
||||
name="Gaming-Download" \
|
||||
parent=global \
|
||||
packet-mark=gaming-download \
|
||||
priority=1 \
|
||||
max-limit=100M
|
||||
|
||||
# Mark gaming traffic
|
||||
/ip firewall mangle add \
|
||||
chain=prerouting \
|
||||
src-address=192.168.31.50 \
|
||||
action=mark-packet \
|
||||
new-packet-mark=gaming-upload \
|
||||
passthrough=yes
|
||||
|
||||
/ip firewall mangle add \
|
||||
chain=postrouting \
|
||||
dst-address=192.168.31.50 \
|
||||
action=mark-packet \
|
||||
new-packet-mark=gaming-download \
|
||||
passthrough=yes
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Step 4.9: Optimize Streaming Settings
|
||||
|
||||
**Sunshine Settings (Server):**
|
||||
## Streaming Settings
|
||||
|
||||
| Setting | LAN Value | Remote Value |
|
||||
|---------|-----------|--------------|
|
||||
@@ -278,188 +147,44 @@ ssh -i /root/.ssh/mikrotik_key -p 2222 unraid@192.168.31.1
|
||||
| Resolution | Native | 1080p |
|
||||
| Codec | HEVC | HEVC |
|
||||
|
||||
**Moonlight Settings (Client):**
|
||||
|
||||
| Setting | LAN Value | Remote Value |
|
||||
|---------|-----------|--------------|
|
||||
| Video Codec | HEVC (if supported) | HEVC |
|
||||
| Frame Pacing | V-Sync | On |
|
||||
| Bitrate | Auto or 50+ Mbps | 20 Mbps |
|
||||
| Resolution | Match display | 1080p |
|
||||
|
||||
---
|
||||
|
||||
## Network Path Analysis
|
||||
|
||||
**Tailscale P2P (Same Network):**
|
||||
```
|
||||
MacBook → Router → Nobara PC
|
||||
Latency: <1ms additional overhead
|
||||
```
|
||||
|
||||
**Tailscale Relayed (Different Network):**
|
||||
```
|
||||
MacBook → Tailscale DERP → Nobara PC
|
||||
Latency: ~20-50ms additional overhead
|
||||
```
|
||||
|
||||
**With Tailscale Direct (NAT Traversal Success):**
|
||||
```
|
||||
MacBook (Office) → Internet → Home Router → Nobara PC
|
||||
Latency: RTT/2 + encoding latency (~30-80ms typical)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Service Interruption Assessment
|
||||
|
||||
| Action | Risk | Impact | Mitigation |
|
||||
|--------|------|--------|------------|
|
||||
| Install Sunshine | NONE | Nobara only | - |
|
||||
| Install Tailscale | NONE | Nobara only | - |
|
||||
| MikroTik QoS | LOW | May affect other traffic briefly | Test during low usage |
|
||||
| Firewall rules | LOW | Nobara only | Can revert |
|
||||
|
||||
---
|
||||
|
||||
## Verification Checklist
|
||||
|
||||
- [ ] Sunshine installed and running on Nobara
|
||||
- [ ] VA-API encoding verified: `vainfo` shows HEVC support
|
||||
- [ ] Tailscale running on Nobara: `tailscale status`
|
||||
- [ ] Sunshine Web UI accessible: `https://<tailscale-ip>:47990`
|
||||
- [ ] Moonlight paired successfully
|
||||
- [ ] Desktop streaming works (low latency)
|
||||
- [ ] Game streaming works at 60 FPS
|
||||
- [ ] Remote streaming works (via Tailscale from external network)
|
||||
- [ ] MikroTik QoS queue active (optional)
|
||||
- [x] Tailscale running on Nobara: 100.98.57.73
|
||||
- [x] VA-API encoding verified: H.264 + HEVC
|
||||
- [ ] Sunshine installed (native)
|
||||
- [ ] KMS capture working
|
||||
- [ ] Sunshine Web UI accessible
|
||||
- [ ] Moonlight paired
|
||||
- [ ] Desktop streaming works
|
||||
- [ ] Game streaming at 60 FPS
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### High Latency / Stuttering
|
||||
### Encoder Fails
|
||||
```bash
|
||||
# Verify VA-API
|
||||
vainfo
|
||||
|
||||
1. **Check Tailscale connection type:**
|
||||
```bash
|
||||
tailscale status
|
||||
# Look for "direct" vs "relay"
|
||||
```
|
||||
|
||||
2. **Force direct connection:**
|
||||
```bash
|
||||
tailscale ping <client-hostname>
|
||||
```
|
||||
|
||||
3. **Lower bitrate in Moonlight**
|
||||
|
||||
### Encoding Errors
|
||||
|
||||
1. **Verify VA-API:**
|
||||
```bash
|
||||
sudo vainfo
|
||||
# Should show HEVC/H264 encode support
|
||||
```
|
||||
|
||||
2. **Check Sunshine logs:**
|
||||
```bash
|
||||
journalctl -u sunshine -f
|
||||
# Or: ~/.config/sunshine/sunshine.log
|
||||
```
|
||||
|
||||
3. **Fall back to software encoding:**
|
||||
```ini
|
||||
# sunshine.conf
|
||||
encoder = software
|
||||
```
|
||||
|
||||
### No Audio
|
||||
|
||||
1. **Check PulseAudio/PipeWire:**
|
||||
```bash
|
||||
pactl list sinks
|
||||
```
|
||||
|
||||
2. **Set Sunshine audio sink:**
|
||||
- Web UI → Audio → Select correct output
|
||||
|
||||
---
|
||||
|
||||
## Security Considerations
|
||||
|
||||
1. **Tailscale-only access:** Sunshine is only reachable via Tailscale network
|
||||
|
||||
2. **PIN pairing:** Each client must be manually paired
|
||||
|
||||
3. **Web UI protection:** Consider adding Authentik forward auth (optional)
|
||||
|
||||
4. **Firewall:** Block Sunshine ports from non-Tailscale interfaces
|
||||
|
||||
---
|
||||
|
||||
## Optional: Expose Sunshine Web UI via Traefik
|
||||
|
||||
If you want to manage Sunshine remotely via browser:
|
||||
|
||||
**Add to Traefik dynamic.yml:**
|
||||
```yaml
|
||||
http:
|
||||
routers:
|
||||
sunshine-secure:
|
||||
rule: "Host(`sunshine.xtrm-lab.org`)"
|
||||
entryPoints:
|
||||
- https
|
||||
middlewares:
|
||||
- default-headers
|
||||
- authentik-forward-auth # Protect with Authentik
|
||||
tls:
|
||||
certResolver: cloudflare
|
||||
service: sunshine
|
||||
|
||||
services:
|
||||
sunshine:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "https://192.168.31.50:47990" # Nobara IP
|
||||
# Check Sunshine logs
|
||||
journalctl --user -u sunshine -f
|
||||
```
|
||||
|
||||
**MikroTik hairpin NAT (if needed):**
|
||||
```routeros
|
||||
# Only if accessing from LAN via external hostname
|
||||
/ip/firewall/nat add chain=srcnat \
|
||||
action=masquerade \
|
||||
src-address=192.168.31.0/24 \
|
||||
dst-address=192.168.31.50 \
|
||||
dst-port=47990 \
|
||||
protocol=tcp
|
||||
### Connection Issues
|
||||
```bash
|
||||
# Check Tailscale connectivity
|
||||
tailscale ping kaloyans-macbook-air
|
||||
|
||||
# Verify ports
|
||||
ss -tlnp | grep sunshine
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Files Modified
|
||||
## Related Documents
|
||||
|
||||
| File/System | Change | Backup Required |
|
||||
|-------------|--------|-----------------|
|
||||
| Nobara: ~/.config/sunshine/ | Sunshine config | No (new install) |
|
||||
| Nobara: firewalld | Allow Tailscale ports | Can revert |
|
||||
| MikroTik: Queue | Gaming priority | N/A |
|
||||
| Traefik dynamic.yml (optional) | Sunshine route | YES |
|
||||
|
||||
---
|
||||
|
||||
## Performance Expectations
|
||||
|
||||
| Scenario | Expected Latency | FPS |
|
||||
|----------|------------------|-----|
|
||||
| LAN (same network) | 5-15ms | 60-120 |
|
||||
| Remote (Tailscale direct) | 30-60ms | 60 |
|
||||
| Remote (Tailscale relay) | 50-100ms | 60 |
|
||||
|
||||
---
|
||||
|
||||
## Dependencies for Next Phase
|
||||
|
||||
Phase 5 (RustDesk) provides:
|
||||
- Alternative remote access when gaming not required
|
||||
- Lower resource usage for general desktop access
|
||||
- Additional fallback for remote management
|
||||
- [00-CURRENT-STATE.md](./00-CURRENT-STATE.md) - Infrastructure overview
|
||||
- [05-PHASE5-RUSTDESK.md](./05-PHASE5-RUSTDESK.md) - RustDesk for general remote access
|
||||
|
||||
Reference in New Issue
Block a user