Friday, 5 January 2018

Making pre-loaded Raspberry Pi image

If you want to install a Raspberry Pi for some purpose, you will end up putting an image on an SD card and installing in the Pi. You can get pre-loaded SD cards even.

SD cards die!

You can get industrial SD cards! These have more write cycles, wide temperature range, and even have S.M.A.R.T. They are more expensive. The one thing I hear all the time with anyone using Pis is that the SD cards die. There are many good ways to reduce this - turn off some logging, log to a RAM disk, remote logging, not ever running mysql on it, and so on. But a good SD card is also a good start and I think probably worth it.

Installing an image.

So you download an image, the stretch lite is a start. I renamed to pi.img for the following examples.

Now, you install it on a memory card. The instructions for Mac are simple, and involve using a dd command. Important, on a Mac, is use the /dev/rdiskN not /dev/diskN as it is massively faster (character and block device versions of the raw disk access). You have to eject/unmount it before you can do the dd, and once you have finished...

sudo dd if=pi.img of=/dev/rdisk4

You end up with a bootable Debian image on you Pi. Yay!

Making a custom image?

There are ways to make a customer image, e.g. which allow you to make the image you want to start with, but there may be further tweaks you want to the image itself, and the following shows a way to do that.

You cannot ssh to it!

This is a pain, you have to find a monitor, HDMI cable, keyboard, and faff about. I want an image I can ssh to. I understand why it is not the default, but if you are making something headless you need to be able to ssh to it.

The trick here is changing the image. However, as this is a complete "disk" image with partition table and boot and main partitions, you cannot simply mount it, you have to mount part of it.

First off, find the partitions. There are normally two - a boot and a linux partition.

excalibur:/tmp# fdisk -l pi.img
Disk pi.img: 1.7 GiB, 1858076672 bytes, 3629056 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x37665771

Device     Boot Start     End Sectors  Size Id Type
pi.img1          8192   93236   85045 41.5M  c W95 FAT32 (LBA)
pi.img2         94208 3629055 3534848  1.7G 83 Linux

To allow booting you are going to want to mount the boot partition and add a file to it.. You need the start and size of the boot partition. As they are in sectors multiple by 512.

excalibur:/tmp# bc
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'. 

And then you can mount...

excalibur:/tmp# mkdir boot
excalibur:/tmp# mount -v -o offset=4194304,sizelimit=43543040 -t vfat pi.img boot
mount: /dev/loop0 mounted on /tmp/boot.

Then all you have to do is create a file called ssh in the boot partition.

excalibur:/tmp# touch boot/ssh

And unmount

excalibur:/tmp# umount boot

Now you have an image that will boot and allow ssh, yah...

Pre-installing some stuff...

I also wanted to change the default password, add ssh keys, update the Debian install, and pre-install a few things. Now, you can do this on a Pi, i.e. install the image, ssh in, and do stuff, but then how do you make an image of that to put on the next Pi? Well, you could image your SD, but that can be 8G, 16G or 32G or whatever, and also ends up not working on another SD some of the time. What I wanted was a clean (small) image that I could install on an SD with some pre-installed stuff.

The trick is very much as above, mount the image, but to do anything you have to be running on a Pi, so I ended up with a running Pi, and loading the image on to that Pi itself, and then on the Pi I mounted the image. Yes, Russian dolls come to mind.

This time we just need the start of the linux partition.

excalibur:/tmp# bc

bc 1.06.95

Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'. 

And then you mount.

excalibur:/tmp# mkdir pi

excalibur:/tmp# mount -v -o offset=48234496 -t ext4 pi.img pi

mount: /dev/loop0 mounted on /tmp/pi.

Then you chroot in to it

excalibur:/tmp# chroot pi

At this point you are running in a new root file system. You can run commands like passwd, and
apt-get and so on as normal. When you have finished, simply exit the chroot and unmount...

excalibur:/tmp# umount pi

And now you have an image that has stuff pre-installed, with the right password or ssh keys as you have installed, all ready to go.


  1. Don't forget you can now ditch the card and boot your rpi3 from a usb mass storage device by setting a permanent efuse option

  2. Useful summary, Revk.

    There is a handy shortcut to getting ssh control of a new, headless RaspberryPi ... after making the new SD card image you can 'touch /boot/ssh'. If /boot/ssh file (with no or any contents) exists at boot, sshd will be enabled when the Pi boots.

    (And if you want wireless connectivity, /boot/wpa_supplicant will be moved into /etc to pass the relevant wifi config.)


    1. Isn’t that exactly what is said?

    2. Why not just eject and reinsert the SD card, as /boot is FAT32, it should auto mount...

    3. Yes, I see what you mean now, D'Oh.

  3. It's been a while since I played with my RPi but if the number of write-cycles bothers you there's always the rasberrypi version of Tiny Core Linux,

    IIRC after booting it doesn't touch the SD card. You can also create your own distro with the apps you want to create an embedded device. An example of this is PiCorePlayer,

    There's also a community of bare metal programmers for the RPi which I've dabbled with myself, However not all specs are made available and this has been a source of consternation between the programmers and the RPi foundation.

  4. FYI, there's an easy way to mount multi-partition images using the kpartx command rather than calculating offsets - see this post:

  5. you can also use 'losetup' to attach an image as a partitioned disk - so that you get a bunch of devices appearing, one for the disk and one for each partition. Use losetup --partscan and then mount the individual partitions.

  6. Similarly, there's kpartx which will make your disk image behave like a normal disk, enabling you to mount partitions without manually sorting out offsets and what have you.

    1. Which is exacttly what losetup does.

    2. kpartx really works at a level above losetup.

      It can create device mapper entries for all partitions in an image, that you then only need mount, no need to do the losetup stuff yourself (though it does use loop devices underneath)


      kpartx -a disk.img

      will create /dev/dm-* files for each partition and lvm volume group it finds. These can then simply be mounted etc.

  7. We prefer running Debian (Sjoerd Simons, Collabora) rather than Raspbian, since at least in the early days grafting KDE onto it with decent large-screen support was a problem. You'll always need a small Raspbian filesystem at the start so that you can get low-level firmware updates, their pukka kernel, and the all-important vcgencmd program and support libraries.

    xl2tpd runs fairly well but you need to compile it to not use kernel facilities. I passed that on to your support people a year or so ago but it never got to the relevant bit on your website.

  8. It's usually not the actual SD-card that breaks, brownouts and violent shutdowns seem to make the Pi write garbage to the card, effectively corrupting the filesystem.