Revised 2025-01-30
This post accompanies the YouTube videos below:
Full install, part 1
https://youtu.be/cL9l2uAFYck
Full install, part 2
https://youtu.be/gdVeDLidTnU
Minimal install, part1
https://youtu.be/x3zZ-nIP4mQ
Minimal install, part 2
https://youtu.be/22VgIrxkaI0
This is based on the GenPi64 (https://github.com/sakaki-/gentoo-on-rpi-64bit) project initially created and maintained by Sakaki and now continued to be maintained at https://github.com/GenPi64/gentoo-on-rpi-64bit . I would encourage you to take a look at these resources as well for some background information.
I am providing the already completed SD card image files which have all the below steps already completed. Feel free to download these already completed SD card images if the guide is giving you trouble or just would like to skip to the conclusion. These are the exact SD card images that were made in the video with the exception of two things (deleted SSH host keys and added a one time script to resize the root partition on next boot).
In order to create an SD card from these images the following command can be used. Be sure the SD card (and all partitions) are unmounted before proceeding and DOUBLE CHECK the of= command since everything on the destination will be DELETED. For the command following image.zst is the downloaded file and /target/device is the SD card. The command requires sudo (or root). The sum file is the sha512sum hash calculated with the command sha512sum to verify file integrity.
Full install, username demouser, password demouser
https://dev.drassal.net/genpi64/20250129_full.zst
https://dev.drassal.net/genpi64/20250129_full.zst.sum
Minimal install, username user, password user
https://dev.drassal.net/genpi64/20250129_minimal.zst
https://dev.drassal.net/genpi64/20250129_minimal.zst.sum
This is the command below to write those SD card images to an SD card.
zstdcat image.zst | sudo dd bs=1M iflag=fullblock of=/target/device status=progress
What I am presenting here is close to what the new maintainers of the GenPi64 project are doing but you can think of this as a slightly different fork of the original GenPi64 project by Sakaki. In the end the goals are very similar (install Linux Gentoo on a 64-bit Raspberry Pi) but through slightly different approaches.
The aim for this guide is to provide a simple easy to follow guide on installing Linux Gentoo on a Raspberry Pi. Why install Gentoo on a Raspberry Pi? Gentoo is (for the most part) a build from source flavor of Linux allowing a very customizable installation. With a few exceptions 99.9% of the software in a Linux Gentoo installation is built from source downloaded from the Gentoo repository. This sounds really complicated but once you get a grasp and become accustomed to Gentoo you may come to like it.
Personally I was introduced to Gentoo around the year 2010 and while not for everything I have used it for many things including my development workstation (full GUI install with the Mate, a fork from Gnome2) and Raspberry Pi based IoT projects. With Gentoo you have to option to install everything or nothing, and compile support in for everything or nothing. This includes the kernel as well, which I covered in a couple previous posts below.
Raspberry Pi 64-bit Linux kernel rebuild
https://www.drassal.net/wp/raspberry-pi-64-bit-linux-kernel-rebuild
Raspberry Pi 64-bit boot partition rebuild
https://www.drassal.net/wp/raspberry-pi-64-bit-boot-partition-rebuild
This is a guide to follow up on that work (and use the pieces built above, but slightly updated) to install a fully functional Linux Gentoo installation on a Raspberry Pi. This will work on any of the 64-bit capable Raspberry Pi boards however the best GUI experience will come from the Raspberry Pi 4 and 5. The Raspberry Pi 3B and 3B+ will also work but due to memory limitation might not provide a pleasant GUI experience. However, the minimal install (no GUI) works great on the 3B and 3B+ for IoT projects or headless (no monitor) applications.
First up the things you will need to follow along will be the following:
+ Computer or Raspberry Pi running Linux (most flavors like Raspberry Pi OS, Ubuntu, etc will work)
+ Raspberry Pi 5 recommended but 4 will be ok
+ Recommend getting highest RAM you can get but should be ok with 2GB
+ 99% of packages are binary prebuilds so memory for compiling is not a concern
* Good power USB-C Raspberry Pi power supply
+ not all power supplies are created equally
+ many hard to trace down crashes and strange behavior can be traced down to a bad power supply
+ the USB-C support on Raspberry Pi 4 is a little glitchy so get a recommended power supply
+ 5.1V 3.0A has worked for me, I also have a 5V 4A unit by Physical Computing Lab that works great
+ Case is not required but recommended to shield from accidental damage and static electricity issues
+ the official case with built in fan has been working great
+ while a heatsink and fan is not required (the CPU will clock down automatically) it is nice to have
+ USB micro SD card reader (or equivalent)
+ USB keyboard and mouse to connect to the Raspberry Pi
+ micro HDMI to HDMI cable to connect the Raspberry Pi to a display
+ SD card (16GB or larger recommended but 8GB should work)
+ not all SD cards are created equally
+ Personally I use and recommend the below SD card
+ SanDisk Extreme PRO microSDXC UHS-1 Card 64GB (up to 200MB/s read, 90MB/s write)
+ SanDisk model SDSQXCU-064G-GN6MA (UPC 6 19659 18857 3)
+ for less demanding non GUI projects I use the below (it is much slower)
+ SanDisk Ultra microSDHC UHS-1 Card 32GB (up to 100MB/s read)
+ model SDSQUNR-032G-GN3MN (UPC 6 19659 18438 4)
+ Wired ethernet connection with internet access
With the requirements out of the way let’s get down to getting the installation started. The full copy/paste script used for this process is available for download here:
Through a lot of this guide I use “vi” or “vim” to do file editing. Nano can be used too if that is easier. There are use differences between “vi” and “vim” namely how the arrow keys and backspace keys work in editing mode. It is preferable to install “vim” instead.
Basic commands for vim are the following. When a file is opened for editing you will be in command mode. Text editing mode is entered by pressing “i” on the keyboard. After this vim acts as a normal text editor with full functions to arrow keys and backspace. Pressing escape will exit editing mode. While in command mode, to exit with saving type this then press enter “:wq”. The “:” will start a command entry, then “w” means write, then “q” means quit. To quit (if nothing has been edited) can just do a “:q” and press enter. However, if there are unsaved changes there will be a warning and will need to override it by typing “:q!” and this will exit. Before you use “:wq” nothing has been saved to disk yet. Also “:w” can be used to just write (save) the current file without exiting. A new line can be created below the current line by (making sure you are in command mode by pressing ESC) then pressing “o” on the keyboard. An entire line can also be deleted by (making sure you are in command mode by pressing ESC) then typing “dd” on the keyboard. These are the commands I use most often. This is just a brief explanation on how to use vim but there are many detailed guides available.
Part 1 – SD card preparation
First, on the Linux computer insert the micro SD card into the USB adapter and insert it into the PC, or into the SD card slot if your PC is so equipped. Open up a terminal window then we will need to find out what device the SC card is. I don’t think it has to be said that everything on this SD card will be erased. This can be seen by a commands like the following:
ls /dev
mount
dmesg
And we are looking for something like /dev/sda /dev/sdb /dev/mmcblk0
Once we know that device, make sure it is the device we think it is (don’t want to mistake it as the next commands will rewrite the partition table and format it) by checking dmesg and look at the last few lines and it should give a little information about the SD card as well as the size.
Note, devices like /dev/sda1 and /dev/sdb2 refer to the partition on the device, we want the base device, not a partition on it. The below commands will happily write to a partition too but it won’t work correctly. Assuming our device is /dev/sdc let’s continue with the below commands.
First setup some environment variables to make our life easier, this is where we will set the SD card device, from here on out it will remember it. If you close the terminal window, or use another one, you will need to execute this again. Environment variables are only available to the current terminal session.
SDCARD=/dev/sdc
Now we want to make a working folder that will hold all the various files we are going to download and for this example we are going to use the folder genpi64 in the home folder. Create that folder and change to it below:
mkdir ~/genpi64
cd genpi64
Now that we are in the working folder download the following files that will be used during installation:
Note, these files are available from public repositories and original sources are noted below. I have tried to do a lot of the heavy lifting here by extracting the files from the original repositories and bundling them up to speed up installation. Of course you are free to extract the files yourself. The kernel would need to be built from source to extract the kernel and modules. These sources are freeze frames of the dates marked on the files.
#download stage3 tarball
wget https://dev.drassal.net/genpi64/stage3-arm64-openrc-splitusr-20250112T234833Z.tar.xz
wget https://dev.drassal.net/genpi64/stage3-arm64-openrc-splitusr-20250112T234833Z.tar.xz.DIGESTS
#original file https://distfiles.gentoo.org/releases/arm64/autobuilds
While not necessary we can verify the DIGEST (sha512 hash) to check integrity of the file:
#check sha512 hash
#the output of the two below lines *should* matchsha512sum "stage3-arm64-openrc-splitusr-20250112T234833Z.tar.xz" | cut -f 1 -d' '
sed -n '/SHA512 HASH/{n;p;}' "stage3-arm64-openrc-splitusr-20250112T234833Z.tar.xz.DIGESTS" | grep "stage3-arm64-openrc-splitusr-20250112T234833Z.tar.xz"'$' | tail -n 1 | cut -f 1 -d' '
Download other necessary files below
#download bootfs tarball
wget https://dev.drassal.net/genpi64/bootfs_20250128.tar.bz2
#original https://github.com/raspberrypi/firmware
#download kernel modules
wget https://dev.drassal.net/genpi64/rootfs_modules_20250128.tar.bz2
#original https://github.com/raspberrypi/linux
#download firmware-nonfree
wget https://dev.drassal.net/genpi64/rootfs_firmware-nonfree_20250128.tar.bz2
#original https://github.com/RPi-Distro/firmware-nonfree.git
#download firmware-bluez
wget https://dev.drassal.net/genpi64/rootfs_firmware-bluez_20250128.tar.bz2
#original https://github.com/RPi-Distro/bluez-firmware.git
#downlaod kernel sources
wget https://dev.drassal.net/genpi64/linux-6.6.74-raspberrypi_20250128.tar.bz2
#original https://github.com/raspberrypi/linux
After all the downloading we should have something similar to the following in our folder:
ls -l
-rw-r--r-- 1 user user 33389459 1月 29 22:14 bootfs_20250128.tar.bz2
-rw-r--r-- 1 user user 582929975 1月 29 22:16 linux-6.6.74-raspberrypi_20250128.tar.bz2
-rw-r--r-- 1 user user 157652 1月 29 22:15 rootfs_firmware-bluez_20250128.tar.bz2
-rw-r--r-- 1 user user 1514076 1月 29 22:15 rootfs_firmware-nonfree_20250128.tar.bz2
-rw-r--r-- 1 user user 39917774 1月 29 22:17 rootfs_modules_20250128.tar.bz2
-rw-r--r-- 1 user user 216210408 1月 22 14:08 stage3-arm64-openrc-splitusr-20250112T234833Z.tar.xz
-rw-r--r-- 1 user user 1351 1月 22 14:08 stage3-arm64-openrc-splitusr-20250112T234833Z.tar.xz.DIGESTS
Now we can get to preparing the SD card.
First let’s make sure it is not mounted, it is never wise to modify the partition table of a mounted filesystem, very bad things can happen. Unmount any possibly mounted partitions by using commands similar to the below. Since we setup the SDCARD environment variable above we can just use that.
sudo umount ${SDCARD}1
sudo umount ${SDCARD}2
Errors might occur if the filesystem is already unmounted (or does not exist) but that is no problem. Double check with the command “mount” to see currently mounted partitions and be sure the umount was successful.
Next is our first major change to the SD card filesystem, this will preeminently alter the filesystem on the SD card so be sure the device (ex. /dev/sdc) is correct! Since we setup the SDCARD environment variable above we can just use that. Alter the partition table with the following commands. This is all on a single line so copy/paste the entire chunk at once.
sudo parted --script ${SDCARD} \
mklabel msdos \
mkpart primary fat32 1MiB 512MiB \ \
mkpart primary ext4 512MiB \ 100% \
set 1 boot on \
set 1 lba on
Next we need to change the PARTUUID of the SD card (this is how the kernel will locate the root partition at boot time). We need to set it to a known value. There are other ways to do this but for now let’s just go with this. Execute the following chunk of code, copy/paste it all at once.
sudo fdisk "${SDCARD}" <<EOF &> /dev/null
p
x
i
0x6c586e13
r
p
w
EOF
The above commands could also be executed through the interface in fdisk but this single command is faster. The PARTUUID is of course 0x6c586e13. This will be important later.
Now time to format the partitions, in this example we will be using the btrfs filesystem (as opposed to the common ext4 filesystem. It was used on the original GenPi64 project. If you would like to use ext4 then alter the below command, but a few other changes will be necessary as well. For now let’s just go with btrfs.
#format the partitions
sudo mkfs.vfat -F 32 -n bootfs ${SDCARD}1
sudo mkfs.btrfs ${SDCARD}2 -L rootfs -f
Now we will create a couple folders to serve as mount points for the SD card.
#create mount points
mkdir -p bootfs
mkdir -p rootfs
Now we can mount the SD card to these above created mount points. At this point the SD card is now mounted (it will not show up as ejectable in the GUI and might even disappear) but we can verify it is mounted with the “mount” command. Also, it is a bad idea to physically remove the SD card now as it will now be mounted. Serious filesystem corruption could result.
#mount the partitions
sudo mount -o,rw,nosuid,nodev,relatime,uid=0,gid=0 ${SDCARD}1 bootfs
sudo mount -o,noatime,compress=zstd:15,ssd,discard,x-systemd.growfs ${SDCARD}2 rootfs
Now comes to populating the SD card with the necessary files. First populate the already prepared boot partition. This partition can be built from scratch as well but it is a rather time consuming process to gather all the files, but it is covered in a previous post here:
Raspberry Pi 64-bit boot partition rebuild
https://www.drassal.net/wp/raspberry-pi-64-bit-boot-partition-rebuild/
#copy the boot files
sudo tar xjfp bootfs_20250128.tar.bz2 -C bootfs
Extract the stage3 tarball into the SD card. We are pretty much building the root filesystem from scratch (from a stage3 tarball as many say).
#copy in the stage3 tarball
#extract to the sdcard (Raspberry64)
sudo tar xfp stage3-arm64-openrc-splitusr-20250112T234833Z.tar.xz -C rootfs
Next is to copy over the kernel modules. These are essentially device drivers that are not specifically built into the kernel and many things (like WiFi, sound, video) will not work properly without them.
#extract the current kernel modules to the sdcard
sudo mkdir -p rootfs/lib/modules
sudo tar xpjf rootfs_modules_20250128.tar.bz2 -C rootfs/lib/modules/.
Now we will copy over the device driver firmware. Many devices these says don’t come with the firmware (software that runs inside the hardware) programmed in, it is supplied as the driver is loaded. These are the firmware blobs required for various Raspberry Pi hardware.
#extract the nonfree firmware to the sdcard
sudo mkdir -p rootfs/lib/firmware
sudo tar xpjf rootfs_firmware-nonfree_20250128.tar.bz2 -C rootfs/lib/firmware/.
Then we have some firmware specific to the BlueTooth hardware.
#extract the nonfree firmware to the sdcard
sudo mkdir -p rootfs/lib/firmware
sudo tar xpjf rootfs_firmware-bluez_20250128.tar.bz2 -C rootfs/lib/firmware/.
Finally let’s copy in the kernel sources. This is not specifically required but will assist with installing software. It is common for software installed on a Gentoo system to verify the kernel version during installation (to see how the kernel is configured for optimal settings). This is a slightly large chunk of files so might take a minute to copy over.
#extract the kernel source to the rootfs
sudo mkdir -p rootfs/usr/src/linux-6.6.74-raspberrypi_20250128
sudo tar xpjf linux-6.6.74-raspberrypi_20250128.tar.bz2 -C rootfs/usr/src/linux-6.6.74-raspberrypi_20250128/.
Next we need to set a symbolic link to these kernel sources so the system can locate them. The common place kernel sources are searched for is /usr/src/linux . While we could just drop the files there it is common to drop the files in their own folder to allow multiple kernel sources to be present and create a symbolic link to the version currently in use.
#create the symbolic link to linux sources
cd rootfs/usr/src
ls -l
sudo ln -s linux-6.6.74-raspberrypi_20250128 linux
ls -l
cd ../../..
Now we need to setup a root password so we can actually login in to the new installation after it is started up. This can be accomplished by adding the hash for a new password to the /etc/shadow file. We will generate the hash below with the following commands. Setting the variable ROOT_PASSWORD to a desired password. For this guide we will just leave it as “root” but will be disabling the root account (erasing the password hash) at the end of installation. Execute the below commands to get a hash output.
#set the root password
#the below lines will set it auto-magically
#change the ROOT_PASSWORD variable to change it
ROOT_PASSWORD="root"
ROOT_PASSWORD_SALT=$(openssl rand -base64 12)
ROOT_PASSWORD_HASHED=$(openssl passwd -6 -salt "${ROOT_PASSWORD_SALT}" "${ROOT_PASSWORD}")
echo "password hash = ${ROOT_PASSWORD_HASHED}"
Next we will edit the /etc/shadow file to set the password. There are two ways to go about this, one way programmatically editing it and it will be automagically set, or we can edit the file ourself.
For the automagic method execute the following command:
#to automatically do a search replace
USER="root"
sudo sed -Ei 's/^('"${USER}"':)([^:]+)(..+)$/\1'${ROOT_PASSWORD_HASHED//\//\\/}'\3/g' rootfs/etc/shadow
If desired to manually edit the file, open the file up in your favorite editor (vim will be used here) and edit it. Root permissions will be required to write (and even read) the file. We will replace the “*” on the “root” line with the hash printed out above. The hash will look this (for the password “root”).
$6$LgsV7MZIY4lRScdT$B8jsNQXovzUitTPQUiOIPAnGgetQn2kJnWNbNa/CF27yiTom54WCHriMiWKy1f/ij8sDjEgi7Qif7dGrbeA3e1
Therefore our complete line will look like this…
root:$6$LgsV7MZIY4lRScdT$B8jsNQXovzUitTPQUiOIPAnGgetQn2kJnWNbNa/CF27yiTom54WCHriMiWKy1f/ij8sDjEgi7Qif7dGrbeA3e1:10770:0:::::
And to do the editing in vim execute the following.
#to do it by hand
sudo vi rootfs/etc/shadow
Now we have a few small details like the keyboard layout (change if needed). In my case I change it to “jp106” to account for the keyboard I am typing on. This will only affect the keyboard physically connected to the Raspberry Pi (not the SSH session).
#fix keyboard layout
#keyboard list available from
ls -l rootfs/usr/share/keymaps/i386/qwerty
#check sub directories in rootfs/usr/share/keymaps/i386 for other desired layouts
ls -l rootfs/usr/share/keymaps/i386
#set the desired keyboard map
sudo vi rootfs/etc/conf.d/keymaps
KEYMAP="us"
Next we will want access to the internet as the installation process will download sources (and binary packages) from a remote server. To accomplish this create a symbolic link to the network adapter. This is common Linux practice for OpenRC based Linux installations. However, after install is completed (for the full install) we will switch over to NetworkManager.
#add symbolic link for ethernet adapater net.eth0
cd rootfs/etc/init.d
sudo ln -s net.lo net.end0
ls -l
cd ../../..
Then set the hostname for the Raspberry Pi. For this guide we will just call it “pi64” but feel free to customize it.
#setup hostname to pi64
sudo sh -c "echo 'pi64' > rootfs/etc/hostname"
Now comes to setting up where the portage tree will be downloaded from. The portage tree is basically a catalogue of all the software available install automatically through the package manager “emerge” which is similar to “apt-get” used in Ubuntu or “yum” used in CentOS (now Rocky).
A Gentoo system can have multiple portage trees to allow installation of software from various sources. In our installation we will use the mainline “gentoo” repository but also add one called “genpi64” which is the custom overlay offering a custom profile and some additional software from the GenPi64 project.
Another important note is that we are not going to point to the official repository and the reason being that the official repository is always in a state of change with packages always being updated. For the GenPi64 project I have cached a local copy of the gentoo repository and working off that. It is possible a package upgrade may break this guide and in order to prevent those kinds of issues from arising we are using a frozen (on 2025-01-15) version of the official portage tree.
If desired the Raspberry Pi can be switched back over after installation is done and updated to the bleeding edge, but the time consuming process rebuilding packages from source will most likely be required.
While I have made the frozen cache of the portage tree available I do not have the hard disk space on the server to cache the entire sources repository so that will unfortunately not be available, however, prebuilt binary packages are.
To add these portage trees we need to create and add the following data to the files below.
#setup the local portage tree
sudo mkdir -p rootfs/etc/portage/repos.conf
sudo vi rootfs/etc/portage/repos.conf/gentoo.conf
Add the below text to that file and save:
[DEFAULT]
main-repo = gentoo
[gentoo]
location = /var/db/repos/gentoo
sync-type = rsync
sync-uri = rsync://dev.drassal.net/gentoo-portage_20250115
auto-sync = yes
sync-rsync-verify-jobs = 1
sync-rsync-verify-metamanifest = yes
sync-rsync-verify-max-age = 24
sync-openpgp-key-path = /usr/share/openpgp-keys/gentoo-release.asc
sync-openpgp-key-refresh-retry-count = 40
sync-openpgp-key-refresh-retry-overall-timeout = 1200
sync-openpgp-key-refresh-retry-delay-exp-base = 2
sync-openpgp-key-refresh-retry-delay-max = 60
sync-openpgp-key-refresh-retry-delay-mult = 4
Next the genpi64 portage tree:
##setup the local portage tree
sudo mkdir -p rootfs/etc/portage/repos.conf
sudo vi rootfs/etc/portage/repos.conf/genpi64.conf
Add the below text to that file and save:
[DEFAULT]
main-repo = gentoo
[genpi64]
# Overlay for 64-bit Gentoo on the RPi3 and RPi4 SBCs
# Maintainer: sakaki (sakaki@deciban.com)
location = /var/db/repos/genpi64
sync-type = rsync
sync-uri = rsync://dev.drassal.net/genpi64-portage_20250115
priority = 100
auto-sync = yes
Next we need to add some options to the make.conf file. This file controls global options when installing software and we need to make some changes for the Raspberry Pi. Open up and paste the following to the bottom of the current file.
#add the following to the portage make.conf file
sudo vi rootfs/etc/portage/make.conf
Paste the below text to the bottom of the file then save:
# global USE flag overrides
USE=""
# override default build parallelism by changing the following
# two lines, and modifying the values as required
# Pi3 users (or Pi4 users with a 1GiB variant) should be
# less aggressive here
MAKEOPTS="-j5 -l4"
EMERGE_DEFAULT_OPTS="--jobs=5 --load-average=4"
# caution! many parallel threads and / or emerge jobs may cause your
# RPi3/4 to run out of memory during large builds, or genup runs
# per https://wiki.gentoo.org/wiki/Raspberry_Pi_VC4
VIDEO_CARDS="fbdev vc4 v3d"
INPUT_DEVICES="evdev synaptics"
# uncomment to build binary packages as a byproduct of each emerge
FEATURES="${FEATURES} buildpkg"
# uncomment to use binary packages from PORTAGE_BINHOST, where available,
# (and build normally, where not)
FEATURES="${FEATURES} getbinpkg"
PORTAGE_BINHOST="https://dev.drassal.net/genpi64/pi64pie_20250115_binpkgs"
# set gentoo sources mirror
GENTOO_MIRRORS="https://mirrors.evowise.com/gentoo/ https://mirrors.lug.mtu.edu/gentoo/ http://distfiles.gentoo.org"
PKGDIR=/var/cache/binpkgs
DISTDIR=/var/cache/distfiles
PYTHON_TARGETS="python3_11 python3_12 python3_13"
Now we need to setup some additional things such as ssh so we can log into the Raspberry Pi from our other PC to continue setup. While not absolutely required it is much easier to copy/paste into an ssh session than typing everything. There will not be a GUI on the Raspberry Pi until we install it.
We need to allow the root user to be able to login using ssh, disabled by default:
#allow root to login with ssh
sudo vi rootfs/etc/ssh/sshd_config
Change the below line
#PermitRootLogin prohibit-password
to this then save the file:
PermitRootLogin yes
Don’t worry, we will disable root ssh login before we are done, but it helps us easily finish the installation.
Then we are going to fix an annoying issue with the Raspberry Pi, the annoying f0 respawn error that appears on the console:
#fix annoying f0 respawn error
#this is specific to raspberry pi
sudo vi rootfs/etc/inittab
comment out the below line (near the bottom of the file)
f0:12345:respawn:/sbin/agetty 9600 ttyAMA0 vt100
change to look like below
#f0:12345:respawn:/sbin/agetty 9600 ttyAMA0 vt100
Now edit fstab to mount the boot partition (not required but makes things easier later)
*** fixup fstab to mount the bootfs
sudo vi rootfs/etc/fstab
Add the following line at the bottom of the file. Remember when I said the PARTUUID would be important later? This is one of the two places it is important.
PARTUUID=6c586e13-01 /boot vfat defaults,auto,noatime,umask=0022,uid=0,gid=100 0 0
Now the other important part is the cmdline.txt file. This is where we tell the kernel where to find (and mount) the root filesystem. If this is wrong the Raspberry Pi will kernel panic and not boot.
#change cmdline.txt to point to the correct root partition
#change rootdelay to zero (only needed for external spinning hard disk)
sudo vi bootfs/cmdline.txt
Change that single line of text to the following. There should be no extra lines or spaces in the file, only exactly what is below. The PARTUUID also needs to be correct as stated above.
console=serial0,115200 console=tty1 dwc_otg.lpm_enable=0 root=PARTUUID=6c586e13-02 rootfstype=btrfs rootdelay=0 fsck.repair=yes rootwait
This wraps up the initial SD card creation and it is now ready for the Raspberry Pi, but we are not done yet. What we have done above just sets it up for booting, but we only minimal software installed now (from the stage3 tarball) and need to emerge the system (as it is commonly said).
Unmount the partitions then insert the SD card in the Raspberry Pi and turn it on (making sure the monitor and network cable is connected). It should run through a normal looking Linux startup and end with a login prompt. Check to see what address the Raspberry Pi was assigned also, we will need that to login in to the Raspberry Pi with an ssh session. If you connect the monitor after starting up the Raspberry Pi you may not get any video as the Raspberry Pi does a display detection at startup. Be sure the monitor is plugged in and turned on before powering up the Raspberry Pi.
Unmount the partitions then delete the folders we used as mount points:
sudo umount ${SDCARD}1
sudo umount ${SDCARD}2
rmdir bootfs
rmdir rootfs
Now on our other PC ssh into the Raspberry Pi as the user “root” and we will continue the remaining setup steps. The next steps will depend a little on if you want a minimal setup or a full (with GUI) setup. Follow the appropriate part 2 section below. The full GUI installation will include Xorg and applications such as Firefox and LibreOffice. The minimal installation will not include a GUI and very minimal applications (for IoT or monitor-less installations). Skip to the appropriate section.
Part 2 (full installation)
This is part 2 that will install a full GUI (Xorg and Xfce) along with useful applications like Firefox and LibreOffice. If you are looking for a more minimal installation without a GUI then scroll down to the part 2 (minimal installation) section.
After the Raspberry Pi is started up we need to start the ethernet (so it gets an IP address) and startup ssh (so we can ssh into it). The username will be “root” with a password of “root” if setup that way previously. Login to the Raspberry Pi then execute the following two commands:
/etc/init.d/net.end0 start
/etc/init.d/sshd start
ssh root@192.168.3.104
Setup ssh to startup automatically. We won’t setup net.end0 to startup automatically as this will be handled by NetworkManager soon.
rc-udpate add sshd default
Next setup the clock. The Raspberry Pi 5 has an internal RTC but requires a battery to be connected. To be consistent (as Raspberry 3B, 3B+, and 4 don’t include an RTC) we will ignore the RTC and use the software clock. This sets the clock based on last shutdown time. But we will also install ntp to retrieve and update the clock from an internet time source. If later on the hardware RTC will be it can always be setup later.
For now disable hwclock and enable swclock.
#setup the swclock
rc-update del hwclock boot
rc-update add swclock boot
#stop hwclock and start swclock
#will need to set date time again
/etc/init.d/hwclock stop
/etc/init.d/swclock start
We should set the timezone to our current location to make it easier to set the clock. This is required for HTTPS communications. In my case I am in JST timezone so I set it as follows. Timezones can also be seen in the /usr/share/zoneinfo folder and subfolders.
#set timezone first if desired to assist with setting datetime correctly
#available timezones can be seen here
ls -l /usr/share/zoneinfo
ls -l /usr/share/zoneinfo/US
cd /etc
ln -sf /usr/share/zoneinfo/Japan localtime
cd
For these new settings to take effect we need to reload our profile.
#reload profile to get new timezone settings
env-update && source /etc/profile
Set the current date time using the below command (we will install ntp later to get it from the internet but right now ntp is not yet installed).
#set datetime
#To set the system clock, e.g. 23:54, January 29, 2025:
#emerges will fail if date is set wrong
date 012923542025
Now restart swclock to save the date time for next reboot.
#restart swclock to save new datetime
/etc/init.d/swclock restart
Now we get to the real installation here and downloading/installing all the packages. First we need to retrieve the portage tree(s) which can be done with the below command, this will take a minute to complete.
emerge --sync
Now we need to set the profile and we will set it to the GenPi64 profile. The profile has a large role in deciding what packages are installed and how the system is setup. Choosing something other than GenPi64 will drastically complicate the installation. I have spent a lot of time setting various USE flags and ACCEPT KEYWORDS in the GenPi64 profile to take a lot of the difficulties out of the installation process. Also note that the GenPi64 profile here is different from the original GenPi64 and the current GenPi64 project profile.
#check available profiles if desired
eselect profile list
#set the profile
#must use this one to get everything installed correctly
eselect profile set genpi64:default/linux/arm64/23.0/split-usr/desktop/genpi64
Set configuration for the rpi-64bit-meta package by editing the below file using nano (the only text editor on the Raspberry Pi now).
#copy the package.use file in
#this is required to set the meta package dev-embedded/rpi-64bit-meta options
#the selected options will result in a full emerge with Xorg and all applications
nano /etc/portage/package.use/rpi-64bit-meta
Paste the below contents into the file then press Ctrl + x to save and exit. Press enter when prompted for the filename (it will not change).
# Enable/disable any metapackage USE flags you want here, and then
# re-emerge dev-embedded/rpi-64bit-meta to have the effect taken up
# e.g. you might set (uncommented):
#
# dev-embedded/rpi-64bit-meta -weekly-genup
#
# to disable the automated weekly genup (package update)
# run.
#
# Unless you override them, the default metapackage flags are used.
# At the time of writing, those are (default flag status shown as + or -):
#
# + boot-fw : pull in the /boot firmware, configs and bootloader
# + kernel-bin : pull in the binary kernel package
# - porthash : pull in repo signature checker, for isshoni.org rsync
# + weekly-genup: pull in cron.weekly script, to run genup automatically
# + innercore: pull in essential system packages for image (RPi initscripts etc.)
# + core: pull in main packages for image (clang etc.) (requires innercore)
# + xfce: pull in packages for baseline Xfce4 system (requires core)
# - pitop: pull in Pi-Top support packages (NB most users will NOT want this;
# the Pi-Top is a DIY laptop kit based around the RPi3) (requires xfce)
# - apps: pull in baseline desktop apps (libreoffice etc.) (requires xfce)
#
# NB the main point of the core, xfce, pitop and apps USE flags is just to let
# you reduce what is in your @world set (/var/lib/portage/world).
dev-embedded/rpi-64bit-meta apps -weekly-genup
We need to accept a license agreement for a font that will be installed and that can be done using the below command. Failure to do so will cause an emerge failure requesting acceptance of the license agreement.
#the following license keywords need to be added
mkdir -p /etc/portage/package.license
cd /etc/portage/package.license
echo "media-fonts/ipamonafont grass-ipafonts" > ipamonafont
cd
We are now ready to emerge (install) the system. The next command will take some time to complete and can be left unattended while the packages are being installed. There should be no errors encountered and every package (except the final meta package) should be binary installs (no compiling). The below command will calculate dependencies and should create a list of 731 packages to install. Confirm with a “y” and enter then the installation can be left unattended until complete. This may take about an hour or so to complete depending on SD card speed, internet speed, and other factors.
emerge --ask -j5 --keep-going rpi-64bit-meta
When the installation is done the prompt will return and we will need to run etc-update to update one configuration file (/etc/portage/package.use/rpi-64bit-meta). We do this by executing etc-update then choosing “1” pressing “q” to exit the file viewer then pressing “2” to discard changes and confirm with “y”.
etc-update
1) /etc/portage/package.use/rpi-64bit-meta (1)
*** q to exit the file display
2) Delete update, keeping original as is
All packages are installed but we have a little more important configuration to finish up before we are done.
Set vim as the default editor (or if you prefer nano can set instead).
#set vim as default editor
eselect editor list
eselect editor set "vim"
env-update && source /etc/profile
Finally we will emerge ntp to automatically set the clock from an internet time source. Run the below command and type “y” and press enter to install ntp.
#emerge ntp
emerge -j5 --ask net-misc/ntp
Now let’s retrieve the current time from an internet time source and set the local clock. We will execute it explicitly so the clock is synced immediately. If we just run it in the background it may take some time to sync. If nptd is running in the background it must be stopped first.
#ensure nptd is stopped
/etc/init.d/ntpd start
#update the system clock with nptd
ntpd -gq
Enable npt to startup automatically and also start it now.
#start nptd
/etc/init.d/ntpd start
#add ntpd to autostart
rc-update add ntpd default
Next we need to enable sudo (or password-less sudo in the case of this guide) by executing “visudo” and editing it. This will depend on whether vim or nano is the default editor, but either way edit this below line:
#enable passwordless sudo
visudo
Look for this line:
## Same thing without a password
# %wheel ALL=(ALL) NOPASSWD: ALL
Change it to the following then save the file:
## Same thing without a password
%wheel ALL=(ALL) NOPASSWD: ALL
Create the user account and set the password. In the case of this guide we will call the user “demouser” and set the password to “demouser” which can be changed anytime.
#create user account
useradd demouser
passwd demouser
Add this new user to the “wheel” group so it can use sudo.
#add user to wheel group (for sudo)
usermod -aG wheel demouser
Now we will disable the root login, this can be done many ways but the method in this guide just replaces the password hash with an asterisk “*”.
sudo vi /etc/shadow
Look for the like for root and change it to the following (removing the password hash). Save the file.
root:*:10770:0:::::
Next need to add a few necessities to start automatically (this is for the GUI):
#add display-manager (and other necessities) to the default run level
rc-update add dbus default
rc-update add NetworkManager default
rc-update add display-manager default
Next setup the display manager which provides the login screen. Need to tell the system which display manager to use (there are many available) and in the case of this guide we are using lightdm. Edit the following file and change DISPLAY_MANAGER to lightdm.
#set lightdm to the default display manager
vi /etc/conf.d/display-manager
Change the DISPLAY_MANAGER line as follows then save the file.
DISPLAY_MANAGER="lightdm"
The next step is somewhat optional but I like to do it. The display manager, by default, will show the last logged in user’s wallpaper as the background. I personally don’t like this so I disable it by editing file “vi /etc/lightdm/lightdm-gtk-greeter.conf” and adding the “user-background# setting to the bottom of the file as follows:
#disable display of the user's personal wallpaper
#add the following to the greeter settings file
vi /etc/lightdm/lightdm-gtk-greeter.conf
This is what the top block of code looks like after the edit.
user-background=false
This next setting I never got to function correctly but will add it here for consistancy and that is setting the default Xsession (the GUI that will load after logging in to the display manager (lightdm).
#Most display managers can automatically start the Xfce session by adding XSESSION="Xfce4" to /etc/env.d/90xsession:
#Otherwise, it will read the value of the XSESSION variable from the /etc/env.d/90xsession file and execute the relevant session accordingly.
#Values for XSESSION are available in /etc/X11/Sessions/. To set a system wide default session run:
echo XSESSION="Xfce4" > /etc/env.d/90xsession
env-update && source /etc/profile
Then next (since I can’t get it to work, and to avoid having a black Xsession that loads nothing after logging in) we just remove Xsession completely. Again, I am not sure why I could not get this working but just going with it for the sake of this guide.
#remove XSession entry for the display manager
#this will cause it to default to xfce
#maybe if the above 90xsession worked correctly we could leave it
rm /usr/share/xsessions/Xsession.desktop
Next to fix something that I think is an issue with the settings in Xfce we will edit the below file. If the default icons are changed in the settings then the default can’t be changed back since it is hidden. This appears to be a disagreement topic among developers of what should be done but let’s just change it on our system for now.
#fix an issue with xfce
#fix an option to show the "Icons" under "Appearance" correctly for selection
vi /usr/share/icons/Adwaita/index.theme
Change this line
Hidden=true
to the following, and the top block should look close to this. Save the file.
Hidden=false
Finally we have two settings for Xorg (the GUI system) that are rather important. The first is the keyboard layout (this is different from the console) and the display driver settings. By default the keyboard layout should match the system but I have seen issues with this so I manually set this. These config files do not exist so we will create them as we edit them. Only do this if it is necessary to change the keyboard layout. The following is an example of a “jp106” keyboard layout.
#fix keyboard layout in Xorg
#change the layout to a desired value
#only need to create this file to alter the keyboard layout
#example provided for a jp106 keyboard layout
#add the below file with the below contents
mkdir -p /etc/X11/xorg.conf.d
vi /etc/X11/xorg.conf.d/99-keyboard-layout.conf
Copy paste the below contents into the file then save it. Feel free to edit this to match your keyboard layout.
Section "InputClass"
Identifier "system-keyboard"
MatchIsKeyboard "on"
Option "XkbLayout" "jp,us"
Option "XkbModel" "jp106"
Option "XkbOptions" "grp:alt_shift_toggle"
EndSection
Now onto the display settings, this should work automatically but for some reason does not on the Raspberry Pi. Usually this is not required.
#setup video in Xorg
#raspberry pi requirement
mkdir -p /etc/X11/xorg.conf.d
vi /etc/X11/xorg.conf.d/99-video.conf
Copy paste the below contents into the file then save it.
Section "OutputClass"
Identifier "vc4"
MatchDriver "vc4"
Driver "modesetting"
Option "PrimaryGPU" "true"
Option "Accel" "true"
Option "RenderAccel" "true"
Option "HWCursor" "true"
Option "AddARGBGLXVisuals" "true"
Option "TripleBuffer" "true"
Option "DPI" "144"
Option "IndirectMemoryAccess" "true"
Option "UseSysmemPixmapAccel" "true"
EndSection
Section "Device"
Identifier "kms"
Driver "modesetting"
Option "AccelMethod" "msdri3"
Option "UseGammaLUT" "off"
EndSection
This about wraps it up, finally. The only thing left is to restart the Raspberry Pi and hope everything comes up correctly. At this point your wired internet can also be disconnected (after restart) and WiFi settings can be inputted after logging in (on the Raspberry Pi keyboard).
#restart to check if the display manager starts correctly
shutdown -r now
Part 2 (minimal installation)
After the Raspberry Pi is started up, and we know the IP address ssh into it, the next commands will take place in that ssh terminal window. Password will be as was set above.
After the Raspberry Pi is started up we need to start the ethernet (so it gets an IP address) and startup ssh (so we can ssh into it). The username will be “root” with a password of “root” if setup that way previously. Login to the Raspberry Pi then execute the following two commands:
/etc/init.d/net.end0 start
/etc/init.d/sshd start
ssh root@192.168.3.104
Setup ssh to startup automatically. We will also add net.end0 to startup automatically.
rc-udpate add sshd default
rc-update add net.end0 default
Next setup the clock. The Raspberry Pi 5 has an internal RTC but requires a battery to be connected. To be consistent (as Raspberry 3B, 3B+, and 4 don’t include an RTC) we will ignore the RTC and use the software clock. This sets the clock based on last shutdown time. But we will also install ntp to retrieve and update the clock from an internet time source. If later on the hardware RTC will be it can always be setup later.
For now disable hwclock and enable swclock.
#setup the swclock
rc-update del hwclock boot
rc-update add swclock boot
#stop hwclock and start swclock
#will need to set date time again
/etc/init.d/hwclock stop
/etc/init.d/swclock start
We should set the timezone to our current location to make it easier to set the clock. This is required for HTTPS communications. In my case I am in JST timezone so I set it as follows. Timezones can also be seen in the /usr/share/zoneinfo folder and subfolders.
#set timezone first if desired to assist with setting datetime correctly
#available timezones can be seen here
ls -l /usr/share/zoneinfo
ls -l /usr/share/zoneinfo/US
cd /etc
ln -sf /usr/share/zoneinfo/Japan localtime
cd
For these new settings to take effect we need to reload our profile.
#reload profile to get new timezone settings
env-update && source /etc/profile
Set the current date time using the below command (we will install ntp later to get it from the internet but right now ntp is not yet installed).
#set datetime
#To set the system clock, e.g. 23:54, January 29, 2025:
#emerges will fail if date is set wrong
date 012923542025
Now restart swclock to save the date time for next reboot.
#restart swclock to save new datetime
/etc/init.d/swclock restart
Now we get to the real installation here and downloading/installing all the packages. First we need to retrieve the portage tree(s) which can be done with the below command, this will take a minute to complete.
emerge --sync
Now we need to set the profile and we will set it to the GenPi64 profile. The profile has a large role in deciding what packages are installed and how the system is setup. Choosing something other than GenPi64 will drastically complicate the installation. I have spent a lot of time setting various USE flags and ACCEPT KEYWORDS in the GenPi64 profile to take a lot of the difficulties out of the installation process. Also note that the GenPi64 profile here is different from the original GenPi64 and the current GenPi64 project profile.
#check available profiles if desired
eselect profile list
#set the profile
#must use this one to get everything installed correctly
eselect profile set genpi64:default/linux/arm64/23.0/split-usr/desktop/genpi64
Set configuration for the rpi-64bit-meta package by editing the below file using nano (the only text editor on the Raspberry Pi now).
#copy the package.use file in
#this is required to set the meta package dev-embedded/rpi-64bit-meta options
#the selected options will result in a full emerge with Xorg and all applications
nano /etc/portage/package.use/rpi-64bit-meta
Paste the below contents into the file then press Ctrl + x to save and exit. Press enter when prompted for the filename (it will not change).
# Enable/disable any metapackage USE flags you want here, and then
# re-emerge dev-embedded/rpi-64bit-meta to have the effect taken up
# e.g. you might set (uncommented):
#
# dev-embedded/rpi-64bit-meta -weekly-genup
#
# to disable the automated weekly genup (package update)
# run.
#
# Unless you override them, the default metapackage flags are used.
# At the time of writing, those are (default flag status shown as + or -):
#
# + boot-fw : pull in the /boot firmware, configs and bootloader
# + kernel-bin : pull in the binary kernel package
# - porthash : pull in repo signature checker, for isshoni.org rsync
# + weekly-genup: pull in cron.weekly script, to run genup automatically
# + innercore: pull in essential system packages for image (RPi initscripts etc.)
# + core: pull in main packages for image (clang etc.) (requires innercore)
# + xfce: pull in packages for baseline Xfce4 system (requires core)
# - pitop: pull in Pi-Top support packages (NB most users will NOT want this;
# the Pi-Top is a DIY laptop kit based around the RPi3) (requires xfce)
# - apps: pull in baseline desktop apps (libreoffice etc.) (requires xfce)
#
# NB the main point of the core, xfce, pitop and apps USE flags is just to let
# you reduce what is in your @world set (/var/lib/portage/world).
dev-embedded/rpi-64bit-meta -apps -xfce -core -pulseaudio -weekly-genup
We need to accept a license agreement for a font that will be installed and that can be done using the below command. Failure to do so will cause an emerge failure requesting acceptance of the license agreement.
#the following license keywords need to be added
mkdir -p /etc/portage/package.license
cd /etc/portage/package.license
echo "media-fonts/ipamonafont grass-ipafonts" > ipamonafont
cd
We are now ready to emerge (install) the system. The next command will take some time to complete and can be left unattended while the packages are being installed. There should be no errors encountered and every package (except the final meta package) should be binary installs (no compiling). The below command will calculate dependencies and should create a list of 223 packages to install. Confirm with a “y” and enter then the installation can be left unattended until complete. This may take about a half hour or so to complete depending on SD card speed, internet speed, and other factors.
emerge --ask -j5 --keep-going rpi-64bit-meta
When the installation is done the prompt will return and we will need to run etc-update to update one configuration file (/etc/portage/package.use/rpi-64bit-meta). We do this by executing etc-update then choosing “1” pressing “q” to exit the file viewer then pressing “2” to discard changes and confirm with “y”.
etc-update
1) /etc/portage/package.use/rpi-64bit-meta (1)
*** q to exit the file display
2) Delete update, keeping original as is
All packages are installed but we have a little more important configuration to finish up before we are done.
Set vim as the default editor (or if you prefer nano can set instead).
#set vim as default editor
eselect editor list
eselect editor set "vim"
env-update && source /etc/profile
Finally we will emerge ntp to automatically set the clock from an internet time source. Run the below command and type “y” and press enter to install ntp.
#emerge ntp
emerge -j5 --ask net-misc/ntp
Now let’s retrieve the current time from an internet time source and set the local clock. We will execute it explicitly so the clock is synced immediately. If we just run it in the background it may take some time to sync. If nptd is running in the background it must be stopped first.
#ensure nptd is stopped
/etc/init.d/ntpd start
#update the system clock with nptd
ntpd -gq
Enable npt to startup automatically and also start it now.
#start nptd
/etc/init.d/ntpd start
#add ntpd to autostart
rc-update add ntpd default
Next we need to enable sudo (or password-less sudo in the case of this guide) by executing “visudo” and editing it. This will depend on whether vim or nano is the default editor, but either way edit this below line:
#enable passwordless sudo
visudo
Look for this line:
## Same thing without a password
# %wheel ALL=(ALL) NOPASSWD: ALL
Change it to the following then save the file:
## Same thing without a password
%wheel ALL=(ALL) NOPASSWD: ALL
Create the user account and set the password. In the case of this guide we will call the user “demouser” and set the password to “demouser” which can be changed anytime.
#create user account
useradd user
passwd user
Add this new user to the “wheel” group so it can use sudo.
#add user to wheel group (for sudo)
usermod -aG wheel user
Now we will disable the root login, this can be done many ways but the method in this guide just replaces the password hash with an asterisk “*”.
sudo vi /etc/shadow
Look for the like for root and change it to the following (removing the password hash). Save the file.
root:*:10770:0:::::
This about wraps it up, finally. The only thing left is to restart the Raspberry Pi and hope everything comes up correctly. Unlike the full installation above we did not install NetworkManager and still rely on wired ethernet for network (internet) access. WiFi can be setup using wpa_supplicant but that is a little beyond the scope of this guide. Upon restart we will not get any fancy GUI graphics, just a text login prompt.
#restart to check if the system starts correctly
shutdown -r now
Conclusion
This about wraps up a basic Raspberry Pi Linux Gentoo install, hope it went smooth on your side and will try to keep this guide up to date every few months (and update the downloads). Feel free to download the completed files as well, it has all the above steps completed along with two additions. First, the ssh host keys have been deleted and will be generated on first boot. Second, there is a partition resize script that will run first boot (then automatically reboot, it happens rather quickly). These two above changes keep the Raspberry Pi more secure, but do remember to change the “demouser” or “user” password (whichever version was downloaded).