Making FreeBSD jails with jail.conf

So far making jails in FreeBSD with jail.conf is the easiest method I’ve tried (out of the several jail mangers I’ve tried). I’m not sure if any jail manager can be easier than this.

vnet, yep.
mounts, yep.
pkgs, yep.
resource limits, yep.

I am building myself a script to handle “templates” which will consist of a few config files that list the name, IP, mountings and whatnot but below is a quick script for you to play with after you do the initial “classic jail setup” items listed in the handbook. NOTE: Absolutely zero error handling on the below script (this is not a “production ready” version). Use with caution!

#!/bin/sh

# Script Arguments
jailname=$1
epairid=$2

# Global variables.
media=14.1-RELEASE-base.txz
containers=/usr/local/jails/containers/$jailname

# Create the directory.
mkdir -p $containers

# Extract the base.
tar -xf /usr/local/jails/media/$media -C $containers --unlink

# Copy DNS server 
cp /etc/resolv.conf $containers/etc/resolv.conf

# Copy timezone
cp /etc/localtime $containers/etc/localtime

# update to latest patch
# freebsd-update -b $containers/ fetch install

# Create the jail.conf file.
echo "$jailname {" > /etc/jail.conf.d/${jailname}.conf
echo '
  # STARTUP/LOGGING
  exec.start = "/bin/sh /etc/rc";
  exec.stop  = "/bin/sh /etc/rc.shutdown";
  exec.consolelog = "/var/log/jail_console_${name}.log";

  # PERMISSIONS
  allow.raw_sockets;
  exec.clean;
  mount.devfs;
  devfs_ruleset = 5;

  # PATH/HOSTNAME
  path = "/usr/local/jails/containers/${name}";
  host.hostname = "${name}";

  # VNET/VIMAGE
  vnet;
  vnet.interface = "${epair}b";' >> /etc/jail.conf.d/${jailname}.conf
echo "
  # NETWORKS/INTERFACES
  \$id = \"${epairid}\"; 
  \$ip = \"192.168.0.\${id}/24\";
  \$gateway = \"192.168.0.1\";
  \$bridge = \"bridge0\"; 
  \$epair = \"epair\${id}\";" >> /etc/jail.conf.d/${jailname}.conf
echo '  
  # ADD TO bridge INTERFACE
  exec.prestart  = "/sbin/ifconfig ${epair} create up";
  exec.prestart += "/sbin/ifconfig ${epair}a up descr jail:${name}";
  exec.prestart += "/sbin/ifconfig ${bridge} addm ${epair}a up";
  exec.start    += "/sbin/ifconfig ${epair}b ${ip} up";
  exec.start    += "/sbin/route add default ${gateway}";
  exec.poststop = "/sbin/ifconfig ${bridge} deletem ${epair}a";
  exec.poststop += "/sbin/ifconfig ${epair}a destroy";
}' >> /etc/jail.conf.d/${jailname}.conf

And another to cleanup the jail. NOTE: same as above, no error
checking! Use with caution.

#!/bin/sh

jailname=$1

# stop the jail
service jail stop $jailname

# Remove flags.
chflags -R 0 /usr/local/jails/containers/$jailname

# Delete directory
rm -rf /usr/local/jails/containers/$jailname

# Delete the .conf file.
rm /etc/jail.conf.d/${jailname}.conf

Last Saturday morning before everyone got up I hacked up a more robust version that reads a few config files (one for the userland and jail location) and one for the jail specific variables (name, IP, mounts, etc)–for a template system–and creates a jail.conf file in /etc/jail.conf.d/. My script became a bit “too monolithic” for my taste but it worked for the most part. Last night I ran a simple test to see if I could do the setup portion too–which worked(ish)–but the script needs to be rewritten to include a more robust error trapping system (to account for conditions like when jail start up fails).

This was fun but it turns out these jail managers written in shell script are hard to write. If I do take this further, I will rewrite in C (or get a bit more organized instead of hacking the skeleton code up in the early morning).