Hey tech adventurers! 👋
What if the hardware you already own could become part of your homelab?
That spare Linux box. An old Mac. A mini PC sitting under the TV.
Or, in my case, my wife’s Steam Deck. 😅
She can’t play 24/7, so when the Deck is idle, I figured its CPU might as well do something useful.
So I installed BarkVisor on SteamOS and turned it into another Device in my Home. It can run VMs, join my other Mac and Linux machines, and even run small local AI models with Ollama.
And yes, it still plays games. I’m not that terrible of a husband.
This post is the “I actually did it on a Steam Deck” walkthrough: practical, step-by-step, and no kernel seminar.
The bigger idea, though, is simple:
You probably already have a machine that could run BarkVisor.
| Role | Machine | Listens |
|---|---|---|
| Home (UI + control) | Mac/Linux on the LAN | :7777 HTTP,:7778 mTLS |
| Device (this tutorial) | Steam Deck (or similar SteamOS / handheld Linux) | :7777 API only,:7778 agent, Ollama:11434 |
Example LAN: Home 192.168.10.10, Deck 192.168.8.133.
You never open the Deck’s :7777 in a browser. Pair once. Then lives in BarkVisor.
Same class of machine: Steam Deck and Lenovo Legion Go–style handhelds running SteamOS / Arch-ish Linux. The unlock + pacman bits below are SteamOS / Deck-specific. Adjust paths (/home/deck) if your user isn’t deck.
Switch to Desktop Mode. Set a sudo password if you haven’t (passwd).
SteamOS root is tiny (~5GB). BarkVisor, models, and VM disks go under /home. Do not fill the root partition. Future-you will thank present-you.
Unlock the OS and trust SteamOS package keys (once — when pacman complains about unknown trust / GitLab CI Package Builder):
sudo steamos-readonly disable
sudo pacman-key --init
sudo pacman-key --populate archlinux
sudo pacman-key --populate holo
sudo pacman-key --lsign-key 889B5EBDDD505A683621900DAF1D2199EF0A3CCF
Install the VM stack. Arch/SteamOS splits QEMU — qemu-base alone is not enough for BarkVisor’s virtio-gpu-pci, and cloud-init needs mkisofs from cdrtools:
sudo pacman -S qemu-base edk2-ovmf \
qemu-hw-display-virtio-gpu qemu-hw-display-virtio-gpu-pci \
cdrtools swtpm
Sanity check (you want a line with virtio-gpu-pci and a writable /dev/kvm):
command -v qemu-system-x86_64 qemu-img mkisofs
qemu-system-x86_64 -device help | grep virtio-gpu-pci
ls /usr/share/edk2/x64/OVMF_CODE.4m.fd
ls -l /dev/kvm
Do not pipe install.sh into sudo on SteamOS. Use the Linux tarball under home. Agent mode = no SPA on the Deck. The Deck is a worker, not a kiosk.
Current release at time of writing: 1.0.0-alpha.3 (check GitHub releases if you’re reading this from the future).
VER=1.0.0-alpha.3 # or whatever current release is
PREFIX="$HOME/.local/opt/barkvisor"
mkdir -p "$PREFIX" "$HOME/.local/share/barkvisor" "$HOME/.local/bin" \
"$HOME/.config/barkvisor" "$HOME/.config/systemd/user"
cd /tmp
curl -fL -O "https://github.com/pmdroid/barkvisor/releases/download/v${VER}/barkvisor-${VER}-linux-x86_64.tar.gz"
curl -fL -O "https://github.com/pmdroid/barkvisor/releases/download/v${VER}/barkvisor-${VER}-linux-x86_64.tar.gz.sha256"
sha256sum -c "barkvisor-${VER}-linux-x86_64.tar.gz.sha256"
tar -xzf "barkvisor-${VER}-linux-x86_64.tar.gz"
SRC="barkvisor-${VER}-linux-x86_64/root/usr/local"
install -m 0755 "$SRC/bin/barkvisor" "$PREFIX/bin/barkvisor"
ln -sfn barkvisor "$PREFIX/bin/barkvisor-agent"
cp -a "$SRC/lib/barkvisor" "$PREFIX/lib/"
CLI wrapper (sets the bundled Swift LD_LIBRARY_PATH — yes, Swift on a Steam Deck, we’re living deliciously):
cat > "$HOME/.local/bin/barkvisor" << 'EOF'
#!/usr/bin/env bash
PREFIX="${HOME}/.local/opt/barkvisor"
export LD_LIBRARY_PATH="${PREFIX}/lib/barkvisor/swift:${PREFIX}/lib/barkvisor/compat${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
exec -a "$(basename "$0")" "${PREFIX}/bin/barkvisor" "$@"
EOF
chmod +x "$HOME/.local/bin/barkvisor"
ln -sfn barkvisor "$HOME/.local/bin/barkvisor-agent"
grep -q '.local/bin' ~/.bashrc || echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
export PATH="$HOME/.local/bin:$PATH"
Env + user systemd service (data on home, no frontend dir):
Click to expand: barkvisor.env + barkvisor-agent.service
cat > "$HOME/.config/barkvisor/barkvisor.env" << EOF
BARKVISOR_PORT=7777
BARKVISOR_DATA_DIR=$HOME/.local/share/barkvisor
BARKVISOR_SOCKET_DIR=$XDG_RUNTIME_DIR/barkvisor
HOME=$HOME
LD_LIBRARY_PATH=$HOME/.local/opt/barkvisor/lib/barkvisor/swift:$HOME/.local/opt/barkvisor/lib/barkvisor/compat
EOF
cat > "$HOME/.config/systemd/user/barkvisor-agent.service" << EOF
[Unit]
Description=BarkVisor API-only Device daemon
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
WorkingDirectory=$HOME/.local/share/barkvisor
EnvironmentFile=-$HOME/.config/barkvisor/barkvisor.env
ExecStart=$HOME/.local/opt/barkvisor/bin/barkvisor-agent
Restart=on-failure
RestartSec=3
TimeoutStopSec=8
KillMode=mixed
RuntimeDirectory=barkvisor
LimitNOFILE=65536
[Install]
WantedBy=default.target
EOF
systemctl --user daemon-reload
systemctl --user enable --now barkvisor-agent.service
curl -sS http://127.0.0.1:7777/api/health
barkvisor-agent doctor
Health should be "status":"ok". GET http://127.0.0.1:7777/ returning JSON 404 is correct for agent-only. You’re not broken. You’re disciplined.
SteamOS / Desktop Mode note: Desktop Mode already has a user session, so the service starts with that session. It will not start in Game Mode unless you enable lingering (loginctl enable-linger deck, needs root).
On Home (the machine that already finished BarkVisor setup):
http://<home-ip>:7777
192.168.10.10) barkvisor://pair/v1?code=…&host=…&port=7777&agentPort=7778&hostId=…&fp=…
The short printed code is not enough. Ask me how I know. 😅
On the Deck, with the agent already up:
Click to expand: join with full barkvisor:// offer
barkvisor-agent join --code 'barkvisor://pair/v1?code=…&host=192.168.10.10&port=7777&agentPort=7778&hostId=…&fp=…'
Or set BARKVISOR_JOIN_CODE in barkvisor.env before first start only.
With a current build, Home should hop immediately. Refresh Home: the Deck appears reachable, workload counts populate. Join talks HTTP to Home :7777; ongoing control is mTLS to the Deck :7778.
Confirm on the Deck:
Click to expand: confirm 7777 + 7778 listening
ss -ltn | grep -E '7777|7778'
Want Home’s Models UI to point at the handheld? Keep Ollama under ~/.local too — not /usr/local.
mkdir -p ~/.local ~/.ollama/models
curl -fsSL https://ollama.com/download/ollama-linux-amd64.tar.zst \
| tar --zstd -xf - -C ~/.local
Listen on all interfaces so Home and guest VMs can reach it. Example user unit knobs:
systemctl --user enable --now ollama.service
curl -sS http://127.0.0.1:11434/api/version
curl -sS http://192.168.8.133:11434/api/version # use your Deck LAN IP
ollama pull llama3.2 # example
Steam Deck iGPU is ignored unless OLLAMA_IGPU_ENABLE=1. Then from Home: Settings / Models pointed at http://<deck-ip>:11434. Guest VMs on NAT see the Deck as 10.0.2.2:11434.
On Home, with the Deck selected (or Create VM → this Device):
NAT SSH: add a port forward (e.g. host 2222 → guest 22) on that VM, then from your laptop:
ssh -p 2222 ubuntu@192.168.8.133
(Guest default user is ubuntu if you used the Ubuntu template. Swap in your Deck’s LAN IP.)
systemctl --user status barkvisor-agent ollama
journalctl --user -u barkvisor-agent -f
barkvisor-agent doctor
du -sh ~/.local/share/barkvisor/{disks,images,efivars}
Home is the UI: VMs, VNC, serial, images, pairing. The Deck just works (or complains in journalctl).
Good: extra QEMU capacity on the LAN. Ollama on the Deck iGPU (~16GB visible VRAM on a Z2 Go-class machine). Agent-only so you’re not burning cycles on a SPA nobody will open.
| Symptom | Check |
|---|---|
| Home: TLS handshake failed | :7778 up; join completed; restartbarkvisor-agent once if you’re on an older build |
virtio-gpu-pci is not a valid device |
pacman -S qemu-hw-display-virtio-gpu qemu-hw-display-virtio-gpu-pci |
mkisofs /genisoimage not found |
pacman -S cdrtools |
| BdsDxe no bootable option | Cloud clone must leave GPT EFI PART at LBA 1; never run sgdisk on a.qcow2 file |
| pacman “unknown trust” | pacman-key --lsign-key 889B5EBDDD505A683621900DAF1D2199EF0A3CCF |
| Ollama only on localhost | OLLAMA_HOST=0.0.0.0:11434 and restart the user unit |
Closing / pizza 🍕
Steam Deck as a headless BarkVisor Device: agent tarball in $HOME, SteamOS QEMU plus virtio-gpu and cdrtools, pair with a full barkvisor:// offer, optional Ollama on 0.0.0.0:11434. Control everything from Home on the LAN. The Deck just runs VMs and models.
Was this a responsible use of a gaming handheld? Debatable. Does it make my LAN slightly more overbuilt? Absolutely. Built with ❤️ and questionable infrastructure decisions.
P.S. Don’t want to click through every step yourself? Paste this post to your agent. They’ll have no problem doing it. 🤖
More: barkvisor.dev · github.com/pmdroid/barkvisor