Modern, open-source management platform for FreeBSD managing Virtual Machines (Bhyve), Jails, and ZFS storage.
What is Sylve?
Sylve is a modern, open-source management platform for FreeBSD: Bhyve VMs, jails, ZFS, and networking behind one web UI. It manages the host from inside its own jail, so it needs host access a normal container never gets -- kernel modules, devfs entries like /dev/pf and /dev/vmm, ZFS delegation, and allow.vmm. Both deploy methods below wire that up for you.
Version Tags
Both tags ship Sylve's prebuilt native-FreeBSD binary from a GitHub release; they differ only in which release they track.
1. Prepare the host (one time). Kernel modules are loaded automatically at jail start via load-kld labels; only the boot-only kern.racct tunable touches loader.conf:
pkginstall-yappjailsysutils/py-director
["$(sysctl-nkern.racct.enable)"="1"]||echo'kern.racct.enable="1"'>>/boot/loader.conf
# reboot if `sysctl -n kern.racct.enable` is still 0 (Sylve requires racct)sysrcappjail_enable=YES
options:# Equivalent to 'network_host: host'.# Use it only if you don't have problems with Sylve managing your pf(4).#- alias:#- ip4_inherit:## The jail will use its own network stack without touching with the host's;# in addition, AppJail will configure an IPv4 address that you can use to# communicate with Sylve via the jail's IPv4 address or hostname (if you# have enabled DNS in AppJail).-virtualnet:':<random>default'-nat:services:sylve:name:sylveoptions:-from:ghcr.io/daemonless/sylve:nightly-template:!ENV'${PWD}/sylve-template.conf'-container:'args:--pull'-label:'load-kld:1'-label:'load-kld.load-vmm:vmm'-label:'load-kld.load-if-bridge:if_bridge'-label:'load-kld.load-cryptodev:cryptodev'-label:'load-kld.load-if-epair:if_epair'-label:'load-kld.load-nullfs:nullfs'-label:'load-kld.load-netlink:netlink'-label:'load-kld.load-nlsysevent:nlsysevent'-label:'load-kld.load-nmdm:nmdm'-label:'load-kld.load-pf:pf'-label:'load-kld.load-pflog:pflog'-label:'load-kld.load-if-wg:if_wg'-label:'load-kld.load-linux:linux'-label:'load-kld.load-linux.module:linuxelf'-label:'load-kld.load-linux64:linux64'-label:'load-kld.load-linux64.module:linux64elf'-label:'load-kld.load-pty:pty'-label:'load-kld.load-linprocfs:linprocfs'-label:'load-kld.load-linsysfs:linsysfs'-label:'load-kld.load-ctl:ctl'-label:'load-kld.load-iscsi:iscsi'-device:'include$devfsrules_hide_all'-device:'include$devfsrules_unhide_basic'-device:'include$devfsrules_unhide_login'-device:'include$devfsrules_jail'-device:'include$devfsrules_jail_vnet'-device:'pathzfsunhide'-device:'pathzvolunhide'-device:"path'zvol/*'unhide"-device:"path'zvol/*/*'unhide"-device:"path'zvol/*/*/*'unhide"-device:"path'zvol/*/*/*/*'unhide"-device:"path'zvol/*/*/*/*/*'unhide"-device:'pathshmunhide'-device:'pathpfunhide'-device:'pathpflogunhide'-device:'pathbpfunhide'-device:"path'bpf*'unhide"-device:'pathvmmunhide'-device:"path'vmm/*'unhide"-device:'pathvmm.iounhide'-device:"path'vmm.io/*'unhide"-device:'pathvmmctlunhide'-device:"path'nmdm*'unhide"-device:"path'tap*'unhide"-device:'pathmemunhide'-device:'pathkmemunhide'-device:'pathpciunhide'-device:'pathiounhide'-device:'pathcamunhide'-device:"path'cam/ctl'unhide"-device:"path'da*'unhide"-device:"path'ada*'unhide"-device:"path'nda*'unhide"-device:"path'pass*'unhide"-device:"path'xpt*'unhide"-device:"path'nvme*'unhide"-device:'pathiscsiunhide'volumes:-sylve-data:/var/db/sylvevolumes:sylve-data:device:!ENV'${SYLVE_DATA_LOCATION}'
1. Prepare the host (one time). Generate the setup script, review it, then run it -- it loads the kernel modules, adds a devfs ruleset, creates the ZFS dataset, and installs the OCI createRuntime hook (ocijail can't express devfs rulesets or ZFS delegation through annotations). Each step asks before running; already-configured steps are skipped:
podmanrun--rmghcr.io/daemonless/sylve:latesthost-setup>sylve-setup.sh
lesssylve-setup.sh# review exactly what it will changeshsylve-setup.sh# or: sh sylve-setup.sh -y
If it reports that kern.racct needs a reboot, reboot before continuing (Sylve requires it).
2. Create the deployment files. init writes compose.yaml and .env into the current directory (it refuses to overwrite existing files without --force):
The jail's hostname (node-identity check). Podman: hostname: in compose.yaml.
SYLVE_DATA_LOCATION
--
Host path for Sylve's data (/var/db/sylve in the jail).
SYLVE_DATASET
zroot/sylve
ZFS dataset delegated to Sylve. AppJail: ${dataset} in sylve-template.conf.
TZ
System default
Timezone.
Ports
Port
Service
Description
8181
sylve
Web UI (HTTPS)
Network Mode
The Podman path shares the host network (network_mode: host) so Sylve manages the host's interfaces, firewall, and VMs directly. The AppJail path defaults to its own vnet + NAT to avoid clobbering the host's pf(4) rules -- uncomment alias/ip4_inherit in appjail-director.yml for host networking instead.
FreeBSD-Specific Notes
selected_node_not_found
If requests fail with selected_node_not_found, Sylve's EnsureCorrectHost check is comparing its configured hostname against the one you're browsing to -- set the jail's hostname to the name you reach it at.
Never bind-mount /dev
A nullfs /dev (-v /dev:/dev) makes Bhyve guest-memory mmap fail with ENXIO (Unable to setup memory (6)) -- VM creation succeeds but the guest never boots. Both deploy methods mount a real devfs via a ruleset; don't override it.
Undo (Podman host-setup)
sh sylve-setup.sh --undo removes Sylve's OCI hook and devfs ruleset. It never touches your ZFS dataset (it prints the zfs destroy command if you want it gone).