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
2020-12-02 release.
The resultant Pi OS can be considered an alternative to OpenWrt for RPi boards. It is secured with nftables and dnscrypt-proxy.
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 fi
to your home country in /etc/hostapd/hostapd.conf
.
Unmount and take the sd card out.
Insert the card into sd card slot of RPi board and boot. Login password is Ra5pb3rry
.
Optional: It might be helpful to read the section Network Configuration Details.
Pi-router build is tested with Debian bullseye, buster, Ubuntu Focal Fossa, and Fedora 33.
To install the required dependencies for pi-router on Debian, bullseye, 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 libarchive-tools
.
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.
Upon execution, 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:
IMG_DATE
Date on which the image is built.
IMG_FILENAME
Combination of IMG_DATE
and IMG_NAME
(defined in router-config
).
ZIP_FILENAME (Default: unset)
IMG_FILENAME
prefixed with image_
.
RELEASE
(Default: buster
)
The release version to build image against. Valid values are jessie
, stretch
, buster
, bullseye
, and testing
.
Note that pi-router
is tested with buster
only.
APT_PROXY
(Default: unset)
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-cacher
or 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 build.sh
)
This is the top-level directory for pi-router
. It contains stage
directories, build scripts, and by default both work
and
deploy
directories. Changing this variable is not recommended.
SCRIPT_DIR
Directory containing helper scripts.
WORK_DIR
(Default: "$BASE_DIR/work"
)
Directory in which pi-router
builds 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_DIR
stores 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.
DEPLOY_DIR
(Default: "$BASE_DIR/deploy"
)
Output directory for target system image.
DEPLOY_ZIP
(Default: 1)
By default, the image is deployed only as a compressed zip archive.
LOG_FILE
(Default: "$WORK_DIR/build.log"
)
ENABLE_DEBUG
(Default: unset)
Sets the UART connectivity for debugging purposes
TARGET_HOSTNAME
(Default: rpirouter
)
FIRST_USER_NAME
(Default: pi
)
User name for the first user
FIRST_USER_PASS
(Default: Ra5pb3rry
)
Password for the first user.
WPA_ESSID
(Default: pisecrouter
)
WPA_PASSWORD
(Default: 3T01F24h15h~
)
WPA_COUNTRY
(Default: fi
)
This value should be changed with the corresponding two letters country code.
ENABLE_SSH
(Default: 1)
SSH
is enabled by default.
LOCALE_DEFAULT
(Default: English("US"))
KEYBOARD_MAP
(Default: us
)
KEYBOARD_LAYOUT
(Default: "English (US)")
TIMEZONE_DEFAULT
(Default: "Europe/Helsinki")
STAGE_LIST
(Default: stage*
)
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 pi-router
directory.
A minimal 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:
chroot
of the image build directory.debconf-set-selections
to configure things like locale, etc.00-packages
, except these will be installed using the --no-install-recommends -y
parameter to apt-get
.quilt
. If a file named EDIT
is present
in the directory, the build process will be interrupted with a bash session, allowing an opportunity to
create/revise the patches.If the stage
directory contains a file called EXPORT_IMAGE
then 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,
e.g.
$ 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 Debian
or Fedora
. It might be worth noting that Docker build can be used on Debian
or Fedora
as well. Running Docker build is as simple as issuing the command below:
$ ./build-docker.sh
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
Similar to build.sh
, 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:
PRESERVE_CONTAINER=1 ./build-docker.sh
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.
Pi-router
makes use of dnsmasq
, dhcpcd
, and 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 RPi
board.
Pi-router
does not handle the case of WAN side address supplied by a USB to RJ-45 dongle plugged into one of the four supports WAN side address supplied by an RJ-45 to USB 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 RPi
USB portsmak-dev
branch. In order to test, define (usually eth1
) WAN_INTERFACE
in router-config
and run the build
script. 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-client
service
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.