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. What you end up with 🍕 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. 1. Prep the Deck (Desktop Mode) 🛠️ 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): Click to expand: SteamOS unlock + pacman keys 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: Click to expand: QEMU + OVMF + cdrtools + swtpm 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): Click to expand: host sanity checks 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 2. Install BarkVisor agent only (no UI) 🐕 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). Click to expand: download + verify + install agent under ~/.local 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/" # skip share/barkvisor/frontend — agent mode, no SPA CLI wrapper (sets the bundled Swift LD_LIBRARY_PATH — yes, Swift on a Steam Deck, we’re living deliciously): Click to expand: ~/.local/bin/barkvisor wrapper + PATH 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). 3. Pair the Deck to Home 🔗 On Home (the machine that already finished BarkVisor setup): Open http://<home-ip>:7777 Settings → Pairing → Add a Device Pick the LAN address the Deck can reach (e.g. 192.168.10.10) Copy the full offer: 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' # LISTEN 0.0.0.0:7777 and 0.0.0.0:7778 4. Ollama on the Deck (optional) 🧠 Want Home’s Models UI to point at the handheld? Keep Ollama under ~/.local too — not /usr/local. Click to expand: install Ollama under ~/.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: Click to expand: ollama.service env hints + start # ~/.config/systemd/user/ollama.service # Environment=OLLAMA_HOST=0.0.0.0:11434 # Environment=OLLAMA_MODELS=/home/deck/.ollama/models # Environment=OLLAMA_IGPU_ENABLE=1 # ExecStart=/home/deck/.local/bin/ollama serve 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. 5. First Ubuntu VM from Home 🚀 On Home, with the Deck selected (or Create VM → this Device): Images — download Ubuntu 24.04 LTS (or 26.04) cloud image for x86_64. Wait until status is ready. Create VM / Ubuntu Server template. Place it on the steamdeck Device. Disk 16–64 GB; NAT is enough. Create, wait until provisioning finishes (clone + cloud-init ISO). Start. 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.) 6. Everyday commands (on the Deck) 🧰 Click to expand: status, logs, doctor, disk usage systemctl --user status barkvisor-agent ollama journalctl --user -u barkvisor-agent -f barkvisor-agent doctor # disks / images live here 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 at / not great at ⚖️ 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. If something looks wrong 🧯 Symptom Check Home: TLS handshake failed :7778 up; join completed; restart barkvisor-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