In previous post we have prepared our jail host to be jail-friendly. In this one we will set up our first jail.

Create Required Folders

All of our jails will reside under /usr/jails. This directory does not exist on vanilla FreeBSD installation therefore we need to create it:

mkdir /usr/jails

I will also create directories for storing SSL certificates:

mkdir /etc/ssl/selfsigned
mkdir /usr/local/etc/letsencrypt

These folders will be nullfs-mounted into jails. This will enable storing all the certificates on jail host, and eliminate the need to replicate them into all the jails.

Jail Creation

It is time to install our first jail. In next chapter about Poudriere, this jail will become our custom package repository, therefore it is appropriate to name it

env BSDINSTALL_DISTSITE="" bsdinstall jail /usr/jails/

Familiar bsdinstall wizard will:

  • ask for optional components to install (I de-select them all)
  • fetch and extract distribution files
  • ask for root password (it should be different from the one on jail host)
  • ask for any services to be started at boot time (I de-select them all)
  • ask to add any users (I add user marko with default UID of 1001, default group marko, additional groups wheel and operator, tcsh as shell, and strong password)

Passwords should be different between jails, and most importantly between jail host and jails.

Jail Deletion

bsdinstall sets immutable flag on some files, which prevents their deletion with rm -rf. In order to be able to delete jail this flag needs to be removed first.

chflags -R noschg /usr/jails/
rm -rf /usr/jails/
jail.conf Creation

All the parameters of our jails will be set through /etc/jail.conf:

Make sure to always edit highlighted lines according to your environment.

You can safely use copy button in code blocks - it will copy only text and commands, not line numbers and terminal prompts.


path           = "/usr/jails/${host.hostname}";
exec.prestart  = "/sbin/mount_nullfs -o ro /usr/local/etc/letsencrypt \
exec.prestart += "/sbin/mount_nullfs -o ro /etc/ssl/selfsigned \
exec.start     = "/bin/sh /etc/rc";
exec.stop      = "/bin/sh /etc/rc.shutdown";
exec.poststop  = "/sbin/umount /usr/jail/${host.hostname}/etc/ssl/letsencrypt/";
exec.poststop += "/sbin/umount /usr/jail/${host.hostname}/etc/ssl/selfsigned/";

pkg_example_org {
  host.hostname    =;
  host.domainname  =;
  ip4.addr         = 'lo1|';
  ip4.addr        += 'em0|';

In order to start jails at host's boot time, I need to enable the feature in host's rc.conf:

sysrc jail_enable="YES"

Jails are started, stopped or restarted in same fashion as any other services in FreeBSD, with service <servicename> (start|stop|restart). Without additional arguments, this would start / stop / restart all the jails declared in jail.conf. For starting / stopping / restarting single jail, we need to pass its name as an argument to the command.

Let's start our first jail:

service jail start

We can see the list of all running jails with jls command:


...which should show output similar to:

JID  IP Address      Hostname                      Path
  1               /usr/jails/

Assuming our jail is running we can log into it by passing jid and path to shell executable to jexec command:

jexec 1 /bin/tcsh

Notice prompt changed

uname -a

Some admins don't like to enable ssh access to jails. Instead, they ssh exclusively to host, and then jexec to jails. As for myself, I like to have ssh access to my jails. Throughout this tutorial series, I will be logging into my jails by means of ssh, but before enabling it in jails' rc.conf, do not forget to edit their sshd_config so that it binds only to specified IP address, as described in previous chapter.

All of my jails start with the following rc.conf as default template:


cron_flags="$cron_flags -J 15"

We can exit jail's shell and return to host's shell by typing exit. After jail restart (check above if you forgot how), we can ssh into it and continue with its configuration and usage as usual.

Next Post Previous Post