Skip to content

Creation

Sylve creates bhyve virtual machines from common command-line flags or a complete JSON request. A VM can start with managed raw or ZVOL storage, installation media or a cloud image, a network attachment, VNC, and boot-time behavior.

List existing VMs before choosing an RID:

Terminal window
doas sylve vms list

VM RIDs are unique integers from 1 through 9999. An empty node reports No VMs found.

The initial disk must use an existing ZFS pool. Installation media and cloud images are referenced by download UUID, not by the numeric download ID:

Terminal window
doas zpool list
doas sylve downloads list --json
doas sylve switches list

Use a switch name or none during creation. Network objects and switch configuration are covered in the earlier networking guides.

Without --file, only --rid and --name are required. Omitted settings use these defaults:

Setting Default
CPU topology 1 socket, 1 core, 1 thread
RAM 1 GiB
Initial storage None
Initial network None
VNC Disabled
Start at host boot Disabled
Guest clock UTC

This minimal command creates a registered VM without disks or networking:

Terminal window
doas sylve vms create --rid 301 --name example-vm

The interactive console accepts the same named creation options without the leading sylve:

vms create --rid 301 --name example-vm

The following real example creates a 1 vCPU Alpine VM with 1 GiB of RAM, a 4 GiB managed raw disk, an attached installer ISO, VNC bound to the local host, and one interface on TTT:

Terminal window
doas sylve vms create \
--rid 301 \
--name docs-alpine \
--description "CLI documentation example" \
--cpu-sockets 1 \
--cpu-cores 1 \
--cpu-threads 1 \
--ram 1GiB \
--storage-pool zroot \
--storage-type raw \
--storage-size 4GiB \
--storage-emulation virtio-blk \
--iso 306a765d-c9d0-5d53-8a67-bd48b2e0adbe \
--switch TTT \
--network-emulation virtio \
--boot-rom uefi \
--vnc-enabled=true \
--vnc-port 5901 \
--vnc-bind 127.0.0.1 \
--vnc-resolution 1024x768 \
--vnc-wait=false \
--start-at-boot=false \
--start-order 0 \
--time-offset utc \
--json

Loki returned the identifiers of every resource created or attached:

{
"created": true,
"rid": 301,
"name": "docs-alpine",
"storageAttachmentIds": [5, 6],
"networkAttachmentIds": [3],
"macObjectIds": [12],
"generatedMacObjectIds": [12]
}

The first storage attachment is the managed raw disk. The second is the retained ISO image. Because no existing MAC object was supplied, Sylve generated MAC object 12 for network attachment 3.

A real Sylve 0.3.0 session inspecting the VM, its managed disk and ISO, and its generated network attachment.
Flag Purpose
--rid <id> Unique VM RID from 1 through 9999. Required without --file.
--name <name> VM name. Required without --file.
--description <text> Optional descriptive text.
--cpu-sockets <count> Positive CPU socket count.
--cpu-cores <count> Positive cores per socket.
--cpu-threads <count> Positive threads per core.
--ram <size> RAM using a human-readable size such as 1GiB.
--storage-pool <pool> Pool for the initial managed raw disk or ZVOL.
--storage-type <type> none, raw, or zvol.
--storage-size <size> Initial managed disk size, such as 20GiB.
--storage-emulation <type> virtio-blk, ahci-hd, or nvme.
--iso <uuid> Download UUID for an ISO or disk image.
--cloud-init-image <uuid> Download UUID for a cloud-init-capable image. Mutually exclusive with --iso.
--switch <name> Initial switch name or none.
--network-emulation <type> virtio or e1000.
--boot-rom <type> uefi, uboot, or none, subject to guest architecture.
--vnc-enabled=<bool> Explicitly enable or disable VNC.
--vnc-port <port> VNC TCP port from 1 through 65535.
--vnc-bind <address> Address on which VNC listens.
--vnc-resolution <size> VNC resolution such as 1024x768.
--vnc-password-file <path> Read the VNC password from a host file.
--vnc-wait=<bool> Wait for a VNC client before guest boot.
--start-at-boot=<bool> Start the VM when the host starts.
--start-order <number> Non-negative ordering value for host startup.
--time-offset <value> Guest clock mode: utc or localtime.

Boolean flags accept explicit true and false. This matters when a command-line flag overrides a value loaded from a JSON file.

Use --cloud-init-image instead of --iso for a download categorized as cloud-init. Cloud-init data, metadata, and network configuration are read from files on the Sylve host:

Terminal window
doas sylve vms create \
--rid 302 \
--name cloud-vm \
--storage-pool zroot \
--storage-type raw \
--storage-size 12GiB \
--storage-emulation virtio-blk \
--cloud-init-image 3936aa0f-b178-538f-b1fa-6c9abbe583e6 \
--cloud-init-data-file /root/cloud-init/user-data.yaml \
--cloud-init-metadata-file /root/cloud-init/meta-data.yaml \
--cloud-init-network-config-file /root/cloud-init/network-config.yaml \
--switch TTT \
--network-emulation virtio \
--boot-rom uefi

Paths are resolved by the daemon on the Sylve host. Prefer absolute paths, especially when the direct CLI attaches to an already-running daemon.

Use --file for CPU pinning, PCI passthrough, TPM, serial, ACPI and APIC settings, QGA, raw cloud-init content, an existing MAC object, or extra bhyve options.

{
"name": "json-vm",
"rid": 303,
"description": "Created from a strict request",
"iso": "306a765d-c9d0-5d53-8a67-bd48b2e0adbe",
"storagePool": "zroot",
"storageType": "raw",
"storageSize": 4294967296,
"storageEmulationType": "virtio-blk",
"switchName": "TTT",
"switchEmulationType": "virtio",
"macId": 13,
"cpuSockets": 1,
"cpuCores": 2,
"cpuThreads": 1,
"cpuPinning": [],
"ram": 2147483648,
"tpmEmulation": false,
"pciDevices": [],
"serial": true,
"vncEnabled": true,
"vncPort": 5903,
"vncBind": "127.0.0.1",
"vncPassword": "",
"vncResolution": "1024x768",
"vncWait": false,
"cloudInit": false,
"bootRom": "uefi",
"extraBhyveOptions": [],
"apic": true,
"acpi": true,
"ignoreUMSR": false,
"qemuGuestAgent": false,
"startAtBoot": false,
"startOrder": 0,
"timeOffset": "utc"
}

Submit the request with:

Terminal window
doas sylve vms create --file /root/vm-303.json

macId is optional. When it is omitted for a configured switch, Sylve creates a MAC object for the attachment. When it is supplied, it must identify an existing MAC object.

The decoder rejects unknown fields and multiple JSON documents. Explicit creation flags override matching fields from the file:

Terminal window
doas sylve vms create \
--file /root/vm-303.json \
--name replacement-name \
--ram 4GiB \
--vnc-enabled=false

List all VMs or inspect one RID:

Terminal window
doas sylve vms list
doas sylve vms get --rid 301
doas sylve vms get --rid 301 --json

The concise output captured from Loki is:

RID Name vCPUs RAM Networks
────────────────────────────────────────────────
301 docs-alpine 1 1 GiB 1

Inspect the resources attached during creation:

Terminal window
doas sylve vms storage list --rid 301
doas sylve vms network list --rid 301

The corresponding console forms place the RID after the leaf command:

vms get 301
vms storage list 301
vms network list 301

The storage inventory labels the raw disk as managed and the ISO as retained. Later storage and deletion guides explain how those ownership classifications affect detach and removal operations.