Running a Docker Host under OpenBSD using vmd(8)

       920 words, 5 minutes

The OpenBSD virtual machine daemon works pretty well with Linux VMs nowadays. This was time for me to see if I could replace the Synology Docker service with some Docker host provided by vmd(8).

Setup the virtual machine(s) environment

I’m currently running OpenBSD 7.1/amd64. Read the manpage to ensure commands are still valid at the time of reading.

Enable vmd(8):

# rcctl enable vmd
# rcctl start vmd

All my vm related stuff go to a dedicated place:

# mkdir /opt/vm
# cd /opt/vm

I’m using Alpine Linux as the Docker Host and use the “Virtual” image for installation:

# ftp \

I already have a bridge(4) and a vether(4) interface for other purposes. VMs will be added to the bridge to gain network access.

I don’t want to filter on the tap(4) interface of each VMs. So the pf.conf(5) file has to be modified.

# grep tap /etc/pf.conf
pass on tap

Create the VM and install Alpine Linux

Create the virtual disk, setup vmd and start the VM:

# vmctl create -s 64G docker.qcow2
vmctl: qcow2 imagefile created

# cat /etc/vm.conf
switch "uplink" {
        interface bridge0

vm "docker" {

        memory 2G

        cdrom "/opt/vm/alpine-virt-3.16.2-x86_64.iso"
        disk "/opt/vm/docker.qcow2"

        interface {
                switch "uplink"
                locked lladdr fe:e1:ba:d2:02:30

# rcctl restart vmd

# vmctl start -c -B cdrom docker
Connected to /dev/ttyp1 (speed 115200)
Welcome to Alpine Linux 3.16
Kernel 5.15.59-0-virt on an x86_64 (/dev/ttyS0)

The bootloader detects COM parameters, boots the OS and gets you to the prompt. Read the User Handbook and proceed to installation. The process is quite straight forward. I choosed the “sys” disk layout.

localhost login: root
Welcome to Alpine!

The Alpine Wiki contains a large amount of how-to guides and general
information about administrating Alpine systems.
See <>.

You can setup the system with the command: setup-alpine

You may change this message by editing /etc/motd.

localhost:~# setup-alpine
Installation is complete. Please reboot.

# poweroff

Modify vm.conf(5) by commenting “disable” and reload vmd to restart the VM automatically.

Setup the Docker host

Connect to the VM using SSH to finish the configuration.

Looking for “docker” in the Alpine Linux packages repository, it shows the repository list has to be updated.

# vi /etc/apk/repositories

# apk update
OK: 17026 distinct packages available

# apk add docker
Executing docker-20.10.16-r3.pre-install
Executing busybox-1.35.0-r17.trigger
Executing ca-certificates-20220614-r0.trigger
OK: 285 MiB in 82 packages

Enable the Docker management for non-root user:

# addgroup myself docker

Have Docker start by default:

# rc-service docker status
 * status: stopped

# rc-update add docker
 * service docker added to runlevel default

# rc-service docker start
 * Caching service dependencies ...  [ ok ]
 * Mounting cgroup filesystem ...    [ ok ]
 * /var/log/docker.log: creating file
 * /var/log/docker.log: correcting owner
 * Starting Docker Daemon ...        [ ok ]

# docker ps

And that’s basically all :)

Test the Docker service

Run a simple test container to ensure eveyrthing works properly:

# docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
2db29710123e: Pull complete 
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker
 3. The Docker daemon created a new container from that image which runs
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which
    sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:

For more examples and ideas, visit:

# docker image ls
hello-world   latest    feb5d9fea6a5   11 months ago   13.3kB

Manage Docker from OpenBSD

Running Docker using OpenBSD’s vmd(8) is great. But managing Docker from the OpenBSD workstation is even greater.

Install the docker-cli package and set the user environment to target the Docker host. Then run the test container to ensure it works remotely and properly.

# pkg_add docker-cli
docker-cli-20.10.5: ok

# export DOCKER_HOST=ssh://user@docker-host
# docker ps
# docker run hello-world

As an example, an InfluxDB container can be run this way. Connect to the Docker host to prepare things. This means a dedicated storage directory with specific permissions limited to a dedicated user.

# mkdir -p /home/containers/influxdb/etc
# mkdir -p /home/containers/influxdb/data

# addgroup -g 10000 influxdb
# adduser -h /home/containers/influxdb \
  -g InfluxDB -s /sbin/nologin -G influxdb  \
  -D -u 10000 influxdb

# chown -R influxdb:influxdb /home/containers/influxdb

Back to the workstation, populate and run the container.

# docker pull influxdb:1.8
Status: Downloaded newer image for influxdb:1.8

# docker run --user 10000:10000 influxdb:1.8 \
  influxd config > /home/containers/influxdb/etc/influxdb.conf
Merging with configuration at: /etc/influxdb/influxdb.conf
reporting-disabled = false
bind-address = ""

# docker run -d --user 10000:10000 --name influxdb          \
  --restart=unless-stopped -p 8086:8086 -p 25826:25826/udp  \
  -v /home/containers/influxdb/data:/var/lib/influxdb       \
  -v /home/containers/influxdb/etc:/etc/influxdb            \

# docker ps -a            
CONTAINER ID   IMAGE          COMMAND                  CREATED      STATUS      PORTS                                                                                      NAMES
c8f12af8e96b   influxdb:1.8   "/ infl…"   9 days ago   Up 9 days>8086/tcp, :::8086->8086/tcp,>25826/udp, :::25826->25826/udp   influxdb

The InfluxDB service can now be access from tcp/dockerhost:8086. And I can now stop the Docker service on my Synology and only use OpenBSD to play with containers.