[Linux] Run Jeedom in a LXC container

Jeedom is open-source software for home-automation; if you plan on installing it on your server, you should read this first.

Indeed, if you follow the official installation instructions, you'll create a a big mess on your machine that you'll have a hard time to rollback.

Most of the time Jeedom assumes it's root and you're even required to give sudo rights to the user www-data! Can you image that?

Still not convinced? Listen to this: the setup script for Jeedom changes the MOTD to "Welcome to Jeedom"! WTF, guys! Just because I'm installing your software doesn't mean you own my machine!

To work around this, we'll use LXC containers that are available on recent Linux kernel.
To make it short, an LXC container is like a lightweight virtual machine, without the cost of a virtualization technology like VirtualBox.

This article is a step by step guide to install Jeedom in an container. It assumes that the linux kernel supports this technology; as it was the case with the Ubuntu 14.04 that I used.

Install the LXC command line

Even though the support for containers is already bundle in the Linux kernel. You need to install the command line tools:

sudo apt-get install lxc

Update lxc templates

LXC containers are created from templates like "Ubuntu Precise", "CentOS", etc.
By default very few templates are available, if you want more of them, run:

sudo apt-add-repository ppa:ubuntu-lxc/lxc-stable
sudo apt-get update
sudo apt-get dist-upgrade

Create container

Now let's create a container named jeedom1:

sudo lxc-create -t download -n jeedom1

This command is interactive, choose the followings:

  1. Distribution = ubuntu
  2. Release = vivid
  3. Architecture = amd64 (most likely)

Basic container commands

Now that the container is created, you can:

  1. Start the container with: sudo lxc-start -n jeedom1
  2. Open terminal with: sudo lxc-attach -n jeedom1
  3. Close terminal with: ctrl-a+ctrl-d or exit
  4. Shut the container down with: sudo lxc-stop -n jeedom1
  5. Destroy the container with: sudo lxc-destroy -n jeedom1 (but don't do it now)

Allow container to access the Z-wave USB device

Edit /var/lib/lxc/jeedom1/config and add:

# Z-wave USB
lxc.cgroup.devices.allow = c 166:* rwm
lxc.mount.entry = /dev/ttyACM0 dev/ttyACM0 none  bind,create=file 0 0

This configuration works for a Zwave.me ZME UZB1; you'll have to adapt it if you're using another transceiver. In particular, 166 is the major device id, you can do a ls -al /dev/ttyACM0 to find the one for your device.

Start the container and install Jeedom

Time to install Jeedom, we'll follow the official installation instructions:

# Start the container
sudo lxc-start -n jeedom1

# Connect to the container
sudo lxc-attach -n jeedom1

# The following commands are executed in the container

# Do as told in Jeedom installation instructions
cd /root
apt-get update
apt-get install -y curl wget
wget https://raw.githubusercontent.com/jeedom/core/stable/install/install.sh
chmod +x install.sh
./install.sh 
echo "www-data ALL=(ALL) NOPASSWD: ALL" | (EDITOR="tee -a" visudo)

# Exit from container and go back to host
exit

Forward HTTP port to the container

Right now Jeedom is running in the container and the web interface is accessible only from the host. You probably want to had a firewall rule to map the Jeedom port to a port of the host.

Use the following command to get the names and the IP addresses of the existing containers:

 sudo lxc-ls --fancy

Now that you have the IP, add a routing rule with:

sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 7080 -j DNAT --to <YOUR_CONTAINER_IP>:80

This command routes all traffic going to the port 7080 of the host to the port 80 of the container.

Additional tips

To start the container when the host boots, add the following lines to /var/lib/lxc/jeedom1/config:

# Auto start
lxc.start.auto = 1
lxc.start.delay = 5

To workaround a bug in current Jeedom version I had to type the following command in the container:

mkdir -p /usr/share/nginx/www/jeedom/plugins/openzwave/data

To diagnose problem with the openzwave plugin, use the following command

python /usr/share/nginx/www/jeedom/plugins/openzwave/ressources/zwaveserver/openZWave.py \
  --pidfile=/tmp/openzwave.pid \
  --device=/dev/ttyACM0 \
  --log=Debug \
  --port=8083 \
  --config_folder=/usr/share/nginx/www/jeedom/plugins/openzwave/ressources/openzwave/config \
  --data_folder=/usr/share/nginx/www/jeedom/plugins/openzwave/data \
  --callback=http://127.0.0.1:80/jeedom/plugins/openzwave/core/php/jeeZwave.php 
  --apikey=<YOUR_API_KEY> \
  --serverId=0

Conclusion

It's much better like this. The mess is still here but in a container, so that your host machine is pristine.

However, there is still an issue. As you saw we're starting the container with sudo lxc-start; this is because we're running a "privileged" container.

It's possible to run the container as a non root user, it's called "unprivilged" container and it'll hopefully be the topic of a future blog post.