Back to Blog

NVIDIA DGX Spark Remote Access Runbook

15 min read

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:

  1. Access your DGX when you want.
  2. You don't want your DGX to connect to a real monitor.
  3. You bring your laptop to anywhere and you want to access your workstation.
  4. 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

ComponentRoleWhere
HDMI Dummy Plug (4K)Tells GPU a monitor is connected — GPU renders displayDGX Spark HDMI port
NVIDIA DRM ModesettingEnables KMS capture — required for Blackwell GPUGRUB kernel parameter
Sunshine (ARM64)Captures desktop and streams via NVENCDGX Spark
KMS CaptureScreen capture method — stable on Blackwell GB10Sunshine config
Auto-login (GDM)Boots to desktop so Sunshine starts automaticallyDGX Spark
TailscaleEncrypted tunnel for remote access from any networkBoth devices
MoonlightReceives and displays the streamYour 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 installable or libcurl4 not installable, you downloaded the amd64 version. These libraries are not installable because the package targets the wrong CPU architecture. Always use the arm64 .deb for 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 doesCaptures directly from NVIDIA framebufferCaptures via Linux kernel display planes
Encoder usedNVENC (GPU-accelerated)NVENC (GPU-accelerated)
PerformanceMarginally faster in theoryEffectively identical in practice
Blackwell GB10Crashes on client disconnectStable — no crash
Requires modesetNoYes (Step 2)
Verdict for DGX SparkDo not useUse 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=kms tells Sunshine to use KMS instead of NvFBC for screen capture. encoder=nvenc tells 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 enable creates a symlink in the WantedBy target's .wants directory. If you change WantedBy without disabling first, the old symlink in xdg-desktop-autostart.target.wants remains, and the new one in default.target.wants is 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
  1. Click Advanced then proceed past the self-signed certificate warning.
  2. Create a username and password on first launch — this secures your Sunshine web UI.
  3. Go to Configuration and set: Resolution to 1920x1080, FPS to 60. The encoder is already set to nvenc via 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 .dmg and drag to Applications
  • Windows: download the .exe installer 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.

  1. Open Moonlight — the DGX Spark appears automatically on the home screen.
  2. If it doesn't appear, click + and enter the DGX Spark's local IP (run hostname -I on the DGX Spark).
  3. Click the DGX Spark tile — Moonlight shows a PIN.
  4. Open the Sunshine web UI at https://localhost:47990, go to PIN tab, enter the PIN.
  5. 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.

  1. Make sure Tailscale is connected on both your laptop and the DGX Spark.
  2. Get the DGX Spark Tailscale IP: run tailscale ip on DGX, or check https://login.tailscale.com/admin/machines.
  3. Open Moonlight, click +, enter the Tailscale IP (e.g. 100.64.x.x).
  4. Connect and pair with PIN as above (first time only).
  5. Click Desktop to start streaming.

Check connection type: Run tailscale status on your laptop. direct means peer-to-peer — full bandwidth. relay means 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.

  1. Connect your laptop to the company VPN.
  2. 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:

OrderWhat happensResult
1Kernel boots with nvidia-drm.modeset=1NVIDIA DRM modesetting active
2Tailscale starts (system service)VPN tunnel live — SSH accessible
3GDM auto-login firesUser session starts
4systemd user instance startsUser services can now run
5Sunshine waits 15 seconds (ExecStartPre sleep)Desktop finishes initializing
6Sunshine starts — KMS capture + NVENC encoderStream 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.

FixProblem it solvesWhat to do
NVIDIA DRM modesettingKMS capture fails with GPU driver doesn't support universal planes: /dev/dri/card1Add nvidia-drm.modeset=1 nvidia.NVreg_UsePageAttributeTable=1 to GRUB_CMDLINE_LINUX_DEFAULT, run sudo update-grub
KMS capture instead of NvFBCNvFBC 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 overrideSunshine never auto-starts after reboot because xdg-desktop-autostart.target is never activated on DGX OSCreate ~/.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

ActionCommand
Check statussystemctl --user status sunshine
Startsystemctl --user start sunshine
Stopsystemctl --user stop sunshine
Restartsystemctl --user restart sunshine
View logs (last 50)journalctl --user -u sunshine -n 50 --no-pager
Watch live logsjournalctl --user -u sunshine -f
View merged service filesystemctl --user cat sunshine
Open web UIhttps://localhost:47990

SSH tip: When running systemctl --user commands over SSH, first run: export XDG_RUNTIME_DIR=/run/user/$(id -u) — otherwise the user session may not be found.

Tailscale Commands

ActionCommand
Check status + devicestailscale status
Get Tailscale IPtailscale ip
Connect / re-authenticatesudo tailscale up
Disconnectsudo tailscale down
Check P2P vs relaytailscale netcheck
Admin consolehttps://login.tailscale.com/admin

Part 7 — Troubleshooting

SymptomLikely CauseFix
GPU doesn't support universal planesnvidia-drm.modeset not enabledAdd nvidia-drm.modeset=1 to GRUB, run update-grub, reboot
NvFBC crash after client disconnectsBlackwell GB10 NvFBC cleanup bugSet capture=kms in sunshine.conf
Sunshine inactive (dead) after rebootxdg-desktop-autostart.target not activated on DGX OSOverride with WantedBy=default.target, disable then re-enable service
Black screen on connectNo display outputCheck HDMI dummy plug is inserted
DGX Spark not in MoonlightDifferent network or not discoveredClick + and enter IP manually
Tailscale shows relayNAT blocking direct pathOpen UDP port 41641 on office firewall
Install error: libcap2 not installableDownloaded amd64 instead of arm64Re-download sunshine-ubuntu-24.04-arm64.deb
systemctl --user fails over SSHXDG_RUNTIME_DIR not setRun: export XDG_RUNTIME_DIR=/run/user/$(id -u)
Tailscale re-auth after 90 daysKey expiry not disabledAdmin console → device → Disable key expiry
Poor quality / lagWrong encoder or low bitrateVerify encoder=nvenc in conf; raise bitrate to 30–50 Mbps

If Sunshine shows inactive (dead): Run export XDG_RUNTIME_DIR=/run/user/$(id -u) then systemctl --user start sunshine. Check that the override.conf was applied correctly with systemctl --user cat sunshine — the [Install] section should show WantedBy=default.target.


Part 8 — Quick Reference

Key Files on DGX Spark

FilePurpose
/etc/default/grubAdd nvidia-drm.modeset=1 here
/etc/gdm3/custom.confAuto-login configuration
~/.config/sunshine/sunshine.confcapture=kms and encoder=nvenc
~/.config/systemd/user/sunshine.service.d/override.confWantedBy=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

ResourceURL / Command
Sunshine web UI (on DGX)https://localhost:47990
Moonlight downloadhttps://moonlight-stream.org
Tailscale admin consolehttps://login.tailscale.com/admin
DGX local IPhostname -I
DGX Tailscale IPtailscale ip
Sunshine GitHub releaseshttps://github.com/LizardByte/Sunshine/releases