2024: Domino Containers - The Next Step. News from the Domino Container commu...
FreeBSD Jail Complete Example
1. FreeBSD Jail Complete Example
The goals of the setup described below are:
Create a simple and easy to understand jail structure. This implies not having to
run a full installworld on each and every jail.
Make it easy to add new jails or remove existing ones.
Make it easy to update or upgrade existing jails.
Make it possible to run a customized FreeBSD branch.
Be paranoid about security, reducing as much as possible the possibility of
compromise.
Save space and inodes, as much as possible.
As it has been already mentioned, this design relies heavily on having a single master
template which is read-only (known as nullfs) mounted into each jail and one read-write
device per jail. A device can be a separate physical disc, a partition, or a vnode backed
md(4) device. In this example, we will use read-write nullfs mounts.
The file system layout is described in the following list:
Each jail will be mounted under the /home/j directory.
/home/j/mroot is the template for each jail and the read-only partition for all of
the jails.
A blank directory will be created for each jail under the /home/j directory.
Each jail will have a /s directory, that will be linked to the read-write portion of
the system.
Each jail shall have its own read-write system that is based upon /home/j/skel.
Each jailspace (read-write portion of each jail) shall be created in /home/js.
Note: This assumes that the jails are based under the /home partition. This can, of course,
be changed to anything else, but this change will have to be reflected in each of the
examples below.
15.6.1.2 Creating the Template
This section will describe the steps needed to create the master template that will be the
read-only portion for the jails to use.
It is always a good idea to update the FreeBSD system to the latest -RELEASE branch.
Check the corresponding Handbook Chapter to accomplish this task. In the case the
update is not feasible, the buildworld will be required in order to be able to proceed.
Additionally, the sysutils/cpdup package will be required. We will use the portsnap(8)
utility to download the FreeBSD Ports Collection. The Handbook Portsnap Chapter is
always good reading for newcomers.
2. 1. First, create a directory structure for the read-only file system which will contain
the FreeBSD binaries for our jails, then change directory to the FreeBSD source
tree and install the read-only file system to the jail template:
2. # mkdir /home/j /home/j/mroot
3. # cd /usr/src
4. # make installworld DESTDIR=/home/j/mroot
5. Next, prepare a FreeBSD Ports Collection for the jails as well as a FreeBSD
source tree, which is required for mergemaster:
6. # cd /home/j/mroot
7. # mkdir usr/ports
8. # portsnap -p /home/j/mroot/usr/ports fetch extract
9. # cpdup /usr/src /home/j/mroot/usr/src
10. Create a skeleton for the read-write portion of the system:
11. # mkdir /home/j/skel /home/j/skel/home /home/j/skel/usr-X11R6
/home/j/skel/distfiles
12. # mv etc /home/j/skel
13. # mv usr/local /home/j/skel/usr-local
14. # mv tmp /home/j/skel
15. # mv var /home/j/skel
16. # mv root /home/j/skel
17. Use mergemaster to install missing configuration files. Then get rid of the extra
directories that mergemaster creates:
18. # mergemaster -t /home/j/skel/var/tmp/temproot -D /home/j/skel -
i
19. # cd /home/j/skel
20. # rm -R bin boot lib libexec mnt proc rescue sbin sys usr dev
21. Now, symlink the read-write file system to the read-only file system. Please make
sure that the symlinks are created in the correct s/ locations. Real directories or
the creation of directories in the wrong locations will cause the installation to fail.
22. #
cd /home/j/mroot
23. #
mkdir s
24. #
ln -s s/etc etc
25. #
ln -s s/home home
26. #
ln -s s/root root
27. #
ln -s ../s/usr-local usr/local
28. #
ln -s ../s/usr-X11R6 usr/X11R6
29. #
ln -s ../../s/distfiles usr/ports/distfiles
30. #
ln -s s/tmp tmp
31. #
ln -s s/var var
32. As a last step, create a generic /home/j/skel/etc/make.conf with its contents
as shown below:
33. WRKDIRPREFIX?= /s/portbuild
Having WRKDIRPREFIX set up this way will make it possible to compile FreeBSD
ports inside each jail. Remember that the ports directory is part of the read-only
system. The custom path for WRKDIRPREFIX allows builds to be done in the read-
write portion of every jail.
15.6.1.3 Creating Jails
3. Now that we have a complete FreeBSD jail template, we can setup and configure the jails
in /etc/rc.conf. This example demonstrates the creation of 3 jails: “NS”, “MAIL” and
“WWW”.
1. Put the following lines into the /etc/fstab file, so that the read-only template for
the jails and the read-write space will be available in the respective jails:
2. /home/j/mroot /home/j/ns nullfs ro 0 0
3. /home/j/mroot /home/j/mail nullfs ro 0 0
4. /home/j/mroot /home/j/www nullfs ro 0 0
5. /home/js/ns /home/j/ns/s nullfs rw 0 0
6. /home/js/mail /home/j/mail/s nullfs rw 0 0
7. /home/js/www /home/j/www/s nullfs rw 0 0
Note: Partitions marked with a 0 pass number are not checked by fsck(8)
during boot, and partitions marked with a 0 dump number are not backed
up by dump(8). We do not want fsck to check nullfs mounts or dump to
back up the read-only nullfs mounts of the jails. This is why they are
marked with “0 0” in the last two columns of each fstab entry above.
8. Configure the jails in /etc/rc.conf:
9. jail_enable="YES"
10. jail_set_hostname_allow="NO"
11. jail_list="ns mail www"
12. jail_ns_hostname="ns.example.org"
13. jail_ns_ip="192.168.3.17"
14. jail_ns_rootdir="/usr/home/j/ns"
15. jail_ns_devfs_enable="YES"
16. jail_mail_hostname="mail.example.org"
17. jail_mail_ip="192.168.3.18"
18. jail_mail_rootdir="/usr/home/j/mail"
19. jail_mail_devfs_enable="YES"
20. jail_www_hostname="www.example.org"
21. jail_www_ip="62.123.43.14"
22. jail_www_rootdir="/usr/home/j/www"
23. jail_www_devfs_enable="YES"
Warning: The reason why the jail_name_rootdir variable is set to
/usr/home instead of /home is that the physical path of the /home
directory on a default FreeBSD installation is /usr/home. The
jail_name_rootdir variable must not be set to a path which includes a
symbolic link, otherwise the jails will refuse to start. Use the realpath(1)
utility to determine a value which should be set to this variable. Please see
the FreeBSD-SA-07:01.jail Security Advisory for more information.
24. Create the required mount points for the read-only file system of each jail:
25. # mkdir /home/j/ns /home/j/mail /home/j/www
26. Install the read-write template into each jail. Note the use of sysutils/cpdup,
which helps to ensure that a correct copy is done of each directory:
27. # mkdir /home/js
28. # cpdup /home/j/skel /home/js/ns
29. # cpdup /home/j/skel /home/js/mail
4. 30. # cpdup /home/j/skel /home/js/www
31. In this phase, the jails are built and prepared to run. First, mount the required file
systems for each jail, and then start them using the /etc/rc.d/jail script:
32. # mount -a
33. # /etc/rc.d/jail start
The jails should be running now. To check if they have started correctly, use the jls(8)
command. Its output should be similar to the following:
# jls
JID IP Address Hostname Path
3 192.168.3.17 ns.example.org /home/j/ns
2 192.168.3.18 mail.example.org /home/j/mail
1 62.123.43.14 www.example.org /home/j/www
At this point, it should be possible to log onto each jail, add new users or configure
daemons. The JID column indicates the jail identification number of each running jail.
Use the following command in order to perform administrative tasks in the jail whose
JID is 3:
# jexec 3 tcsh
15.6.1.4 Upgrading
In time, there will be a need to upgrade the system to a newer version of FreeBSD, either
because of a security issue, or because new features have been implemented which are
useful for the existing jails. The design of this setup provides an easy way to upgrade
existing jails. Additionally, it minimizes their downtime, as the jails will be brought down
only in the very last minute. Also, it provides a way to roll back to the older versions
should any problems occur.
1. The first step is to upgrade the host system in the usual manner. Then create a
new temporary read-only template in /home/j/mroot2.
2. # mkdir /home/j/mroot2
3. # cd /usr/src
4. # make installworld DESTDIR=/home/j/mroot2
5. # cd /home/j/mroot2
6. # cpdup /usr/src usr/src
7. # mkdir s
The installworld run creates a few unnecessary directories, which should be
removed:
# chflags -R 0 var
# rm -R etc var root usr/local tmp
8. Recreate the read-write symlinks for the master file system:
9. # ln -s s/etc etc
10. # ln -s s/root root
11. # ln -s s/home home
5. 12. # ln -s ../s/usr-local usr/local
13. # ln -s ../s/usr-X11R6 usr/X11R6
14. # ln -s s/tmp tmp
15. # ln -s s/var var
16. The right time to stop the jails is now:
17. # /etc/rc.d/jail stop
18. Unmount the original file systems:
19. # umount /home/j/ns/s
20. # umount /home/j/ns
21. # umount /home/j/mail/s
22. # umount /home/j/mail
23. # umount /home/j/www/s
24. # umount /home/j/www
Note: The read-write systems are attached to the read-only system (/s)
and must be unmounted first.
25. Move the old read-only file system and replace it with the new one. This will
serve as a backup and archive of the old read-only file system should something
go wrong. The naming convention used here corresponds to when a new read-
only file system has been created. Move the original FreeBSD Ports Collection
over to the new file system to save some space and inodes:
26. # cd /home/j
27. # mv mroot mroot.20060601
28. # mv mroot2 mroot
29. # mv mroot.20060601/usr/ports mroot/usr
30. At this point the new read-only template is ready, so the only remaining task is to
remount the file systems and start the jails:
31. # mount -a
32. # /etc/rc.d/jail start