Recently, I have setup a stack of Raspberry Pis into to test out Docker Swarm, Kubernetes and OpenFAAS. The biggest problem I found with this is setting up the Pi itself - it’s not difficult as such, just fiddly.

To me, setting up a Pi involves the following:

  1. Download the operating system
  2. Enable SSH
  3. Connect to the WiFi
  4. Delete the user pi
  5. Create another user with passwordless sudo access, a secure password and SSH key
  6. Configure a unique hostname
  7. Setup a static IP

None of these are terribly difficult but, for me at least, it involves asking my wife if she can remember where I last put my keyboard, connecting up a monitor and ensuring that I do all the tasks exactly. I don’t like doing the same thing repeatedly when I can automate it.

Automation FTW

There are many guides out there about setting up a Pi headlessly that work nicely, but they all tend to involve flashing the SD card with the OS then putting the card into your laptop and making the changes on the SD card. What I wanted was a way of actually making the change to the OS image BEFORE putting it on the SD card.

And I wanted to be able to put the same image on multiple SD cards and without any conflicts on the networking etc.

After a fair bit of hacking, I found that if I mounted a .img file to my machine, edited files on and then unmounted it, the files were written to the .img file.

Configuration

So far, this has only been tested on Fedora and building Raspbian. I’m very happy to receive PRs to make this work on different machines and with different target OSes

Firstly, and unsurprisingly, we need to create a configuration in order to tell the script what to do. Save this to ./settings.sh.

#!/bin/sh

PI_WIFI_SSID="MY-WIFI-SSID"
PI_WIFI_PASS="MY-WIFI-PASSWORD"
PI_HOSTNAME="hostname"
PI_SSH_KEY="/path/to/ssh-key.pub"
PI_USERNAME="my-username"
PI_OS="https://downloads.raspberrypi.org/raspbian_lite/images/raspbian_lite-2017-07-05/2017-07-05-raspbian-jessie-lite.zip"

The PI_OS variable can be any valid version of Raspbian which you can download from:

The only one that won’t actually be identical to what you specify here is the PI_HOSTNAME. In order to keep the hostnames unique on the network, the hostname on the Pi will actually become the PI_HOSTNAME, followed by the IP address received by DHCP. If your PI_HOSTNAME is hostname and the IP address is 192.168.0.10, then the hostname will actually become hostname-192-168-0-10

Running

sudo make build

The reason you need to run this with root privileges is because we need to be able to mount the image. This will take about a minute or so to configure the file and will save the configured image to ./cache/os.img.

On this image, this will put a configuration script at /setup.sh, which will be invoked by /etc/rc.local. Assuming it runs successfully, it will be deleted after it’s been run. You can also view the logs from this script at /var/log/rc.local.log

Flashing

Use Etcher and create as many copies of it as you need. You can use the same image on all the different Pis you have.

Running

Put the SD card and power it up. It will take about a minute for it to fully setup and allow you to connect via SSH.

To connect to it over SSH, ssh -i /path/to/ssh-key [email protected] and you’ll have a fully functioning Pi that you can do whatever you need with.