Software setup

Installing a Raspberry Pi 2 with Debian

See https://wiki.debian.org/RaspberryPi2 for details. As of 2015-12, the instructions on that wiki page essential say the following. Mount the microSDHC card on your computer, then download collabora’s Debian image (173 MB) for the Raspberry Pi 2 and copy it onto the microSDHC card, assuming it was recognized by your computer as /dev/sdb:

midna $ sudo apt-get install bmap-tools
midna $ wget https://images.collabora.co.uk/rpi2/jessie-rpi2-20150705.img.{bmap,gz}
midna $ sudo bmaptool copy jessie-rpi2-20150705.img.gz /dev/sdb

Then, put the microSDHC card into your Raspberry Pi 2 and connect it to power and ethernet. Wait for it to show up on your network.

The root password is “debian”, and you should change it once you’re logged in:

jessie-rpi # passwd
jessie-rpi # hostnamectl set-hostname fts.example.net

Install your public key (DigitalOcean has a good introduction to SSH public keys), then disable password-based login:

fts # sed -i 's,#*\s*PasswordAuthentication .*,PasswordAuthentication no,g' /etc/ssh/sshd_config

Configuring the Raspberry Pi 2 for freetserv

fts # export FTS_MASTER="https://raw.githubusercontent.com/freetserv/freetserv/master"
fts # apt-get install minicom cu screen

Install the udev rules for stable port numbering, the helper scripts, and an explanatory motd file which will be displayed when logging in via SSH:

fts # curl ${FTS_MASTER}/udev/freetserv.rules -O /etc/udev/rules.d/freetserv.rules
fts # curl ${FTS_MASTER}/fts-adduser -O /usr/local/bin/fts-adduser
fts # curl ${FTS_MASTER}/fts-port-owner -O /usr/local/bin/fts-port-owner
fts # chmod +x /usr/local/bin/fts-*
fts # curl ${FTS_MASTER}/motd -O /etc/motd

Configure adduser(8) to not create individual groups for new users, making all users end up in the users group.

fts # sed -i 's,^USERGROUPS=yes$,USERGROUPS=no,g' /etc/adduser.conf

Install the watchdog script to make the watchdog LED connected to GPIO4 blink for a second every other second:

fts # curl ${FTS_MASTER}/watchdog.service -O /etc/systemd/system/watchdog.service
fts # curl ${FTS_MASTER}/watchdog.sh -O /usr/local/bin/watchdog.sh
fts # chmod +x /usr/local/bin/watchdog.sh
fts # systemctl daemon-reload
fts # systemctl restart watchdog
fts # systemctl enable watchdog

Nit: avoiding watchdog.sh’s sleep processes

When running under bash(1), dash(1) or zsh(1), the watchdog.sh script spawns a sleep(1) process every second. While that’s not a problem per se, the slight overhead in creating new processes might be enough to make the watchdog LED not blink precisely every other second.

If you want to get rid of the external sleep(1) processes, you can run the watchdog script in ksh(1), which has sleep built-in:

fts # apt-get install ksh
fts # sed -i 's,/bin/sh,/bin/ksh,g' /usr/local/bin/watchdog.sh

Enable the Raspberry Pi’s hardware watchdog, so that when the system crashes, it will be rebooted within 10 seconds:

fts # echo bcm2708_wdog >> /etc/modules-load.d/raspberry-pi-watchdog.conf
fts # sed -i 's,^#*\s*RuntimeWatchdogSec=.*,RuntimeWatchdogSec=20s,g' /etc/systemd/system.conf

See the Admin Guide for how to use the newly installed fts-adduser and fts-port-owner scripts.

Making the system read-only (optional)

Experience has shown how the first part of an embedded system that fails often is the storage medium, e.g. a CompactFlash card back in the days, or a microSDHC card in the specific case of a Raspberry Pi 2. Hence, I like to reduce the number of write cycles on the storage medium as much as possible, and therefore run my embedded devices with their root file system mounted read-only.

Mount the microSDHC card in a card-reader on a different computer. This is necessary because we need the file system of the Raspberry Pi to not be in use while we perform these steps.

Create a new 1G partition to be mounted read-writeable for /home:

midna $ echo '- 1G - -' | sudo sfdisk --append /dev/sdb
midna $ sudo mkfs.ext4 /dev/sdb3
midna $ pmount sdb2

midna # cat >/media/sdb2/etc/fstab <<'EOF'
/dev/mmcblk0p2 / ext4 ro,relatime,errors=remount-ro,discard 0 1
/dev/mmcblk0p1 /boot/firmware vfat defaults 0 2 
/dev/mmcblk0p3 /home ext4 relatime,errors=remount-ro,discard 0 1
tmpfs /tmp tmpfs defaults 0 0
EOF

midna # cat >/media/sdb2/etc/systemd/system/var.mount <<'EOF'
[Unit]
Before=local-fs.target

[Mount]
What=tmpfs
Where=/var
Type=tmpfs
Options=noatime

[Install]
WantedBy=multi-user.target
EOF

midna # cat >/media/sdb2/etc/systemd/system/copyvar.service <<'EOF'
[Unit]
Description=Copies /var.ro/* to /var
After=var.mount
Before=ifupdown.service local-fs.target
DefaultDependencies=no

[Service]
Type=oneshot
ExecStart=/usr/bin/find /var.ro -mindepth 1 -maxdepth 1 -exec /bin/cp -r '{}' '/var' \073

[Install]
WantedBy=multi-user.target
EOF

midna # ln -s /media/sdb2/etc/systemd/system/var.mount /media/sdb2/etc/systemd/system/multi-user.target.wants/var.mount
midna # ln -s /media/sdb2/etc/systemd/system/copyvar.service /media/sdb2/etc/systemd/system/multi-user.target.wants/copyvar.service
midna # mv /media/sdb2/var /media/sdb2/var.ro
midna # mkdir /media/sdb2/var
midna $ pumount sdb2