How to use FreeBSD Jails with ZFS
In this guide we will see how to use FreeBSD Jails using the Z file system. This will allow us to create a skeleton jail (i.e., a base image) that will be copied every time we need to deploy a new service. One of the key advantages of this approach is that each Jail is initially identical to the skeleton, meaning that it consumes virtually no additional space until its data begins to diverge from the template.
Create a ZFS partition
To avoid assuming any prior steps, we will begin by creating a new ZFS partition:
# gpart add -t freebsd-zfs da0s1 # replace 'da0s1' with your actual disk
Next, let’s enable pool auto mount at boot by adding the following entry to the
/etc/rc.conf file:
zfs_enable="YES"
Create a new pool
Let’s now proceed by creating a new ZFS pool on the /dev/da0s1b partition:
# zpool create zroot /dev/da0s1b
Then, we can create two datasets called jails and jails/template, respectively. The former will store the actual Jails while the latter will provide a skeleton for creating new services.
# zfs create -o mountpoint=/usr/jails zroot/jails
# zfs create zroot/jails/template
Create the template Jail
Let’s now set up the template Jail. We will begin by installing the base system on it
using bsdinstall(8). When prompted, we will omit the root password.
# bsdinstall jail /usr/jails/template
Now, we can proceed by creating a snapshot of the template Jail
# zfs snapshot zroot/jails/template@clean
The base template is ready for duplication, let’s try it.
Create a new Jail
We are now ready to create a new Jail using the template we have created in the previous step.
# zfs clone zroot/jails/template@clean zroot/jails/www
Before starting it, let’s create a simple configuration file under /etc/jail.conf:
# Get Jail path
$jail_path="/usr/jails";
path="$jail_path/$name";
# Global settings
mount.devfs;
exec.clean;
exec.start="sh /etc/rc";
exec.stop="sh /etc/rc.shutdown";
allow.raw_sockets=1;
ip4=inherit;
www {
host.hostname="www";
}
Then, let’s add the following two lines to /etc/rc.conf:
[...]
jail_list="www"
jail_enable="YES"
Finally, to start the Jail, we can issue the following command:
# service jail start www
We can retrieve a list of running jails by running jls:
# jls
JID IP Address Hostname Path
1 www /usr/jails/www
The Jail is now up and ready to use. As an example, we will try to configure the nginx web server:
# pkg -j www install nginx
# sysrc -f /usr/jails/www/etc/rc.conf nginx_enable="YES"
nginx_enable: NO -> YES
# service -j www nginx start
Testing
Let’s now make sure that the web server is running on port 80. We can verify
that by issuing the following command:
# sockstat -46l
USER COMMAND PID FD PROTO LOCAL ADDRESS FOREIGN ADDRESS
www nginx 1005 6 tcp4 *:80 *:*
root nginx 1004 6 tcp4 *:80 *:*
Destroying a Jail
Last but not least, to remove a Jail, shut it down using service jail stop www, destroy its ZFS
dataset using:
# zfs destroy zroot/jails/www
Then, remove it from the jail_list variable on /etc/rc.conf.