rpi23-gen-image.sh
is an Debian Linux bootstrapping shell script for generating Debian OS images for Raspberry Pi 2 (RPi2, 32 bit) and Raspberry Pi 3 (RPi3, 64 bit) computers.
Note by Michael Franzl:
This is a fork of the original project by github user "drtyhlpr". My fork is developed into a slightly different direction:
- Only official Debian releases 9 ("Stretch") and newer are supported. Debian 10 ("Buster") has been tested too and works well.
- Only the official/mainline/vanilla Linux kernel is supported (not the raspberry flavor kernel).
- The Linux kernel must be pre-cross-compiled on the PC running this script (instructions below).
- Only U-Boot booting is supported.
- The U-Boot sources must be pre-downloaded and pre-cross-compiled on the PC running this script (instructions below).
- An apt caching proxy server must be installed to save bandwidth (instructions below).
- The installation of the system to an SD card is done by simple copying or rsyncing, rather than creating, shrinking and expanding file system images.
- The FBTURBO option is removed in favor or the working VC4 OpenGL drivers of the mainline Linux kernel.
All of these simplifications are aimed at higher bootstrapping speed and maintainability of the script. For example, we want to avoid testing of all of the following combinations:
RPi2 with u-boot, with official kernel
RPi2 without u-boot, with official kernel
RPi2 with u-boot, with raspberry kernel
RPi2 without u-boot, with raspberry kernel
RPi3 with u-boot, with official kernel
RPi3 without u-boot, with official kernel
RPi3 with u-boot, with raspberry kernel
RPi3 without u-boot, with raspberry kernel
Thus, this script only supports:
RPi2 with u-boot with official kernel
RPi3 with u-boot with official kernel
A RPi2 (setting RPI_MODEL=2) is well supported. It will run the arm architecture of Debian, and a 32-bit kernel. You should get very good results, see my related blog posts:
https://blog.michael.franzl.name/2016/10/31/raspberry-pi-debian-stretch/
https://blog.michael.franzl.name/2016/11/10/setting-i2c-speed-raspberry-pi/
The newer RPi 3 B V1.2 (setting RPI_MODEL=3) is supported too. It will run the arm64 architecture of Debian, and a 64-bit kernel. The support of this board by the Linux kernel will very likely improve over time. Newer revisions of version 3 may work but have not been tested yet. If you run into problems with a different board, please do NOT file Issue reports. Instead, please fork this project and contribute back.
In general, this script is EXPERIMENTAL. I do not provide ISO file system images. It is better to master the process rather than to rely on precompiled images. In this sense, use this project only for educational purposes.
Basically, we will deboostrap a minimal Debian 9 ("Stretch") system for the Raspberry on a regular PC running also Debian 9 ("Stretch"). Then we copy that system on a SD card, then boot it on the Raspberry.
We will work with the following directories:
~/workspace
|- rpi23-gen-image
|- linux
|- u-boot
|- raspberry-firmware
Set up your working directory:
mkdir workspace
cd workspace
Do the following steps as root user.
This way, you won't have to re-download hundreds of megabytes of Debian packages from the Debian server every time you run the rpi23-gen-image
script.
apt-get install apt-cacher-ng
Check its status page:
http://localhost:3142
The following list of Debian packages must be installed on the build system because they are essentially required for the bootstrapping process.
apt-get install debootstrap debian-archive-keyring qemu-user-static binfmt-support dosfstools rsync bmap-tools whois git bc device-tree-compiler dbus psmisc python-dev
For a RPi2, you also need:
apt-get install crossbuild-essential-armhf
For a RPi3, you also need:
apt-get install crossbuild-essential-arm64
Get the Linux mainline kernel. This is a very large download, about 2GB. (For a smaller download of about 90 MB, consider downloading the latest stable kernel as .tar.xz from https://kernel.org.)
git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
cd linux
For now, please use exactly this commit ID, which has been confirmed working:
60e8d3e11645a1b9c4197d9786df3894332c1685 (Feb 2017, approx. version 4.10)
git checkout 60e8d3e1
If you run into problems using another commit ID, please do NOT file Issue reports. Instead, please fork this project and contribute back.
Working configuration files for this Linux kernel revision are included in this repository. (working-rpi2-linux-config.txt
and working-rpi3-linux-config.txt
).
If you want to generate the default .config
file that is also working on the Raspberry, execute
make mrproper
For a RPi2:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- multi_v7_defconfig
For a RPi3:
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- defconfig
Whichever .config
file you have at this point, if you want to get more control as to what is enabled in the kernel, you can run the graphical configuration tool at this point:
apt-get install libglib2.0-dev libgtk2.0-dev libglade2-dev
For a RPi2:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- gconfig
For a RPi3:
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- gconfig
Before compiling the kernel, back up your .config
file so that you don't lose it after the next make mrproper
:
cp .config ../kernelconfig-backup.txt
Clean the sources:
make mrproper
Optionally, copy your previously backed up .config
:
cp ../kernelconfig-backup.txt .config
Find out how many CPU cores you have to speed up compilation:
NUM_CPU_CORES=$(grep -c processor /proc/cpuinfo)
Run the compilation on all CPU cores. This takes about 10 minutes on a modern PC:
For a RPi2:
make -j${NUM_CPU_CORES} ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
For a RPi3:
make -j${NUM_CPU_CORES} ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu-
Verify that you have the required kernel image.
For a RPi2 this is:
./arch/arm/boot/zImage
For a RPi3 this is:
./arch/arm64/boot/Image.gz
cd ..
git clone git://git.denx.de/u-boot.git
For now, please use exactly this commit ID, which has been confirmed working:
b24cf8540a85a9bf97975aadd6a7542f166c78a3
git checkout b24cf8540a
If you run into problems using another commit ID, please do NOT file Issue reports. Instead, please fork this project and contribute back.
Let's increase the maximum kernel image size from the default (8 MB) to 64 MB. This way, u-boot will be able to boot even larger kernels. Edit ./u-boot/include/configs/rpi.h
and add above the very last line (directly above "#endif"):
#define CONFIG_SYS_BOOTM_LEN (64 * 1024 * 1024)
Find out how many CPU cores you have to speed up compilation:
NUM_CPU_CORES=$(grep -c processor /proc/cpuinfo)
Compile for a RPi model 2 (32 bits):
make -j${NUM_CPU_CORES} ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- rpi_2_defconfig all
Compile for a RPi model 3 (64 bits):
make -j${NUM_CPU_CORES} ARCH=arm CROSS_COMPILE=aarch64-linux-gnu- rpi_3_defconfig all
Verify that you have the required bootloader file:
./u-boot.bin
The Raspberry Pi still needs some binary proprietary blobs for booting. Get them:
cd ..
mkdir -p raspberry-firmware/boot
cd raspberry-firmware/boot
wget https://github.com/raspberrypi/firmware/raw/master/boot/bootcode.bin
wget https://github.com/raspberrypi/firmware/raw/master/boot/fixup_cd.dat
wget https://github.com/raspberrypi/firmware/raw/master/boot/fixup.dat
wget https://github.com/raspberrypi/firmware/raw/master/boot/fixup_x.dat
wget https://github.com/raspberrypi/firmware/raw/master/boot/start_cd.elf
wget https://github.com/raspberrypi/firmware/raw/master/boot/start.elf
wget https://github.com/raspberrypi/firmware/raw/master/boot/start_x.elf
Confirmed working revision: bf5201e9682bf36370bc31d26b37fd4d84e1cfca
This is where you call the rpi23-gen-image.sh
script contained in this repository.
cd ../..
git clone https://github.com/michaelfranzl/rpi23-gen-image.git
cd rpi23-gen-image
For example:
DEBIAN_RELEASE="stretch" \
USER_NAME="pi" \
PASSWORD="xxx" \
APT_INCLUDES="i2c-tools,rng-tools,avahi-daemon,rsync,vim" \
APT_PROXY="localhost:3142" \
UBOOTSRC_DIR="$(pwd)/../u-boot" \
KERNELSRC_DIR="$(pwd)/../linux" \
RPI_MODEL=2 \
HOSTNAME="rpi2" \
RPI_FIRMWARE_DIR="$(pwd)/../raspberry-firmware" \
ENABLE_REDUCE=true \
REDUCE_SSHD=true \
./rpi23-gen-image.sh
You may want to modify the variables according to the section "Command-line parameters" below.
The file example.sh
in this repostory contains a working example for RPi3.
Insert a SD card into the card reader of your host PC. You'll need two partitions on it. I'll leave as an exercise for the reader the creation of a partition table according to the following output of fdisk
for a 32GB card:
Device Boot Start End Sectors Size Id Type
/dev/mmcblk0p1 2048 500000 497953 243.1M c W95 FAT32 (LBA)
/dev/mmcblk0p2 501760 62552063 62050304 29.6G 83 Linux
The following commands will erase all contents of the SD card and install the system (copy via rsync) on the SD card:
umount /dev/mmcblk0p1
umount /dev/mmcblk0p2
mkfs.vfat /dev/mmcblk0p1
mkfs.ext4 /dev/mmcblk0p2
mkdir -p /mnt/raspcard
mount /dev/mmcblk0p2 /mnt/raspcard
mkdir -p /mnt/raspcard/boot/firmware
mount /dev/mmcblk0p1 /mnt/raspcard/boot/firmware
rsync -avc ./images/stretch/build/chroot/ /mnt/raspcard
sync
umount /dev/mmcblk0p1
umount /dev/mmcblk0p2
sync
Note about SD cards: Cheap (or sometimes even professional) SD cards can be weird. I've repeatedly noticed corrupt/truncated files even after proper rsync and proper umount on different brand new SD cards. To verify that all files have been transferred correctly, make a diff
between the two directories:
diff -rq ./images/stretch/build/chroot/ /mnt/raspcard
Insert the SD card into the Raspberry Pi, and if everything went well, you should see a console-based login prompt on the screen. Login with the login details you've passed into the script (USER_NAME and PASSWORD).
Alternatively, if you have included "avahi-daemon" in your APT_INCLUDES, you don't need a screen and keyboard and can simply log in via SSH from another computer, even without knowing the Rasberry's dynamic/DHCP IP address (replace "hostname" and "username" with what you have set as USER_NAME and HOSTNAME above):
ssh username@hostname.local
Remember to change usernames, passwords, and SSH keys!
Running top
shows that the freshly booted system uses only 23 MB out of the availabl 1GB RAM! Confirmed for both RPi2 and RPi3.
The Raspberry doesn't have a real time clock. But the default systemd
conveniently syncs time from the network. Check the output of timedatectl
. Confirmed working for both RPi2 and RPi3.
The working device node is available at /dev/hwrng
. Confirmed working for both RPi2 and RPi3.
Also try I2C support:
apt-get install ic2-tools
i2cdetect -y 0
Confirmed working for both RPi2 and RPi3.
As of the kernel revision referenced above, this only works on the RPi2. The RPi3 has only the red PWR LED on all the time, but otherwise is working fine.
By default, the green onboard LED of the RPi blinks in a heartbeat pattern according to the system load (this is done by kernel feature LEDS_TRIGGER_HEARTBEAT).
To use the green ACT LED as an indicator for disc access, execute:
echo mmc0 > /sys/class/leds/ACT/trigger
To toggle the red PWR LED:
echo 0 > /sys/class/leds/PWR/brightness # Turn off
echo 1 > /sys/class/leds/PWR/brightness # Turn on
Or use the red PWR LED as heartbeat indicator:
echo heartbeat > /sys/class/leds/PWR/trigger
If ENABLE_WIRELESS
was set to true
during install, the WLAN interface should be detected. Inspect if lsmod
lists the module brcmfmac
. Also check if networkctl
lists wlan0
. It should be straightforward from here to set up a wireless network connection.
The Raspberry hardware sets the MAC address of the ethernet adapter to a random value at each reboot. To make it constant, we need to spoof it before the ethernet adapter comes up. We'll do so using systemd:
Install macchanger:
apt install macchanger
Create the file /etc/systemd/system/macspoof@.service
with the following contents. Also in this file, change the MAC address to a value of your choice:
[Unit]
Description=macchanger on %I
Wants=network-pre.target
Before=network-pre.target
BindsTo=sys-subsystem-net-devices-%i.device
After=sys-subsystem-net-devices-%i.device
[Service]
ExecStart=/usr/bin/macchanger --mac=1a:2a:3a:4a:5a:6a %I
Type=oneshot
[Install]
WantedBy=multi-user.target
Enable this service:
systemctl enable macspoof@eth0
After all reboots, the MAC address should be the static value entered in the file.
systemd
now replaces decades-old low-level system administration tools. Here is a quick cheat sheet:
Reboot machine:
systemctl reboot
Halt machine (this actually turns off the RPi):
systemctl halt
Show all networking interfaces:
networkctl
Show status of the Ethernet adapter:
networkctl status eth0
Show status of the local DNS caching client:
systemctl status systemd-resolved
Successfully tested on the RPi2 and RPI3.
If you want to install a graphical user interface, I would suggest the light-weight LXDE window manager. Gnome is still too massive to run even on a GPU-accelerated Raspberry.
apt-get install task-lxde-desktop lxde-common
Reboot, and you should be greeted by the LightDM greeter screen!
Successfully tested on the RPi2 and RPI3.
apt-get install mesa-utils
glxgears
glxinfo | grep '^OpenGL'
Glxinfo should output:
OpenGL vendor string: Broadcom
OpenGL renderer string: Gallium 0.4 on VC4
OpenGL version string: 2.1 Mesa 12.0.3
OpenGL shading language version string: 1.20
OpenGL ES profile version string: OpenGL ES 2.0 Mesa 12.0.3
OpenGL ES profile shading language version string: OpenGL ES GLSL ES 1.0.16
Only successfully tested on the RPi2. Not yet tested on the RPI3.
In case you want to compile and deploy another Mainline Linux kernel directly on the Raspberry, proceed as described above, but you don't need the ARCH
and CROSS_COMPILE
flags. Instead, you need the -fno-pic
compiler flag for modules. The following is just the compilation step (configuration and installation omitted):
make -j5 CFLAGS_MODULE="-fno-pic"
make modules_install
The script accepts certain command-line parameters to enable or disable specific OS features, services and configuration settings. These parameters are passed to the rpi23-gen-image.sh
script via (simple) shell-variables. Unlike environment shell-variables (simple) shell-variables are defined at the beginning of the command-line call of the rpi23-gen-image.sh
script.
Set Debian packages server address. Choose a server from the list of Debian worldwide mirror sites. Using a nearby server will probably speed-up all required downloads within the bootstrapping process.
Set Proxy server address. Using a local Proxy-Cache like apt-cacher-ng
will speed-up the bootstrapping process because all required Debian packages will only be downloaded from the Debian mirror site once.
A comma separated list of additional packages to be installed during bootstrapping.
Specifiy the target Raspberry Pi hardware model. The script at this time supports the Raspberry Pi models 2
and 3
.
Set the desired Debian release name. Only use "stretch" or newer.
Set system host name. It's recommended that the host name is unique in the corresponding subnet.
Set system root
password. The same password is used for the created user pi
. It's STRONGLY recommended that you choose a custom password.
Set default system locale. This setting can also be changed inside the running OS using the dpkg-reconfigure locales
command. Please note that on using this parameter the script will automatically install the required packages locales
, keyboard-configuration
and console-setup
.
Set default system timezone. All available timezones can be found in the /usr/share/zoneinfo/
directory. This setting can also be changed inside the running OS using the dpkg-reconfigure tzdata
command.
These options are used to configure keyboard layout in /etc/default/keyboard
for console and Xorg. These settings can also be changed inside the running OS using the dpkg-reconfigure keyboard-configuration
command.
Set the name of the model of your keyboard type.
Set the supported keyboard layout(s).
Set the supported variant(s) of the keyboard layout(s).
Set extra xkb configuration options.
This parameter is used to set up networking auto configuration in /etc/systemd/network/eth.network
.
#####ENABLE_DHCP
=true
Set the system to use DHCP. This requires an DHCP server running in your local network.
These parameters are used to set up a static networking configuration in /etc/systemd/network/eth.network
. The following static networking parameters are only supported if ENABLE_DHCP
was set to false
.
#####NET_ADDRESS
=""
Set a static IPv4 or IPv6 address and its prefix, separated by "/", eg. "192.169.0.3/24".
#####NET_GATEWAY
=""
Set the IP address for the default gateway.
#####NET_DNS_1
=""
Set the IP address for the first DNS server.
#####NET_DNS_2
=""
Set the IP address for the second DNS server.
#####NET_DNS_DOMAINS
=""
Set the default DNS search domains to use for non fully qualified host names.
#####NET_NTP_1
=""
Set the IP address for the first NTP server.
#####NET_NTP_2
=""
Set the IP address for the second NTP server.
Enable serial console interface. Recommended if no monitor or keyboard is connected to the RPi2/3. In case of problems fe. if the network (auto) configuration failed - the serial console can be used to access the system.
Enable IPv6 support. The network interface configuration is managed via systemd-networkd.
Install and enable OpenSSH service. The default configuration of the service doesn't allow root
to login. Please use the user pi
instead and su -
or sudo
to execute commands as root.
Allow the installation of non-free Debian packages that do not comply with the DFSG. This is required to install closed-source firmware binary blobs.
Download and install the closed-source firmware binary blob that is required to run the internal wireless interface of the Raspberry Pi model 3
. This parameter is ignored if the specified RPI_MODEL
is not 3
.
If set to false, disable and uninstall rsyslog (so logs will be available only in journal files)
Enable sound hardware and install Advanced Linux Sound Architecture.
Install and enable D-Bus message bus. Please note that systemd should work without D-bus but it's recommended to be enabled.
Install Xorg open-source X Window System.
Install a user defined window manager for the X Window System. To make sure all X related package dependencies are getting installed ENABLE_XORG
will automatically get enabled if ENABLE_WM
is used. The rpi23-gen-image.sh
script has been tested with the following list of window managers: blackbox
, openbox
, fluxbox
, jwm
, dwm
, xfce4
, awesome
.
Use debootstrap script variant minbase
which only includes essential packages and apt. This will reduce the disk usage by about 65 MB.
Reduce the disk space usage by deleting packages and files. See REDUCE_*
parameters for detailed information.
Enable iptables IPv4/IPv6 firewall. Simplified ruleset: Allow all outgoing connections. Block all incoming connections except to OpenSSH service.
Create non-root user with password set via $PASSWORD variable. Unless overridden with USER_NAME
=user, username will be pi
.
Non-root user to create. Ignored if ENABLE_USER
=false
Set root user password so root login will be enabled
Enable password root login via SSH. May be a security risk with default password, use only in trusted environments.
Enable IPv4/IPv6 network stack hardening settings.
Path to a directory with scripts that should be run in the chroot before the image is finally built. Every executable file in this directory is run in lexicographical order.
Install kernel headers with built kernel.
Path to a directory of a pre-built and cross-compiled Linux kernel.
Path to a directory of a pre-built and cross-compiled u-boot bootoader. Download it with git clone git://git.denx.de/u-boot.git
.
The directory containing a local copy of the firmware from the RaspberryPi firmware project. The directory must be specified and must exist.
The following list of parameters is ignored if ENABLE_REDUCE
=false.
Configure APT to use compressed package repository lists and no package caching files.
Remove all doc files (harsh). Configure APT to not include doc files on future apt-get
package installations.
Remove all man pages and info files (harsh). Configure APT to not include man pages on future apt-get
package installations.
Replace vim-tiny
package by levee
a tiny vim clone.
Remove bash
package and switch to dash
shell (experimental).
Remove PCI related hwdb files (experimental).
Replace openssh-server
with dropbear
.
Remove all locale
translation files.
The functions of this script that are required for the different stages of the bootstrapping are split up into single files located inside the bootstrap.d
directory. During the bootstrapping every script in this directory gets executed in lexicographical order:
Script | Description |
---|---|
10-bootstrap.sh |
Debootstrap basic system |
11-apt.sh |
Setup APT repositories |
12-locale.sh |
Setup Locales and keyboard settings |
13-kernel.sh |
Build and install RPi2/3 Kernel |
20-networking.sh |
Setup Networking |
21-firewall.sh |
Setup Firewall |
30-security.sh |
Setup Users and Security settings |
31-logging.sh |
Setup Logging |
41-uboot.sh |
Build and Setup U-Boot |
50-firstboot.sh |
First boot actions |
99-reduce.sh |
Reduce the disk space usage |
All the required configuration files that will be copied to the generated OS image are located inside the files
directory. It is not recommended to modify these configuration files manually.
Directory | Description |
---|---|
apt |
APT management configuration files |
boot |
Boot and RPi2/3 configuration files |
dpkg |
Package Manager configuration |
etc |
Configuration files and rc scripts |
firstboot |
Scripts that get executed on first boot |
initramfs |
Initramfs scripts |
iptables |
Firewall configuration files |
locales |
Locales configuration |
modules |
Kernel Modules configuration |
mount |
Fstab configuration |
network |
Networking configuration files |
sysctl.d |
Swapping and Network Hardening configuration |
xorg |
fbturbo Xorg driver configuration |
Debian custom packages, i.e. those not in the debian repositories, can be installed by placing them in the packages
directory. They are installed immediately after packages from the repositories are installed. Any dependencies listed in the custom packages will be downloaded automatically from the repositories. Do not list these custom packages in APT_INCLUDES
.
Scripts in the custom.d directory will be executed after all other installation is complete but before the image is created.
All information related to the bootstrapping process and the commands executed by the rpi23-gen-image.sh
script can easily be saved into a logfile. The common shell command script
can be used for this purpose:
script -c 'APT_SERVER=ftp.de.debian.org ./rpi23-gen-image.sh' ./build.log