-
Notifications
You must be signed in to change notification settings - Fork 2
ephemeral
Overlord will take care not to destroy the jail with your valuable virtual machine in vmjail deployments. However, this approach does not honor "The Ephemeral Concept" of AppJail, which has many advantages that cannot be ignored, particularly when updating or upgrading the jail and its contents.
metadata.yml:
kind: metadata
datacenters:
main:
entrypoint: !ENV '${ENTRYPOINT}'
access_token: !ENV '${TOKEN}'
deployIn:
labels:
- vm-only
metadata:
ts_auth_key: !ENV '${TS_AUTH_KEY}'
resolv.conf: |
nameserver 172.0.0.1
timezone: 'America/Caracas'
loader.conf: |
nvme_load="YES"
if_bridge_load="YES"
bridgestp_load="YES"
if_wg_load="YES"
kern.racct.enable=1
ssh_key: !ENV '${SSH_KEY}'
sshd_config: |
# Ports
Port 22
# Authentication
PubkeyAuthentication yes
AuthenticationMethods publickey
PermitRootLogin prohibit-password
PrintMotd no
# Forwarding
X11Forwarding no
AllowAgentForwarding yes
# Connection checks
ClientAliveCountMax 3
ClientAliveInterval 15
# Compression
Compression no
# Limits
LoginGraceTime 40
# Public keys
AuthorizedKeysFile /etc/ssh/authorized_keys
# SFTP
Subsystem sftp internal-sftp
sysctl.conf: |
# A bit of hardening
security.bsd.see_other_uids=0
security.bsd.see_other_gids=0
security.bsd.see_jail_proc=0
kern.randompid=1
# Allow packet filtering in if_bridge(4)
net.link.bridge.pfil_member=1
net.link.bridge.pfil_bridge=1
pkg.conf: |
FreeBSD: {
url: "pkg+http://pkg.FreeBSD.org/${ABI}/latest",
mirror_type: "srv",
signature_type: "fingerprints",
fingerprints: "/usr/share/keys/pkg",
enabled: yes
}
appVM.appConfig: |
<%page args="appvm_use_pkgbase='0',poweroff='0'"/>
kind: 'vmJail'
vmName: ${appName}
makejail: 'gh+DtxdF/vm-makejail'
overwrite: true
% if poweroff != "0":
poweroff: true
% endif
datastore: '/var/appjail-vm/${appName}/data'
options:
- fstab: '/var/appjail-vm/${appName}/data vm-data <volumefs>'
template:
loader: 'bhyveload'
cpu: '${ncpu}'
memory: '${memory}'
network0_type: 'virtio-net'
network0_switch: 'public'
wired_memory: 'YES'
diskLayout:
driver: 'nvme'
size: '${disk}'
from:
% if appvm_use_pkgbase == "0":
type: 'components'
components:
- base.txz
- kernel.txz
osArch: amd64
osVersion: '${fbsdver}'
% else:
type: 'appjailImage'
entrypoint: gh+AppJail-makejails/pkgbase
imageName: pkgbase
imageArch: amd64
imageTag: '${fbsdver}'
% endif
disk:
scheme: 'gpt'
partitions:
- type: 'freebsd-boot'
size: '512k'
alignment: '1m'
- type: 'freebsd-swap'
size: '${swap}'
alignment: '1m'
- type: 'freebsd-ufs'
alignment: '1m'
format:
flags: '-U'
bootcode:
bootcode: '/boot/pmbr'
partcode: '/boot/gptboot'
index: 1
fstab:
- device: '/dev/nda0p3'
mountpoint: '/'
type: 'ufs'
options: 'rw,sync'
dump: 1
pass: 1
- device: '/dev/nda0p2'
mountpoint: 'none'
type: 'swap'
options: 'sw'
dump: 0
pass: 0
script-environment:
- HOSTNAME: '${hostname}'
script: |
<%text filter="n">
set -xe
set -o pipefail
. "/metadata/environment"
sysrc -f /mnt/etc/rc.conf ifconfig_vtnet0="inet 192.168.8.2/24"
sysrc -f /mnt/etc/rc.conf defaultrouter="192.168.8.1"
sysrc -f /mnt/etc/rc.conf fsck_y_enable="YES"
sysrc -f /mnt/etc/rc.conf clear_tmp_enable="YES"
sysrc -f /mnt/etc/rc.conf dumpdev="NO"
sysrc -f /mnt/etc/rc.conf moused_nondefault_enable="NO"
sysrc -f /mnt/etc/rc.conf hostname="${HOSTNAME}"
if [ -f "/metadata/resolv.conf" ]; then
cp -a /metadata/resolv.conf /mnt/etc/resolv.conf
fi
if [ -f "/metadata/loader.conf" ]; then
cp /metadata/loader.conf /mnt/boot/loader.conf
fi
if [ -f "/metadata/zerotier_network" ]; then
pkg -c /mnt install -y zerotier
zerotier_network=`head -1 -- "/metadata/zerotier_network"`
cat << EOF > /mnt/etc/rc.local
while :; do
if ! /usr/local/bin/zerotier-cli join ${zerotier_network}; then
sleep 1
continue
fi
break
done
rm -f /etc/rc.local
EOF
sysrc -f /mnt/etc/rc.conf zerotier_enable="YES"
elif [ -f "/metadata/ts_auth_key" ]; then
pkg -c /mnt install -y tailscale
ts_auth_key=`head -1 -- "/metadata/ts_auth_key"`
echo "/usr/local/bin/tailscale up --accept-dns=false --auth-key=\"${ts_auth_key}\" && rm -f /etc/rc.local" > /mnt/etc/rc.local
sysrc -f /mnt/etc/rc.conf tailscaled_enable="YES"
fi
if [ -f "/metadata/timezone" ]; then
timezone=`head -1 -- "/metadata/timezone"`
ln -fs "/usr/share/zoneinfo/${timezone}" /mnt/etc/localtime
fi
if [ -f "/metadata/sshd_config" ]; then
sysrc -f /mnt/etc/rc.conf sshd_enable="YES"
cp /metadata/sshd_config /mnt/etc/ssh/sshd_config
fi
if [ -f "/metadata/ssh_key" ]; then
cp /metadata/ssh_key /mnt/etc/ssh/authorized_keys
fi
if [ -f "/metadata/sysctl.conf" ]; then
cp /metadata/sysctl.conf /mnt/etc/sysctl.conf
fi
if [ -f "/metadata/pkg.conf" ]; then
mkdir -p /mnt/usr/local/etc/pkg/repos
cp /metadata/pkg.conf /mnt/usr/local/etc/pkg/repos/Latest.conf
fi
</%text>
metadata:
- resolv.conf
- loader.conf
- timezone
- sshd_config
- ssh_key
- sysctl.conf
- pkg.conf
- ts_auth_keyapp.yml:
kind: appConfig
datacenters:
main:
entrypoint: !ENV '${ENTRYPOINT}'
access_token: !ENV '${TOKEN}'
deployIn:
labels:
- desktop
appName: 'myvm'
appFrom: 'appVM.appConfig'
appConfig:
ncpu: '2'
memory: '2G'
disk: '30G'
swap: '2G'
fbsdver: '15.snap-full'
hostname: 'myvm'
appvm_use_pkgbase: '1'Note: I'm using an appConfig deployment here because it is easier to customize with different types of installations.
In this article, the most relevant parameters are:
...
overwrite: true
...
datastore: '/var/appjail-vm/${appName}/data'
...
options:
- fstab: '/var/appjail-vm/${appName}/data vm-data <volumefs>'
When overwrite is set to true, Overlord will destroy your jail if you reapply the deployment, which is what we want to do. datastore, when specified, is used by Overlord to create that directory and the .img and .iso subdirectories (which are not so relevant here, but you will see later that they become important in other types of installations such as iso or img). And last but not least, there is the entry in fstab(5), which becomes the default data store for vm-bhyve and where the virtual machine data will be stored.
console:
$ overlord apply -f metadata.yml
$ overlord apply -f app.yml
$ overlord get-info -f app.yml -t projects --filter-per-project
datacenter: http://controller.namespace.lan:8888
entrypoint: main
chain: None
labels:
- all
- desktop
- services
- vm-only
projects:
myvm:
state: UNFINISHED
last_log: 2025-08-07_15h34m33s
locked: True
services:
- {'name': 'vm', 'status': 66, 'jail': 'myvm'}
up:
operation: RUNNING
last_update: 7.19 seconds
job_id: 117
$ overlord get-info -f app.yml -t projects --filter-per-project
datacenter: http://controller.namespace.lan:8888
entrypoint: main
chain: None
labels:
- all
- desktop
- services
- vm-only
projects:
myvm:
state: DONE
last_log: 2025-08-07_15h34m33s
locked: False
services:
- {'name': 'vm', 'status': 0, 'jail': 'myvm'}
up:
operation: COMPLETED
output:
rc: 0
stdout: {'errlevel': 0, 'message': None, 'failed': []}
last_update: 1 minute and 32.7 seconds
job_id: 117
restarted: False
$ overlord get-info -f app.yml -t vm --filter-per-project
datacenter: http://controller.namespace.lan:8888
entrypoint: main
chain: None
labels:
- all
- desktop
- services
- vm-only
projects:
myvm:
virtual-machines:
operation: RUNNING
last_update: 1 minute and 36.41 seconds
job_id: 117
$ overlord get-info -f app.yml -t vm --filter-per-project
datacenter: http://controller.namespace.lan:8888
entrypoint: main
chain: None
labels:
- all
- desktop
- services
- vm-only
projects:
myvm:
virtual-machines:
operation: COMPLETED
output: |
md0 created
md0p1 added
md0p2 added
md0p3 added
/dev/md0p3: 28670.0MB (58716160 sectors) block size 32768, fragment size 4096
using 46 cylinder groups of 625.22MB, 20007 blks, 80128 inodes.
with soft updates
super-block backups (for fsck_ffs -b #) at:
192, 1280640, 2561088, 3841536, 5121984, 6402432, 7682880, 8963328, 10243776,
11524224, 12804672, 14085120, 15365568, 16646016, 17926464, 19206912,
20487360, 21767808, 23048256, 24328704, 25609152, 26889600, 28170048,
29450496, 30730944, 32011392, 33291840, 34572288, 35852736, 37133184,
38413632, 39694080, 40974528, 42254976, 43535424, 44815872, 46096320,
47376768, 48657216, 49937664, 51218112, 52498560, 53779008, 55059456,
56339904, 57620352
bootcode written to md0
partcode written to md0p1
ifconfig_vtnet0: -> inet 192.168.8.2/24
defaultrouter: NO -> 192.168.8.1
fsck_y_enable: NO -> YES
clear_tmp_enable: NO -> YES
dumpdev: NO -> NO
moused_nondefault_enable: YES -> NO
hostname: -> myvm
[myvm.appjail] Installing pkg-2.2.1...
[myvm.appjail] Extracting pkg-2.2.1: .......... done
Updating FreeBSD repository catalogue...
[myvm.appjail] Fetching data.pkg: .......... done
Processing entries:
Processing entries............. done
FreeBSD repository update completed. 36062 packages processed.
Updating FreeBSD-kmods repository catalogue...
[myvm.appjail] Fetching meta.conf: . done
[myvm.appjail] Fetching data.pkg: .. done
Processing entries: .......... done
FreeBSD-kmods repository update completed. 199 packages processed.
Updating FreeBSD-base repository catalogue...
[myvm.appjail] Fetching data.pkg: ... done
Processing entries: .......... done
FreeBSD-base repository update completed. 561 packages processed.
All repositories are up to date.
The following 2 package(s) will be affected (of 0 checked):
New packages to be INSTALLED:
ca_root_nss: 3.108 [FreeBSD]
tailscale: 1.84.2_1 [FreeBSD]
Number of packages to be installed: 2
The process will require 36 MiB more space.
12 MiB to be downloaded.
[myvm.appjail] [1/2] Fetching tailscale-1.84.2_1.pkg: .......... done
[myvm.appjail] [2/2] Fetching ca_root_nss-3.108.pkg: ........ done
Checking integrity... done (0 conflicting)
[myvm.appjail] [1/2] Installing ca_root_nss-3.108...
[myvm.appjail] [1/2] Extracting ca_root_nss-3.108: ....... done
[myvm.appjail] [2/2] Installing tailscale-1.84.2_1...
[myvm.appjail] [2/2] Extracting tailscale-1.84.2_1: ...... done
=====
Message from ca_root_nss-3.108:
--
FreeBSD does not, and can not warrant that the certification authorities
whose certificates are included in this package have in any way been
audited for trustworthiness or RFC 3647 compliance.
Assessment and verification of trust is the complete responsibility of
the system administrator.
This package installs symlinks to support root certificate discovery
for software that either uses other cryptographic libraries than
OpenSSL, or use OpenSSL but do not follow recommended practice.
If you prefer to do this manually, replace the following symlinks with
either an empty file or your site-local certificate bundle.
* /etc/ssl/cert.pem
* /usr/local/etc/ssl/cert.pem
* /usr/local/openssl/cert.pem
tailscaled_enable: -> YES
sshd_enable: NO -> YES
vm_list: -> myvm
Starting myvm
* found guest in /vm/myvm
* booting...
[00:00:00] [ debug ] Cloning https://github.com/AppJail-makejails/pkgbase as /usr/local/appjail/cache/tmp/.appjail/appjail.MKDRFh8cuH ...
[00:00:00] [ info ] [pkgbase] pkgbase (arch:amd64, tag:15.snap-full): already up to date.
+ set -o pipefail
+ . /metadata/environment
+ export 'HOSTNAME=myvm'
+ sysrc -f /mnt/etc/rc.conf 'ifconfig_vtnet0=inet 192.168.8.2/24'
+ sysrc -f /mnt/etc/rc.conf 'defaultrouter=192.168.8.1'
+ sysrc -f /mnt/etc/rc.conf 'fsck_y_enable=YES'
+ sysrc -f /mnt/etc/rc.conf 'clear_tmp_enable=YES'
+ sysrc -f /mnt/etc/rc.conf 'dumpdev=NO'
+ sysrc -f /mnt/etc/rc.conf 'moused_nondefault_enable=NO'
+ sysrc -f /mnt/etc/rc.conf 'hostname=myvm'
+ [ -f /metadata/resolv.conf ]
+ cp -a /metadata/resolv.conf /mnt/etc/resolv.conf
+ [ -f /metadata/loader.conf ]
+ cp /metadata/loader.conf /mnt/boot/loader.conf
+ [ -f /metadata/zerotier_network ]
+ [ -f /metadata/ts_auth_key ]
+ pkg -c /mnt install -y tailscale
pkg: Warning: Major OS version upgrade detected. Running "pkg bootstrap -f" recommended
+ head -1 -- /metadata/ts_auth_key
+ ts_auth_key=[REDACTED]
+ echo '/usr/local/bin/tailscale up --accept-dns=false --auth-key="[REDACTED]" && rm -f /etc/rc.local'
+ sysrc -f /mnt/etc/rc.conf 'tailscaled_enable=YES'
+ [ -f /metadata/timezone ]
+ head -1 -- /metadata/timezone
+ timezone=America/Caracas
+ ln -fs /usr/share/zoneinfo/America/Caracas /mnt/etc/localtime
+ [ -f /metadata/sshd_config ]
+ sysrc -f /mnt/etc/rc.conf 'sshd_enable=YES'
+ cp /metadata/sshd_config /mnt/etc/ssh/sshd_config
+ [ -f /metadata/ssh_key ]
+ cp /metadata/ssh_key /mnt/etc/ssh/authorized_keys
+ [ -f /metadata/sysctl.conf ]
+ cp /metadata/sysctl.conf /mnt/etc/sysctl.conf
+ [ -f /metadata/pkg.conf ]
+ mkdir -p /mnt/usr/local/etc/pkg/repos
+ cp /metadata/pkg.conf /mnt/usr/local/etc/pkg/repos/Latest.conf
last_update: 21.26 seconds
job_id: 117We can log into our jail and install a package. After doing so, let's reapply the deployment to see what happens.
$ ssh root@100.78.139.110
The authenticity of host '100.78.139.110 (100.78.139.110)' can't be established.
ED25519 key fingerprint is SHA256:+0KHV4m5X42UZgZ2N+qtJDwm4EFl0yhvYo6VRenZlxc.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '100.78.139.110' (ED25519) to the list of known hosts.
root@myvm:~ # pkg install -y fastfetch
Bootstrapping pkg from pkg+http://pkg.FreeBSD.org/FreeBSD:15:amd64/latest, please wait...
Verifying signature with trusted certificate pkg.freebsd.org.2013102301... done
Installing pkg-2.2.1...
Newer FreeBSD version for package pkg:
To ignore this error set IGNORE_OSVERSION=yes
- package: 1500054
- running userland: 1500053
Ignore the mismatch and continue? [y/N]: y
Extracting pkg-2.2.1: 100%
Updating FreeBSD repository catalogue...
pkg: Repository FreeBSD has a wrong packagesite, need to re-create database
Fetching meta.conf: 100% 179 B 0.2kB/s 00:01
Fetching data.pkg: 100% 10 MiB 230.3kB/s 00:46
Processing entries: 0%
Processing entries: 100%
FreeBSD repository update completed. 36062 packages processed.
Updating FreeBSD-kmods repository catalogue...
FreeBSD-kmods repository is up to date.
Updating FreeBSD-base repository catalogue...
FreeBSD-base repository is up to date.
All repositories are up to date.
Updating database digests format: 100%
The following 5 package(s) will be affected (of 0 checked):
New packages to be INSTALLED:
FreeBSD-bluetooth: 15.snap20250721070021 [FreeBSD-base]
FreeBSD-libsdp: 15.snap20250707041723 [FreeBSD-base]
fastfetch: 2.48.1 [FreeBSD]
hwdata: 0.397,1 [FreeBSD]
yyjson: 0.11.1 [FreeBSD]
Number of packages to be installed: 5
The process will require 12 MiB more space.
2 MiB to be downloaded.
[1/5] Fetching FreeBSD-bluetooth-15.snap20250721070021.pkg: 100% 182 KiB 186.6kB/s 00:01
[2/5] Fetching yyjson-0.11.1.pkg: 100% 126 KiB 129.1kB/s 00:01
[3/5] Fetching fastfetch-2.48.1.pkg: 100% 446 KiB 228.3kB/s 00:02
[4/5] Fetching hwdata-0.397,1.pkg: 100% 2 MiB 344.8kB/s 00:05
[5/5] Fetching FreeBSD-libsdp-15.snap20250707041723.pkg: 100% 8 KiB 8.3kB/s 00:01
Checking integrity... done (0 conflicting)
[1/5] Installing FreeBSD-bluetooth-15.snap20250721070021...
[1/5] Extracting FreeBSD-bluetooth-15.snap20250721070021: 100%
[2/5] Installing FreeBSD-libsdp-15.snap20250707041723...
[2/5] Extracting FreeBSD-libsdp-15.snap20250707041723: 100%
[3/5] Installing hwdata-0.397,1...
[3/5] Extracting hwdata-0.397,1: 100%
[4/5] Installing yyjson-0.11.1...
[4/5] Extracting yyjson-0.11.1: 100%
[5/5] Installing fastfetch-2.48.1...
[5/5] Extracting fastfetch-2.48.1: 100%
root@myvm:~ # fastfetch
``` ` root@myvm
` `.....---.......--.``` -/ ---------
+o .--` /y:` +. Kernel: FreeBSD 15.0-CURRENT
yo`:. :o `+- Uptime: 7 mins
y/ -/` -o/ Shell: sh
.- ::/sy+:. Terminal: /dev/pts/0
/ `-- / CPU: Intel(R) Core(TM) i5-7500T (2) @ 3.30 GHz
`: :` Memory: 342.90 MiB / 1.96 GiB (17%)
`: :` Swap: 0 B / 2.00 GiB (0%)
/ / Disk (/): 501.37 MiB / 27.12 GiB (2%) - ufs
.- -. Local IP (vtnet0): 192.168.8.2/24
-- -. Locale: C.UTF-8
`:` `:`
.-- `--.
.---.....----.
root@myvm:~ #
Shared connection to 100.78.139.110 closed.
$ overlord apply -f app.yml
$ overlord get-info -f app.yml -t projects --filter-per-project
datacenter: http://controller.namespace.lan:8888
entrypoint: main
chain: None
labels:
- all
- desktop
- services
- vm-only
projects:
myvm:
state: UNFINISHED
last_log: 2025-08-07_15h47m57s
locked: True
services:
- {'name': 'vm', 'status': 0, 'jail': 'myvm'}
up:
operation: RUNNING
last_update: 13.58 seconds
job_id: 119
$ overlord get-info -f app.yml -t projects --filter-per-project
datacenter: http://controller.namespace.lan:8888
entrypoint: main
chain: None
labels:
- all
- desktop
- services
- vm-only
projects:
myvm:
state: DONE
last_log: 2025-08-07_15h47m57s
locked: False
services:
- {'name': 'vm', 'status': 0, 'jail': 'myvm'}
up:
operation: COMPLETED
output:
rc: 0
stdout: {'errlevel': 0, 'message': None, 'failed': []}
last_update: 55.5 seconds
job_id: 119
restarted: False
$ overlord get-info -f app.yml -t vm --filter-per-project
datacenter: http://controller.namespace.lan:8888
entrypoint: main
chain: None
labels:
- all
- desktop
- services
- vm-only
projects:
myvm:
virtual-machines:
operation: COMPLETED
output: |
vm_list: -> myvm
Starting myvm
* found guest in /vm/myvm
* booting...
last_update: 1 minute and 22.62 seconds
job_id: 119There are more changes that can be noticed here: the fact that the deployment takes less time since the virtual machine is not customized like the first time and simply starts up.
$ ssh root@100.78.139.110
Last login: Thu Aug 7 15:47:46 2025 from 100.65.139.52
root@myvm:~ # fastfetch
``` ` root@myvm
` `.....---.......--.``` -/ ---------
+o .--` /y:` +. Kernel: FreeBSD 15.0-CURRENT
yo`:. :o `+- Uptime: 4 mins
y/ -/` -o/ Shell: sh
.- ::/sy+:. Terminal: /dev/pts/0
/ `-- / CPU: Intel(R) Core(TM) i5-7500T (2) @ 3.30 GHz
`: :` Memory: 192.38 MiB / 1.96 GiB (10%)
`: :` Swap: 0 B / 2.00 GiB (0%)
/ / Disk (/): 564.89 MiB / 27.12 GiB (2%) - ufs
.- -. Local IP (vtnet0): 192.168.8.2/24
-- -. Locale: C.UTF-8
`:` `:`
.-- `--.
.---.....----.
root@myvm:~ #
Shared connection to 100.78.139.110 closed.Even if our jail is destroyed over and over again, it's not a problem because the data is stored outside the jail.
$ tree /var/appjail-vm/myvm
/var/appjail-vm/myvm
└── data
└── myvm
├── console
├── disk0.img
├── myvm.conf
├── run.lock
└── vm-bhyve.log
3 directories, 5 filesWe're not done yet, there's more to say here.
debian.yml:
kind: vmJail
datacenters:
main:
entrypoint: !ENV '${ENTRYPOINT}'
access_token: !ENV '${TOKEN}'
deployIn:
labels:
- desktop
vmName: 'debian'
makejail: 'gh+DtxdF/vm-makejail'
overwrite: true
datastore: '/var/appjail-vm/debian/data'
options:
- pkg: grub2-bhyve
- pkg: qemu-tools
- fstab: '/var/appjail-vm/debian/data vm-data <volumefs>'
- fstab: '/var/os-images/uploads /vm/.img nullfs ro'
template:
loader: 'grub'
cpu: '4'
memory: '4G'
network0_type: 'virtio-net'
network0_switch: 'public'
wired_memory: 'YES'
grub_run_partition: '1'
grub_run_dir: '/boot/grub'
uuid: 'c0f801f2-8b43-4004-b778-d701879d7359'
diskLayout:
driver: 'ahci-hd'
size: '40G'
from:
type: 'img'
imgFile: 'debian-13-generic-amd64-daily.qcow2'
cloud-init:
meta-data:
instance-id: 'c0f801f2-8b43-4004-b778-d701879d7359'
local-hostname: debian.lan
network-config:
version: 2
ethernets:
id0:
match:
name: 'enp0s5'
addresses:
- 192.168.8.2/24
routes:
- to: default
via: 192.168.8.1
nameservers:
search: []
addresses: [172.0.0.1]
user-data:
resize_rootfs: True
manage_etc_hosts: localhost
user:
name: user
homedir: '/user'
ssh_authorized_keys:
- !ENV '${SSH_KEY}'
sudo: 'ALL=(ALL) NOPASSWD:ALL'
package_update: True
package_upgrade: True
runcmd:
- ['sh', '-c', 'curl -x socks5://10.0.0.50:9050 -fsSL https://tailscale.com/install.sh | sh']
- ['tailscale', 'up', !ENV '--auth-key=${TS_AUTH_KEY}']The above deployment is similar to the first one, but there is an additional entry:
...
options:
...
- fstab: '/var/appjail-vm/debian/data vm-data <volumefs>'
- fstab: '/var/os-images/uploads /vm/.img nullfs ro'
And this is where datastore is most valuable: datastore will create the subdirectories .img and .iso in the specified directory (datastore's value), which is necessary before mounting the directory containing the images (in this case /var/os-images/uploads) in /vm/.iso or /vm/.img. This is necessary because fstab(5) will first attempt to mount /var/appjail-vm/debian/data on the vm-data volume, and if it does not contain the .iso and .img subdirectories, the next entry /var/os-images/uploads, which will be mounted on /vm/.img, will fail.
console:
$ overlord apply -f debian.yml
$ overlord get-info -f debian.yml -t projects --filter-per-project
datacenter: http://controller.namespace.lan:8888
entrypoint: main
chain: None
labels:
- all
- desktop
- services
- vm-only
projects:
debian:
state: UNFINISHED
last_log: 2025-08-07_16h15m49s
locked: True
services:
- {'name': 'vm', 'status': 0, 'jail': 'debian'}
up:
operation: RUNNING
last_update: 30.9 seconds
job_id: 123
$ overlord get-info -f debian.yml -t projects --filter-per-project
datacenter: http://controller.namespace.lan:8888
entrypoint: main
chain: None
labels:
- all
- desktop
- services
- vm-only
projects:
debian:
state: DONE
last_log: 2025-08-07_16h15m49s
locked: False
services:
- {'name': 'vm', 'status': 0, 'jail': 'debian'}
up:
operation: COMPLETED
output:
rc: 0
stdout: {'errlevel': 0, 'message': None, 'failed': []}
last_update: 2 minutes and 6.1 seconds
job_id: 123
restarted: False
$ overlord get-info -f debian.yml -t vm --filter-per-project
datacenter: http://controller.namespace.lan:8888
entrypoint: main
chain: None
labels:
- all
- desktop
- services
- vm-only
projects:
debian:
virtual-machines:
operation: COMPLETED
output: |
vm_list: -> debian
Starting debian
* found guest in /vm/debian
* booting...
last_update: 54.26 seconds
job_id: 123
$ ssh user@100.89.3.114
The authenticity of host '100.89.3.114 (100.89.3.114)' can't be established.
ED25519 key fingerprint is SHA256:QJvf2940g8JlsnTiWosIYR8VKHeBjfooxoj2qmS+jHE.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '100.89.3.114' (ED25519) to the list of known hosts.
Linux debian 6.12.35+deb13-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.12.35-1 (2025-07-03) x86_64
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
user@debian:~$ sudo apt install fastfetch
Installing:
fastfetch
Installing dependencies:
libyyjson0
Summary:
Upgrading: 0, Installing: 2, Removing: 0, Not Upgrading: 0
Download size: 632 kB
Space needed: 2083 kB / 38.9 GB available
Continue? [Y/n] y
Get:1 file:/etc/apt/mirrors/debian.list Mirrorlist [30 B]
Get:2 https://deb.debian.org/debian trixie/main amd64 libyyjson0 amd64 0.10.0+ds-1+b1 [89.3 kB]
Get:3 https://deb.debian.org/debian trixie/main amd64 fastfetch amd64 2.40.4+dfsg-1 [543 kB]
Fetched 632 kB in 1s (481 kB/s)
Selecting previously unselected package libyyjson0:amd64.
(Reading database ... 29601 files and directories currently installed.)
Preparing to unpack .../libyyjson0_0.10.0+ds-1+b1_amd64.deb ...
Unpacking libyyjson0:amd64 (0.10.0+ds-1+b1) ...
Selecting previously unselected package fastfetch.
Preparing to unpack .../fastfetch_2.40.4+dfsg-1_amd64.deb ...
Unpacking fastfetch (2.40.4+dfsg-1) ...
Setting up libyyjson0:amd64 (0.10.0+ds-1+b1) ...
Setting up fastfetch (2.40.4+dfsg-1) ...
Processing triggers for man-db (2.13.1-1) ...
Processing triggers for libc-bin (2.41-12) ...
user@debian:~$ fastfetch
_,met$$$$$gg. user@debian
,g$$$$$$$$$$$$$$$P. -----------
,g$$P"" """Y$$.". OS: Debian GNU/Linux 13 (trixie) x86_64
,$$P' `$$$. Host: BHYVE (1.0)
',$$P ,ggs. `$$b: Kernel: Linux 6.12.35+deb13-amd64
`d$$' ,$P"' . $$$ Uptime: 9 mins
$$P d$' , $$P Packages: 327 (dpkg)
$$: $$. - ,d$$' Shell: bash 5.2.37
$$; Y$b._ _,d$P' Terminal: /dev/pts/0
Y$$. `.`"Y$$$$P"' CPU: 4 x Intel(R) Core(TM) i5-7500T (4) @ 3.30 GHz
`$$b "-.__ Memory: 445.67 MiB / 3.83 GiB (11%)
`Y$$b Swap: Disabled
`Y$$. Disk (/): 1.27 GiB / 39.17 GiB (3%) - ext4
`$$b. Local IP (enp0s5): 192.168.8.2/24
`Y$$b. Locale: C.UTF-8
`"Y$b._
`""""
user@debian:~$
logout
Shared connection to 100.89.3.114 closed.
$ overlord apply -f debian.yml
$ overlord get-info -f debian.yml -t projects --filter-per-project
datacenter: http://controller.namespace.lan:8888
entrypoint: main
chain: None
labels:
- all
- desktop
- services
- vm-only
projects:
debian:
state: UNFINISHED
last_log: 2025-08-07_16h30m27s
locked: True
services:
- {'name': 'vm', 'status': 66, 'jail': 'debian'}
up:
operation: RUNNING
last_update: 12.67 seconds
job_id: 125
$ overlord get-info -f debian.yml -t projects --filter-per-project
datacenter: http://controller.namespace.lan:8888
entrypoint: main
chain: None
labels:
- all
- desktop
- services
- vm-only
projects:
debian:
state: DONE
last_log: 2025-08-07_16h30m27s
locked: False
services:
- {'name': 'vm', 'status': 0, 'jail': 'debian'}
up:
operation: COMPLETED
output:
rc: 0
stdout: {'errlevel': 0, 'message': None, 'failed': []}
last_update: 3 minutes and 33.49 seconds
job_id: 125
restarted: False
$ overlord get-info -f debian.yml -t vm --filter-per-project
datacenter: http://controller.namespace.lan:8888
entrypoint: main
chain: None
labels:
- all
- desktop
- services
- vm-only
projects:
debian:
virtual-machines:
operation: COMPLETED
output: |
vm_list: -> debian
Starting debian
* found guest in /vm/debian
* booting...
last_update: 3 minutes and 34.73 seconds
job_id: 125
$ ssh user@100.89.3.114
Linux debian 6.12.38+deb13-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.12.38-1 (2025-07-16) x86_64
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Thu Aug 7 20:28:43 2025 from 100.65.139.52
user@debian:~$ fastfetch
_,met$$$$$gg. user@debian
,g$$$$$$$$$$$$$$$P. -----------
,g$$P"" """Y$$.". OS: Debian GNU/Linux 13 (trixie) x86_64
,$$P' `$$$. Host: BHYVE (1.0)
',$$P ,ggs. `$$b: Kernel: Linux 6.12.38+deb13-amd64
`d$$' ,$P"' . $$$ Uptime: 5 mins
$$P d$' , $$P Packages: 327 (dpkg)
$$: $$. - ,d$$' Shell: bash 5.2.37
$$; Y$b._ _,d$P' Terminal: /dev/pts/0
Y$$. `.`"Y$$$$P"' CPU: 4 x Intel(R) Core(TM) i5-7500T (4) @ 3.30 GHz
`$$b "-.__ Memory: 348.50 MiB / 3.83 GiB (9%)
`Y$$b Swap: Disabled
`Y$$. Disk (/): 1.27 GiB / 39.17 GiB (3%) - ext4
`$$b. Local IP (enp0s5): 192.168.8.2/24
`Y$$b. Locale: C.UTF-8
`"Y$b._
`""""
user@debian:~$
logout
Shared connection to 100.89.3.114 closed.And the last character in this scenario is the iso installation type, which is a little different from the others.
app.yml:
kind: vmJail
datacenters:
main:
entrypoint: !ENV '${ENTRYPOINT}'
access_token: !ENV '${TOKEN}'
deployIn:
labels:
- desktop
vmName: 'fbsd143'
makejail: 'gh+DtxdF/vm-makejail'
overwrite: true
datastore: '/var/appjail-vm/fbsd143/data'
options:
- fstab: '/var/appjail-vm/fbsd143/data vm-data <volumefs>'
- fstab: '/var/os-images/uploads /vm/.iso nullfs ro'
template:
loader: 'uefi'
cpu: '4'
memory: '2G'
graphics: 'yes'
graphics_listen: '0.0.0.0'
graphics_res: '1280x720'
xhci_mouse: 'yes'
network0_type: 'virtio-net'
network0_switch: 'public'
wired_memory: 'YES'
diskLayout:
driver: 'nvme'
size: '40G'
from:
type: 'iso'
isoFile: 'FreeBSD-14.3-RELEASE-amd64-disc1.iso'Similar to the others mentioned, with the subtle difference that instead of /vm/.img we use /vm/.iso.
console:
$ overlord apply -f app.yml
$ overlord get-info -f app.yml -t projects --filter-per-project
datacenter: http://controller.namespace.lan:8888
entrypoint: main
chain: None
labels:
- all
- desktop
- services
- vm-only
projects:
fbsd143:
state: UNFINISHED
last_log: 2025-08-07_16h47m22s
locked: True
services:
- {'name': 'vm', 'status': 0, 'jail': 'fbsd143'}
up:
operation: RUNNING
last_update: 42.16 seconds
job_id: 129
$ overlord get-info -f app.yml -t projects --filter-per-project
datacenter: http://controller.namespace.lan:8888
entrypoint: main
chain: None
labels:
- all
- desktop
- services
- vm-only
projects:
fbsd143:
state: DONE
last_log: 2025-08-07_16h47m22s
locked: False
services:
- {'name': 'vm', 'status': 0, 'jail': 'fbsd143'}
up:
operation: COMPLETED
output:
rc: 0
stdout: {'errlevel': 0, 'message': None, 'failed': []}
last_update: 2 minutes and 37.92 seconds
job_id: 129
restarted: False
$ overlord get-info -f app.yml -t vm --filter-per-project
datacenter: http://controller.namespace.lan:8888
entrypoint: main
chain: None
labels:
- all
- desktop
- services
- vm-only
projects:
fbsd143:
virtual-machines:
operation: COMPLETED
output: |
Starting fbsd143
* found guest in /vm/fbsd143
* booting...
last_update: 2 minutes and 46.78 seconds
job_id: 129After installing the guest operating system from our VNC client, mark this deployment as installed and reapply the deployment, and Overlord will mark this virtual machine as complete, however, this will not destroy the jail. After marking this virtual machine as complete, Overlord can recreate the jail after you reapply the deployment. Therefore, the deployment must be applied at least twice.
app.yml:
kind: vmJail
datacenters:
main:
entrypoint: !ENV '${ENTRYPOINT}'
access_token: !ENV '${TOKEN}'
deployIn:
labels:
- desktop
vmName: 'fbsd143'
makejail: 'gh+DtxdF/vm-makejail'
overwrite: true
datastore: '/var/appjail-vm/fbsd143/data'
options:
- fstab: '/var/appjail-vm/fbsd143/data vm-data <volumefs>'
- fstab: '/var/os-images/uploads /vm/.iso nullfs ro'
template:
loader: 'uefi'
cpu: '4'
memory: '2G'
graphics: 'yes'
graphics_listen: '0.0.0.0'
graphics_res: '1280x720'
xhci_mouse: 'yes'
network0_type: 'virtio-net'
network0_switch: 'public'
wired_memory: 'YES'
diskLayout:
driver: 'nvme'
size: '40G'
from:
type: 'iso'
isoFile: 'FreeBSD-14.3-RELEASE-amd64-disc1.iso'
installed: trueconsole:
$ overlord apply -f app.yml
$ overlord get-info -f app.yml -t projects --filter-per-project
datacenter: http://controller.namespace.lan:8888
entrypoint: main
chain: None
labels:
- all
- desktop
- services
- vm-only
projects:
fbsd143:
state: DONE
last_log: 2025-08-07_16h47m22s
locked: False
services:
- {'name': 'vm', 'status': 0, 'jail': 'fbsd143'}
up:
operation: NOOP
last_update: 6.5 seconds
job_id: 131
$ overlord get-info -f app.yml -t vm --filter-per-project
datacenter: http://controller.namespace.lan:8888
entrypoint: main
chain: None
labels:
- all
- desktop
- services
- vm-only
projects:
fbsd143:
virtual-machines:
operation: COMPLETED
output: |
vm_list: -> fbsd143
Starting fbsd143
* found guest in /vm/fbsd143
* booting...
last_update: 24.17 seconds
job_id: 131
$ overlord apply -f app.yml
$ overlord get-info -f app.yml -t projects --filter-per-project
datacenter: http://controller.namespace.lan:8888
entrypoint: main
chain: None
labels:
- all
- desktop
- services
- vm-only
projects:
fbsd143:
state: DONE
last_log: 2025-08-07_16h47m22s
locked: False
services:
- {'name': 'vm', 'status': 0, 'jail': 'fbsd143'}
up:
operation: RUNNING
last_update: 3.28 seconds
job_id: 133
$ overlord get-info -f app.yml -t projects --filter-per-project
datacenter: http://controller.namespace.lan:8888
entrypoint: main
chain: None
labels:
- all
- desktop
- services
- vm-only
projects:
fbsd143:
state: DONE
last_log: 2025-08-07_17h00m24s
locked: False
services:
- {'name': 'vm', 'status': 0, 'jail': 'fbsd143'}
up:
operation: COMPLETED
output:
rc: 0
stdout: {'errlevel': 0, 'message': None, 'failed': []}
last_update: 8.72 seconds
job_id: 133
restarted: False
$ overlord get-info -f app.yml -t vm --filter-per-project
datacenter: http://controller.namespace.lan:8888
entrypoint: main
chain: None
labels:
- all
- desktop
- services
- vm-only
projects:
fbsd143:
virtual-machines:
operation: COMPLETED
output: |
vm_list: -> fbsd143
Starting fbsd143
* found guest in /vm/fbsd143
* booting...
last_update: 22.45 seconds
job_id: 133