nova

module
v0.0.0-...-9b5f04d Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 30, 2026 License: MIT

README

Nova

A modern, lightning-fast, cloud-native replacement for Vagrant. Single binary, rootless by default, built on OS-native hypervisors.

Nova manages local virtual machines using declarative HCL configuration, OCI image distribution, and cloud-init provisioning — the same tools and patterns you use in production.

Features

  • Single binary, zero daemons — one Go executable, no background services
  • Rootless by default — user-space networking and hypervisor APIs, no sudo
  • OS-native hypervisors — Apple Virtualization.framework on macOS, QEMU/KVM on Linux
  • OCI image distribution — pull VM images from container registries (GHCR, Docker Hub)
  • Cloud-init provisioning — standard cloud-config YAML, just like production clouds
  • Shell provisioners — run scripts and inline commands over SSH after boot
  • Golden image export — sysprep and export VMs as standalone images (replaces Packer)
  • Declarative HCL config — variables, interpolation, multi-node clusters
  • Multi-node clusters — spin up networked node groups with a single command
  • Configurable users — define SSH users with keys, password hashes, and groups
  • Network chaos engineering — inject latency, packet loss, and partitions between nodes
  • Interactive TUI — real-time monitoring dashboard with interactive network controls
  • Cluster snapshots — save/restore/share full cluster state via OCI registries or portable archives
  • Cross-architecture — run x86_64 VMs on ARM Macs via Rosetta 2
  • Lua plugin system — extend Nova with custom DNS resolvers, secret injectors, and lifecycle hooks

Quick Start

# Initialize a new project
nova init

# Edit nova.hcl to configure your VM, then:
nova up

# SSH into the VM
nova shell

# Check status
nova status

# Tear it down
nova down

Installation

Prerequisites
  • Go 1.22+
  • qemu-img — for disk overlays and snapshots
    • macOS: brew install qemu
    • Linux: apt install qemu-utils or dnf install qemu-img
Linux
go install github.com/tripleclabs/nova/cmd/nova@latest
macOS

macOS requires the com.apple.security.virtualization entitlement to use Virtualization.framework. Install and codesign in one block:

go install github.com/tripleclabs/nova/cmd/nova@latest
codesign --force -s - --entitlements <(cat <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"><dict>
    <key>com.apple.security.virtualization</key><true/>
</dict></plist>
EOF
) $(go env GOPATH)/bin/nova

The binary lands in $GOPATH/bin/nova (usually ~/go/bin/nova). Make sure that's on your $PATH.

Shell completions
# bash
nova completion bash > /etc/bash_completion.d/nova

# zsh
nova completion zsh > "${fpath[1]}/_nova"

# fish
nova completion fish > ~/.config/fish/completions/nova.fish

Images

Nova has built-in support for common Linux distributions. Just use the shorthand in nova.hcl and Nova will pull the official cloud image automatically on nova up:

vm {
  image = "ubuntu:24.04"   # or ubuntu:22.04, alpine:3.21, alpine:3.20
}

No manual downloading required. The image is cached locally after the first pull.

Pre-fetching

To download an image ahead of time (e.g. before going offline):

nova image get ubuntu:24.04
nova image get alpine:3.21
Custom images

Package any local qcow2 or raw disk image into the nova cache:

nova image build myimage.qcow2 --tag nova.local/myimage:latest --os ubuntu

Use --push to also upload it to a registry so your team can pull it automatically:

nova image build myimage.qcow2 --tag ghcr.io/myorg/myimage:latest --os ubuntu --push

Once pushed, anyone can reference ghcr.io/myorg/myimage:latest in nova.hcl and it will be pulled on nova up.

Managing the cache
nova image list                        # show all cached images
nova image rm nova.local/ubuntu:24.04  # remove an image

Configuration

Nova uses HCL configuration files. Run nova init to generate a starter config.

Single VM
variable "project_name" {
  default = "my-project"
}

vm {
  name   = var.project_name
  image  = "ubuntu:24.04"
  cpus   = 2
  memory = "2G"

  port_forward {
    host  = 8080
    guest = 80
  }

  shared_folder {
    host_path  = "."
    guest_path = "/workspace"
  }
}
Multi-Node Cluster
defaults {
  image  = "ubuntu:24.04"
  cpus   = 2
  memory = "2G"
}

network {
  subnet = "10.0.0.0/24"
}

node "control" {
  cpus   = 4
  memory = "8G"
  port_forward {
    host  = 6443
    guest = 6443
  }
}

node "worker-1" {}
node "worker-2" {}

Nodes automatically get static IPs from the subnet and /etc/hosts entries for name resolution.

Cloud-Init

Place a cloud-config.yaml alongside your nova.hcl:

#cloud-config
package_update: true
packages:
  - curl
  - git
runcmd:
  - echo "Hello from Nova" > /tmp/hello

Nova merges your config with its own defaults (SSH key injection, hostname, nova user) without clobbering your entries.

Shell Provisioners

Run scripts and commands over SSH after the VM boots. Provisioners run during nova up, not just during export.

# Top-level provisioners run on ALL nodes first
provisioner "shell" {
  inline = [
    "apt-get update",
    "apt-get install -y nginx curl",
  ]
}

node "control" {
  image = "ubuntu:24.04"

  # Node-level provisioners run after top-level ones
  provisioner "shell" {
    script  = "./scripts/control-plane.sh"
    timeout = "10m"
  }
}

Provisioner options:

Field Description
script Path to a local script to upload and execute (mutually exclusive with inline)
inline List of commands to run in a single SSH session (joined with &&)
timeout Max execution time (default: 5m)
env Map of environment variables to pass to the script
Users

Define a user to create alongside the internal nova user. When a user block is present, nova shell connects as that user.

user {
  name    = "deploy"
  ssh_key = file("~/.ssh/id_ed25519.pub")
  groups  = ["sudo", "docker"]
  shell   = "/bin/bash"
}

vm {
  image = "ubuntu:24.04"
}

User options:

Field Description
name Username (required, cannot be nova or root)
ssh_key SSH public key string
password_hash Pre-hashed password (crypt(3) format, use mkpasswd to generate)
groups Additional groups for the user
shell Login shell (defaults to distro default)

At least one of ssh_key or password_hash is required. The user block can be placed at top-level (applies to all nodes) or inside vm/node blocks (node-level overrides top-level).

Exporting Images

Nova can replace Packer for building golden VM images. The workflow: define a VM, provision it, then export a standalone disk image.

nova up                                           # Boot and provision
nova export myvm                                  # Export as qcow2 (default)
nova export myvm --format vmdk -o golden.vmdk     # Export as VMware image
nova export myvm --snapshot pre-export            # Snapshot before export for safety
nova export myvm --zero                           # Zero free space for smaller images

Supported output formats:

Format Target Hypervisors
qcow2 (default) KVM, libvirt, Proxmox
raw Direct dd-to-disk, Apple VZ
vmdk VMware ESXi, Workstation, Fusion
vhdx Microsoft Hyper-V
ova VMware vSphere/ESXi, Proxmox (includes OVF descriptor)

Export automatically runs sysprep to clean machine-specific state (machine-id, SSH host keys, cloud-init state, DHCP leases, logs) so the image boots cleanly in a new environment. The cleanup is OS-aware — Ubuntu/Debian, Alpine, and Fedora each get appropriate treatment.

A user block is required for export — this prevents the internal nova user from leaking into production images. Use --no-clean to bypass this for debugging.

CLI Reference

Command Description
nova init Generate default nova.hcl and cloud-config.yaml
nova up Create and start VMs from configuration
nova down [name] Gracefully stop a VM
nova status Show status of all managed VMs
nova destroy [name] Force kill a VM and delete all data
nova shell [name] SSH into a running VM (uses configured user if set)
nova shell -c "cmd" Run a command in the VM
nova export [name] Export a VM as a standalone disk image
nova image get <distro:version> Pre-fetch a known distro image
nova image build <file> --tag <ref> Package a local disk image into the cache
nova image list List cached images
nova image rm <ref> Remove a cached image
nova link degrade a b Add latency/loss between nodes
nova link partition a b Hard partition two nodes
nova link heal a b Remove conditions between nodes
nova link status Show active network conditions
nova link reset Clear all network conditions
nova monitor Launch interactive TUI dashboard
nova snapshot save <name> Snapshot all machine disks
nova snapshot restore <name> Revert to a saved snapshot
nova snapshot list List saved snapshots
nova snapshot delete <name> Delete a snapshot
nova snapshot export <name> Export snapshot as portable archive
nova snapshot import <file> Import snapshot from archive
nova snapshot push <name> <ref> Push snapshot to OCI registry
nova snapshot pull <ref> Pull snapshot from OCI registry
nova version Print version

Network Chaos Engineering

Degrade the link between two nodes:

nova link degrade control worker-1 --latency 100ms --jitter 20ms --loss 5%

Create a hard network partition:

nova link partition worker-1 worker-2

Heal a link:

nova link heal worker-1 worker-2

Launch the interactive TUI to visualize and control network conditions in real time:

nova monitor

Snapshots

Save the state of your entire cluster (instant, uses qcow2 CoW snapshots):

nova snapshot save before-migration

Restore it later:

nova snapshot restore before-migration

Share cluster states with your team — via portable files or OCI registries:

# Portable file (no registry needed)
nova snapshot export before-migration -o before-migration.novasnap
# scp, airdrop, USB, whatever
nova snapshot import before-migration.novasnap

# Or via OCI registries
nova snapshot push before-migration ghcr.io/myteam/nova-snaps:bug-123
nova snapshot pull ghcr.io/myteam/nova-snaps:bug-123

Plugins

Nova has a Lua plugin system. Place .lua files in ~/.nova/plugins/ and they'll be loaded automatically.

Example: Custom DNS Resolver
-- ~/.nova/plugins/dns-resolver.lua
local records = {
    ["api.nova"]   = "10.0.0.10",
    ["db.nova"]    = "10.0.0.20",
}

nova.register("dns_resolve", function(hostname)
    return records[hostname]
end)
Available Hooks
Hook Arguments Return
dns_resolve hostname IP string or nil
on_vm_start vm_name (ignored)
on_vm_stop vm_name (ignored)
on_snapshot snapshot_name (ignored)
on_link node_a, node_b, action (ignored)
Host Functions
Function Description
nova.log(msg) Log a message from your plugin
nova.register(hook, fn) Register a hook handler

See examples/plugins/ for complete examples.

Architecture

nova (single binary)
 |
 +-- internal/config      HCL parser, multi-node schema, validation
 +-- internal/image       OCI pull/cache, CoW disks, snapshot push/pull
 +-- internal/hypervisor  HAL interface, Apple VZ engine, QEMU engine
 +-- internal/cloudinit   SSH keygen, cloud-config merging, ISO builder
 +-- internal/network     Port forwarding, chaos conditioning
 +-- internal/state       Machine state store, locking
 +-- internal/vm          Orchestrator (ties everything together), export pipeline
 +-- internal/provisioner Shell provisioner execution over SSH
 +-- internal/sysprep     OS-aware image cleanup for export
 +-- internal/snapshot    Cluster snapshots, pack/unpack, portable archives
 +-- internal/plugin      Lua plugin runtime, hook dispatch
 +-- internal/cmd         Cobra CLI commands, TUI monitor

Requirements

  • macOS (Apple Silicon or Intel): macOS 13+ for Virtualization.framework
  • Linux: QEMU/KVM with qemu-system and qemu-img
  • Both: qemu-img for CoW disk overlays and snapshots

Development

make build    # Build the binary
make test     # Run all tests
make clean    # Remove build artifacts

License

MIT

Directories

Path Synopsis
cmd
nova command
internal
cloudinit
Package cloudinit handles SSH key generation, cloud-init config merging, and NoCloud ISO creation.
Package cloudinit handles SSH key generation, cloud-init config merging, and NoCloud ISO creation.
cmd
Package cmd client.go provides shared gRPC client helpers for CLI commands that route through the daemon.
Package cmd client.go provides shared gRPC client helpers for CLI commands that route through the daemon.
config
Package config parses and validates nova.hcl configuration files.
Package config parses and validates nova.hcl configuration files.
daemon
Package daemon implements the Nova gRPC daemon server.
Package daemon implements the Nova gRPC daemon server.
distro
Package distro provides a registry of known Linux distributions with their official cloud image download URLs and cloud-init configuration profiles.
Package distro provides a registry of known Linux distributions with their official cloud image download URLs and cloud-init configuration profiles.
hypervisor
Package hypervisor defines the abstraction layer for VM lifecycle management.
Package hypervisor defines the abstraction layer for VM lifecycle management.
image
Package image handles OCI image pulling, caching, and disk management.
Package image handles OCI image pulling, caching, and disk management.
network
Package network provides user-space port forwarding and network utilities.
Package network provides user-space port forwarding and network utilities.
plugin
Package plugin implements Nova's Lua-based plugin system.
Package plugin implements Nova's Lua-based plugin system.
provisioner
Package provisioner implements post-boot provisioning of VMs.
Package provisioner implements post-boot provisioning of VMs.
snapshot
Package snapshot implements cluster-level snapshot save, restore, list, delete, and OCI push/pull ("time travel").
Package snapshot implements cluster-level snapshot save, restore, list, delete, and OCI push/pull ("time travel").
state
Package state manages Nova's local state directory (~/.nova/).
Package state manages Nova's local state directory (~/.nova/).
sysprep
Package sysprep prepares a VM for export by removing machine-specific state so the image boots cleanly in a new environment.
Package sysprep prepares a VM for export by removing machine-specific state so the image boots cleanly in a new environment.
vm
Package vm provides the high-level orchestration that ties together configuration, image management, hypervisor, and state.
Package vm provides the high-level orchestration that ties together configuration, image management, hypervisor, and state.
pkg
novatest
Package novatest provides a Go test SDK for Nova.
Package novatest provides a Go test SDK for Nova.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL