Skip to content

SynVirt Build Guide

Synced read-only from /home/synnet/mirrors/synvirt-product/docs/build.md. Edit at the source, not here.

Last updated: 2026-05-01


  1. Prerequisites
  2. Compiling the Daemon
  3. Running in Dev Mode
  4. Building the ISO
  5. Iterating against a running appliance
  6. Troubleshooting

All compilation happens on a Debian 13 Trixie host — the same distro the live ISO targets, so the dev environment and the shipping runtime stay binary-compatible.

Terminal window
sudo apt update && sudo apt install -y \
build-essential \
curl \
git \
pkg-config \
libssl-dev \
xorriso \
isolinux \
syslinux-common \
cpio \
gzip \
rsync \
live-build \
sshpass
Terminal window
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source "$HOME/.cargo/env"
rustup toolchain install 1.95
rustc --version # should print rustc 1.95.x

The repository pins the toolchain in rust-toolchain.toml; rustup will automatically select the right version whenever you invoke cargo inside the project directory.

Optional: local VM runtime for ISO smoke-tests

Section titled “Optional: local VM runtime for ISO smoke-tests”

Any hypervisor that can boot both BIOS-legacy and strict-UEFI firmware works. The recommended default on Debian 13 is native QEMU with UEFI (ovmf) because it reuses the same codebase SynVirt ships — install with sudo apt install -y qemu-system-x86 ovmf.


Terminal window
# Debug build (faster compile, larger binary, unoptimised)
cargo build -p synvirt-daemon
# Release build (slower compile, optimised)
cargo build -p synvirt-daemon --release

Build output locations:

Build type Binary path
Debug target/debug/synvirt-daemon
Release target/release/synvirt-daemon

The project is a Cargo workspace. Cargo.toml at the root lists the full crate set; CLAUDE.md §2 documents each crate’s role.


Terminal window
cargo run -p synvirt-daemon -- --dev

Then open https://localhost:8443 in your browser and accept the self-signed certificate warning (expected in dev mode).

Behaviour Dev (--dev) Production
Listen port 8443 443
TLS certificate Self-signed, auto-generated Supplied via config / env
Static assets path crates/daemon/assets/ /opt/synvirt/web-ux/
Log format Pretty (human-readable) JSON structured
Default log level debug info
Terminal window
# Override port
SYNVIRT_PORT=9443 cargo run -p synvirt-daemon -- --dev
# Override log level
SYNVIRT_LOG=trace cargo run -p synvirt-daemon -- --dev

Terminal window
cd iso-builder
./build.sh

The script:

  1. Compiles synvirt-daemon, synvirt-console, synvirt-boot-splash, synvirt-live, and supporting binaries in release mode.
  2. Fetches pinned upstream artefacts for the guest-tools ISO (virtio-win) into iso-builder/vendor/guest-tools/.
  3. Drives live-build through bootstrap + chroot + binary stages, reusing iso-builder/live-build/cache/ across runs so kernel + ZFS DKMS compile only once until FORCE_REBUILD=1 purges the cache.
  4. Emits iso-builder/output/SynVirt-<VERSION>-amd64.iso (hybrid BIOS-legacy + strict-UEFI) plus the sibling guest-tools.iso.

Build times:

Path Duration
First build or FORCE_REBUILD=1 30–45 minutes
Incremental rebuild (cache hit) 2–5 minutes

scripts/deploy-to-host.sh hot-swaps the daemon binary + systemd units

  • dashboard tree onto a running SynVirt node without rebuilding the ISO. Useful during active development — the full build + ISO + reinstall cycle only runs at the end of a feature.
Terminal window
SSHPASS=<password> HOST=<ip> ./scripts/deploy-to-host.sh hot

Stages:

Stage Description
inspect Report the appliance’s current release, enabled units, and active tty state.
build cargo build --release -p synvirt-daemon -p synvirt-console -p synvirt-boot-splash.
push scp the new binaries + service unit files to /tmp/ on the host.
apply Install the binaries into /opt/synvirt/bin/, reload systemd, restart the daemon.
web-ux Pack + scp + atomically replace /opt/synvirt/web-ux/.
reboot Issue a reboot and wait for ping-back.
verify Post-reboot smoke-check of tty1 ownership + active units.
all inspect → build → push → apply → web-ux → reboot → verify.
hot Fast loop for dev: build → push → apply → web-ux (no reboot).

Running guests survive the daemon restart because libvirt and QEMU own the per-VM VNC listener sockets, not the daemon. The daemon process swap is invisible to active VNC sessions; the browser WebSocket is the only thing that needs to reconnect.


Symptom: Browser shows “NET::ERR_CERT_AUTHORITY_INVALID” or similar.

Cause: The self-signed certificate is not trusted by the OS certificate store. Expected in dev mode.

Fix: Click “Advanced” → “Proceed” in Chromium-based browsers, or “Accept the Risk and Continue” in Firefox. For permanent trust, import the certificate from /etc/synvirt/tls/ into your OS trust store.


2. cargo: command not found after a fresh shell

Section titled “2. cargo: command not found after a fresh shell”

Cause: The Rust toolchain is installed under $HOME/.cargo/bin/ but the current shell has not sourced the profile snippet that adds it to PATH.

Fix:

Terminal window
source "$HOME/.cargo/env"
rustc --version

Persist by appending to ~/.profile:

Terminal window
export PATH="$HOME/.cargo/bin:$PATH"

Symptom: iso-builder/build.sh stops with a download or checksum error.

Fix: Clear the cached Debian netinstall image at iso-builder/cache/ and re-run. If a specific mirror keeps failing, edit the DEBIAN_MIRROR variable at the top of build.sh to a closer one (see https://www.debian.org/mirror/list).


Symptom: libvirt refuses to start guests, or VMs run in TCG mode (slow).

Cause: Nested virtualisation is not enabled on the outer hypervisor.

Fix: Enable nested virtualisation on the host that runs the dev VM, reboot, and confirm /dev/kvm exists on the dev VM. Dev mode works in TCG fallback for smoke-testing but performance will be unrepresentative of production.