After creating the SD card for this project, I next wanted to automate the initial Pi setup on the first login – further configuring system settings and installing applications. While it might have been possible to do some of that with pi-gen or Yocto layers, I just wanted a simple script to execute initially. In the previous post, sd-card-write.sh
copies this script to the SD card as /boot/setup.sh
.
System Configuration and Password
It doesn’t seem to be well documented but raspi-config
can be run non-interactively with a nonint
option. Browsing the source, various methods like do_camera are available to be called. Later I stumbled upon this raspi-config Gist that provides a nice template for easily scripting various configuration tasks.
#!/bin/bash echo "Running automated raspi-config tasks" # Via https://gist.github.com/damoclark/ab3d700aafa140efb97e510650d9b1be # Execute the config options starting with 'do_' below grep -E -v -e '^\s*#' -e '^\s*$' <<END | \ sed -e 's/$//' -e 's/^\s*/\/usr\/bin\/raspi-config nonint /' | bash -x - # # Drop this file in SD card root. After booting run: sudo /boot/setup.sh # --- Begin raspi-config non-interactive config option specification --- # Hardware Configuration do_boot_wait 0 # Turn on waiting for network before booting do_boot_splash 1 # Disable the splash screen do_overscan 1 # Enable overscan do_camera 1 # Enable the camera do_ssh 0 # Enable remote ssh login # System Configuration do_configure_keyboard us do_hostname ${host} do_change_timezone America/New_York do_change_locale LANG=en_US.UTF-8 # Don't add any raspi-config configuration options after 'END' line below & don't remove 'END' line END
The ${host}
value is a placeholder set when running a script to create the SD card.
It can be important to set the locale details (especially keyboard layout); by default it’s UK English and the password I entered on my keyboard contained an “@” character. I spent a few minutes scratching my head after failed ssh login attempts once.
After the raspi-config
steps quickly execute the script first starts the password change process with sudo passwd pi
. Using /usr/bin/raspi-config do_change_pass
is another option but it’s slower going through that UI. This is the only part of the process requiring user input; use of pi-gen could avoid this by changing the default user credentials.
System Updates
Next package lists are updated and packages are upgraded.
echo "Updating packages" sudo apt-get update && sudo apt-get -y upgrade
Get:1 http://archive.raspberrypi.org/debian buster InRelease [25.1 kB] Get:2 http://raspbian.raspberrypi.org/raspbian buster InRelease [15.0 kB] Get:3 http://raspbian.raspberrypi.org/raspbian buster/main armhf Packages [13.0 MB] Get:4 http://archive.raspberrypi.org/debian buster/main armhf Packages [280 kB] Fetched 13.3 MB in 7s (1,865 kB/s) Reading package lists... Done Reading package lists... Done Building dependency tree Reading state information... Done Calculating upgrade... Done The following packages have been kept back: binutils binutils-arm-linux-gnueabihf binutils-common libbinutils The following packages will be upgraded: bluez curl firmware-atheros firmware-brcm80211 firmware-libertas firmware-misc-nonfree firmware-realtek libcurl4 libgnutls30 libicu63 libpam-systemd libsystemd0 libudev1 raspi-config rpi-eeprom rpi-eeprom-images systemd systemd-sysv udev 19 upgraded, 0 newly installed, 0 to remove and 4 not upgraded. Need to get 31.2 MB of archives ...
Enabling the Camera
I didn’t spend much time trying to figure out why, but do_camera
via non-interactive raspi-config
didn’t seem to work; there were no errors but the camera wasn’t enabled afterwards. Various posts indicated this could be done via directly modifying /boot/config.txt
so that’s the route I went:
echo "Enabling camera" sed -i "s/start_x=0/start_x=1/g" /boot/config.txt
Docker and Reboot
A helper script to install and run the application (described in upcoming post) is next moved to the home directory for convenient execution. I considered having the setup script run the app install script but found it more flexible keeping them separated.
echo "Moving pull script from boot to home" mv /boot/pull.sh /home/pi
This script works by pulling the application image from a Docker registry so Docker first needs to be installed.
echo "Installing Docker" # Installing docker will disconnect ssh curl -sSL https://get.docker.com | sh echo "Finishing docker setup" sudo usermod -aG docker pi
Afterwards, all these script changes are finalized with a restart.
echo "Restarting to apply changes. After run ssh pi@${host}.local" # Reboot after all changes above complete /sbin/shutdown -r now
The full script is available here: setup.sh.
Going Further
Later I ended up using pi-gen here to move some of this setup to a pre-built custom Pi image. See Using Pi-Gen to Build a Custom Raspbian Lite Image for details.
Up Next
Deploying, Running, Debugging .NET Code on Raspberry Pi – The next post in this series covers a few common ways to get .NET Code on the Pi and run and debug it.
This was super helpful!