====== Create a FreeBSD Jail ====== This page documents the standard way of creating a new FreeBSD jail on **bane**: build (or reuse) a FreeBSD release image, clone it into a new dataset with ZFS, write the jail config, and start the jail with ''jailer''. All commands are run on **bane** as **root** -- SSH to bane and become root first. ---- ===== Building a FreeBSD release image ===== Jails are cloned from a clean FreeBSD **release image** -- a minimal base install kept in its own ZFS dataset under ''zbane/jails/image/''. The image is built once per release (e.g. ''15.1-RELEASE'') and then reused for every new jail. ==== 1. Create the dataset ==== Make a dataset for the release version under ''zbane/jails/image/'': zfs create zbane/jails/image/15.1-RELEASE ==== 2. Install the base system ==== Go to the dataset's mountpoint: cd /usr/local/jails/image/15.1-RELEASE Then install the base system -- the same release that is on your host -- into that folder: bsdinstall jail . ''bsdinstall'' will ask which distribution sets to install (''base'', ''doc'', ''lib32'', ''src'', ...). **You only need the ''base'' set** -- uncheck everything else. The result is a minimal FreeBSD userland (no ''lib32'', ''doc'', ''src'' or ''ports''). ==== 3. Snapshot the image ==== Take a snapshot of the finished image. By convention the snapshot is named after the patch level the base install reports (''bsdinstall'' installs the base already patched to the current errata level): chroot /usr/local/jails/image/15.1-RELEASE /bin/freebsd-version -u # -> 15.1-RELEASE-p6 zfs snapshot zbane/jails/image/15.1-RELEASE@p6 New jails are then cloned from this snapshot. ---- ===== Creating a jail from the image ===== ==== 1. Generate a UUID ==== uuidgen -r Use the **first segment** of the generated UUID (the first field): for ''f9ba13cb-e512-454e-be10-a7092ed0e3e9'' use ''f9ba13cb''. It ends up in the jail's VNET interface name (''j${uuid}ng0''), so every jail gets a unique interface. ==== 2. Clone the image into the new jail ==== Clone the release image into the new jail's dataset with ''zfs send / recv'': zfs send zbane/jails/image/15.1-RELEASE@p6 | zfs recv -v zbane/jails/passwd-01 The destination dataset must not exist yet -- ''zfs recv'' creates it. It inherits its mountpoint from ''zbane/jails'' and appears under ''/usr/local/jails/passwd-01'', exactly the ''path'' used in the jail config below. ==== 3. Write the jail config ==== Jail config files live in ''/etc/jail.conf.d'' (the host's ''/etc/jail.conf'' includes every ''*.conf'' in that directory). Create ''/etc/jail.conf.d/name-01.conf'' using this template: name-01 { $uuid = ""; devfs_ruleset = 10; $bridge = "prod"; $domain = "abi.am"; $if_name_0 = "j${uuid}ng0"; vnet; vnet.interface = "${if_name_0}"; exec.prestart = "service ngbuddy jail ${if_name_0} $bridge"; exec.start += "/sbin/ifconfig lo0 127.0.0.1 up"; exec.start += "/sbin/ifconfig ${if_name_0} ether 58:9c:fc:ab:10:12"; exec.start += "/sbin/ifconfig ${if_name_0} inet 172.20.200.102/24"; exec.start += "/sbin/route add default 172.20.200.1"; exec.start += "/bin/sh /etc/rc"; exec.stop = "/bin/sh /etc/rc.shutdown jail"; exec.poststop += "service ngbuddy unjail ${if_name_0} ${name}"; host.hostname = "${name}.${domain}"; path = "/usr/local/jails/${name}"; exec.consolelog = "/var/log/jail/${name}.log"; persist; depend = pr-01, log-01, dns-01; } Values to fill in: * **Block name / file name** -- the block name (''name-01'') and the config file name must match the jail's name (''${name}'' expands to it at runtime). * **''$uuid''** -- the first segment of your generated UUID (e.g. ''f9ba13cb'' -> interface ''jf9ba13cbng0''). * **''ether''** -- a free MAC address in the ''58:9c:fc:ab:xx:xx'' range; must be unique per jail. * **''inet''** -- a free IPv4 address in ''172.20.200.0/24'' (the jail network; gateway ''172.20.200.1''). * **''$domain''** -- ''abi.am'' for externally visible jails, ''local.abi.am'' for internal ones. * **''depend''** -- the jails that must be running before this one starts. Everything else stays as-is: the ''exec.prestart''/''exec.poststop'' hooks call ''ngbuddy'' to create and destroy the jail's netgraph interface on the ''prod'' bridge automatically, and ''exec.consolelog'' sends the jail's console output to ''/var/log/jail/name-01.log''. ==== 4. Start the jail ==== jailer start name-01 That's it -- the jail is up. Verify with: jls jailer list and get a shell inside the jail with: jailer console name-01 ---- ===== See also ===== * [[infra:backup_dataset|Backup a Dataset]] -- uses the same ZFS send/recv mechanism * [[infra:servers:UpdatingFreeBSD|Update FreeBSD Servers]] * [[infra:howto:start|How To's]] If you created a new jail, add an entry to [[infra:changelog]].