FreeBSD - How to setup & configure jail with ezjail

OS virtualization is a technology that enable multiple copies of guest OS to run on top of a host OS. Why do we wanna do this?
- partition resources to share across multiple guest OS (current hardware to run multiple light guest OS. e.g. FreeBSD & Linux)
- enhance security (guest OS are isolated and thus hacking into a guest OS leaves other OS safe)
- saves power & money (hosting rack space & power are minimize)
- creating environments (application or OS testing, backup, legacy apps, admin delegation)
- improves server management (guest OS within virtualization are easier to move, copy, backup & remove)

FreeBSD Jail first appear in FreeBSD 4.x, introduced by Poul-Henning Kamp. Jail is a powerful OS virtualization that achieves security, cost, management & flexibility. Because of all these advantages, jail can some time be quite complex to setup & configure. Ezjail offers the simplicity to configure & maintain jails, without the complexity of getting our hands dirty. :p

Ezjail is a framework that controls jail. Ezjail takes care of the complicated part and makes setting up & maintenance of jail fun. Ezjail is develop by Dirk Engling, thanks Dirk. :)

FreeBSD jail does have its limitation. Here are the ones I've bump :
- resource control, e.g. ram & processor cannot be partition, they are all equally being shared. But hard disk space can be separate and control by implementing hard disk partition (or slice).
- all guest OS have to use the same kernel version as the host OS

Okay, enough of talking. Here's a simple step-by-step guide on how to setup Ezjail. Firstly, install Ezjail from sysutils/ezjail using Portmanager then proceed the below steps:

Setup & configure

  1. Update the ezjail's environment & give a copy of FreeBSD's ports tree to base of jail which will be linked to newly created jails using ezjail :
    ezjail-admin update -ip
    (this is to save inodes & space)
  2. Prepare the rc.conf (of the host) with the following example :
    #The server that host our jails
    ifconfig_em0="inet netmask"
    #interface that the jails will be using
    ifconfig_rl0="inet netmask"
    #another note, jail can also be setup & configure using alias
    #e.g. ifconfig_em0_alias0="inet netmask"
    #make ezjail services & jails auto start up
  3. Create a jail :
    ezjail-admin create firstjail
  4. Assign FQDN to jail's hostname in its config file "/usr/local/etc/ezjail/firstjail".
    export jail_firstjail_hostname="firstjail.example.com
  5. Start the ezjail service :
    /usr/local/etc/rc.d/ezjail.sh start
  6. The jail is ready & can be access using the jail's console. Start the console of the jail by :
    ezjail-admin console firstjail

Console - ssh

Since jail is another virtual server, we'll need to configure it so that other system admin or user can have a way to access it. We'll start by configuring secure shell on it.
  1. Start the console of the jail by :
    ezjail-admin console firstjail
  2. Within the jail's console, enable ssh via its /etc/rc.conf (of the jail) :
    grep ssh /etc/defaults/rc.conf >> /etc/rc.conf
  3. Start the ssh of the jail with :
    /etc/rc.d/sshd start
  4. By the way, remember to setup DNS & hostname of the jail. Edit the file and fill in appropriate values :
    • /etc/resolv.conf
    • /etc/hosts

Ports tree

The same ports tree can be share among jails & the host system, /usr/ports in the base system are linked to /usr/jails/basejail/usr/ports. But the jail will see it as "/usr/ports". Even it is linked, it is read only for the jails. After all, jails are meant to separate with the host and other jails so to decrease the security risk.
There's one problem for this setup though. When installing compiling ports, it needs to write temporary files, downloaded files & index files to ports directory. We'll need to create these directories and tell ports (within jail) to use that instead of (the default) /usr/ports directory. Here is how to configure it :
mkdir $j/var/ports
mkdir $j/var/ports/distfiles
mkdir $j/var/ports/packages
mount_nullfs -o rw /usr/ports/distfiles $j/var/ports/distfiles

Next, input the below lines into /etc/make.conf so that ports know about the directories created and use it :
WRKDIRPREFIX=           /var/ports
DISTDIR=                /var/ports/distfiles
PACKAGES=               /var/ports/packages
INDEXDIR=               /var/ports

Finally, just like a normal FreeBSD box, jail's ports tree needs to be updated as well.
  1. Update the ports tree of the jails by :
    ezjail-admin update -P
  2. After this, ssh to the jail and install softwares (e.g. apache22) as usual. No need to update the ports tree as "ezjail-admin -P" will update it.

Jails are isolated, the same goes to the ports tree within the jail. Installing ports within the jail will NOT affect the host system. Just remember to issue the command:
ezjail-admin update -P
to update the ports tree of the jails. Now, we can continue to install the latest software from ports into jail.


  1. On some cases, first time issuing "ezjail-admin update -ip", the below error pops out :
    >>> Installing everything
    cd /usr/src; make -f Makefile.inc1 install
    ===> share/info (install)
    install -o root -g wheel -m 444  dir-tmpl  /usr/jails/fulljail/usr/share/info/dir
    install:No such file or directory
    *** Error code 1
    Stop in /usr/src/share/info.
    *** Error code 1
    Stop in /usr/src.
    *** Error code 1
    Stop in /usr/src.
    *** Error code 1
    Stop in /usr/src.
    *** Error code 1
    Stop in /usr/src.
    Error: The command 'make installworld' failed.
    Refer to the error report(s) above.
    The problem is jail can't find the kernel source. So, the solution to this is :
    cd /usr/src;make buildworld
  2. Some might encounter the below error message when getting the source :
    cd: can't cd to /usr/src/tools/build/make_check
    >>> Building an up-to-date make(1)
    cd: can't cd to /usr/src/usr.bin/make
    *** Error code 2
    Stop in /usr/src.
    *** Error code 1
    Stop in /usr/src.
    Then we'll have to fetch the source tree, but first, install the port devel/subversion :
    portmaster -dwv devel/subversion
    Then, fetch the source treee :
    svn co http://svn.freebsd.org/base/stable/9 /usr/src
  3. If /usr/local/etc/rc.d./ezjail starting takes a bit too long, it might cause by FQDN. Change the config file of the jail /usr/local/etc/ezjail/firstjail according to the following :
    export jail_firstjail_hostname="firstjail"
    export jail_firstjail_hostname="firstjail.example.com"
    and make sure the FQDN resolve. In another words, the value for parameter "export jail_firstjail_hostname" have to be in FQDN (Fully qualified Domain Name)
  4. While ping from inside jail, the error pops up :
    ping: socket: Operation not permitted
    It is cause be jail are not permitted to access raw socket. If you must do it, the solution is :
    sysctl security.jail.allow_raw_sockets=1
    /usr/local/etc/rc.d/ezjail.sh restart firstjail

    ** it is not recommended to enable raw socket within jail as tools such as perl/nc can interact with socket and thus post security concern. use other tools to test connection. e.g. nslookup, host, telnet & etc
  5. When creating jails using "ezjail-admin create firstjail", an warning message appears at the end of the output :
    Warning: Some services already seem to be listening on all IP, (including
    This may cause some confusion, here they are:
    root     sshd       902   4  tcp4   *:22                *:*
    root     syslogd    685   7  udp4   *:514                 *:*
    this due to the host's services are listening to all IPs & interfaces. Configure the services listed in the error message to listen only the intended IP. e.g.
    in /etc/ssh/sshd_config, specify
    so that the ssh daemon listens only on & localhost
    as for syslogd, add/change parameter in /etc/rc.conf :
    syslogd_enable="YES"            # Run syslog daemon (or NO).
    syslogd_flags="-s -b"         # Flags to syslogd (if enabled).
    and issue the command :
    /etc/rc.d/syslogd restart
    this would make syslogd to listen only on localhost.
  6. Within the jail, this is how to stop various services to bind on the network interface :
    1. stop syslogd from listening on network interface, put the below into /etc/rc.conf :
    2. stop sendmail from starting, put the below into /etc/rc.conf:

Some tips

  • Okay, creating jails now are fairly easy and effortless. But how can we delete it???
    ezjail-admin delete -w testingonly
    this will delete the jail directory and respective config files (/etc/fstab.firstjail & /usr/local/etc/ezjail/firstjail)
  • List current jails :
    ezjail-admin list
    where :
    • D = Directory base (same kind of jail this post creating)
    • R = Running or started
    • S = Stopped
    • N = Not running because it is disabled
  • Stop a particular jail :
    /usr/local/etc/rc.d/ezjail.sh stop [jail name]
    /usr/local/etc/rc.d/ezjail.sh stop firstjail
  • The jail's file system are actually store at /usr/jails/<hostname>/.
    e.g. /usr/jails/firstjail/.
    Because of this, we can just edit the jail's ssh server config file at /usr/jails/firstjail/etc/sshd_config.

Have fun & Ciao !!!

Reference :

1 comment:

Mel Mudin said...

Any posts on how to secure the host and jail?