Jails with nullfs mount of base system on FreeBSD 11 ---------------------------------------------------------------------- Last edited: $Date: 2017/02/12 14:41:20 $ When setting up a fresh FreeBSD 11 server, I used the system with nullfs jails as described on my page Jails with nullfs mount of base system on FreeBSD 10 without buildworld. See: gopher://box.matto.nl/0/freebsd10jails.txt I did changed the basic file structure a bit, to make it less complex to read. This is the system that I use now: /jails : directory for every thing jail related /jails/master : directory with the base filesystem, that will get read only nullfs mounted in the jails /jails/skeleton : directory with the files that will be writeable, each jail gets it own set /jails/files/<jailname> : directory where files from skeleton are copied to /jails/<jailname> : empty directory, where everything gets nullfs mounted The /jails/master is nullfs read only mounted into the jail directory of every jail, so this part exists only once on the hard disk. Every jail gets a number of files that are writeable, like `/etc/rc.conf` and `/etc/ssh/sshd_config`. These files are copied once from `/jails/skeleton` to `/jails/files/<jailname>`. Every jail will have its own set, so this part exists as many times on your harddisk as you have jails. ## Prepare base system The base system will be mounted read-only into the jail. We populate the base system from the install CDROM. mkdir -p /jails/master setenv DESTDIR /jails/master mount_cd9660 /dev/cd0 /mnt tar -xf /mnt/usr/freebsd-dist/base.txz -C $DESTDIR tar -xf /mnt/usr/freebsd-dist/doc.txz -C $DESTDIR cd umount /mnt cp /etc/resolv.conf $DESTDIR/etc/ chroot $DESTDIR tzsetup pkg install cpdup With this last step (`pkg install cpdup`) we force the system to install the pkg utility. Later on in the process this will not be as easy as this, because we are going to move directories like /etc out of the base system. ## Prepare template for the read-write part of the jail First setup the directory for the template: mkdir /jails/skeleton/ /jails/skeleton/home /jails/skeleton//usr-X11R6 Now populate it by moving parts of the base system into it: cd /jails/master mv etc /jails/skeleton/ mv usr/local /jails/skeleton//usr-local mv tmp /jails/skeleton/ mv var /jails/skeleton/ mv root /jails/skeleton/ And create symlinks back into the base system: cd /jails/master mkdir s ln -s s/etc etc ln -s s/home home ln -s s/root root ln -s /s/usr-local usr/local ln -s /s/usr-X11R6 usr/X11R6 ln -s s/tmp tmp ln -s s/var var ## Creating the directories for a new jail Two directories are created for the new jail: /jails/<jailname> /jails/files/<jailname> The `/jails/<jailname>` will be populated by a nullfs mount The `/jails/files/<jailname>` will get real files by copying the skel directory to it. ### Populate /jails/files/ cpdup /jails/skeleton /jails/files/<jailname> ### Edit /etc/fstab On the host add the following lines to /etc/fstab: /jails/master /jails/<jailname> nullfs ro 0 0 /jails/files/<jailname> /jails/<jailname>/s nullfs rw 0 0 ### Edit /etc/jail.conf /etc/jail.conf has a block with general configuration for all jails: devfs_ruleset = 4; allow.raw_sockets = 0; exec.clean; exec.start = "/bin/sh /etc/rc"; exec.stop = "/bin/sh /etc/rc.shutdown"; mount.devfs; allow.set_hostname = 0; allow.sysvipc = 0; Below this part, for each jail a block has to be added to /etc/jail.conf: <jailname> { host.hostname = "<jailname>"; path = "/jails/<jailname>"; ip4.addr += "<ipaddress>/32"; exec.system_user = "root"; exec.jail_user = "root"; exec.consolelog = "/var/log/jail_<jailname>_console.log"; } ## Edit sshd_config The host will have a sshd_config, and every jail will have one, too. It is important that every instance of the sshd-server will listen only to one ip address. So, first change the /etc/ssh/sshd_config file of the host. Change the line with the ListenAddress by uncommenting it and adding the ip address of the host to it. Every jail needs also the right listen address in the sshd_config file of the jail. ## Create ip address alias for the jail The configuration of the network interface has to be extended with the ip address of the new jail. So you have to make an alias for it. This can be done in /etc/rc.conf, but then either the network has to be restarted or the alias must also be made manually with the ifconfig command. Below is a example line for the /etc/rc.conf file: ifconfig_re0_alias0="inet 192.168.1.100 netmask 0xffffff00" ## Start the jail When the directories are populated and the config files are edited, we can start the jail. First we mount the nullfs mounts: mount -a Now we can chroot into the jail directory and set the root password. cd /jails/<jailname> chroot . passwd exit And start the jail: jail -c <jailname> See if the jail is started, and add a user. jls jexec <jailnumber> /bin/sh ps aux adduser exit ## Script to create a new jail When the /jails/master and /jails/skeleton is populated, the following script can be used to create a new jail. #!/bin/sh ######## # script to set up nullfs jail # $1 is name of jail # $2 is ip address of jail ######## ### Check that two arguments are given ### if [ $# -ne 2 ] then echo "Not two arguments supplied!" echo "Usage: " echo " $0 <jailname> <jail ip-address>" exit fi ### Setup jail files ### mkdir -p /jails/$1 mkdir -p /jails/files/$1 cpdup /jails/skeleton /jails/files/$1 ### Configure sshd to listen only to jail ip address ### echo "ListenAddress $2" >> /jails/files/$1/etc/ssh/sshd_config ### Add jail to /etc/jail.conf ### cat << EOB | sed "s/JAILNAME/$1/g" | sed "s/IPADDRESS/$2/g" >> /etc/jail.conf JAILNAME { host.hostname = "JAILNAME.example.com"; path = "/jails/JAILNAME"; ip4.addr += "IPADDRESS/32"; exec.system_user = "root"; exec.jail_user = "root"; exec.consolelog = "/var/log/jail_JAILNAME_console.log"; } EOB ### Add jail file system to /etc/fstab ### cat << EOB1 | sed "s/JAILNAME/$1/g" | sed "s/IPADDRESS/$2/g" >> /etc/fstab # JAILNAME /jails/master /jails/JAILNAME nullfs ro 0 0 /jails/files/JAILNAME /jails/JAILNAME/s nullfs rw 0 0 EOB1 cat << EOB2 | sed "s/JAILNAME/$1/g" > /jails/files/$1/etc/rc.conf hostname="JAILNAME.example.com" defaultrouter="192.168.1.254" sshd_enable="YES" sendmail_enable="NO" sendmail_submit_enable="NO" sendmail_outbound_enable="NO" sendmail_msp_queue_enable="NO" EOB2 ### Get latest alias line and calculate next alias ### ### Will only work for alias 1 to alias 10 ### ### alias0 has to exist, or this will fail ### p=`grep alias /etc/rc.conf | tail -n 1 | cut -d'=' -f 1 | tail -c 2 | sed 's/ //g'` p=`expr $p + 1` echo "ifconfig_re0_alias$p=\"inet $2 netmask 0xffffff00\"" >> /etc/rc.conf echo "end of script" echo "" echo "Proceed with the following steps" echo "* mount -a (to mount jail file system)" echo "" echo "* ifconfig re0 $2 netmask 255.255.255.0 alias (to set alias manualy)" echo " (or restart network with: /etc/rc.d/netif restart && /etc/rc.d/routing restart)" echo "" echo "* chroot to /jails/$1 and set root password and add a user" echo "" echo "* jail -c $1 (to start the new jail $1)" Have fun! $Id: freebsd11jails.txt,v 1.4 2017/02/12 14:41:20 matto Exp $