Register for the iXsystems Community to get an ad-free experience and exclusive discounts in our eBay Store.

Install script for Domoticz with open-zwave driver in iocage jail


Nov 1, 2016
A friend of mine, who is into home automation, wanted to install the domoticz system with drivers for the Aeotec Z-Stick Z-Wave USB stick into FreeNAS 11.1. I took as a challenge to find out, how difficult would it be to write a fairly complex, but fully automatic installation script of a FreeNAS jail.

This script is based on the wiki article at
Also, man iocage and the FreeBSD iocage documentation at are great resources.

This was originally done for a warden jail. The code that has to do with devfs rules was necessary there, but now that this script creates the domoticz jail in iocage, some of that code is superfluous. Also, some other services are installed in my friend's domoticz jail, so some settings in this script are not necessary just for domoticz.

The jail needs access to the Z-Wave USB device /dev/cuaU0 in the host system. In the iocage jail I could not access this device until I set devfs_ruleset=0. This basically gives the jail potentially access to everything in the host's /dev. I think the correct way would be to give access to only those devices that the jail really needs access to. I just couldn't figure out the correct devfs settings. Feel free to experiment with the iocage jail settings.

At the start of the script you will find some settings, which you should set before running the script.

JAIL_IP is the ip4_addr property. That is, the interface name and the ipv4 address and netmask you want to give for the jail. You can use e.g. vnet0 for the interface. If the start of this string is "vnet", the script will set vnet=on for the jail automatically. Note: to use vnet in iocage, you may need to set some tunables in FreeNAS. You can find many threads about that topic on this forum.

DEFAULT_ROUTER is the default router's ipv4 address.

For DOMOTICZ_DB_DIR you may enter a directory or a dataset on the FreeNAS side to be used as the database directory for domoticz. If this directory does not exist when you run this script, then this setting will not be applied, and domoticz will have it's database only in /var/db/domoticz/ in the jail.

If AUTOBOOT=1, then the script will set boot=on for the jail. If AUTOBOOT=0, then the boot property will not be set.

That's all you need to do. When you start the script, everything will be automatic. It takes about 15 minutes for the script to do this installation in my Freenas 11.1 VM. When the script has finished, it will show you the URL to access domoticz. Note: if domoticz seems unresponsive, turn off adblocking in your browser.

Obviously, this installation is of little use, if you don't have the Z-Wave USB stick or any other compatible device. You can still install domoticz, but there isn't much to to do in domoticz, if you don't have any hardware to play with.

With this script I want to show that it is quite possible to write "one click" installation scripts for iocage jails in FreeNAS 11.1.

To undo everything this script does, just type
iocage destroy domoticz
and delete user "domoticz" and group "domoticz" from FreeNAS.

The code is just ONE script file.

# Network settings:

# Domoticz database directory in the host. Set to "" if you don't want to use this feature:

if [ "$(id -u)" != "$(id -u root)" ]; then
	# could do:
	# eval "sudo $0"
	echo "You must be root to run this installer."
	exit 1

show_msg() {
	echo "**************************************************************"
	echo "*"
	while (( "$#" )); do
		echo "* $1"
	echo "*"
	echo "**************************************************************"

fn="$(basename $0)"
TMPFILE="$(mktemp -q '/tmp/'"$fn"'.XXXX')"
[ -e $TMPFILE ] || exit 1

# Detect or create user domoticz in the host
DOMOTICZ_UID="$(id -u domoticz)"
if [ -z "$DOMOTICZ_UID" ]; then
   pw useradd -q -n domoticz -s /sbin/nologin -h -
   DOMOTICZ_UID="$(id -u domoticz)"
DOMOTICZ_GID="$(id -g domoticz)"

# Detect Z-Wave device and set /etc/devfs.rules
addr="$(dmesg | sed -rn 's/.*umodem.*addr ([0-9]+).*/\1/p' | tail -n 1)"
if [ -n "$addr" ]; then
	if [ -n "$(grep 'devfsrules_jail_allow_usb' /etc/devfs.rules)" ]; then
		sed -r "s/(devfsrules_jail_allow_usb=)([0-9]+)/\1${addr}/" /etc/devfs.rules >$TMPFILE
		mv -f $TMPFILE /etc/devfs.rules
		echo "[devfsrules_jail_allow_usb=${addr}]" >> /etc/devfs.rules
		echo "add path 'cu*' unhide" >> /etc/devfs.rules

JROOT="$(jls | awk '$3 ~ /domoticz/ {print $4}')"
if [ -z "$JROOT" ]; then
	show_msg "Creating domoticz jail..."
	printf '{ "pkgs": [ "python3", "openssl", "sqlite3", "expat", "curl", "libiconv", ' >$TMPFILE
	printf '"gmake", "cmake", "subversion", "git", "devel/boost-libs", ' >> $TMPFILE
	printf '"devel/boost-python-libs", "devel/boost-all" ]}' >> $TMPFILE
	[ "${JAIL_IP:0:4}" == "vnet" ] && VNET="vnet=on"
	[ $AUTOBOOT -ne 0 ] && BOOTFLAG="boot=on"
	iocage create -n "domoticz" -r 11.1-RELEASE -p $TMPFILE ip4_addr="$JAIL_IP" \
		   defaultrouter="$DEFAULT_ROUTER" $VNET allow_raw_sockets="1" $BOOTFLAG
	[ $? -eq 0 ] || exit 1
	iocage set allow_mount="1" allow_mount_devfs="1" enforce_statfs="1" domoticz
	iocage set mount_devfs="1" allow_mount_nullfs="1" allow_mount_tmpfs="1" domoticz
	iocage set devfs_ruleset="0" domoticz

	JROOT="$(jls | awk '$3 ~ /domoticz/ {print $4}')"	
	sed '1,/--divider--$/d' "$0" > $TMPFILE
	[ -s "$TMPFILE" ] && dbdir="$(sed -rn 's/.*_dbdir:=(\/.*)}.*/\1/p' $TMPFILE)"
	[ -n "$dbdir" ] || dbdir="/var/db/domoticz"
	if [ "$(iocage get state domoticz)" != "up" ]; then
		iocage start domoticz &> /dev/null
		if [ $? -ne 0 ]; then
			show_msg "Error: The domoticz jail has been created," "but it does not start."
			exit 1

	# Build the domoticz jail
	cat << EOF | iocage chroot domoticz
	pw groupadd -n domoticz -g $DOMOTICZ_GID
	pw useradd -n domoticz -u $DOMOTICZ_UID -g $DOMOTICZ_GID -m -s /sbin/nologin -h -
	pw groupmod dialer -m domoticz
	git clone /home/domoticz/open-zwave-read-only
	gmake -C /home/domoticz/open-zwave-read-only
	git clone /home/domoticz/domoticz
	cmake -DCMAKE_BUILD_TYPE=Release /home/domoticz/domoticz/CMakeLists.txt
	make -j 2 -C /home/domoticz/domoticz
	chown -R domoticz:domoticz /home/domoticz/domoticz
	[ ! -d "$dbdir" ] && mkdir -p "$dbdir"
	chown domoticz: "$dbdir"
	mkdir /var/run/domoticz
	chown :domoticz /var/run/domoticz
	chmod 770 /var/run/domoticz
	echo "" >>/etc/rc.conf
	echo "# Lines added by domoticz" >> /etc/rc.conf
	echo 'hostname="domoticz"' >> /etc/rc.conf
	echo 'devfs_enable="YES"' >> /etc/rc.conf
	echo 'devfs_system_ruleset="devfsrules_common"' >> /etc/rc.conf
	echo 'domoticz_enable="YES"' >> /etc/rc.conf
	if [ -d "$DOMOTICZ_DB_DIR" ]; then
		iocage fstab -a domoticz "$DOMOTICZ_DB_DIR"  "$dbdir"  nullfs  rw  0  0
		show_msg "Warning: Database directory not outside of the jail."

# Trying to install the domoticz service in the jail
if [ ! -s $TMPFILE ]; then
	sed '1,/--divider--$/d' "$0" > $TMPFILE
if [ -s $TMPFILE ]; then
	cp -f $TMPFILE "${JROOT}/etc/rc.d/domoticz"
	chmod 555 "${JROOT}/etc/rc.d/domoticz"

if [ $AUTOBOOT -eq 0 ]; then
	iocage stop domoticz &> /dev/null
	iocage restart domoticz &> /dev/null

# Creating the ttyUSB# device(es) and setting permissions
for cua in $(ls /dev/cuaU* 2>/dev/null); do
	ln -sf "$cua" "${JROOT}/dev/ttyUSB${cua: -1}"
chown root:domoticz "${JROOT}/dev/ttyU"* &> /dev/null
chmod 660 "${JROOT}/dev/ttyU"* &> /dev/null

domoip="$(jls | awk '$3 ~ /domoticz/ {print $2}')"
if [ "$(iocage get state domoticz)" == "up" ]; then
	show_msg "Domoticz is now running." "" \
	"The web user interface is at:" "" "http://$domoip:8080"
	show_msg "Domoticz is now installed. Start it from" \
		"the FreeNAS new UI Jails section," \
		"or by running:" "" "iocage start domoticz" "" \
		"The web user interface will be at:" "http://$domoip:8080"
rm "$TMPFILE" &> /dev/null
exit 0

# Do not remove or alter the divider line below!
# --divider--
#! /bin/sh

# PROVIDE: domoticz
# REQUIRE: LOGIN cleanvar
# KEYWORD: shutdown

# Add the following lines to /etc/rc.conf to enable domoticz:
#domoticz_enable (bool): set to "YES" to start domotics at boot
#domoticz_dbdir (str):   Default to "/var/db/domoticz"
#						domoticz database directory
#domoticz_user (str):	Default to www, user for starting domoticz
#domoticz_group (str):   Default to www, group for stating domoticz
#domoticz_pidfile (str): Custum PID file path and name
#						Default to "/var/run/domoticz/${hostname}.pid".
#domoticz_args (str):	Custom additional arguments to be passed

. /etc/rc.subr


load_rc_config $name

: ${domoticz_dbdir:=/var/db/domoticz}
: ${domoticz_user:=domoticz}
: ${domoticz_group:=domoticz}
: ${domoticz_enable:=no}
: ${domoticz_directory:="/home/domoticz/domoticz/"}
: ${domoticz_args:="-syslog -daemon"}


command_args="-dbase ${domoticz_dbdir}/domoticz.db -pidfile ${pidfile} ${domoticz_args}"

domoticz_stop() {
		if [ -e "${pidfile}" ]; then
				echo "Stopping ${name}..."
				kill -9 `cat ${pidfile}`
				rm ${pidfile}

run_rc_command "$1"

edit: simplified code by removing unnecessary sed usage
Last edited:
Oct 9, 2017
i've managed to install and run domo in warden for a few years now. And also updated it by the knowledge i've gathered using google. It's currently still running in warden, but i've upgraded to 11.2 and tried to install a new instance to iocage, but have problems runnig your script.
I know for sure that the problem is in the lack of my knowledge, which is based on google.
I created a new jail (domo) and when i edited the script to my needs (set the IP and new uid/guid name) i've got following when i ran script:
root@domo:/ # /bin/sh
id: domoticz2: no such user
id: domoticz2: no such user
id: domoticz2: no such user
* 1: not found
************************************************************** ${JAIL_IP:0...}: Bad substitution