Deployment guide

Deploy a large MoE on DGX Spark with vLLM: single node and a two-node pair

The deployment order that avoids the silent hangs we hit on our own GB10 pair: weights and image pinned, head before peer, readiness by endpoint not by feel, and the kernel-selection check that separates the fast configuration from the one most people run.

Platform:
DGX Spark (GB10)
Time to complete:
2-3 h
Updated:
9/1/2026

This is the tutorial version of our serving recipe — the same steps, ordered for someone doing it the first time, with the traps we paid for marked before you reach them. It was written on a real pair of GB10 units serving a 284B-parameter MoE; a single Spark follows the same path minus the fabric section.

You need: one or two DGX Spark units on current firmware, Docker with NVIDIA runtime, and a lot of disk — frontier-class weights are measured in the hundreds of gigabytes per node.

Step 1 — pin everything before you download anything

Three identities decide whether your deployment is debuggable later: the model revision, the container digest, and the firmware version. Write all three down first. main moves, tags move, and the Spark’s firmware updates have historically changed behavior enough to flip community sentiment on the whole device. A deployment you cannot name precisely is a deployment you cannot ask anyone to help debug.

# record these three lines somewhere permanent:
# model:    <repo> @ <revision>
# image:    vllm/vllm-openai@sha256:<digest>
# firmware: (from your system info)

Step 2 — weights on every node

For a pair: the full weights go on BOTH nodes, identical revision. Budget real time for this and verify sizes match when done. For a single node, pick a model that actually fits one device — the frontier class does not, which is why the pair exists.

Step 3 — single node first, even if you own two

Bring up one node alone before touching tensor parallelism. You want to learn the container’s behavior — startup time, memory pattern, log shape — without the fabric as a second variable:

docker run -d --name vllm --gpus all \
  -v /var/lib/llm/models:/models -p 8000:8000 \
  vllm/vllm-openai@sha256:YOUR_DIGEST \
  --model /models/YOUR-MODEL --max-model-len 32768

Readiness is an endpoint, not a feeling: the server is up when curl localhost:8000/v1/models answers. Weight loading on this class of model takes minutes — watch docker logs -f vllm and do not restart it out of impatience halfway through.

Step 4 — for a pair: head first, then peer, in that order

The rank-0 node hosts the coordination store. A peer that starts before the head is listening dies on a broken pipe with no useful error — this ordering bug reads obvious written down and cost us real hours live. The sequence that works: launch the head, wait until the store port shows in ss -tln, only then launch the peer. Fabric settings (head and peer IPs, HCA, GID index) belong in environment variables at the top of your launch script, not scattered through it.

Step 5 — verify the kernel selection took effect

For MoE models, vLLM’s automatic backend selection can deliberately skip the kernel purpose-built for your model’s quantization. Grep the logs for the MoE backend line and confirm which one loaded — the difference is not cosmetic. If your model family ships a specialized backend, set it explicitly and check the log again. In our experience this one check separates a published Spark number from a disappointed forum post.

Step 6 — the smoke test

Same discipline as on any box: send a real chat completion, verify content is non-empty and finish_reason is stop, and take token counts from usage.completion_tokens — under speculative decoding, streaming-event counts lie.

Step 7 — monitoring, before you need it

Stock GPU observability half-works on GB10 unified memory: dcgm-exporter does not function and NVML answers N/A on much of what you would alert on. Set up the textfile-collector workaround now — you do not want to discover the observability gap during your first incident.

Where to go next

← All guides