Skip to content
Patrick McGuire edited this page Nov 20, 2021 · 4 revisions

Table of Contents

sdm

Raspberry Pi SSD/SD Card Image Manager

Description

sdm provides a quick and easy way to build consistent, ready-to-go SSDs and/or SD cards for the Raspberry Pi. This command line management tool is especially useful if you:

  • have multiple Raspberry Pi systems and you want them all to start from an identical and consistent set of installed software packages, configuration scripts and settings, etc.
  • want to rebuild your Pi system in a consistent manner with all your favorite packages and customizations already installed. Every time.
  • want to do the above repeatedly and a LOT more quickly.
What does ready-to-go mean? It means that every one of your systems is fully configured with Keyboard mapping, Locale, Timezone, and WiFi set up as you want, all of your personal customizations and all desired RasPiOS packages and updates installed.

In other words, all ready to work on your next project.

With sdm you'll spend a lot less time rebuilding SSDs/SD Cards, configuring your system, and installing packages, and more time on the things you really want to do with your Pi.

Someone in the RaspberryPi.org forums said "Generally I get by by reflashing an SD card and reinstalling everything from the notes I made previously. That is not such a long winded process."

While better than not having ANY notes, this approach requires relatively complete notes, and careful attention to detail each and every time you need to reflash a card.

sdm lets you keep your notes in simple working bash code and comments, and makes a "not such a long winded process" into a single command that you run whenever you need to create a new SD card or SSD. And the disk is built with ALL of your favorite apps installed and all your favorite customizations.

As a bonus, sdm includes an optional script to install and configure apt-cacher-ng. apt-cacher-ng is a RasPiOS package that lets you update all your Pis quickly by caching downloaded packages locally on your LAN. This can greatly reduce install and update time, as well as internet network consumption.

sdm is for RasPiOS, and runs on RasPiOS Stretch and Buster. It can also run on other Linux systems. See the 'Compatibility' section below. sdm requires a USB SD Card reader to write a new SD Card, or a USB adapter to write a new SSD. You cannot use sdm to rewrite the running system's SD Card or system disk.

sdm is written completely in Bash, except for the Captive Portal module, which is Python. This means that you can:

  • Easily inspect EVERYTHING that sdm does
  • Easily make changes to sdm, although by using provided customization hooks, you can avoid modifying sdm itself and ease your "sdm upgrade problem"
Have questions about sdm? Please don't hesitate to ask in the Issues section of this github. If you don't have a github account (so can't post an issue/question here), please feel free to email me at: [email protected].

Need more details? Watch sdm in action here

If you find sdm useful, please consider starring it to help me understand how many people are using it. Thanks!

Usage overview

sdm Quick Start

Here's how to quickly and easily to create and customize an IMG file and burn it to an SD Card. It's assumed that there is an SD Card in /dev/sde.

Throughout this document read "SD Card" as "SSD or SD Card". They are treated equivalently by sdm.

  • Install sdm and systemd-container: sudo curl -L https://raw.githubusercontent.com/gitbls/sdm/master/EZsdmInstaller | bash
  • If needed, download the desired RasPiOS zipped IMG from the raspberrypi.org website and unzip it. Direct link to the downloads: Raspberry Pi Downloads. Pick the latest image in the folder raspios_full_armhf (32-bit), raspios_lite_armhf (32-bit), raspios_arm64 (64-bit Beta), or raspios_lite_arm64 (64-bit Beta), as appropriate.
  • Customize the image: sudo /usr/local/sdm/sdm 2020-08-20-raspios-buster-armhf-full.img --customize --wpa /path/to/working/wpa_supplicant.conf --L10n --restart
sdm will copy your Localizaton settings (Keymap, Locale, Timezone, and WiFi Country) from the system on which it's running, and prompt for a new password for user 'pi'. No additional packages will be installed in this example, but 'apt update' and 'apt upgrade' will be done.
  • Burn the image onto the SD Card: sudo /usr/local/sdm/sdm --burn /dev/sde --hostname mypi1 2020-08-20-raspios-buster-armhf-full.img
Now, load the SD card into a Pi and power it up. The system will come up as it always does:
  • Resizes the root file system and restarts automatically
  • After the system restarts it goes through a complete system startup, just as it always does on a fresh SD Card
  • Toward the end of the boot process an sdm systemd service script runs once and sets the WiFi country, unblocking WiFi. It will also take other actions as needed to fulfill the switch settings.
  • When the system boot is fully complete (it can take a while on a large SD card!), the system automatically restarts again
When the system comes back up your Pi is all happy, ready to go, and configured with:
  • The latest RasPiOS updates installed for all installed packages
  • Password set for user 'pi'
  • Hostname set to mypi1, or whatever you choose to use as the hostname
  • Keymap, Locale, and Timezone configured the same as the system on which you are running sdm (easily changeable, of course)
  • Wifi configured and operational
  • SSH enabled
What else can sdm do? Here are a few examples:
  • Install applications — Editors (emacs, vim, etc), and any other packages you always install in a new system. sdm has two built-in package install lists, creatively named apps and xapps. You can select which of the two lists to include when you build an image, so you can build images with no additional apps, apps only, xapps only, or both.
  • Install and configure VNC — Have every system come up with VNC installed and configured, using either RealVNC on the console, or TightVNC or TigerVNC virtual desktops. Or a combination of RealVNC on the console AND virtual desktops.
  • Install and configure an Access Point (hotspot) — Install a customizable, fully operational hotspot in any of three modes: local, routed, or bridged.
  • Enable Pi-specific devices — Easily enable camera, i2c, etc, via raspi-config automation
  • Personal customizations — Have every system come up running with your own customizations such as your favorite .bashrc and any other files that you always want on your system
  • Append Custom fstab file to /etc/fstab — Automatically append your site-specific fstab entries to /etc/fstab
  • systemd service configuration and management — If there are services that you always enable or disable, you can easily configure them with sdm
  • Other customizations — Done through a simple batch script. The file sdm-customphase is a skeleton Custom Phase Script that you can copy, modify, and use. Full disclosure: You'll need to use a Custom Phase Script to copy your .bashrc or perform systemd service management, etc.
See the sections Custom Phase Script and Burn Scripts below for details.
  • Burn SD Card Image for network distribution — You can build a customized SD Card Image to distribute via a mechanism other than an actual SD Card, such as the Internet.
The recipient can burn the SD Card using any one of a number of tools on Linux (Installing Operating System Images), Windows (Installing Operating System Images Using Windows), or MacOS (Installing Operating System Images Using MacOS).
  • Update an already-burned RasPiOS SD Card or SSD — use the --explore command switch to nspawn into the SD Card or SSD. While in the nspawn you can take care of system management activities in a near-online manner, such as changing the password for an account, installing additional packages, etc.
This can be VERY handy if you forget the password to the 'pi' account on your favorite SD Card, for instance. You can boot up a second SD Card, install sdm on it, and then use sdm --explore to update the 'pi' account password on that favorite SD Card.

Detailed Installation and Usage Guide

Installation is simple. sdm must be installed in and uses the path /usr/local/sdm both on your running system and within images that it manages. The simplest way to install sdm is to use EZsdmInstaller, which performs the commands listed in the really long way:

sudo curl -L https://raw.githubusercontent.com/gitbls/sdm/master/EZsdmInstaller | bash
Or, download the Installer script to examine it before running:
curl -L https://raw.githubusercontent.com/gitbls/sdm/master/EZsdmInstaller -o ./EZsdmInstaller
chmod 755 ./EZsdmInstaller
# Inspect the EZsdmInstaller script if desired
sudo ./EZsdmInstaller
Or, download it the really long way:
sudo mkdir -p /usr/local/sdm /usr/local/sdm/1piboot
sudo curl -L https://raw.githubusercontent.com/gitbls/sdm/master/sdm -o /usr/local/sdm/sdm
sudo curl -L https://raw.githubusercontent.com/gitbls/sdm/master/sdm-phase0 -o /usr/local/sdm/sdm-phase0
sudo curl -L https://raw.githubusercontent.com/gitbls/sdm/master/sdm-phase1 -o /usr/local/sdm/sdm-phase1
sudo curl -L https://raw.githubusercontent.com/gitbls/sdm/master/sdm-cparse -o /usr/local/sdm/sdm-cparse
sudo curl -L https://raw.githubusercontent.com/gitbls/sdm/master/sdm-firstboot -o /usr/local/sdm/sdm-firstboot
sudo curl -L https://raw.githubusercontent.com/gitbls/sdm/master/sdm-apt -o /usr/local/sdm/sdm-apt
sudo curl -L https://raw.githubusercontent.com/gitbls/sdm/master/sdm-apt-cacher -o /usr/local/sdm/sdm-apt-cacher
sudo curl -L https://raw.githubusercontent.com/gitbls/sdm/master/sdm-customphase -o /usr/local/sdm/sdm-customphase
sudo curl -L https://raw.githubusercontent.com/gitbls/sdm/master/sdm-logmsg -o /usr/local/sdm/sdm-logmsg
sudo curl -L https://raw.githubusercontent.com/gitbls/sdm/master/sdm-cportal -o /usr/local/sdm/sdm-cportal
sudo curl -L https://raw.githubusercontent.com/gitbls/sdm/master/sdm-hotspot -o /usr/local/sdm/sdm-hotspot
sudo curl -L https://raw.githubusercontent.com/gitbls/sdm/master/sdm-1piboot/1piboot.conf -o /usr/local/sdm/1piboot/1piboot.conf
sudo chmod -R 755 /usr/local/sdm/'''
sudo chmod 644 /usr/local/sdm/{sdm-apps-example,sdm-xapps-example} /usr/local/sdm/1piboot/1piboot.conf
sudo apt install systemd-container qemu-user-static binfmt-support --no-install-recommends --yes

sdm Operation Details

sdm operates on the SD Card image in distinct phases:

  • Phase 0: Operating in the logical context of your physical RasPiOS system, copying files into the RasPiOS IMG file. sdm takes care of Phase 0 for you. The Phase 0 script sdm-phase0 performs the Phase 0 copying. It will also optionally call a Custom Phase script provided by you to perform customized personal steps. See Custom Phase Script below for details.
  • Phase 1: Operating inside the IMG file and in the context of that system (via systemd-nspawn). When operating in this context, all changes made only affect the SD Card IMG, not the physical RasPiOS system on which sdm is running
Most, but not all commands can be used in Phase 1. For instance, most systemctl commands don't work because systemd is not running in the nspawn'ed image. Importantly, however, systemctl disable and systemctl enable do work.
Other functions you might want to do in Phase 1 include: add new users, set or change passwords, install packages, etc. In other words, you can do almost everything you want to configure a system for repeated SD card burns.
Once sdm has started the nspawn container, it will automatically run /usr/local/sdm/sdm-phase1 to perform Phase 1 customization. As with Phase 0, your optional Custom Phase Script will be called. After Phase 1 completes, sdm will provide a command prompt inside the container unless you specified --batch, in which case sdm will exit the container. NOTE: When sdm provides a command prompt, either with Phase 1 customization or with --mount, the terminal colors are changed (if your terminal supports it) to remind you that the IMG is mounted. See the section on Terminal Colors below.
  • Phase 2: Write the SD Card. Using the sdm --burn command, the IMG is written to the new physical SD card using dd, and the new system name is written to the SD card. This enables a single IMG file to be the source for as many Pi systems as you'd like. Of course, you can burn the SD Card using a different tool if you'd prefer, although you'll need to set the hostname with another mechanism.
  • Phase 3: Boot the newly-created SD card on a Pi. When the new system boots the first time, the systemd service sdm-firstboot.service sets WiFi Country, and any device-specific settings you've enabled (see below), and then disables itself so it doesn't run on subsequent system boots.
Once Phase 1 is completed, Phase 2 and Phase 3 can be repeated as often as needed to create fresh bootable devices for one or more of your Pi fleet configured exactly as you want them to be.

Usage Examples

  • sudo /usr/local/sdm/sdm --customize --poptions apps --apps @myapps --user bls --uid 1600 --hdmigroup 2 --hdmimode 82 2020-08-20-raspios-buster-armhf-full.img
Installs the apps from the list in the file myapps into the image, creates user bls with the specified UID, and sets the HDMI settings in /boot/config.txt needed for my monitor.
  • sudo /usr/local/sdm/sdm --customize --poptions apps --apps "iperf3 zip nmap" --user bls --uid 1600 --bootconfig hdmigroup:2,hdmimode:82 2020-08-20-raspios-buster-armhf-full.img
This is similar to the above, showing how config.txt settings can be specified individually and apps can be listed on the command line instead of an @file.
  • sudo /usr/local/sdm/sdm --burn /dev/sdc --host sky 2020-08-20-raspios-buster-armhf-full.img
sdm burns the image to the SD Card in /dev/sdc and sets the hostname to 'sky'.
NOTE: While sdm does check that the device is a block device and is not mounted, it is still a good idea to double check that you're writing to the device you think you are before pressing ENTER.
  • sudo /usr/local/sdm/sdm --explore 2020-08-20-raspios-buster-armhf-full.img
sdm enters nspawn on the image for you to work on it. For example, you might want to do an apt update and apt upgrade, install additional packages, or make other configuration or customization changes, before you burn a new SD Card.

sdm Script Details

sdm consists of a primary script sdm and several supporting scripts:

  • sdm-phase0 — Script run by sdm before nspawn-ing into the IMG file. sdm-phase0 has access to the running Pi system as well as the file system within the IMG file. You can customize what's done in Phase 0 by using a Custom Phase Script (see below). sdm-phase0 performs several steps:
    • If --user is specified, creates the user's home directory so that your Custom Phase script can copy files into it during Phase 0. The user is also enabled to use sudo like the user pi.
    • Miscellaneous requested configuration changes: Setting hdmigroup and hdmimode, any other boot config settings, and the eeprom directory.
    • Calls the Custom Phase Script for Phase 0 if specified. See Custom Phase Script below.
  • sdm-phase1 — Asks for and changes the password for the pi user. Optionally, if you used the sdm --user switch, creates your personal account, sets its password, directory and protections, etc. If --aptcache was specified, the IMG is enabled as an apt-cacher-ng client. See below for details on apt-cacher-ng.
sdm-phase1 installs the apps that you've specified. You control which applications are installed by using the --apps switch. The value for the --apps switch can either be a quoted, space-separated list ("pkg1 pkg2 pgk3"), or @somefile, where somefile has a list of applications to install, one per line. Comments are indicated by a pound sign (#) and are ignored, so you can document your app list if desired. If the specified file is not found, sdm will look in the sdm directory (/usr/local/sdm).
sdm-phase1 also installs the 'X' apps that you've specified. You control which applications are installed by using the --xapps switch. The value for the --xapps switch is treated the same as for the --apps switch above. This is probably more interesting if you're using RasPiOS Lite, which does not include the X Windows software in the image. The example file sdm-xapps-example provides one example of installing a minimal X Windows system, but since there are a multitude of ways to install X11, display managers, window managers, and X11-based applications, you'll undoubtedly want to build your own xapps list.
  • There is no restriction that the xapps list actually contains X Windows apps; it can be used as a set of secondary apps if desired.
  • App installation is enabled by providing the apps and/or xapps values to the --poptions command switch.
  • sdm does not require that you separate your app list into "apps" and "X apps". This is done solely to provide you with more fine-grained control over app selection. For instance, you might not want to install the X apps into a server image, but want both sets installed on a Desktop configuration.
  • sdm-apt — sdm-apt is an optional script that you can use to issue apt commands when in Phase 1 or via sdm --explore. It logs the apt output in /etc/sdm/apt.log along with all the other apt operations done in by sdm in customizing your image. Refer to the script for details.
  • sdm-firstboot — sdm-firstboot is a systemd service run on first system boot to set the WiFi country, enables Pi-specific devices if configured, and optionally run any Custom FirstBoot scripts.
  • 1piboot/ — Configuration file and sample scripts. You may edit the configuration file (1piboot.conf) if you wish, or you can use the --bootset command switch to control all the settings. See the next section for details. This directory will also be installed onto the SD Card in /usr/local/sdm/1piboot.
If enabled, the custom scripts in 1piboot/0-.sh are run when the system first boots, and can perform system tuning improvements. The custom scripts are enabled by the switch --bootscripts on either the command line that builds the IMG, or on the sdm --burn command when burning a new SD card. The scripts can do anything you want, of course, although having several small focused scripts is probably preferable for your sanity over the long term.
  • sdm-cparse — Helper script that defines some sdm-internal bash functions.
  • sdm-cportal — Implements the Captive Portal for --loadlocal wifi
  • sdm-logmsg — Helper script for the Captive Portal.
  • sdm-customphase — Custom Phase Script skeleton. Use this as a starting point to build your own Custom Phase Script. See Custom Phase Script below.
  • sdm-apt-cacher — Configures and installs apt-cacher-ng. This is optional, but highly recommended, especially with slower internet connections. sdm will use this with the --aptcache command switch. See the section on apt-cacher-ng below for details.

1piboot.conf

1piboot/1piboot.conf is a configuration file that describes RasPiOS-related configuration settings to be made in your image. Configuration settings are made when the system first boots. All of these settings use raspi-config to make the actual changes to the system. sdm does not syntax check the settings.

The settings in 1piboot.conf can be controlled by editing the config file, or via the --bootset command switch. For instance, you can set serial=0 in 1piboot.conf or you can use the --bootset serial=0 command switch. In addition, you can use --bootset when you customize the image and override the setting when you --burn the SD Card or --burnfile a new IMG file.

First Boot configuration settings

The following can only be set in the context of a running system, so are set during the first boot of the operating system. Details on each of these settings are available in the sudo raspi-config command. Unless otherwise specified, you enable the setting by uncommenting the corresponding line in 1piboot.conf and setting it to 0 (enabled) or other value as noted (e.g., audio, pi4video, boot_behaviour, and boot_order).

  • boot_splash — Enable a splash screen at boot time
  • boot_wait — Wait for a network connection to be established
  • camera — Enable the camera
  • i2c — Enable the ARM I2C interface
  • net_names — Enable predictable device names
  • onewire — Enable the one-wire interface
  • rgpio — Enable the network-accessible GPIO server
  • serial — Enable the serial port
  • spi — Enable the SPI interface
  • blanking — Enable screen blanking
  • overscan — Enable compensation for displays with overscan.
  • pixdub — Enable pixel doubling
  • powerled0:Enable disk activity flashing on Power LED, 1:Power LED always on (Pi Zero and Pi400 only)
  • audio — Set the audio setting. Valid settings are: 0:Auto, 1:Force 3.5mm jack, 2:Force HDMI
  • pi4video — Set the Pi4 video mode. Valid settings are: V1:4Kp60, V2:Analog TV out, V3:Disable both 4Kp60 and Analog
  • boot_behaviour — Set the boot behavior. Valid settings are: B1:Text console no autologin, B2:Text console with autologin, B3:Graphical Desktop no autologin, and B4:Graphical Desktop with autologin. NOTE: If --user was specified, autologin will be set for that user. If not, user "pi" is enabled.
  • boot_order — Set the boot order. Valid settings are: B1:Boot from SD Card if available else boot from USB, B2:Boot from USB USB if available else boot from SD Card, B3: Network boot if SD Card boot fails. See the "Boot Order" section below.
  • overclock — Enable overclocking. Valid settings are: None, Modest, Medium, High, Turbo. This setting is for Pi 1 and 2 only and will silently fail on all other Pi models.
NOTE: Not all of the above settings have been thoroughy tested and verified. They simply call raspi-config, so should just work. If you run into a problem, please open an issue on this github.

First Boot Automatic System Restart

One last First Boot setting controls whether the system automatically restarts at the completion of the First Boot processing. This is controlled with the --restart switch (or equivalently --reboot). The automatic system restart will wait until the system boot process has fully completed before restarting.

First Boot Automatic System Restart is useful for a couple reasons:

  • if access to the system requires a configuration setting modified during the First Boot. A restart ensures that all configuration settings are fully enabled.
For example, if the only access to the Pi will be over the serial port, the system must be restarted before the serial port will be active. In this situation the --bootset serial:0 --restart command switches enable the serial port and automatically restart the Pi. After the restart, the serial port is active.
  • You want it to reboot to make it easier to ensure that your configuration and services are as desired
  • You want the system to be fully operational so you can get started!
NOTE: If --restart is specified on RasPiOS Full with Desktop sdm changes the boot_behaviour to B1 (Text console with no autologin) so that the sdm FirstBoot messages are visible. In this case the boot_behaviour is reset to B4 (Graphical Desktop with autologin) for all subsequent reboots, unless the command line included --bootset boot_behaviour:xx command switch was specified.

Boot Order

The boot_order configuration setting is different than other settings, in that in modifies the Raspberry Pi eeprom so that boot from USB disk or boot from Network are enabled. If your Pi already has a current system on it, you can use the command sudo raspi-config do_boot_order XX to set the boot_order to B1 (Boot from SD Card if available else USB device), B2 (Boot from USB if available else SD Card) or B3 (Boot from Network if SD Card boot fails).

If the target system doesn't have a current system on it, you can update the eeprom with sdm by setting up a separate image that is enabled with boot_order, and has all updates installed. Burn that image to an SD card and boot up the target Pi hardware. The system will use raspi-config to change the boot_order setting, and the restart again.

At that point, you can remove the SD card and move ahead with setting up your SSD or Network boot as desired.

Complete sdm Command List

sdm commands consist of:

  • sudo /usr/local/sdm/sdm --customize raspios-image.img
Perform Phase 0 configuration, and drops you in a shell inside the image for Phase 1 customization
  • sudo /usr/local/sdm/sdm --burn /dev/sdX --host hostname raspios-image.img
Burns the IMG file onto the specified SD card and sets the hostname on the card.
  • sudo /usr/local/sdm/sdm --burnfile customized-for-myhostname.img --host myhostname raspios-image.img
Burns the IMG file to the specified SD Card Image and sets the hostname. The customized IMG file must be burned to an SD Card to be used.
  • sudo /usr/local/sdm/sdm --explore raspios-image.img
OR
sudo /usr/local/sdm/sdm --explore /dev/sdX
Uses systemd-nspawn to "go into" the IMG file (first example) or SD Card (second example) to explore and/or make manual changes to the image. When using --explore there is no access to the files in the running system.
  • sudo /usr/local/sdm/sdm --extend [--xmb nnn] raspios-image.img
Extends the image by the specified size and exits.
  • sudo /usr/local/sdm/sdm --mount raspios-image.img
OR
sudo /usr/local/sdm/sdm --mount /dev/sdX
Mounts the IMG file (first example) or SD Card (second example) onto the running system. This enables you to manually and easily copy files from the running RasPiOS system into the IMG.
NOTE: BE VERY CAREFUL! When you use the --mount command you're running as root with access to everything! If you copy or delete a file and neglect to prefix the file directory reference with /mnt/sdm you will modify your running system.
  • sudo /usr/local/sdm/sdm --info what — Display one of the databases that specify timezones, locale, keymaps, and wifi-country. The what argument can be one of time, locale, keymap, or wifi. The requested database is displayed with the less command. --info help will display the list of options.
sdm has a broad set of command switches. These can be specified in any case (UPPER, lower, or MiXeD).
  • --1piboot conffile — Specify a 1piboot.conf file to use instead of the one in /usr/local/sdm/1piboot/1piboot.conf. Note that this is less preferable than using the --bootset command switch.
  • --apps applist — Specifies a list of apps to install. This can be either a quoted list of space-separate apps ("zip iperf3 nmap") or a pointer to a file (@file), which has one package name per line. Comments are preceded by a pound sign ('#') and are ignored. You must specify --poptions apps in order for sdm to process the apps list.
  • --apssid SSID — Use the specified SSID for the Captive Portal instead of the default 'sdm'. See the Captive Portal section below for details.
  • --apip IPaddr — use the specified IP Address instead of the default 10.1.1.1. See the Captive Portal section below for details.
  • --aptcache IPaddr — Use APT caching. The argument is the IP address of the apt-cacher-ng server
  • --apt-dist-upgrade — Some RasPiOS Bullseye images have a strange software configuration, which causes apt-get upgrade to fail. This switch forces sdm to use apt-get --dist-upgrade which updates correctly. (In the 2021-10-30 set of images, the "with Desktop" versions have a set of problematic VLC modules installed.)
  • --b1script script — Call script when burning. script will be called after the output has been burned, and operates in effectively a Phase 0 environment. See section Burn Scripts below.
  • --b2script script — Like --b1script, but is called in an nspawn container. See section Burn Scripts below.
  • --batch — Do not provide an interactive command prompt inside the nspawn container
  • --bootadd key:value,key:value,... — Add new keys/values to /boot/config.txt
  • --bootconfig key:value,key:value,... — Update existing, commented keys in /boot/config.txt
  • --bootset key:value,key:value,... — Change system configuration settings. See 1piboot.conf section above.
  • --bootscripts — Directs sdm-firstboot to run the boot scripts in 1piboot/*.sh. If --bootscripts is specified when creating the sdm-enhanced IMG, every SD Card burned will run the boot scripts on First Boot. If not specified on IMG creation, it can be also be specified when burning the SD Card to run the boot scripts on that SD Card.
  • --cron-d file — Copy the cron file to /etc/cron.d. --cron-d can be specified multiple times to copy multiple files.
  • --cron-hourly file — Copy the cron file to /etc/cron.hourly. --cron-hourly can be specified multiple times to copy multiple files.
  • --cron-daily file — Copy the cron file to /etc/cron.daily. --cron-daily can be specified multiple times to copy multiple files.
  • --cron-weekly file — Copy the cron file to /etc/cron.weekly. --cron-weekly can be specified multiple times to copy multiple files.
  • --cron-monthly file — Copy the cron file to /etc/cron.monthly. --cron-monthly can be specified multiple times to copy multiple files.
  • --cron-systemd — Disable the cron service and enable cron via systemd sockets instead. One less process in the system, but some cron features are not supported, such as user-level crontabs.
  • --cscript scriptname — Specifies the path to your Custom Phase Script, which will be run as described in the Custom Phase Script section below.
  • --csrc /path/to/csrcdir — A source directory string that can be used in your Custom Phase Script. One use for this is to have a directory tree where all your customizations are kept, and pass in the directory tree to sdm with --csrc.
  • --custom[1-4] — 4 variables (custom1, custom2, custom3, and custom4) that can be used to further customize your Custom Phase Script.
  • --datefmt "fmt" — Use the specified date format instead of the default "%Y-%m-%d %H:%M:%S". See man date for format string details.
  • --ddsw "switches" — Provide switches for the dd command used with --burn. The default is "bs=16M iflag=direct". If --ddsw is specified, the default value is replaced.
  • --dhcpcdwait — Enable 'wait for network' (raspi-config System option S6).
  • --dhcpcd file — Append the contents of the specified file to /etc/dhcpcd.conf in the Customized Image.
  • --disable option — Disable specified options in the comma-separated list. Supported options: bluetooth, piwiz, swap, triggerhappy, wifi.
    • bluetooth — Block bluetooth via /etc/modprobe.d/blacklist-sdm-bluetooth.conf and disable the hciuart service
    • piwiz — Don't run piwiz during first system boot if LXDE is installed. All the settings in piwiz can be accomplished in sdm
    • swap — Disables the dphys-swapfile service. No service, no swap file.
    • triggerhappy — Disable the Triggerhappy service, which most people don't use. This also disables the udev rule that creates boot-time log spew.
    • wifi — Disable wifi via /etc/modprobe.d/blacklist-sdm-wifi.conf, which disables the onboard WiFi adapter.
  • --dtoverlay string — Add a dtoverlay to /boot/config.txt with the specified string, one dtoverlay per switch. Multiple --dtoverlay switches can be specified. They will all be added to config.txt
  • --dtparam string — Add a dtparam to /boot/config.txt with the specified string, one dtparam per switch. Multiple --dtparam switches can be specified. They will all be added to config.txt
  • --eeprom value — Change the eeprom value in /etc/default/rpi-eeprom-update. The RasPiOS default is 'critical', which is fine for most users. Change only if you know what you're doing.
  • --exports file — Copy the specified file into the image as /etc/exports
  • --fstab file — Append the contents of the specified file to /etc/fstab in the Customized Image. This is useful if you want the same /etc/fstab entries on your RasPiOS systems.
  • --gadget-mode — Configure the image to be a USB gadget.
  • --groups grouplist — Specify the groups to be added to new user created with --user. The default list is:
dialout,cdrom,floppy,audio,video,plugdev,users,adm,sudo,users,input,netdev,spi,i2c,gpio
  • --hdmi-force-hotplug — Enable the hdmi_force_hotplug setting in /boot/config.txt
  • --hdmigroup num — hdmigroup setting in /boot/config.txt
  • --hdmimode num — hdmimode setting in /boot/config.txt
  • --host hostname or --hostname hostname — Specifies the name of the host to set onto the SD Card when burning it.
  • --hotspot config-file — Install and Configure a hotspot (Access Point). This is done in accordance with the guides on the Raspberry Pi website:
https://www.raspberrypi.org/documentation/configuration/wireless/access-point-routed.md
https://www.raspberrypi.org/documentation/configuration/wireless/access-point-bridged.md
When --hotspot is used, the hotspot is installed and configured at the end of Phase 1. The system is set to automatically restart at the completion of FirstBoot to help ensure that the hotspot is correctly configured. Check the logs!
The hotspot configuration is specified in config-file, which contains a set of directives, one per line. The settings shown here are the defaults:
# Type of hotspot
#  local: Clients can only access the hotspot IP itself
#  routed: Clients can access the hotspot IP; non-local traffic is routed to the Pi's eth0 network
#  bridged: The Client network is bridged onto the Pi's eth0 network
config="local"
# Channel to use
channel="36"
# WiFi mode: "g" for 2.4Ghz, "a" for 5Ghz
# See https://en.wikipedia.org/wiki/List_of_WLAN_channels for legal channels/modes per country
hwmode="a"
# Country: defaults to --wifi-country setting but can be changed here
country="us"
# Network device to use. Default is "wlan0"
dev="wlan0"
# IP address for the hotspot WiFi network device
wlanip="192.168.4.1"
# Range of IP addresses and netmask to use for DHCP server on the hotspot network
dhcprange="192.168.4.2,192.168.4.32,255.255.255.0"
# Lease time for IP addresses leased on the hotspot network
leasetime="24h"
# SSID for the hotspot network
ssid="MyPiNet"
# Passphrase for the hotspot network
passphrase="password"
# Domain name for the hotspot network
domain="wlan.net"
# If enable=true, the hotspot will be enabled at system boot
enable="true"
# If non-null, specifies a file that is concatenated onto /etc/hostapd/hostapd.conf
include=""
  • --journal typetype specifies how to configure the system log. The default is syslog, which is "as configured" in RasPiOS. For the other values, the rsyslog service is disabled and logging configured:
    • persistent: Makes a permanent journal in /var/log
    • volatile: The journal is in memory and not retained across system restarts
    • none: There is no system journal
  • --keymap keymapname — Specifies the keymap to set into the image, or burn onto the SD Card. --keymap can be specified when customizing the image and/or when burning the SD card. Specifying --keymap with --burn overrides whatever is in the image. Also see --l10n. See the layout section in /usr/share/doc/keyboard-configuration/xorg.list for a complete list of keymaps.
  • --l10n — Build the image with the Keymap, Locale, Timezone, and WiFi Country of the system on which sdm is running. Note that the switch name is lowercase L10N, which is shorthand for "localization", just like I18N is shorthand for "internationalization". Both --l10n and --L10n are accepted.
  • --loadlocal USB — WiFi Credentials are read from a USB device. The switch keyword value USB is required. The Credentials must be in the file local-settings.txt in the root directory of the USB device. local-settings.txt has three text lines in it, specifying the WiFi Country, WiFi SSID and password in the format:
  country=2 letter country code
  ssid=yourSSIDname
  password=yourWiFiPassword
local-settings.txt can include 3 additional lines for setting keymap, locale, and timezone. These take the same values as the --keymap, --locale, and --timezone command switches.
The First Boot process will wait for and use the first non-mounted USB device that is found. If the file local-settings.txt is not found on that USB device, First Boot will print a message on the console, and the wait process will be restarted, so the remote user can update their USB device as needed. See /usr/share/zoneinfo/iso3166.tab for the complete WiFi Country code list. If --loadlocal is used, --wifi-country and the WiFi Country setting obtained from --l10n are ignored.
In addition to the switch value USB, the --loadlocal switch also accepts the values flashled and internet. The flashled value causes the First Boot process to flash the green Pi LED with progress indicators. See the LED Flashing section below for details. The internet value causes First Boot to check that the Pi has Internet access. If there is no internet access, First Boot will restart the load from USB process.
  • --loadlocal wifi — Starts a WiFi Captive Portal to obtain and test the WiFi Credentials during the First Boot. See the Captive Portal section below for details. The flashled and internet options are not supported with --loadlocal wifi.
  • --locale localename — The locale is specified just as you'd set it in raspi-config. For example, in the USA, one might use en_US.UTF-8, and in the UK en_UK.UTF-8. See /usr/share/i18n/SUPPORTED for a complete locale list.
  • --logwidth N — Set the maximum log line width before lines are split. Default is 96 characters.
  • --lxde-config args — Copy the specified LXDE app configuration files into the image. See the section below "Using the --lxde-config switch"
  • --modprobe file — Copy the modprobe file to /etc/modprobe.d. --modprobe can be specified multiple times to copy multiple files.
  • --motd file — Copy the specified file to /etc/motd. The original /etc/motd is renamed to /etc/motd.orig. You can easily create a null message of the day by using --motd /dev/null
  • --mouse left — If LXDE is installed, set the Mouse to be left-handed (for those that are in their right mind).
  • --norestart or --noreboot — Do not restart the system after the First Boot. This is useful if you set --restart when you build the image, but want to disable the automatic restart for a particular SD Card when you burn it.
  • --nspawnsw "switches" — Provide additional switches for the systemd-nspawn command. See man systemd-nspawn.
  • --password-pi password — Specify the password for the "pi" user. See Important note about Passwords below for details
  • --password-root password — Specify the password for root. See Important note about Passwords below for details
  • --password-same arg — Specify whether all accounts should have the same password. arg can be yes or no. All accounts includes pi, the user specified by --user, and root, if --rootpwd is specified.
  • --password-user password — Specify the password for the --user user. See Important note about Passwords below for details
  • --poptions value — Controls which functions will be performed by sdm-phase1. Possible values include:
    • apps — install the apps
    • noautoremove — do not do an apt autoremove
    • noupdate — do not do an apt update
    • nodmconsole — do not enable Display Manager on console (xdm or wdm only)
    • noupgrade — do not do an apt upgrade
    • novnc — do not configure VNC even if --vnc on command line
    • samba — streamlined, promptless Samba install
    • xapps — install the xapps
Enter multiple values as a single string separated by commas. For example --poptions apps,xapps or --poptions noupdate,noupgrade
  • --rclocal command — Add the specified command to /etc/rc.local. Multiple --rclocal switches can be specified, and the commands are added in the order specified on the command line.
  • --reboot n — Restart the system at the end of the First Boot after waiting an additional n seconds. The -reboot switch can be used on the command when customizing the IMG (will apply to all SD Cards) or on the --burn command (will apply only to SD cards burned with --restart set. The system will not restart until the boot process has fully completed. Waiting an additional time may be useful if your system has services that take longer to start up on the first boot. sdm waits until n seconds (n=20 for --restart) after the graphical or multi-user target is reached.
  • --redo-customize — Directs sdm to not prompt for confirmation to redo the customization on a target found to already be customized.
  • --regenerate-ssh-host-keys — The sdm FirstBoot process will regenerate the SSH host keys on the first system boot once the system time has been synchronized. The system will move ahead and regenerate the keys if the time has not been synchronized within 60 seconds.
  • --restart — Restart the system at the end of the First Boot. The --restart switch and --reboot are synonomous except that you cannot specify an additional restart wait with the --restart switch.
  • --showapt — Show the output from apt (Package Manager) on the terminal in Phase 1. By default, the output is not displayed on the terminal. All apt output is captured in /etc/sdm/apt.log in the IMG.
  • --showpwd — Show the passwords set on accounts in /etc/sdm/history
  • --ssh SSHoption — Control how SSH is enabled in the image. If --ssh is not specified or if SSHoption is service, SSH will be enabled in the image using the SSH service, just like RasPiOS. if --ssh none is specified SSH will not be enabled at all. If --ssh socket is specified SSH will be enabled using SSH sockets via systemd instead of having the SSH service hanging around all the time.
  • --svcdisable and --svcenable — Enable or disable named services, specified as comma-separate list, as part of the first system boot processing.
  • --swap n — Set the swap size to nMB. This overrides --disable swap
  • --sysctl file — Copy the specified file into the image in /etc/sysctl.d. --sysctl can be speicified multiple times to copy multiple files.
  • --systemd-config item:file — Specify config files for the various systemd functions. item is one of: login, network, resolve, system, timesync, user. The specified file is put into the directory /etc/systemd/item.conf.d, and the filename must be terminated with ".conf" in order for systemd to process them during systemd initialization. See the corresponding man page for details: man logind.conf, man networkd.conf, man resolved.conf, man systemd-system.conf, man timesyncd.conf, and man systemd-user.conf. The most useful of these is probably 'timesync', which lets you easily set a time server address.
  • --timezone tzname — Set the timezone for the system. See sudo timedatectl list-timezones | less for a complete list of timezones.
  • --udev file — Copy the udev rule file to /etc/udev/rules.d. --udev can be specified multiple times to copy multiple files.
  • --user username — Specify a username to be created in the IMG.
  • --uid uid — Use the specified uid rather than the next assignable uid for the new user, if created.
  • --vnc args — Install VNC into the image. See the Installing/Configuring VNC section below for complete details.
  • --vncbase base — Set the base port for VNC virtual desktops; RealVNC Console service is not changed.
  • --wifi-country countryname — Specify the name of the country to use for the WiFi Country setting. See /usr/share/zoneinfo/iso3166.tab for the complete WiFi Country code list. Also see the --l10n command switch which will extract the current WiFi Country setting from /etc/wpa_supplicant/wpa_supplicant.conf or /etc/wpa_supplicant/wpa_supplicant-wlan0.conf on the system on which sdm is running.
  • --wpa conffile — Specify the wpa_supplicant.conf file to use. You can either specify your wpa_supplicant.conf on the command line, or copy it into your image in your sdm-customphase script. See the sample sdm-customphase for an example. --wpa can also be specified when burning the SD Card.
  • --nowpa — Use this to tell sdm that you really meant to not provide a wpa_supplicant.conf file. You must either specify --wpa or --nowpa when customizing an IMG. This is useful if you want to build SD Cards for different networks. You can use --nowpa when you customize the IMG, and then specify --wpa conffile when burning the SD Card.
  • --xapps xapplist — Like --apps, but specifies the list of apps to install when --poptions xapps is specified.
  • --xmb n — Specify the number of MB to extend the image. The default is 2048 (MB), which is 2GB. You may need to increase this depending on the number of packages you choose to install in Phase 1. If the image isn't large enough, package installations will fail. If the image is too large, it will consume more disk space, and burning the image to an SD Card will take longer.

Using the --lxde-config switch

The --lxde-config switch directs sdm to load the specified app LXDE configuration files into the image in the /home/user/.config directory tree. user will be pi by default, or the user specified by --user.

The --lxde-config switch takes a comma-separate argument. The complete switch specification is:

--lxde-config pcmanfm:/path/to/pcmanfm.conf,libfm:/path/to/libfm.conf,lxterminal:/path/to/lxterminal.conf
You do not need to specify all the config files. If you only want to customize lxterminal, you only need specify that. If you are customizing pcmanfm, you'll need to specify config files for both pcmanfm AND libfm (I have no idea why pcmanfm uses two config files!)

Here's how to establish your custom configuration files:

  • Boot a RasPiOS Desktop system with LXDE
  • Customize lxterminal and/or pcmanfm preferences in the apps as desired
  • Copy the configuration files from your Pi to a shared directory, so that they are available on the Pi that you'll be using for sdm. They don't really need to be in a shared directory per se, just a directory available to sdm. The config files can be found at
    • libfm: /home/user/.config/libfm.conf
    • pcmanfm: /home/user/.config/LXDE-pi/pcmanfm.conf
    • lxterminal: /home/user/.config/lxterminal/lxterminal.conf
  • Add the --lxde-config switch with the appropriate arguments to your sdm command line
  • The specified files will be copied into the IMG during Phase 0, when both the host and IMG are acessible
  • The files will be moved to the correct directory locations in /home/user/.config during Phase 1
  • When you boot your newly-created customized image, your settings will be in place
If the target IMG does not have LXDE installed no changes will be made, although the files will be copied to /etc/sdm/assets.

sdm-firstboot

sdm-firstboot is a script executed by the service created in the IMG that runs when the system boots the first time. sdm-firstboot:

  • Sets the WiFi Country
  • Sets other infrequently used device settings
  • Runs scripts dynamically generated by sdm used to defer changes to as late as possible (fstab extension, eeprom settings, console display manager enable, and enabling RealVNC server)
  • Optionally executes custom scripts in /usr/local/sdm/thispi/1piboot/0-.sh
See the examples on this github. sdm Phase 0 copies these files from /usr/local/sdm/1piboot on the running system.

Custom Phase Script

A Custom Phase Script is a script provided by you. It is called 3 times: Once for Phase 0, once for Phase 1, and once after Phase 1 has completed. The first argument indicates the current phase ("0", "1", or "post-install"). The Custom Phase Script needs to be aware of the phase, as there are contextual differences:

  • In Phase 0, the host file system is fully available. The IMG file is mounted on /mnt/sdm, so all references to the IMG file system must be appropriately referenced by prefacing the directory string with /mnt/sdm. This enables the Custom Phase script to copy files from the host file system into the IMG file.
  • In Phase 1 and post-install (both inside nspawn) the host file system is not available at all. Thus, if a file is needed in Phase 1, Phase 0 must copy it into the IMG. References to /mnt/sdm will fail in Phase 1.
If a Custom Phase Script wants to run a script at boot time, even if --bootscripts is not specified, the Custom Phase script should put the script in /etc/sdm/0piboot in the IMG and named 0-.sh (e.g., 010-customize-something.sh). These scripts are always run by FirstBoot.

The best way to build a Custom Phase Script is to start with the example Custom Phase Script sdm-customphase, and extend it as desired.

Installing/Configuring VNC

The --vnc switch is used to install and configure VNC in your image. The arguments to the --vnc switch include:

  • real — Install RealVNC. This is only needed on RasPiOS Lite, as it's already installed on RasPiOS Desktop versions
  • tiger — Install TigerVNC server for virtual desktops
  • tight — Install TightVNC server for virtual desktops
  • resolutions — Specify a list of resolutions for virtual desktops
The arguments real, tiger, and/or tight must precede all resolution settings. see the examples below.

By default Virtual VNC desktops are configured with ports 5901, 5902, ... This can be modified with the --vncbase base switch. For instance, --vncbase 6400 would place the VNC virtual desktops at ports 6401, 6402, ...

For RasPiOS Desktop, RealVNC Server will be enabled automatically. Well, actually, it will be disabled for the first boot of the system as will the graphical desktop, and the sdm FirstBoot service will-reenable both for subsequent use.

For RasPiOS Lite, if --poptions nodmconsole is specified AND the Display Manager is xdm or wdm, the Display Manager will not be started on the console, and neither will RealVNC Server. It can be started later, if desired, with sudo systemctl enable --now vncserver-x11-serviced. Note, however, that you must enable the Display Manager as well for it to really be enabled. To enable the Display Manager:

  • xdm:sed -i "s/\#\:0 local \/usr\/bin\/X :0 vt7 -nolisten tcp/\:0 local \/usr\/bin\/X :0 vt7 -nolisten tcp/" /etc/X11/xdm/Xservers
  • wdm:sed -i "s/\#\:0 local \/usr\/bin\/X :0 vt7 -nolisten tcp/\:0 local \/usr\/bin\/X :0 vt7 -nolisten tcp/" /etc/X11/wdm/Xservers
Examples:
  • --vnc real,tiger,2540x1350,1880x960,1700x1200,1880x1100 — Install/enable RealVNC for connecting to the RasPiOS Console on port 5900. Create 4 VNC virtual desktops, each with a different resolution. These VNC Servers are on TCP ports 5901, 5902, 5903, 5904.
  • --vnc tiger,1024x768 — Install TigerVNC Server with one configured virtual desktop resolution on port 5901

/etc/fstab

sdm does not touch the lines in /etc/fstab created by RasPiOS. You may want to append one or more lines to /etc/fstab to set up other mounts, such as SMB, NFS, etc, and smb provides a couple of different ways to handle importing and appending your custom /etc/fstab into your image.

One way to do this is via a Custom Phase Script. In your Custom Phase Script, your Phase 0 code copies the fstab extension file into the IMG somewhere. Then, your Phase 1 code appends the copied fstab extension to the etc/fstab.

One drawback with this approach is that your fstab additions will be processed during the system FirstBoot. Network timeouts, etc could be an issue. This can be solved by using a Custom bootscript to append your custom fstab file to /etc/fstab.

That's exactly what --fstab does. It copies the file you provide to /etc/sdm/assets in the IMG, and then processes that during the system FirstBoot.

NOTE: No matter which mechanism you use, you'll need to create the mount point directories in the image during Phase 1.

Customization switches that can be used with --burn

These switches can be used with --burn. When used this way, they affect only the output SSD/SD Card, and not the IMG file.

  • --apip
  • --apssid
  • --b1script
  • --b2script
  • --bootscripts
  • --dhcpcd
  • --exports
  • --keymap
  • --locale
  • --noreboot
  • --rebootwait
  • --password-pi
  • --password-user
  • --password-root
  • --rclocal
  • --reboot
  • --sysctl
  • --timezone
  • --wifi-country
  • --wpa

Burn Scripts

There are cases where it is desirable to do per-device customization on the SD Card or burn image after it has been burned. Examples include:

  • Copy additional files onto the SD Card
  • Customized configuration files
  • Customized app installs
If the only differences between your "standard" image and per-device customizations are relatively modest (from your perspective), it you can use Burn Scripts to implement these customizations on the burn output device or file.

In the first case (copying additional files), your script will need access to both the host system and the SD Card. --b1script should be used for this. The execution environment for --b1script is the same as Phase 0 described above, and should follow the guidelines for a Custom Phase Script Phase 0.

In the second and third cases, your script wants to do things in the context of the newly-created system. sdm will nspawn into the SD Card, so your script should follow the guidelines for a Custom Phase Script Phase 1.

Both switches require a /complete/path/to/script as an argument.

If you want to do any logging in your Burn Scripts, execute the command source /mnt/sdm/usr/local/sdm/sdm-cparse (for --b1script) or source /usr/local/sdm/sdm-cparse (for --b2script) at the top of your script. You can then use logtoboth "string to log" to write additional log entries onto the SD Card.

Note that the --b2script script will be copied to /etc/sdm/assets on the SD Card/image before the nspawn, and is not deleted.

Captive Portal

If --loadlocal wifi is specified on the command line during image customization, a Captive Portal is started during the system First Boot. The Captive Portal starts an Access Point named 'sdm' (can be changed with --apssid) and the IP Address 10.1.1.1 (can be changed with --apip). When you connect to http://10.1.1.1 a web page will be displayed that has two links on it.

Clicking on the first link brings up a web form where the user can enter the SSID and Password for the WiFi network that the Pi should be connected to, as well as optionally specifying the Keymap, Locale, and Timezone appropriate for the user and location. There are two checkboxes, both checked, that the user can unselect:

  • Validate WiFi Configuration by Connecting — If this is checked, the user-provided WiFi SSID and Password will be used to validate that the Pi can connect to WiFi. If it is not checked, the SSID and Password are written to wpa_supplicant.conf and no validation is done.
  • Check Internet Connectivity after WiFi Connected — If checked, the captive portal will also test whether the Internet (1.1.1.1) is accessible.
The Captive Portal will complete and the boot process will continue if the WiFi connection test is successful, or if no WiFi validation is done. If there is a problem connecting to WiFi, the Portal will be re-enabled for another try.

If the Pi has only a single WiFi on it (that is, no second WiFi via a USB adapter), the Captive Portal WiFi will be dropped when the WiFi validation is done. The user must reconnect to the Captive Portal WiFi before checking the result of the validation test.

However, if the Pi has a second WiFi available (wlan1), the Captive Portal will use wlan1 for the Captive Portal, and use wlan0 for WiFi validation. In this case, the Captive Portal WiFi does not drop during this process.

The Captive Portal (sdm-cportal) is built in such a way that it is usable outside of sdm. If you try to use it outside of sdm and run into problems, please open an issue on this github.

NOTE: At the current time, the text displayed by the Captive Portal is only available in English. If you would like to contribute translations to other languages, open an issue on this github.

Installing Samba into your IMG

Installing Samba is super-simple! Add samba as one of the values in the comma-separated --poptions list. Samba will be installed silently with no prompts.

In addition to the basic install, you can of course do also do other configuration such as creating shares, creating accounts and setting up Samba passwords, by adding the appropriate commands to your Custom Phase script in the post-install section.

Terminal Colors

If possible (depends on your terminal; xterm definitely works), sdm changes the terminal colors when providing a command prompt in Phase 1, or when using the --mount command, to remind you that things are not quite "normal".

The colors are controlled by the --ecolors command switch, which takes an argument specified as 3 colors. The default is --ecolors blue:gray:red which sets the foreground (text) blue, the background gray, and the cursor red.

The colors for the --mount command are controlled by the --mcolors switch; the default is --mcolors black:LightSalmon1:blue.

apt-cacher-ng

apt-cacher-ng is a great RasPiOS package, and nearly essential if you have more than a couple of Pi systems. The savings in download MB and installation wait time is really quite impressive.

apt-cacher-ng requires a system running the apt-cacher server. For your sanity and the best and most reliable results, run this on a "production", always available Pi.

Once you have configured the server system, copy sdm-apt-cacher to the server and execute the command sudo /path/to/sdm-apt-cacher server. This will install apt-cacher-ng on the server and configure it for use. If the server firewall blocks port 3142 you'll need to add a rule to allow it.

Once you have the apt-cacher server configured you can use the --aptcache IPaddr sdm command switch to configure the IMG system to use the APT cacher.

If you have other existing, running Pis that you want to convert to using your apt-cacher server, copy sdm-apt-cacher to each one and execute the command sudo /path/to/sdm-apt-cacher client.

LED Flashing

As noted above, --loadlocal usb,flashled will cause the First Boot process to flash the Green Pi LED with progress/problem indicators. This is very useful if the Pi doesn't have a monitor attached. The flash codes are ("." is a short flash, and "-" is a long flash):

  • ..- ..- ..- — First Boot is waiting for an unmounted USB device to appear with the file local-settings.txt on it.
  • ... --- ... — An error was found in local-settings.txt. Errors can include:
    • ssid or password are not specified, or are the null string
    • An invalid WiFi Country was specified
    • An invalid Keymap, Locale, or Timezone was specified
  • -- -- -- -- — WiFi did not connect
  • ..... ..... ..... — WiFi connected
  • .-.-.- .-.-.- .-.-.- .-.-.- — Internet is accessible
  • -.-.-. -.-.-. -.-.-. -.-.-. — Internet is not accessible
  • ..-. ..-. ..-. — Waiting for a DHCP-assigned IP address

Compatibility — Non-Pi Linux and Pi 32-bit vs 64-bit

sdm itself is mostly Linux distro-independent and 32-vs-64-bit agnostic. The interoperability issues arise when sdm uses the Linux systemd-nspawn command when customizing an image or using --explore on an image. Other sdm commands should work on any Linux host OS to access or modify a RasPiOS image.

In order to do image customization or use --explore on an image on a non-RasPiOS host (e.g., x86 or x86_64), you must install qemu-user-static, which pulls in package binfmt-support:

    sudo apt install qemu-user-static

These components enable image customization and --explore on an RasPiOS image. If this doesn't work on your x86 Linux system, it may be too old and lacking updated support or fixes. I have tested this on Ubuntu 20.04, and it's able to operate on both RasPiOS 32 and 64-bit images. IMPORTANT: It appears that several Linux distros, such as Debian 10.6.x don't work correctly as of January 2021. Since Ubuntu tends to update more frequently, it has picked up whatever fix is missing from the current released Debian.

Running on 64-bit RasPiOS sdm can customize, explore, burn, and mount both 32-bit and 64-bit RasPiOS images.

However, running on 32-bit RasPiOS sdm can only mount and burn 64-bit images; customization and --explore will not operate on 64-bit images when running on 32-bit RasPiOS. The systemd-nspawn command on 32-bit RasPiOS is not able to operate against a 64-bit RasPiOS image.

Important notes about Passwords

Behavior of --password-same switch

If --password-same y is specified, then all accounts will be given the same password. All accounts includes pi, the user specified by --user, and root, if --rootpwd is specified. The password used is selected as follows:

  • --password-pi password if specified
  • --password-user password if specified
  • --password-root password if specified
  • Password entered in response to the password prompt

Password logging in the IMG or SSD/SD Card

If --showpwd is used, passwords will knowingly be logged in /etc/sdm/history.

However, if any of the password switches (--password-pi, --password-user, or --password-root) are used on the command line, passwords will be logged in /etc/sdm/history because the complete sdm command line is logged there. They will also be retained in /etc/sdm/cparams.

To remove all logged passwords from an sdm-customized IMG or SD card, simply remove the files /etc/sdm/history and /etc/sdm/cparams. You may want to save them for later use or information unless you have recorded the passwords elsewhere.

Note that if you forget any of the passwords, you can use sdm to reset them by using sdm --explore into the IMG or SD Card, and then changing the password for the desired account(s) with the passwd command.

Bread crumbs

sdm leaves a couple of files in /etc/sdm in the IMG that are used to control its operation and log status.

  • apt.log contains all the apt command output (package installs) done during the SD Card creation
  • cparams are the parameters with which sdm was initially run on the image
  • history has the log written by sdm
  • 1piboot.conf is the configuration file used when the IMG was customized
  • auto-1piboot is used by sdm. At the current time, it is only used to reset the boot_behaviour on RasPios Full with Desktop.
  • custom.ized tells sdm that the image has been customized. If this exists, sdm will not rerun Phase 0. If you really want to rerun Phase 0 on an already-customized image, use sdm --explore to nspawn into the image and rm -f /etc/sdm/custom.ized.

Cleaning up dangling mounts

If something is not working right, make sure that there are no dangling mounts in the running RasPiOS system. You can end up with a dangling mount if sdm terminates abnormally, either with an error (please report!) or via an operator-induced termination. If sdm is not running, you should see no "/mnt/sdm" mounts (identified with sudo df).

You can unmount them by manually using sudo umount -v /mnt/sdm/{boot,}. This will umount /mnt/sdm/boot and then /mnt/sdm. You'll need to delete the dangling loop device also.

Loop devices

A couple of quick notes on loop devices, which are used to mount the IMG file into the running system.

  • losetup -a lists all in-use loop devices
  • losetup -d /dev/loopX deletes the loop device /dev/loopX (e.g., /dev/loop0). You may need to do this to finish cleaning up from dangling mounts (which you do first, before deleting the loop device).
  • If your system doesn't have enough loop devices, you can increase the number by adding max_loop=n on end of /boot/cmdline.txt and reboot.

Known Restrictions and Issues

  • sdm uses the single mount point /mnt/sdm, so there can only be one copy of sdm active at once.
  • sdm must be run as root.
  • sdm has been thoroughly tested on RasPiOS Buster 32-bit and 64-bit (beta) IMG files. It has been moderately tested on Raspbian Stretch, but obviously functions added to raspi-config in Buster are not supported on Stretch.

Credits

sdm was inspired by posts by @HawaiianPi and @sakaki in the Raspberry Pi Forum: STICKY: Making your own custom burn-n-boot Raspbian image