-
Notifications
You must be signed in to change notification settings - Fork 2
Node OS Setup Guide Debian 7
⚠️ WARNING: this is a very old guide, meant for advanced developers. If you are looking to get started with a SolarNode device, there are pre-built OS images for many popular devices.
This guide describes the steps I took to create a "minimal" Debian 7 based system with base SolarNode deployment configured on an eBox 3300 (NorhTec JrMX) computer. The overall goals were these:
- No X window system.
- No development tools.
- No daemons or servers unless required by Debian or SolarNode.
- SSH daemon for network access.
- NTP daemon for time synchronization.
- Monit daemon for SolarNode monitoring.
- Boot from SD card.
- Java 7 JRE.
With these goals in mind, let's dive in. You'll need a Linux-based system to work with, I used a Fedora system but any modern distribution should do.
Note: Binary images for the Node OS are also available here: http://sourceforge.net/projects/solarnetwork/files/solarnode These are great if you are after a quick OS setup (but they do not always contain the latest updates), if you want the latest and greatest you should continue reading below.
Download the Debian 7 (wheezy) installer CD. This should be the full 650MB CD, not the netboot image, so it can install the base system without needing the network. You can get the image from
http://www.debian.org/CD/http-ftp/#stable
Once you have the .iso image downloaded, use unetbootin to copy the image to a USB stick. This is a GUI tool that will copy the installer image to the USB stick and make sure it can boot (in theory dd can be used as well, if you're comfortable with that program already). Modern Linux distributions provide unetbootin, e.g. apt-get install unetbootin on Debian-based systems or yum install unetbootin on Fedora-based ones.
Insert your USB stick into your system, run unetbootin as root, and select the Debian .iso image file you downloaded. After a little while, it will complete and offer to reboot your system, which you can decline and then remove the USB stick.
Insert the Debian installer USB stick into the USB port on the back of the eBox and a 512MB or larger SD card into the SD slot. You'll need a monitor and keyboard (USB or PS/2) plugged in as well, but no mouse is required. Turn the node on, and quickly press the Delete key to enter the BIOS setup utility.
Make sure the BIOS boots from the USB stick first, under the Boot menu. The BIOS should list both the USB and SD disks, as USB: and HDD: options, respectively.
Next go to the Advanced > IDE Configuration screen and make sure the Standard IDE Compatible setting is set to Enabled.
Now you can exit the BIOS configuration - F10 to save and exit - and the unetbootin boot menu should appear. Choose the Expert install mode, and let the Debian installer load.
First I manually partitioned and formatted an ext4 filesystem, using a guide. I found the estimated block size of my SD card to be 4MB, so I halved all the settings from the guide:
- First sector: 16384 (8M)
- Size: 952M (divisible by 8M and 4M)
- File system:
mkfs.ext4 -O ^has_journal -E stride=2,stripe-width=512 -b 2048 -L SOLARNODE /dev/mmcblk0p1
Then here are some important options I chose during the Debian install:
- DHCP for network configuration, with solarnode.localdomain as the host name.
- No root user, with a single solar user.
- No NTP time synchronization. The installer will install ntpd but we want to install openntpd manually later, which is smaller and easier to manage.
- Partition the SD card with a single ext4 filesystem, with a label SOLARNODE and the noatime option enabled. Also mark this partition bootable. If your card is larger than 512MB, you can create a partition sized smaller than the full SD card, so the partition can be cloned more easily. I created a 1GB partition (the SD card was 2GB).
- No swap partition. This is to minimize wear on the SD card.
- Select the most recent available i386 kernel.
- Configure a local apt mirror, without the non-free and without the contrib repositories used (they are not needed).
- No to adding/selecting software now. We'll do this manually later.
- Install the Grub boot loader.
At this point, the installer should complete. You can reboot the node, but un-plug the USB stick before the BIOS RAM check completes, so the node boots from the newly minted SD card.
-
Edit
/etc/fstab
to: -
Change the options for root filesystem to noatime,nodiratime,errors=remount-ro, it should look like this:
LABEL=SOLARNODE / ext4 noatime,nodiratime,errors=remount-ro 0 1
-
Add a manual entry for
/run/shm
. Debian provides this by default, but adds the noexec flag, which causes bundles with native libraries in them to fail to load. Add an entry like this:tmpfs /run/shm tmpfs rw,nosuid,nodev,exec,relatime,size=102860k 0 0
-
Edit
/etc/apt/sources.list
to: -
Remove the cdrom entry (which is really the USB stick).
-
Remove all -src sources.
-
Run
apt-get update
. -
Add solar user to dialout group, to allow use of serial ports.
usermod -a -G dialout solar
-
Edit
/etc/default/tmpfs
and set RAMTMP=yes to enable /tmp as a RAM filesystem. -
Disable persistent history in bash, by editing
/etc/bash.bashrc
and addingunset HISTFILE
Now I manually removed and added the software I deemed appropriate for the node.
-
Replace rsyslog with busybox-syslogd, to minimize writing to the SD card:
apt-get remove --purge rsyslog apt-get install busybox-syslogd
-
Install localepurge to remove excess locale data:#!sh
apt-get install localepurge
-
Install monit
-
apt-get install monit
-
Configure
/etc/default/monit
to enable, e.g. START=yes -
Configure
/etc/monit/monitrc
with startup delay, e.g. set daemon 120 with start delay 240; change thestatefile
,idfile
, andeventqueue basedir
paths to start with /var/run instead of /var/lib, e.g.set idfile /var/run/monit/id set statefile /var/run/monit/state set eventqueue basedir /var/run/monit/events
-
Add
/etc/init.d/monit-prep.sh
script that makes sure /var/run/monit exists at startup, as/var/run
is a tmpfs filesystem.#!/bin/sh ### BEGIN INIT INFO # Provides: monit-prep # Required-Start: $remote_fs # Required-Stop: $remote_fs # X-Start-Before: monit # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: prepare for monit ### END INIT INFO DIR=/var/run/monit EDIR=$DIR/events NAME=monit-prep if [ ! -d $DIR ]; then mkdir -p $DIR chmod 755 $DIR fi if [ ! -d $EDIR ]; then mkdir -p $EDIR chmod 700 $EDIR fi exit 0
-
chmod 755 /etc/init.d/monit-prep.sh
-
update-rc.d monit-prep.sh defaults
-
Install sshd
-
apt-get install ssh
-
Add a Monit script to keep
sshd
running:check process sshd with pidfile /var/run/sshd.pid group system group sshd start program = "/etc/init.d/ssh start" stop program = "/etc/init.d/ssh stop" if failed host localhost port 22 with proto ssh then restart if 5 restarts with 5 cycles then timeout depend on sshd_bin depend on sftp_bin depend on sshd_rc check file sshd_bin with path /usr/sbin/sshd group sshd include /etc/monit/templates/rootbin check file sftp_bin with path /usr/lib/openssh/sftp-server group sshd include /etc/monit/templates/rootbin check file sshd_rc with path /etc/ssh/sshd_config group sshd include /etc/monit/templates/rootrc
-
Install OpenNTPD
-
apt-get install openntpd
-
Edit
/etc/default/openntpd
and add-s
to the boot parameters. This will allow NTP to adjust the clock when the system starts up, even if the time difference is very large. -
With the -s flag, if NTP can't connect to the network it can prevent the node from booting for a long time. Instead of letting the OS start OpenNTP, we can let Monit do this later on. Run
update-rc.d openntpd remove
to remove it from system startup, then create a Monit script/etc/monit/conf.d/openntpd
with the following:check process openntpd matching /usr/sbin/ntpd group system group ntpd start program = "/etc/init.d/openntpd start" stop program = "/etc/init.d/openntpd stop" if 4 restarts within 12 cycles then timeout depend ntpd_bin depend ntpd_rc check file ntpd_bin with path /usr/sbin/ntpd group ntpd include /etc/monit/templates/rootbin check file ntpd_rc with path /etc/init.d/openntpd group ntpd include /etc/monit/templates/rootbin
-
Remove nano and docs
apt-get remove --purge nano info manpages
-
Install Java (this pulls in a whopping 160MB+ of stuff) with
apt-get install openjdk-7-jre-headless
-
Install rsync (required for node database backups)
apt-get install rsync
-
Install RXTX and JNA Java libraries, to support serial ports in Java:
apt-get install librxtx-java libjna-java
-
Install
daemon
package, which is used to manage the SolarNode process:apt-get install deamon
Further savings can be found by installing the deborphan and debfoster packages. Use those to identify non-essential packages and remove them.
If you plan to use WiFi, you'll need to install some firmware for the radio and install the wpasupplicant package.
-
apt-get install wpasupplicant
-
You need the rtl8712u.bin firmware file, which is available in git. You can clone this repository via
git clone git://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git
Then copy the linux-firmware/rtlwifi/rtl8712u.bin file to
/lib/firmware/rtlwifi/rtl8712u.bin
. -
Configure a wlan0 device in
/etc/network/interfaces
to match your network settings, e.g.# WiFi auto wlan0 iface wlan0 inet dhcp wpa-ssid mywifi # hexadecimal psk, use wpa_passphrase to generate wpa-psk c0c5618c9d2efc45d02db5b460... # can enable debugging with: # wpa-debug-level 3
The Debian installer will have configured both fstab and Grub to use device UUIDs to specify which device to use for the root filesystem. In order to make this system easier to clone onto other SD cards, I tweaked some of the settings so that the SOLARNODE filesystem label I set up during installation is referenced instead.
-
Update
/etc/fstab
to use labels instead of UUID: -
For the root filesystem, change UUID=XXX to LABEL=SOLARNODE, e.g.
LABEL=SOLARNODE / ext4 noatime,nodiratime,errors=remount-ro 0 1
-
Update Grub to use labels instead of UUIDs. See http://ubuntuforums.org/showpost.php?p=9585951&postcount=13 for reference.
-
Change
/etc/default/grub
so that GRUB_DISABLE_LINUX_UUID="true" -
Change
/etc/grub.d/10_linux
to insert this linelinux_root_device_thisversion="LABEL=`e2label ${GRUB_DEVICE_BOOT} 2>/dev/null`"
directly before these lines (around line 117):
cat << EOF echo '$message' linux ${rel_dirname}/${basename} root=${linux_root_device_thisversion} ro ${args} EOF
-
Change
/usr/lib/grub/grub-mkconfig_lib
to replace these lines (around line 153):# If there's a filesystem UUID that GRUB is capable of identifying, use it; # otherwise set root as per value in device.map. echo "set root='`${grub_probe} --device ${device} --target=drive`'" if fs_uuid="`${grub_probe} --device ${device} --target=fs_uuid 2> /dev/null`" ; then echo "search --no-floppy --fs-uuid --set ${fs_uuid}" fi
to these lines:
# If there's a filesystem UUID that GRUB is capable of identifying, use it; # otherwise set root as per value in device.map. echo "set root='`${grub_probe} --device ${device} --target=drive`'" if auto_label="`e2label ${device} 2>/dev/null`"; then echo "search --no-floppy --label ${auto_label} --set root" elif fs_uuid="`${grub_probe} --device ${device} --target=fs_uuid 2> /dev/null`" ; then echo "search --no-floppy --fs-uuid --set ${fs_uuid}" fi
-
Change
/boot/grub/device.map
to the following:(hd0) /dev/disk/by-label/SOLARNODE
-
Run
update-grub
to regenerate/boot/grub/grub.cfg
. Verify you ended up with a menu entry in/boot/grub/grub.cfg
with lines similar to the following (note the --label SOLARNODE and LABEL=SOLARNODE parts):search --no-floppy --label SOLARNODE --set root echo 'Loading Linux 2.6.32-5-486 ...' linux /boot/vmlinuz-2.6.32-5-486 root=LABEL=SOLARNODE ro quiet
The Debian installer will have set up a udev rule that associates the ethernet and devices with persistent device names, eth0 and wlan0, based on those devices' hardware MAC addresses. In order to make this system easier to clone onto other SD cards, I added a custom udev rules file /etc/udev/rules.d/a10-solarnode.rules
with the following content:
# Rename network interfaces NOT using MAC addresses, so this image can be copied to other devices
SUBSYSTEM=="net", DRIVERS=="?*", KERNEL=="eth*", NAME="lan%n"
SUBSYSTEM=="net", DRIVERS=="?*", KERNEL=="wlan*", NAME="wlan%n"
This will map ethernet devices to lanX and WiFi to wlanX where X starts at 0. This thus provides the lan0 and wlan0 network device names.
Finally, edit /etc/network/interfaces
to rename all references to eth0 to lan0. There should be only two, e.g.
# The primary network interface
allow-hotplug lan0
iface lan0 inet dhcp
The previous udev rules will only work for the first ethernet device, unfortunately. If you must support multiple ethernet devices, you can take a slightly different approach, and create a /etc/udev/rules.d/lan-count.sh
script containing:
#!/bin/sh
egrep '[^w]lan[0-9]+' /proc/net/dev |wc -l
Make sure it is executable, i.e. chmod 755 /etc/udev/rules.d/lan-count.sh
. Then update the first line in /etc/udev/rules.d/a10-solarnode.rules
so the contents look like this:
# Rename network interfaces NOT using MAC addresses, so this image can be copied to other devices
SUBSYSTEM=="net", DRIVERS=="?*", KERNEL=="eth*", PROGRAM="/etc/udev/rules.d/lan-count.sh", NAME:="lan%c"
SUBSYSTEM=="net", DRIVERS=="?*", KERNEL=="wlan*", NAME="wlan%n"
Free up RAM by disabling some extra console TTYs. Edit /etc/inittab
and comment out the TTYs you don't need, e.g.
1:2345:respawn:/sbin/getty 38400 tty1
2:23:respawn:/sbin/getty 38400 tty2
#3:23:respawn:/sbin/getty 38400 tty3
#4:23:respawn:/sbin/getty 38400 tty4
#5:23:respawn:/sbin/getty 38400 tty5
#6:23:respawn:/sbin/getty 38400 tty6
Sometimes the networking on a node can be unreliable. Using ifplugd can help ensure the interface is running.
apt-get install ifplugd
- Edit
/etc/default/ifplugd
, and update the INTERFACES setting, e.g. INTERFACES="lan0 wlan0" - Check
/etc/network/interfaces
to ensure the ones managed by ifplugd don't have auto set, e.g. comment out (or remove) lines like #auto wlan0.
The SolarNode web application runs on port 8080
by default, but we'd like to be able to access it via the standard HTTP port, 80
. We can use iptables
to both provide a firewall for the node as well as setup NAT to translate port 80 into 8080 for us. First create a configuration file suitable for iptables-restore
to read, at /etc/iptables.rules
:
*filter
# Allows all loopback (lo0) traffic and drop all traffic to 127/8 that doesn't use lo0
-A INPUT -i lo -j ACCEPT
-A INPUT ! -i lo -d 127.0.0.0/8 -j REJECT
# Allow all established inbound connections
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Allow outbound traffic
-A OUTPUT -j ACCEPT
# Allows HTTP
-A INPUT -p tcp --dport 80 -j ACCEPT
-A INPUT -p tcp --dport 8080 -j ACCEPT
# Allow SSH
-A INPUT -p tcp -m state --state NEW --dport 22 -j ACCEPT
# Allow ping
-A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT
# log iptables denied calls (access via 'dmesg' command)
-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7
-A INPUT -j REJECT
-A FORWARD -j REJECT
COMMIT
*nat
# Redirect port 80 to 8080 for SolarNode
-A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
COMMIT
Then create an executable file /etc/network/if-pre-up.d/iptables
with
#!/bin/sh
/sbin/iptables-restore </etc/iptables.rules
You can manually load these rules by executing this file directly, too.
If you're creating this as an image for many nodes to copy from, then you should delete the SSH key Debian generated for you, and add a small script to recreate the keys the next time the OS boots. First, delete the keys:
rm -f /etc/ssh/ssh_host_*
Then, add the following to /etc/rc.local
(before the final exit 0
line):
# Make sure SSH keys are generated if they don't exist
if [ -f /etc/ssh/sshd_config -a ! -f /etc/ssh/ssh_host_rsa_key ]; then
dpkg-reconfigure openssh-server
fi
As a final clean up to free space, run apt-get clean
. The sfill
program, available in the
secure-delete package, can help make compressed images created with dd
smaller by forcing
all unused blocks to 0
. Run sfill -f -z -I -ll /
to zero out all unused space. This can
take some time to run.
Now we'll deploy a basic SolarNode platform, and configure it to startup when the node boots. See Deploying the SolarNode application for more information.