SkillAgentSearch skills...

SmolBSD

smolBSD is a tiny BSD UNIX (NetBSD) system creation tool, primarily aimed at building modern, lightweight, fast micro VMs

Install / Use

/learn @NetBSDfr/SmolBSD
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

<div align="center" markdown="1"> <img src="www/smolBSD.png" width=150px>

smolBSD

build your own minimal BSD UNIX system

License Stars Build Status

</div>

What is smolBSD?

smolBSD helps you create a minimal NetBSD 🚩 based BSD UNIX virtual machine that's able to boot and start a service in a couple milliseconds.

  • No prior NetBSD installation is required, a microvm can be created and started from any NetBSD, GNU/Linux, macOS system and probably more.
  • [PVH][4] boot and various optimizations enable NetBSD/amd64 and NetBSD/i386 to directly boot [QEMU][8] or [Firecracker][9] in about 10 milliseconds on 2025 mid-end x86 CPUs.
<div align="center" markdown="1">

microvm typical boot process

<img src="www/boot.png" width=400px> </div>

Usage

Requirements

  • A GNU/Linux, NetBSD or macOS operating system (might work on more systems, but not CPU accelerated)
  • The following tools installed
    • curl
    • git
    • bmake if running on Linux or macOS, make on NetBSD
    • qemu-system-x86_64, qemu-system-i386 or qemu-system-aarch64 depending on destination architecture
    • sudo or doas
    • nm (not used / functional on macOS)
    • bsdtar on Linux (install with libarchive-tools on Debian and derivatives, libarchive on Arch)
    • sgdisk on Linux for GPT boot
    • lsof
    • jq for smoler.sh
    • socat for control socket (optional)
    • picocom for console workloads (optional)
  • A x86 VT-capable, or ARM64 CPU is recommended

Lazy copypasta

Debian, Ubuntu and the like

$ sudo apt install curl git bmake qemu-system-x86_64 binutils libarchive-tools gdisk socat jq lsof picocom

macOS

$ brew install curl git bmake qemu binutils libarchive socat jq lsof picocom

Quickstart

Create a smolBSD image using a Dockerfile

📄 dockerfiles/Dockerfile.caddy:

# Mandatory, either comma separated base sets (here base and etc)
# or base image name i.e. base-amd64.img
FROM base,etc

# Mandatory, service name
LABEL smolbsd.service=caddy
# Optional image minimization to actual content
LABEL smolbsd.minimize=y
# Dockerfile doesn't support port mapping
LABEL smolbsd.publish="8881:8880"

RUN pkgin up && pkgin -y in caddy

EXPOSE 8880

CMD caddy respond -l :8880

⚙️ Build:

host$ ./smoler.sh build dockerfiles/Dockerfile.caddy

🚀 Run:

host$ ./startnb.sh -f etc/caddy.conf

✅ Test:

host$ curl -I 127.0.0.1:8881
HTTP/1.1 200 OK
Server: Caddy
Date: Fri, 23 Jan 2026 18:20:42 GMT

Dive in

Project structure

  • dockerfiles/ smolBSD services Dockerfile examples
  • Makefile the entrypoint for image creation, called by [b]make
  • mkimg.sh image creation script, should not be called directly
  • startnb.sh starts a NetBSD virtual machine using qemu-system-x86_64 or qemu-system-aarch64
  • sets/ contains NetBSD "sets" by architecture, i.e. amd64/base.tgz, evbarm-aarch64/rescue.tgz...
  • pkgs/ holds optional packages to add to a microvm, it has the same format as sets.

A service is the base unit of a smolBSD microvm, it holds the necesary pieces to build a BSD system from scratch.

  • service structure:
service
├── base
│   ├── etc
│   │   └── rc
│   ├── postinst
│   │   └── dostuff.sh
│   ├── options.mk       # Service-specific defaults
│   └── own.mk           # User-specific overrides (not in git)
├── common
│   └── basicrc
└── rescue
    └── etc
        └── rc

A microvm is seen as a "service", for each one:

  • There COULD be a postinst/anything.sh which will be executed by mkimg.sh at the end of root basic filesystem preparation. This is executed by the build host at build time
  • If standard NetBSD init(8) is used, there MUST be an etc/rc file, which defines what is started at vm's boot. This is executed by the microvm.
  • Image specifics COULD be added in make(1) format in options.mk, i.e.
$ cat service/nbakery/options.mk
# size of resulting inage in megabytes
IMGSIZE=1024
# as of 202510, there's no NetBSD 11 packages for !amd64
.if defined(ARCH) && ${ARCH} != "amd64"
PKGVERS=10.1
.endif
  • User-specific overrides COULD be added in own.mk for personal development settings (not committed to repository)

In the service directory, common/ contains scripts that will be bundled in the /etc/include directory of the microvm, this would be a perfect place to have something like:

$ cat common/basicrc
export HOME=/
export PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/pkg/bin:/usr/pkg/sbin
umask 022

mount -a

if ifconfig vioif0 >/dev/null 2>&1; then
        # default qemu addresses and routing
        ifconfig vioif0 10.0.2.15/24
        route add default 10.0.2.2
        echo "nameserver 10.0.2.3" > /etc/resolv.conf
fi

ifconfig lo0 127.0.0.1 up

export TERM=dumb

And then add this to your rc(8):

. /etc/include/basicrc

Dockerfile

If you are more experienced with Dockerfiles, smolBSD services can be generated using such configuration files; while it does not support the entirety of the [Dockerfile reference][10], the well known verbs are implemented and you can generate services configuration files using the smoler.sh script:

$ cat dockerfiles/Dockerfile.myservice
FROM base,etc

LABEL smolbsd.service=myservice

CMD ksh
$ ./smoler.sh build -y dockerfiles/Dockerfile.myservice # -y proceeds with image build
✅ basicdocker service files generated
...

ARG parameters can be overriden using --build-arg:

$ ./smoler.sh build --build-arg FOO=bar --build-arg BAR=baz dockerfiles/Dockerfile.myservice

If no -t <tag> is passed to the build command, the tag will be latest.

List existing images

host$ ./smoler.sh images
IMAGE                             SIZE                      CREATED
base-amd64:latest                 279M                 Mar 16 09:11
basic-amd64:latest                279M                 Mar 16 09:52
bsdshell-amd64:latest             55M                  Mar 23 08:50
caddy-amd64:latest                347M                 Mar 16 10:01
clawd-amd64:latest                2.1G                 Mar 17 14:56
clawd-evbarm-aarch64:latest       2.1G                 Mar 17 14:48
rescue-amd64:latest               20M                  Mar 15 16:41

Pushing and Pulling Images from an OCI Repository

smolBSD supports pushing and pulling images to/from an OCI-compliant repository thanks to the oras project. This allows for easy distribution and versioning of your micro VM images.

You can use the following commands to manage your images:

  • Push an image: ./smoler.sh push <image_file> or ./smoler.sh push <image_name>
$ ./smoler.sh push myimage-amd64:latest
  • Pull an image: ./smoler.sh pull <image_name>
$ ./smoler.sh pull myimage-amd64:latest

Images will be pulled as regular, raw images and placed in the directory they've been uploaded from, by default $(pwd)/images/.

By default, these commands interact with the official repository at ghcr.io/netbsdfr/smolbsd, you can customize the target repository by setting the SMOLREPO environment variable.

Official images are available at: https://github.com/orgs/NetBSDfr/packages

Running images docker-style

To make the experience easier for docker natives, it is also possible to start the microvms with the smoler command:

$ ./smoler.sh run bsdshell-amd64:latest -P

[!Note] If the workload needs a fully functional console (think about vim, tmux...), pass the -P flag to spawn a real pty instead of QEMU's stdio.

You can pass all the startnb.sh flags after the image name, i.e. start the microvm with 1GB memory and 2 cores:

$ ./smoler.sh run bsdshell-amd64:latest -P -m 1024 -c 2

Building images manually

In order to create a smolBSD microvm, you first need to build or fetch a microvm builder.

[!Note] You can use the ARCH variable to specify an architecture to build your image for, the default is to build for the current architecture.

[!Note] In the following examples, replace bmake by make if you are using NetBSD as the host.

  • You can create the builder image yourself if you are running GNU/Linux or NetBSD
$ bmake buildimg
  • Or simply fetch it if you are running systems that do not support ext2 or ffs such as macOS
$ bmake fetchimg

Both methods will create an images/build-<arch>.img disk image that you'll be able to use to build services.

To create a service image using the builder microvm, execute the following:

$ bmake SERVICE=nitro build

This will spawn a microvm running the build image, and will build the service specified with the SERVICE make(1) variable.

Examples

Very minimal (10MB) virtual machine - source

Create a rescue-amd64.img file for use with an amd64 kernel

$ bmake SERVICE=rescue build

Create a rescue-amd64.img file but with read-only root filesystem so the VM can be stopped without graceful shutdown. Note this is the default for rescue as set in service/rescue/options.mk

$ bmake SERVICE=rescue MOUNTRO=y build

Create a rescue-i386.img file for use with an i386 kernel.

$ bmake SERVICE=rescue ARCH=i386 build

Create a rescue-evbarm-aarch64.img file for use with an aarch64 kernel.

$ bmake SERVICE=rescue ARCH=evbarm-aarch64 build

Start the microvm

$ ./startnb.sh -k kernels/netbsd-SMOL -i images/rescue-amd64.img

Image filled with the base set on an x86_64 CPU - source

$ bmake SERVICE=base build
$ ./startnb.sh -k kernels/netbsd-SMOL -i images/base-amd64.img

Runni

Related Skills

View on GitHub
GitHub Stars627
CategoryDevelopment
Updated1h ago
Forks48

Languages

Shell

Security Score

100/100

Audited on Apr 6, 2026

No findings