SmolBSD
smolBSD is a tiny BSD UNIX (NetBSD) system creation tool, primarily aimed at building modern, lightweight, fast micro VMs
Install / Use
/learn @NetBSDfr/SmolBSDREADME
smolBSD
build your own minimal BSD UNIX system
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.
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
curlgitbmakeif running on Linux or macOS,makeon NetBSDqemu-system-x86_64,qemu-system-i386orqemu-system-aarch64depending on destination architecturesudoordoasnm(not used / functional on macOS)bsdtaron Linux (install withlibarchive-toolson Debian and derivatives,libarchiveon Arch)sgdiskon Linux for GPT bootlsofjqforsmoler.shsocatfor control socket (optional)picocomfor 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 servicesDockerfileexamplesMakefilethe entrypoint for image creation, called by[b]makemkimg.shimage creation script, should not be called directlystartnb.shstarts a NetBSD virtual machine usingqemu-system-x86_64orqemu-system-aarch64sets/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 assets.
A service is the base unit of a smolBSD microvm, it holds the necesary pieces to build a BSD system from scratch.
servicestructure:
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.shwhich will be executed bymkimg.shat 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 anetc/rcfile, which defines what is started at vm's boot. This is executed by the microvm. - Image specifics COULD be added in
make(1)format inoptions.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.mkfor 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-Pflag to spawn a realptyinstead of QEMU'sstdio.
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
ARCHvariable to specify an architecture to build your image for, the default is to build for the current architecture.
[!Note] In the following examples, replace
bmakebymakeif 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
ext2orffssuch 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
node-connect
349.7kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
109.7kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
349.7kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
349.7kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
