12 KiB
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)
# Install via Flatpak
flatpak install flathub dev.lizardbyte.app.Sunshine
# Enable autostart
flatpak run --command=sunshine dev.lizardbyte.app.Sunshine &
Method B: Native Package
# Add Sunshine repository
sudo dnf copr enable lizardbyte/stable
sudo dnf install sunshine
# Enable service
sudo systemctl enable --now sunshine
Post-Install:
- Access Sunshine web UI:
https://localhost:47990 - Set initial admin password
- Complete setup wizard
Step 4.2: Configure AMD VA-API Hardware Encoding
Verify AMD GPU:
# 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:
- Open Sunshine Web UI → Configuration → Video
- Set:
- Encoder:
vaapi - Adapter:
/dev/dri/renderD128(default AMD) - Codec:
H.265/HEVC(better compression, lower latency)
- Encoder:
Sunshine config file (~/.config/sunshine/sunshine.conf):
[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
# 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
# ~/.config/sunshine/sunshine.conf
[network]
address_family = both
origin_address = 100.64.x.x # Your Tailscale IP
Option B: Firewall rules (recommended)
# 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
# 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
-
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)
- Add PC manually: Enter Tailscale IP (e.g.,
-
Enter PIN:
- Moonlight displays a 4-digit PIN
- Enter in Sunshine Web UI → PIN Pairing
-
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:
ssh -i /root/.ssh/mikrotik_key -p 2222 unraid@192.168.31.1
Create Simple Queue for Gaming PC:
# 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:
vainfoshows 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)
Troubleshooting
High Latency / Stuttering
-
Check Tailscale connection type:
tailscale status # Look for "direct" vs "relay" -
Force direct connection:
tailscale ping <client-hostname> -
Lower bitrate in Moonlight
Encoding Errors
-
Verify VA-API:
sudo vainfo # Should show HEVC/H264 encode support -
Check Sunshine logs:
journalctl -u sunshine -f # Or: ~/.config/sunshine/sunshine.log -
Fall back to software encoding:
# sunshine.conf encoder = software
No Audio
-
Check PulseAudio/PipeWire:
pactl list sinks -
Set Sunshine audio sink:
- Web UI → Audio → Select correct output
Security Considerations
-
Tailscale-only access: Sunshine is only reachable via Tailscale network
-
PIN pairing: Each client must be manually paired
-
Web UI protection: Consider adding Authentik forward auth (optional)
-
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:
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):
# 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