How to use FreeBSD Jails with ZFS

29th Jan 2019 • Marco Cetica

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:

root@bsd:~ gpart add -t freebsd-zfs da0s1 # replace 'da0s1' with your actual disk

Next, let's enable poll 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:

root@bsd:~ zpoll 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.

root@bsd:~ zfs create -o mountpoint=/usr/jails zroot/jails root@bsd:~ 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.

root@bsd:~ bsdinstall jail /usr/jails/template

Now, we can proceed by creating a snapshot of the template Jail

root@bsd:~ 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.

root@bsd:~ 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:

root@bsd:~ service jail start www

We can retrieve a list of running jails by running jls:

root@bsd:~ 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:

root@bsd:~ pkg -j www install nginx root@bsd:~ sysrc -f /usr/jails/www/etc/rc.conf nginx_enable="YES" nginx_enable: NO -> YES root@bsd:~ 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:

root@bsd:~ # 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:

root@bsd:~ # zfs destroy zroot/jails/www

Then, remove it from the jail_list variable on /etc/rc.conf.