Pi-router is a tool used to generate a custom Raspberry Pi OS image that transforms an
RPi board into a secure router(strictly
speaking an access point). Pi-router is derived from pi-gen and is based on
Grab the binary package from here and unzip it.
$ unzip image_2021-06-29-pirouter.zip
Dump the image on an sd card.
$ sudo dd if=2021-06-29-pirouter.img of=/dev/mmcblk0 bs=4M status=progress conv=fdatasync
Mount the sd card and change the two letter country code from
fito your home country in
Unmount and take the sd card out.
Insert the card into sd card slot of RPi board and boot. Login password is
Optional: It might be helpful to read the section Network Configuration Details.
Pi-router build is tested with Debian buster, Ubuntu Focal Fossa, and Fedora 33.
To install the required dependencies for pi-router on Debian buster, run:
$ apt-get install coreutils quilt parted qemu-user-static debootstrap zerofree \ zip dosfstools bsdtar libcap2-bin grep rsync xz-utils file git curl bc
To achieve the same on Ubuntu Focal Fossa, replace the
bsdtar package with
Similarly, on Fedora 33, run:
$ dnf install coreutils quilt parted qemu-user-static debootstrap zerofree \ zip dosfstools bsdtar libcap grep rsync xz file git curl bc
Other distributions should work but not tested. Feel free to give
pi-router a spin on your favorite distro and let me
know the results.
build.sh will source the file
router-config in the current working directory. This bash shell fragment is
intended to set needed environment variables.
The following environment variables are supported:
Date on which the image is built.
ZIP_FILENAME (Default: unset)
The release version to build image against. Valid values are
testing. Note that
pi-routeris tested with
If you need to use apt proxy, set it here. The proxy setting will not be included in the image, making it safe to use an
apt-cacheror similar package for development.
If Docker is installed, it is possible to set up a local apt caching proxy to speed up subsequent builds like this:
$ docker-compose up -d $ echo 'APT_PROXY=http://172.17.0.1:3142' >> router-config
BASE_DIR(Default location of
This is the top-level directory for
pi-router. It contains
stagedirectories, build scripts, and by default both
deploydirectories. Changing this variable is not recommended.
Directory containing helper scripts.
Directory in which
pi-routerbuilds the target system. This value can be changed if a sufficiently large, fast, storage location is available for running build stages and caching purposes. It is important to note that
WORK_DIRstores a complete copy of the target system for each build stage and it can grow extremely rapidly. This will result in hogging the storage space quickly. If you are building frequently, periodic cleaning of this directory is recommended.
Output directory for target system image.
By default, the image is deployed only as a compressed zip archive.
Sets the UART connectivity for debugging purposes
User name for the first user
Password for the first user.
This value should be changed with the corresponding two letters country code.
SSHis enabled by default.
KEYBOARD_LAYOUT(Default: "English (US)")
If set, then instead of working through the numeric stages in order, this list will be followed. For example, setting to "stage0 stage1 mystage stage2" will run the contents of "mystage" before "stage2". Note the quotes, they are needed around the list. An absolute or relative path can be given for stages outside the
router-config file is included in the build and is the default for
build.sh.If needed, this file can be customized further.
The image is built with the following process:
Loop through all of the stage directories in alphanumeric order
Run the script prerun.sh which is generally just used to copy the build directory between stages. In each stage directory loop through each subdirectory and then run each of the install scripts it contains, again in alphanumeric order. These need to be named with a two digit padded number at the beginning. There are a number of different files and directories which can be used to control different parts of the build process:
- 00-run.sh- An executable unix shell script.
- 00-run-chroot.sh- An executable unix shell script that will run in the
chrootof the image build directory.
- 00-debconf- Contents of this file are passed to
debconf-set-selectionsto configure things like locale, etc.
- 00-packages- A list of packages to be installed.
- 00-packages-nr- As
00-packages, except these will be installed using the
--no-install-recommends -yparameter to
- 00-patches- A directory containing patch files to be applied, using
quilt. If a file named
EDITis present in the directory, the build process will be interrupted with a bash session, allowing an opportunity to create/revise the patches.
stagedirectory contains a file called
EXPORT_IMAGEthen add this stage to a list of images to generate. This is relevant for stage2 only as no image is exported for stage0 or stage1.
Generate the image for the stages with the above file; in this case, for stage2 only.
If the build process is interrupted, it is possible to start from the point of interruption by setting
$ CONTINUE=1 ./build.sh
Please refer to
build.sh for finer details.
Docker can be used to perform the build inside a container. This partially isolates the build from the host system, and allows using the script on distributions other than
Fedora. It might be worth noting that Docker build can be used on
Fedora as well. Running Docker build is as simple as issuing the command below:
If everything goes well, the final image will be in
deploy/ directory. The build container can be removed after the build with the command:
$ docker rm -v pirouter_work
build-docker.sh can be continued from where it left during an interruption:
$ CONTINUE=1 ./build-docker.sh
In case of a failure, the container can be examined by issuing the following command:
$ sudo docker run -it --privileged --volumes-from=pirouter_work pi-router /bin/bash
In case of successful build, the build container is by default removed. This can be changed by issuing the command:
The build process is divided up into several stages for logical clarity and modularity. This causes some initial complexity, but it simplifies maintenance and allows for more easy customization.
Stage 0 - bootstrap. The primary purpose of this stage is to create a usable filesystem. This is accomplished largely through the use of debootstrap, which creates a minimal filesystem suitable for use as a base.tgz on Debian systems. This stage also configures apt settings and installs raspberrypi-bootloader which is missed by debootstrap. The minimal core is installed but not configured, and the system will not quite boot yet.
Stage 1 - truly minimal system. This stage makes the system bootable by installing system files like
/etc/fstab, configures the bootloader, makes the network operable, and installs packages like raspi-config. At this stage the system should boot to a local console from which you have the means to perform basic tasks needed to configure and install the system. This is as minimal as a system can possibly get, and its arguably not really usable in a traditional sense yet. Still, if you want minimal, this is minimal and the rest you could reasonably do yourself as sysadmin.
Stage 2 - router system. This stage produces the router image. It installs some optimized memory functions, sets timezone and charmap defaults, installs fake-hwclock and ntp, wireless LAN and bluetooth support, dphys-swapfile, and other basics for managing the hardware. It also creates necessary groups and gives the pi user access to sudo and the standard console hardware permission groups.
All the customizations needed to transform
RPi into a secure router are done at this stage. Contrary to
pi-gen build stages,
pi-router does not need to go beyond this stage.
Network Configuration Details
Pi-router makes use of
hostapd, to transform the
RPi into a router. The default LAN side gateway ip address is
172.31.31.1/24 and the connected clients are assigned addresses in the range of
172.31.31.2-254. WAN side address is supplied by the RJ-45 connector on
does not handle the case of WAN side address supplied by a USB to RJ-45 dongle plugged into one of the foursupports WAN side address supplied by a USB to RJ-45 dongle with certain limitations. The support is limited to those ethernet to USB adapters whose drivers are built into the kernel and is available in
mak-devbranch. In order to test, define (usually
router-configand run the
buildscript. It is important to keep in mind that the support is of alpha quality.
DHCPv6 support is experimental. In case there is no valid global IPv6 address assigned to WAN interface,
dhcpv6-clientservice will fail.
Linux is able execute binaries from other architectures, meaning that it should be possible to make use of
pi-router on an
x86_64 system, even though it will be running ARM binaries. This requires support from the
binfmt_misc kernel module.
You may see the following error:
update-binfmts: warning: Could not load the binfmt_misc module.
To resolve this, make sure that
binfmt_misc module is loaded and
qemu-arm-static binary is available.
$ lsmod | grep binfmt_misc $ command -v qemu-arm-static
If you find this work useful, consider buying me a coffee.