Client Setup and SSH Access
This chapter covers setup from the operator's perspective — the engineer who wants to SSH into a Spark from their laptop. At this point the Sparks are enrolled and tagged (Chapter 2), and the ACL is configured (Chapter 3). The only remaining steps are installing Tailscale on the client machine, joining the tailnet, and verifying that the SSH connection works.
The steps below use macOS with Homebrew. The Tailscale process is identical on Linux and Windows; only the installation command differs.
Step 1 — Install Tailscale on macOS
brew install tailscale
This installs the tailscale CLI and the tailscaled background daemon via Homebrew. The Tailscale macOS app (from the App Store) is an alternative with a menu-bar UI — both work identically for CLI usage.
Start the daemon
sudo brew services start tailscale
Verify it is running:
brew services list | grep tailscale
Expected output: tailscale started ...
Step 2 — Login and Verify
Authenticate to the tailnet
tailscale login
This opens a browser window to the Tailscale login page. Sign in with the same account whose email was added to group:operators in the ACL policy. On success the terminal prints:
Success.
Bring up the connection
tailscale up
The client connects to the tailnet. No extra flags are needed on a workstation — --ssh is only required on machines that accept inbound SSH.
Check network status
tailscale status
You should see your machine and both Spark nodes listed:
100.124.xx.xx serverlesss-macbook-pro mohnishbasha@ macOS -
100.109.xx.xx spark-bundle1-1 tagged-devices linux -
100.104.xx.xx spark-bundle1-2 tagged-devices linux -
100.70.xx.xx spark-bundle2-1 tagged-devices linux -
100.67.xx.xx spark-bundle2-2 tagged-devices linux -
| Column | Meaning |
|---|---|
| IP (100.x.x.x) | Stable Tailscale IP — does not change even if the machine's LAN IP changes |
| Hostname | Machine name as registered in the tailnet |
| Login | The Tailscale account that owns this device (tagged-devices for machines with ACL tags) |
| OS | Operating system of the peer |
| Status | - = idle, active = currently communicating |
Inspect peer tags
Confirm both Sparks carry the tag:spark tag:
tailscale status --json | jq '.Peer[] | {name: .HostName, tags: .Tags}'
Expected output:
{
"name": "spark-bundle1-1",
"tags": ["tag:spark"]
}
{
"name": "spark-bundle1-2",
"tags": ["tag:spark"]
}
{
"name": "spark-bundle2-1",
"tags": ["tag:spark"]
}
{
"name": "spark-bundle2-2",
"tags": ["tag:spark"]
}
If a machine shows "tags": null, return to the admin console and apply the tag (Chapter 2, Step 3).
Step 3 — SSH into a Spark Node
You can connect using either the Tailscale IP or the MagicDNS hostname. Both work from any device on the tailnet.
By Tailscale IP
tailscale ssh stoke@100.70.xx.xx # spark-bundle2-1
tailscale ssh stoke@100.67.xx.xx # spark-bundle2-2
By MagicDNS hostname
tailscale ssh stoke@spark-bundle2-1.tail8a84f6.ts.net
tailscale ssh stoke@spark-bundle2-2.tail8a84f6.ts.net
You can also use plain ssh if MagicDNS is resolving correctly on your system:
ssh stoke@100.70.xx.xx
tailscale ssh bypasses ~/.ssh/known_hosts checking and always authenticates through tailnet identity. Vanilla ssh works too, but you may see an SSH host-key warning the first time you connect via the Tailscale IP because it is a different path than any previous LAN connection.
A successful connection displays the DGX Spark welcome banner and drops you into a shell as stoke:
Welcome to Ubuntu 22.04.x LTS (GNU/Linux 6.x.x aarch64)
* Documentation: https://help.ubuntu.com
...
stoke@spark-bundle2-1:~$
Routing across all four Sparks
Once on the tailnet, you can SSH between any Spark node directly — also without keys:
# From your laptop — reach any of the four nodes
tailscale ssh stoke@100.109.xx.xx # spark-bundle1-1
tailscale ssh stoke@100.104.xx.xx # spark-bundle1-2
tailscale ssh stoke@100.70.xx.xx # spark-bundle2-1
tailscale ssh stoke@100.67.xx.xx # spark-bundle2-2
The tailnet provides end-to-end encrypted connectivity between all enrolled peers.
Summary: what you now have
| Capability | How it works |
|---|---|
| SSH to spark-bundle1-1 | tailscale ssh stoke@100.109.xx.xx |
| SSH to spark-bundle1-2 | tailscale ssh stoke@100.104.xx.xx |
| SSH to spark-bundle2-1 | tailscale ssh stoke@100.70.xx.xx |
| SSH to spark-bundle2-2 | tailscale ssh stoke@100.67.xx.xx or hostname |
| Add a new operator | Invite to tailnet + add login to group:operators |
| Remove an operator | Remove from tailnet — access revoked everywhere instantly |
| Add a new Spark | Enroll it + apply tag:spark — ACL covers it automatically |