Reference configuration. The hardware is four GEEKOM A9 Mega PCs with 128 GB each. The software stack and commands below are a starting point. Confirm the BIOS, kernel, packages, DS4 commit and a successful four-node request on your systems before relying on the setup.
Before you start
This guide uses pipeline parallelism: each PC runs a different range of model layers. PC1 coordinates the pipeline and serves the API. The setup distributes the GPU workload across the machines; it does not guarantee higher token generation speed.
- Four GEEKOM A9 Mega PCs: AMD Ryzen AI Max+ 395, Radeon 8060S and 128 GB LPDDR5X unified memory per PC.
- Three USB4 or Thunderbolt data cables that support host-to-host networking. Use the rear USB4 ports; a USB-C charging cable or a front data-only port is not a substitute.
- Local NVMe storage: the GGUF is 86.7 GB (about 80.8 GiB) per node. Plan at least 100 GiB free per PC for the model and working files, in addition to space for Ubuntu.
- Local console access on every PC for network changes, plus a separate Ethernet or Wi-Fi connection for software downloads. Keep the USB4 cluster links on a dedicated subnet.
Wire the four PCs
Connect PC1 ↔ PC2, PC2 ↔ PC3 and PC3 ↔ PC4. Do not connect PC4 back to PC1. Leave the regular Ethernet or Wi-Fi connection separate from the USB4 bridge.
| Node | Cluster IP | Network role | DS4 role | Layers |
|---|---|---|---|---|
| PC1 | 192.168.10.10 | One direct link | Coordinator | 0:10 |
| PC2 | 192.168.10.20 | Two links via br0 | Worker 1 | 11:20 |
| PC3 | 192.168.10.30 | Two links via br0 | Worker 2 | 21:30 |
| PC4 | 192.168.10.40 | One direct link | Worker 3 | 31:output |
Rear USB4 port concept
Configure the cluster network
The example subnet is 192.168.10.0/24. If your normal LAN or VPN already uses it, pick a different private subnet and update every example IP, including the DS4 commands. Keep the existing default route on your regular connection.
Identify the USB4 interfaces
At each PC, run the commands below. If needed, disconnect and reconnect one USB4 cable at a time to map the interfaces. Linux names can vary; substitute the actual names in the YAML, including the bridge interface list.
sudo modprobe thunderbolt-net
ip -br link
ip -br addrBack up Netplan and create the file
Run on the local console of each PC. Use the file only if that name is unused, and check existing Netplan or NetworkManager settings for conflicting definitions of these USB4 interfaces. Paste just the YAML for the current PC.
sudo cp -a /etc/netplan "/root/netplan-before-a9-$(date +%Y%m%d-%H%M%S)"
sudoedit /etc/netplan/90-a9-cluster.yamlPC1 · 192.168.10.10
network:
version: 2
ethernets:
thunderbolt0:
renderer: networkd
dhcp4: false
dhcp6: false
link-local: []
optional: true
mtu: 1500
addresses: [192.168.10.10/24]PC2 · 192.168.10.20
network:
version: 2
ethernets:
thunderbolt0:
renderer: networkd
dhcp4: false
dhcp6: false
link-local: []
optional: true
mtu: 1500
thunderbolt1:
renderer: networkd
dhcp4: false
dhcp6: false
link-local: []
optional: true
mtu: 1500
bridges:
br0:
renderer: networkd
interfaces: [thunderbolt0, thunderbolt1]
dhcp4: false
dhcp6: false
link-local: []
optional: true
mtu: 1500
addresses: [192.168.10.20/24]
parameters:
stp: truePC3 · 192.168.10.30
network:
version: 2
ethernets:
thunderbolt0:
renderer: networkd
dhcp4: false
dhcp6: false
link-local: []
optional: true
mtu: 1500
thunderbolt1:
renderer: networkd
dhcp4: false
dhcp6: false
link-local: []
optional: true
mtu: 1500
bridges:
br0:
renderer: networkd
interfaces: [thunderbolt0, thunderbolt1]
dhcp4: false
dhcp6: false
link-local: []
optional: true
mtu: 1500
addresses: [192.168.10.30/24]
parameters:
stp: truePC4 · 192.168.10.40
network:
version: 2
ethernets:
thunderbolt0:
renderer: networkd
dhcp4: false
dhcp6: false
link-local: []
optional: true
mtu: 1500
addresses: [192.168.10.40/24]Check, try and confirm the configuration
Confirm netplan try only when the cluster IP and regular network both work. Netplan rollback has caveats with bridges; if a trial fails, check the restored state at the local console. The examples use MTU 1500 on all links. Leave jumbo frames for a separately tested configuration.
sudo chown root:root /etc/netplan/90-a9-cluster.yaml
sudo chmod 600 /etc/netplan/90-a9-cluster.yaml
sudo netplan generate
sudo netplan tryTest the full chain
From PC1, ping PC2, PC3 and PC4. Repeat from the Workers to PC1 and to neighboring Workers, since pipeline stages exchange data directly. On PC2 and PC3, bridge link should show both USB4 links as members of br0.
ping -c 3 192.168.10.20
ping -c 3 192.168.10.30
ping -c 3 192.168.10.40Prepare Ubuntu and ROCm
Install or confirm Ubuntu
Use Ubuntu 26.04 LTS Desktop (AMD64) and record the point release and kernel actually installed on all four PCs. If installing from scratch, verify the ISO checksum, use the model’s UEFI boot menu and back up the target drive before choosing an erase option. For an existing working installation, skip the reinstall.
Ubuntu 26.04 LTS downloads and checksums · Ubuntu Desktop installation documentation
Install the GPU runtime and build dependencies
Use one package source consistently. The block below follows the DS4 upstream native Ubuntu 26.04 example using Ubuntu packages. Run it on all four PCs. If these packages are unavailable or your DS4 commit has different prerequisites, use its Strix Halo documentation and a matching AMD/Ubuntu installation route. Do not add a focal repository or mix development headers from different ROCm versions.
sudo apt update
sudo apt install build-essential git curl python3 hipcc rocminfo rocm-smi \
libamdhip64-dev libhipblas-dev libhipblaslt-dev librocblas-dev \
librocwmma-dev libhipcub-dev
sudo usermod -aG render,video "$USER"Sign out and back in after the group change. Check that rocminfo can see gfx1151 as a normal user before continuing. Record the actual package versions and keep all four hosts aligned.
cat /etc/os-release
uname -r
id -nG
ls -l /dev/kfd
rocminfo | grep -E 'gfx1151|Radeon 8060S'
hipcc --version
dpkg-query -W hipcc libamdhip64-dev libhipblas-devGPU-visible memory and firmware
Start with the current firmware and kernel settings. The 128 GB is shared memory, and the GPU cannot necessarily address all of it. Only tune if a confirmed GPU allocation failure persists after verifying the runtime, file and small context. Check the DS4 and AMD guidance for the installed kernel; preserve existing boot options, leave memory for Ubuntu, record the previous settings, and change one setting at a time.
AMD Ryzen AI Max memory and kernel guidance · DS4 for AMD Strix Halo
Build DS4 and download the model
Clone the upstream antirez/ds4 repository on PC1 and record its full commit hash. Use the exact same commit on PC2–PC4. These are first-install examples; for an existing checkout, check its status and use the intended commit instead of cloning over it.
PC1: choose and record the commit
mkdir -p "$HOME/a9-cluster"
cd "$HOME/a9-cluster" || exit
git clone https://github.com/antirez/ds4.git
git -C ds4 rev-parse HEADPC2–PC4: check out the same commit
mkdir -p "$HOME/a9-cluster"
cd "$HOME/a9-cluster" || exit
git clone https://github.com/antirez/ds4.git
read -r -p 'Paste the full PC1 DS4 commit: ' commit
git -C ds4 checkout --detach "$commit" &&
git -C ds4 rev-parse HEADAll four PCs: build and check the command-line options
cd "$HOME/a9-cluster/ds4" &&
make strix-halo &&
./ds4 --help &&
./ds4-server --helpBefore starting, confirm that both binaries built, the ROCm backend is available, and the selected commit supports pipeline options --role, --layers, --listen and --coordinator where applicable. The Coordinator also needs the server options --host and --port.
Download and verify the same GGUF on all four PCs
This example uses the original guide’s DeepSeek V4 Flash mixed Q2 file, quantized by jedisct1 for DS4. Download once and copy it to the other PCs if convenient. On every node, verify the published SHA-256. If the file is rejected by your chosen DS4 commit, resolve that mismatch against its model documentation before proceeding.
mkdir -p "$HOME/a9-cluster/models"
cd "$HOME/a9-cluster/models" || exit
df -h .
model='DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix-aligned.gguf'
curl -fL --continue-at - --output "$model.part" \
"https://huggingface.co/jedisct1/DeepSeek-V4-Flash-imatrix-aligned/resolve/main/$model" &&
printf '%s %s\n' '94c95d56b83476547d55219a062a1095c523318d3fba6bd80e4d413687689100' "$model.part" | sha256sum --check - &&
mv -- "$model.part" "$model"If you copied the GGUF from another PC
cd "$HOME/a9-cluster/models" || exit
model='DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix-aligned.gguf'
printf '%s %s\n' '94c95d56b83476547d55219a062a1095c523318d3fba6bd80e4d413687689100' "$model" | sha256sum --check -Start the four nodes
Open a terminal on each PC. Start PC4, PC3 and PC2, then start PC1. Keep the processes in the foreground for the first run. Use the logs to see which Workers connect and which ranges register; there is no fixed wait between commands. All nodes start at --ctx 4096 to limit memory use.
Start in this order
1. PC4 · Worker 3 · 31:output
cd "$HOME/a9-cluster/ds4" || exit
model="$HOME/a9-cluster/models/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix-aligned.gguf"
./ds4 --rocm -m "$model" --ctx 4096 \
--role worker --layers 31:output \
--listen 192.168.10.40 1235 --coordinator 192.168.10.10 12342. PC3 · Worker 2 · 21:30
cd "$HOME/a9-cluster/ds4" || exit
model="$HOME/a9-cluster/models/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix-aligned.gguf"
./ds4 --rocm -m "$model" --ctx 4096 \
--role worker --layers 21:30 \
--listen 192.168.10.30 1235 --coordinator 192.168.10.10 12343. PC2 · Worker 1 · 11:20
cd "$HOME/a9-cluster/ds4" || exit
model="$HOME/a9-cluster/models/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix-aligned.gguf"
./ds4 --rocm -m "$model" --ctx 4096 \
--role worker --layers 11:20 \
--listen 192.168.10.20 1235 --coordinator 192.168.10.10 12344. PC1 · Coordinator · 0:10
cd "$HOME/a9-cluster/ds4" || exit
model="$HOME/a9-cluster/models/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix-aligned.gguf"
./ds4-server --rocm -m "$model" --ctx 4096 \
--role coordinator --layers 0:10 \
--listen 192.168.10.10 1234 --host 127.0.0.1 --port 8080 --debugThe API listens on PC1 at 127.0.0.1:8080 for the first test. The Workers register with PC1 on TCP 1234. The example fixes Worker data listeners to TCP 1235 on their individual cluster IPs. Keep the DS4 data plane on a trusted network; it has no built-in transport authentication or encryption.
If a firewall is active, allow only the required traffic on the USB4 interface or bridge: PC2–PC4 to PC1 TCP 1234, and cluster peers to Worker TCP 1235. Keep the firewall enabled. Do not forward these ports from the internet.
Verify the chat API
Run the following from a second terminal on PC1. /v1/models checks the API listener. A chat reply with a nonempty choices[0].message.content, together with all three registered Worker ranges in the Coordinator log, verifies the full route.
curl -fsS http://127.0.0.1:8080/v1/models |
python3 -m json.tool
curl --fail-with-body -sS http://127.0.0.1:8080/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{"model":"deepseek-v4-flash","messages":[{"role":"user","content":"Explain local AI in one sentence."}],"max_tokens":64,"think":false,"stream":false}' |
python3 -m json.toolA successful model list alone does not verify distributed inference. Keep the terminal logs from all four PCs when checking the result.
Optional: allow a trusted cluster client
After local testing, restart PC1 with --host 192.168.10.10 instead of the loopback address if another node must call the API. Permit TCP 8080 only from trusted clients on the chosen interface. Use an authenticated, encrypted proxy or a VPN if the API must cross network boundaries.
Troubleshoot and recover
No USB4 interface
Use the rear USB4 ports and a known-good data cable. Replug one link at a time, confirm thunderbolt-net is loaded and check ip -br link.
PC4 is unreachable
Check each cable in order, the subnet and MTU, and the two members of br0 on PC2 and PC3. Make sure the cluster subnet does not overlap your LAN or VPN.
A Worker does not register or the route is incomplete
Match the commit, GGUF checksum, context size and layer table. Check bind addresses, local firewall scope and the Worker data port in the logs. Do not send HTTP requests to TCP 1234.
The GPU is missing or runs out of memory
Verify gfx1151, /dev/kfd access and group membership. Close other GPU workloads and retry the baseline before changing firmware or boot parameters.
The chat API responds with an error
Read the response body and Coordinator log. Confirm the three Workers are connected and all ranges are present, and use the model alias reported by /v1/models.
Stop or roll back
Stop the foreground processes with Ctrl+C. If you added only the new YAML file, move it out of /etc/netplan and run sudo netplan apply at the local console. Restore the earlier settings from your backup if you also modified existing files.
References
- GEEKOM A9 Mega specifications
- Ubuntu 26.04 LTS downloads and checksums
- Ubuntu Desktop installation documentation
- Linux USB4 / Thunderbolt networking
- Netplan file security
- Netplan try and rollback caveats
- AMD ROCm installer and OS selection
- AMD Ryzen AI Max memory and kernel guidance
- DS4 for AMD Strix Halo
- DS4 pipeline parallelism
- DS4 server and API
- DeepSeek V4 Flash base model
- jedisct1 GGUF and published SHA-256