NVIDIA DGX Spark Remote Access Runbook
Sunshine + Moonlight + Tailscale
Physical Display / Dummy Plug | Auto-Login | Secure | Mac & Windows
When you get your DGX or similar station, what is the cost efficient method to make sure you can access the station anytime we want. Below is a $5 way to make this happen. If you want:
- Access your DGX when you want.
- You don't want your DGX to connect to a real monitor.
- You bring your laptop to anywhere and you want to access your workstation.
- You don't want montly payment.
Then you should read this or let your Agent read this blog to help you make the plan!
Table of Contents
- Overview
- Prerequisites
- Part 1 — DGX Spark Setup (Server)
- Step 1 — Insert HDMI Dummy Plug
- Step 2 — Enable NVIDIA DRM Modesetting
- Step 3 — Install Sunshine (ARM64)
- Step 4 — Configure Sunshine to Use KMS Capture
- Step 5 — Enable Sunshine as a User Service
- Step 6 — Fix Sunshine Auto-Start After Reboot
- Step 7 — Configure Sunshine via Web UI
- Step 8 — Enable Auto-Login on Boot
- Step 9 — Install Tailscale on DGX Spark
- Step 10 — Reboot and Verify
- Part 2 — Client Setup (Mac or Windows Laptop)
- Part 3 — Connecting to the DGX Spark
- Part 4 — Boot Sequence After Reboot
- Part 5 — DGX Spark Specific Fixes Summary
- Part 6 — Session Management
- Part 7 — Troubleshooting
- Part 8 — Quick Reference
Overview
| Component | Role | Where |
|---|---|---|
| HDMI Dummy Plug (4K) | Tells GPU a monitor is connected — GPU renders display | DGX Spark HDMI port |
| NVIDIA DRM Modesetting | Enables KMS capture — required for Blackwell GPU | GRUB kernel parameter |
| Sunshine (ARM64) | Captures desktop and streams via NVENC | DGX Spark |
| KMS Capture | Screen capture method — stable on Blackwell GB10 | Sunshine config |
| Auto-login (GDM) | Boots to desktop so Sunshine starts automatically | DGX Spark |
| Tailscale | Encrypted tunnel for remote access from any network | Both devices |
| Moonlight | Receives and displays the stream | Your Mac or Windows laptop |
Prerequisites
- HDMI dummy plug (4K) inserted into DGX Spark HDMI port
- SSH access to the DGX Spark on local network
- Tailscale free account at tailscale.com
- Moonlight installed on your Mac or Windows laptop
Part 1 — DGX Spark Setup (Server)
Run all commands via SSH on the DGX Spark. This is a one-time setup.
Step 1 — Insert HDMI Dummy Plug
Physically insert a 4K HDMI dummy plug into any HDMI port on the DGX Spark before doing anything else.
Why this is needed
The NVIDIA Blackwell GPU in the DGX Spark only renders a display framebuffer when it detects a connected monitor. Without a display signal, the GPU does not initialize video output and Sunshine has nothing to capture — resulting in a black screen.
A 4K HDMI dummy plug contains a small chip that emulates the EDID signal of a real monitor, advertising support for resolutions up to 3840x2160. The GPU receives this signal and initializes full hardware-accelerated display output exactly as if a real monitor were attached.
Important: Do not reboot yet — complete all remaining steps first, then reboot once at the end.
Step 2 — Enable NVIDIA DRM Modesetting
This is a DGX Spark-specific requirement. Sunshine uses KMS (Kernel Mode Setting) to capture the screen on Linux, but KMS requires the NVIDIA DRM (Direct Rendering Manager) module to be loaded with modesetting enabled.
What this does
Adding nvidia-drm.modeset=1 to the kernel boot parameters tells the NVIDIA kernel module to activate DRM modesetting on startup. Without this, Sunshine's KMS capture cannot access the display planes and will fail with a "GPU driver doesn't support universal planes" error.
# Edit GRUB boot parameters sudo nano /etc/default/grub
Find the GRUB_CMDLINE_LINUX_DEFAULT line. Add the two NVIDIA parameters inside the existing quotes, space-separated:
# Before (example): GRUB_CMDLINE_LINUX_DEFAULT="quiet splash" # After — just add to the end inside the same quotes: GRUB_CMDLINE_LINUX_DEFAULT="quiet splash nvidia-drm.modeset=1 nvidia.NVreg_UsePageAttributeTable=1"
# Apply the change sudo update-grub
Step 3 — Install Sunshine (ARM64)
The DGX Spark uses an ARM64 Grace CPU. Always download the arm64 package — the amd64 package is for Intel/AMD machines and will not install on ARM.
# Download the ARM64 build for Ubuntu 24.04 wget https://github.com/LizardByte/Sunshine/releases/latest/download/sunshine-ubuntu-24.04-arm64.deb # Install sudo apt install -y ./sunshine-ubuntu-24.04-arm64.deb
Architecture check: If you see errors like
libcap2 not installableorlibcurl4 not installable, you downloaded the amd64 version. These libraries are not installable because the package targets the wrong CPU architecture. Always use the arm64.debfor DGX Spark.
Step 4 — Configure Sunshine to Use KMS Capture
By default, Sunshine on Linux with an NVIDIA GPU automatically uses NvFBC (NVIDIA Frame Buffer Capture) for screen capture. On the DGX Spark's Blackwell GB10 GPU, NvFBC has a bug where Sunshine crashes after every client disconnect. KMS capture is stable.
NvFBC vs KMS — why KMS is the right choice for DGX Spark
| NvFBC (default) | KMS (recommended) | |
|---|---|---|
| What it does | Captures directly from NVIDIA framebuffer | Captures via Linux kernel display planes |
| Encoder used | NVENC (GPU-accelerated) | NVENC (GPU-accelerated) |
| Performance | Marginally faster in theory | Effectively identical in practice |
| Blackwell GB10 | Crashes on client disconnect | Stable — no crash |
| Requires modeset | No | Yes (Step 2) |
| Verdict for DGX Spark | Do not use | Use this |
Both methods use NVENC for encoding, so streaming quality and latency are identical. KMS is simply stable on Blackwell while NvFBC is not.
# Create or edit the Sunshine config file nano ~/.config/sunshine/sunshine.conf
Add these two lines:
capture=kms
encoder=nvenc
What these settings mean:
capture=kmstells Sunshine to use KMS instead of NvFBC for screen capture.encoder=nvenctells Sunshine to use NVIDIA's hardware encoder for video compression. Together they give you stable, GPU-accelerated streaming on the DGX Spark.
Step 5 — Enable Sunshine as a User Service
systemctl --user enable sunshine systemctl --user start sunshine # Verify it started systemctl --user status sunshine
Step 6 — Fix Sunshine Auto-Start After Reboot
This is a DGX Spark-specific issue. Sunshine's service file uses WantedBy=xdg-desktop-autostart.target, which is designed for GNOME session autostart. On DGX OS, this target is never activated after login, so Sunshine never auto-starts.
Why this happens
The xdg-desktop-autostart.target requires a GNOME session to explicitly activate it. On DGX OS's GNOME session, this activation doesn't happen — the session starts but never signals this target. As a result, Sunshine's service is enabled but the target it depends on is never reached, so Sunshine never starts.
The fix is to override the install target to default.target, which is always reached the moment a user session starts — regardless of desktop environment.
# Create an override directory for the service mkdir -p ~/.config/systemd/user/sunshine.service.d # Create the override file cat > ~/.config/systemd/user/sunshine.service.d/override.conf << 'EOF' [Service] # Clear the original 5s sleep and replace with 15s # to give the desktop time to fully initialize ExecStartPre= ExecStartPre=/bin/sleep 15 [Install] # Use default.target instead of xdg-desktop-autostart.target # default.target is always reached when user session starts WantedBy=default.target EOF
Re-enable the service so systemd creates the symlink pointing to the correct target:
systemctl --user daemon-reload systemctl --user disable sunshine systemctl --user enable sunshine # Verify the symlink was created in default.target.wants ls ~/.config/systemd/user/default.target.wants/ # Should show: sunshine.service
Why disable then re-enable? Running
systemctl --user enablecreates a symlink in theWantedBytarget's.wantsdirectory. If you changeWantedBywithout disabling first, the old symlink inxdg-desktop-autostart.target.wantsremains, and the new one indefault.target.wantsis not created. Disable removes the old symlink, enable creates the new one in the correct location.
Step 7 — Configure Sunshine via Web UI
Open the Sunshine web interface in a browser on the DGX Spark (or via SSH tunnel from your laptop):
https://localhost:47990
- Click Advanced then proceed past the self-signed certificate warning.
- Create a username and password on first launch — this secures your Sunshine web UI.
- Go to Configuration and set: Resolution to
1920x1080, FPS to60. The encoder is already set tonvencvia the config file.
Step 8 — Enable Auto-Login on Boot
Sunshine runs as a user service — it only starts after a user is logged in. Enable auto-login so the desktop and Sunshine start automatically after every reboot.
sudo nano /etc/gdm3/custom.conf
Find the [daemon] section and set (replace YOUR_USERNAME with your actual username):
[daemon] AutomaticLoginEnable=true AutomaticLogin=YOUR_USERNAME
Step 9 — Install Tailscale on DGX Spark
Tailscale creates an encrypted WireGuard tunnel so you can access the DGX Spark from any network. It runs as a system service and starts before login.
# One-liner installer — auto-detects ARM64 curl -fsSL https://tailscale.com/install.sh | sh # Authenticate — opens a URL to log in with your Tailscale account sudo tailscale up # Enable on boot (system service — starts before login) sudo systemctl enable tailscaled # Get your Tailscale IP tailscale ip
Disable key expiry: Go to https://login.tailscale.com/admin/machines, find your DGX Spark, click the
...menu, and select Disable key expiry. Without this, Tailscale will require re-authentication every 90 days — locking you out remotely.
Step 10 — Reboot and Verify
Now apply everything with a single reboot:
sudo reboot
After reboot (wait ~30 seconds), SSH back in and verify:
# 1. Verify NVIDIA modesetting is active (must output: Y) cat /sys/module/nvidia_drm/parameters/modeset # 2. Check Sunshine started automatically export XDG_RUNTIME_DIR=/run/user/$(id -u) systemctl --user status sunshine # 3. Check Tailscale is connected tailscale status # 4. Watch Sunshine logs — should show KMS, not NvFBC journalctl --user -u sunshine -n 30 --no-pager
In the Sunshine logs you should see:
Info: Screencasting with KMS ← correct capture method
Info: Creating encoder [hevc_nvenc] ← GPU encoding working
Info: Configuration UI available at [https://localhost:47990]
Part 2 — Client Setup (Mac or Windows Laptop)
Step 1 — Install Moonlight
Download and install Moonlight from the official site: https://moonlight-stream.org
- macOS: download the
.dmgand drag to Applications - Windows: download the
.exeinstaller and run it
Step 2 — Install Tailscale on Your Laptop
Download from https://tailscale.com/download and sign in with the same Tailscale account you used on the DGX Spark. Both devices must be on the same Tailscale network.
Part 3 — Connecting to the DGX Spark
Method A — Same Network (Automatic Discovery)
When your laptop and DGX Spark are on the same network, Moonlight finds the DGX Spark automatically.
- Open Moonlight — the DGX Spark appears automatically on the home screen.
- If it doesn't appear, click
+and enter the DGX Spark's local IP (runhostname -Ion the DGX Spark). - Click the DGX Spark tile — Moonlight shows a PIN.
- Open the Sunshine web UI at
https://localhost:47990, go to PIN tab, enter the PIN. - Pairing complete. Click Desktop in Moonlight to start streaming.
Method B — Remote via Tailscale
When working from home or any other network, use the Tailscale IP.
- Make sure Tailscale is connected on both your laptop and the DGX Spark.
- Get the DGX Spark Tailscale IP: run
tailscale ipon DGX, or check https://login.tailscale.com/admin/machines. - Open Moonlight, click
+, enter the Tailscale IP (e.g.100.64.x.x). - Connect and pair with PIN as above (first time only).
- Click Desktop to start streaming.
Check connection type: Run
tailscale statuson your laptop.directmeans peer-to-peer — full bandwidth.relaymeans traffic routes through Tailscale servers — typically capped at ~5 Mbps. If you see relay, ask IT to open UDP port 41641 on the office network firewall to enable direct P2P.
Method C — Company VPN
If both devices are on the same company VPN, they share a VPN subnet and can connect directly. No Tailscale needed.
- Connect your laptop to the company VPN.
- Open Moonlight and connect using the DGX Spark's VPN IP address.
Part 4 — Boot Sequence After Reboot
With all steps configured, this is what happens automatically after every reboot:
| Order | What happens | Result |
|---|---|---|
| 1 | Kernel boots with nvidia-drm.modeset=1 | NVIDIA DRM modesetting active |
| 2 | Tailscale starts (system service) | VPN tunnel live — SSH accessible |
| 3 | GDM auto-login fires | User session starts |
| 4 | systemd user instance starts | User services can now run |
| 5 | Sunshine waits 15 seconds (ExecStartPre sleep) | Desktop finishes initializing |
| 6 | Sunshine starts — KMS capture + NVENC encoder | Stream available, Moonlight can connect |
SSH as emergency fallback: Tailscale starts at step 2 — before login. Even if Sunshine fails, you can always SSH into the DGX Spark via the Tailscale IP (
ssh your-username@100.64.x.x) and start Sunshine manually.
Part 5 — DGX Spark Specific Fixes Summary
These three fixes are specific to the DGX Spark with the NVIDIA Blackwell GB10 GPU on Ubuntu 24.04 ARM64. They are not required for standard Linux machines.
| Fix | Problem it solves | What to do |
|---|---|---|
| NVIDIA DRM modesetting | KMS capture fails with GPU driver doesn't support universal planes: /dev/dri/card1 | Add nvidia-drm.modeset=1 nvidia.NVreg_UsePageAttributeTable=1 to GRUB_CMDLINE_LINUX_DEFAULT, run sudo update-grub |
| KMS capture instead of NvFBC | NvFBC crashes Sunshine after every client disconnect (Couldn't release NvFBC context from current thread) | Add capture=kms and encoder=nvenc to ~/.config/sunshine/sunshine.conf |
| WantedBy=default.target override | Sunshine never auto-starts after reboot because xdg-desktop-autostart.target is never activated on DGX OS | Create ~/.config/systemd/user/sunshine.service.d/override.conf with WantedBy=default.target, then disable and re-enable the service |
Part 6 — Session Management
Sunshine Commands
| Action | Command |
|---|---|
| Check status | systemctl --user status sunshine |
| Start | systemctl --user start sunshine |
| Stop | systemctl --user stop sunshine |
| Restart | systemctl --user restart sunshine |
| View logs (last 50) | journalctl --user -u sunshine -n 50 --no-pager |
| Watch live logs | journalctl --user -u sunshine -f |
| View merged service file | systemctl --user cat sunshine |
| Open web UI | https://localhost:47990 |
SSH tip: When running
systemctl --usercommands over SSH, first run:export XDG_RUNTIME_DIR=/run/user/$(id -u)— otherwise the user session may not be found.
Tailscale Commands
| Action | Command |
|---|---|
| Check status + devices | tailscale status |
| Get Tailscale IP | tailscale ip |
| Connect / re-authenticate | sudo tailscale up |
| Disconnect | sudo tailscale down |
| Check P2P vs relay | tailscale netcheck |
| Admin console | https://login.tailscale.com/admin |
Part 7 — Troubleshooting
| Symptom | Likely Cause | Fix |
|---|---|---|
| GPU doesn't support universal planes | nvidia-drm.modeset not enabled | Add nvidia-drm.modeset=1 to GRUB, run update-grub, reboot |
| NvFBC crash after client disconnects | Blackwell GB10 NvFBC cleanup bug | Set capture=kms in sunshine.conf |
| Sunshine inactive (dead) after reboot | xdg-desktop-autostart.target not activated on DGX OS | Override with WantedBy=default.target, disable then re-enable service |
| Black screen on connect | No display output | Check HDMI dummy plug is inserted |
| DGX Spark not in Moonlight | Different network or not discovered | Click + and enter IP manually |
| Tailscale shows relay | NAT blocking direct path | Open UDP port 41641 on office firewall |
| Install error: libcap2 not installable | Downloaded amd64 instead of arm64 | Re-download sunshine-ubuntu-24.04-arm64.deb |
systemctl --user fails over SSH | XDG_RUNTIME_DIR not set | Run: export XDG_RUNTIME_DIR=/run/user/$(id -u) |
| Tailscale re-auth after 90 days | Key expiry not disabled | Admin console → device → Disable key expiry |
| Poor quality / lag | Wrong encoder or low bitrate | Verify encoder=nvenc in conf; raise bitrate to 30–50 Mbps |
If Sunshine shows inactive (dead): Run
export XDG_RUNTIME_DIR=/run/user/$(id -u)thensystemctl --user start sunshine. Check that the override.conf was applied correctly withsystemctl --user cat sunshine— the[Install]section should showWantedBy=default.target.
Part 8 — Quick Reference
Key Files on DGX Spark
| File | Purpose |
|---|---|
/etc/default/grub | Add nvidia-drm.modeset=1 here |
/etc/gdm3/custom.conf | Auto-login configuration |
~/.config/sunshine/sunshine.conf | capture=kms and encoder=nvenc |
~/.config/systemd/user/sunshine.service.d/override.conf | WantedBy=default.target fix |
~/.config/systemd/user/default.target.wants/ | Verify sunshine.service symlink is here |
Connection Decision Tree
- Same office network? Open Moonlight → DGX Spark appears automatically → Connect
- Company VPN connected? Open Moonlight → Click
+→ Enter DGX VPN IP → Connect - Working remotely, no VPN? Connect Tailscale → Open Moonlight → Click
+→ Enter Tailscale IP (100.x.x.x) → Connect
URLs
| Resource | URL / Command |
|---|---|
| Sunshine web UI (on DGX) | https://localhost:47990 |
| Moonlight download | https://moonlight-stream.org |
| Tailscale admin console | https://login.tailscale.com/admin |
| DGX local IP | hostname -I |
| DGX Tailscale IP | tailscale ip |
| Sunshine GitHub releases | https://github.com/LizardByte/Sunshine/releases |