# 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. --- ## Prerequisites - **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 --- ## Architecture Overview ``` ┌─────────────────────────────────┐ │ Tailscale Mesh Network │ │ (Encrypted, P2P when possible) │ └─────────────────┬───────────────┘ │ ┌────────────────────────────┼────────────────────────────┐ │ │ │ ▼ ▼ ▼ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ 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 │ │ │ │ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ ``` **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 --- ## Implementation Steps ### Step 4.1: Install Sunshine on Nobara **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 --- ### Step 4.2: Configure AMD VA-API Hardware Encoding **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 ] ``` --- ### 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 ```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 --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):** | Setting | LAN Value | Remote Value | |---------|-----------|--------------| | Bitrate | 50-80 Mbps | 20-40 Mbps | | FPS | 60-120 | 60 | | 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://: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) --- ## Troubleshooting ### High Latency / Stuttering 1. **Check Tailscale connection type:** ```bash tailscale status # Look for "direct" vs "relay" ``` 2. **Force direct connection:** ```bash tailscale ping ``` 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 ``` **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 ``` --- ## Files Modified | 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