Today I had a paid day off, so I took the chance to hook up that raspberry pi 1B+, which I had laying around for some months.
The idea is to use it as a fileserver for the internal network (read: only at home, not exposed to the Internet).
So I don't need a graphical UI, but instead a headless system. Sounds for a minimal distribution. Let's go for Gentoo :-)
If you want to follow along, you should have:
- No fear of GNU/Linux
- Something to take notes
- Internet connection
- A LAN cable
- A sd card (I am using a 2 GiB microSD here)
- A card reader to hook the sd card to a laptop
- Raspberry Pi
- External keyboard for the Raspberry Pi
- Some hours at hand (it took me about five hours with all the read-up)
- A laptop with GNU/Linux to download the needed tar balls
- A laptop with GNU/Linux for mounting the SD card
- Knowledge of a CLI editor (nano is sufficient. I'm using vim, too)
- GParted installed on the laptop (you could go for parted as well...)
Everything ready? Let's go!
Preparing the sd card
I am mainly relying on the Quick Install Guide of Gentoo here.
So first plug the sd card into the card reader and wire that one up to your GNU/Linux box. Backup everything you might need later, because we are going to wipe the card now :-)
Make sure, the card is unmounted. You can verify it like so:
$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sdc 8:32 1 1,9G 0 disk
├─sdc1 8:33 1 33M 0 part
└─sdc2 8:34 1 1,8G 0 part
There MUST NOT be a mountpoint given! In case it is, umount /path/to/mountpoint
it. (You can force umount it if you are not worried about data corruption. After all, you have a backup, right?)
Ready? Fine!
Creating partitions
Let's start gparted
with root permissions (it will prompt you to do so if you are opening it without).
Make sure you are targeting the right device! In my case, that would be sdc
. You can change the device via GParted > Devices.
According to the Quick Install Guide, Raspberry boots off of a FAT32 partition. So we are first deleting all partitions (again, make sure you are on the right device!) and then create new ones. I added a FAT32 one with the minmal size (33MB) at the beginning. A second partition with ext4 takes up all the rest.
A swap partition is a nice-to-have. Since I don't have much space, I skipped to create one.
Both are primary ones. I've assigned labels to them, so they show up nicely when mounted to my laptop :-)
After application of the changes, you can add a flat to the first partition to indicate it's bootable. Therefore rightlick the entry and select edit flags
.
The UI will shortly reload. Close GParted. You are done here.
Double check with lsblk
again.
Later on I ran into an issue with running out of inodes to set up portage. On Telegram's Gentoo chat room, @khaosgrille suggested to change the bytes-per-inode ratio. If you don't know, what an inode is, read up about inodes on Wikipedia.
Because it is not clever to blindly apply commands found on the Internet I myself read up about the options. Since I was using ext4 for the second partition, that let me to man mkfs.ext4
, looking for the usage-type
option. The docs told me to look into /etc/mke2fs.conf
for details.
Turns out, I need the usage type small
. Since I had not put anything on the partition, I entered sudo mkfs.ext4 -T small /dev/sdc2
and confirmed the warning (partition busy). This raised my inode count from 117K to 477K (according to ls -ih /dev/sdc2
). Enough for moving on.
Downloading Gentoo
For the following sections, you should cd /tmp
on your laptop, so the downloaded tar balls are removed during your next boot.
Visit Gentoo's autobuilds for ARM chips and copy the URL for the correct ARM version (in the case of a Raspberry PI first generation that would be ARMv6 with hard FP). You are looking for the file ending with .tar.bz2
.
Switch back to the terminal at /tmp
and download the file: wget <Link-to-tar-ball>
. This can take some time. Go grab a cup of tea.
After the download, I suggest to download portage as well.
Now creating the mount points and mount the SD card:
sudo mkdir /mnt/gentoo
sudo mount /dev/sdc2 /mnt/gentoo
sudo mkdir /mnt/gentoo/boot
sudo mount /dev/sdc1 /mnt/gentoo/boot
Pay attention to mount the first partition to the sub-directory boot
!
Ready to launch the tar bomb?
(by Randall Munroe, CC BY-SA 2.5)
Jokes aside, run the following commands:
sudo tar xfpj /tmp/stage3-armv6j_hardfp-*.tar.bz2 -C /mnt/gentoo/
sudo tar xjf /tmp/portage-latest.tar.bz2 -C /mnt/gentoo/usr
Again, this will take some time. Time for a walk?
Completed? Cool! Now we are only lacking a kernel. There are good and bad news here.
The bad news? The kernels are proprietary. The good ones? The Raspberry Pi Foundation is hosting compiled ones on GitHub. Run the following commands to add the kernel to the sd card:
cd /tmp/
git clone --depth 1 https://github.com/raspberrypi/firmware/
cd /tmp/firmware/boot
sudo cp -r * /mnt/gentoo/boot/
sudo cp -r ../modules /mnt/gentoo/lib/
Pre-boot configuration
Almost finished! Some configuration steps needed until we can boot into Gentoo. Let's go!
fstab
In order to have the partition mounted on boot, you need to edit the fstab file. You can use either nano
or vim
to do so:
sudo vim /mnt/gentoo/etc/fstab
# Append the following lines to the file and write them with <Esc>:wq
/dev/mmcblk0p1 /boot auto noauto,noatime 1 2
/dev/mmcblk0p2 / ext4 defaults,noatime 0 1
I've modified the Quick Install Guide here by using the correct number for my root partition (mounted at /) and adding the defaults
option. Otherwise I found the partition mounted read-only. Keep in mind, that it will likely allow more things than what would be healthy. See man 5 fstab
if you interested in details. First, I've tried to use UUID instead of the device identifier, but on boot I've read, that Linux could not find it. Same with /dev/sdc2
. So stick to the way they are written here.
If you want to understand more about why they are looking so cryptic, read up about Predictable Network Interface Names and udev
.
boot options
Anyway, let's continue with the boot options.
Fire up your editor again:
sudo vim /mnt/gentoo/boot/cmdline.txt
# The file is likely new. Add the following content:
dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait
Pay attention to point to the correct partition for root
! You can read more about cmdline.txt if you want.
Timezone
I ran into a small problem here. So let me explain. First, list all available time zones and copy the correct as localtime:
sudo ls /mnt/gentoo/usr/share/zoneinfo
sudo cp /mnt/gentoo/usr/share/zoneinfo/Europe/Berlin /mnt/gentoo/etc/localtime
Now, the instructions that to pipe the timezone ("Europe/Berlin") into /mnt/gentoo/etc/timezone. This didn't work for me (permission error). So I created the file and added this line as its content.
Clear root password
Last step before we can unmount! Blank the root password so you can set it right after boot:
sudo sed -i 's/^root:.*/root::::::::/' /mnt/gentoo/etc/shadow
Unmount and boot
You're done! Now unmount the sd card and put it into your Raspberry Pi:
sudo umount /mnt/gentoo/boot
sudo umount /mnt/gentoo/boot
(Yes, it's umount
, not unmount
!)
Remove the sdcard from the card reader, put it into the Raspberry Pi, add your keyboard, (HDMI) monitor, LAN cable and power supply. The device will boot as soon as it gets power.
Post-boot configuration
You should be prompted to a screen for login. The username is root
. I wasn't asked for a password. If you are, hit Enter.
Keep in mind, that you are using an US keyboard here!
Change root password
The first thing after boot is to change the root password. Therefore enter passwd
.
I was told that the "authentication token look busy" and learnt, that this is caused by a root partition mounted as read-only. I advise you to go back and get the fstab
and cmdline.txt
files right.
Enabling network on boot
In case you are plugging your LAN cable now, reboot
the raspberry. (Enter your chosen password now ;-) ).
Then follow these steps:
cd /etc/init.d/
ln -sv net.lo net.eth0
rc-service net.eth0 start
rc-update add net.eth0 boot
Muting debug statements
You likely saw messages like
INIT: Id "s0" respawning too fast
so mute those messages.
nano /etc/rc.conf
# Uncomment rc_sys
rc_sys=""
nano /etc/inittab
# Comment s0
# SERIAL CONSOLES
#s0:12345:respawn:/sbin/agetty 9600 ttyS0 vt100
#s1:12345:respawn:/sbin/agetty 9600 ttyS1 vt100
Fix the clock
No, we don't have 1970 any more. So let's fix that one:
rc-update --update
rc-update add swclock boot
rc-update del hwclock boot
date # In case it is not correct, enter it in format MMDDhhmmYYYY
date 050204212013
What happened? The raspberry pi has no hardware clock, but a software one. So we switched it.
Then we entered the correct date in the format of month-day-hour-minutes-year.
What you could do next is adding software for NTP, but on the device, it takes hours.
You likely want to look into cross-compiling software on a more powerful device.
Select a profile
Before you run emerge, make sure you have selected the right profile:
eselect profile list
The output can take a while. Personally I've chosen default/linux/arm/17.0/armv6j (dev)
.
Install packages
Now that's settled, let's use emerge
!
emerge --ask ntp
rc-update add ntp-client default
Start SSHD
To finish up, start the SSH daemon, so you can log into without a screen.
rc-update add sshd default
/etc/init.d/sshd start
At this point you can shutdown the raspberry pi, detach everything and power it on again. Now, you should be able to SSH into it.
I've added my public SSH key as authorized to it to be double sure.
You can look up the IP address via your router.
Finishing up
Some last steps I'd recommend before putting the raspberry pi on the shelf.
Creating a non-root user
The general advice is to not log in as root
. Hence you'll need a second user.
useradd -m -G users,wheel -s /bin/bash john
passwd john
Log out from root by executing exit
and re-login as john
. If you need to become root it is as easy as su -
.
Setting hostname
In order to have a speaking name, it makes sense to define the hostname. Therefore edit these two files:
nano /etc/hostname
# Give it a speaking name. Like raspi
raspi
nano /etc/hosts
# Pay attention to separate the entries with <kbd>tab</kbd>s!
127.0.0.1 localhost
127.0.0.1 raspi.local localhost raspi
Restart the hostname daemon, so the changes take effect:
/etc/init.d/hostname restart
Now you can log in from your laptop as john via SSH:
ssh john@raspi
Shutdown and reboot
In order to safely shutdown your machine, don't pull the plug, but instead issue these commands as root:
reboot
# or, preferably
shutdown -hP now
Install packages without permanent SSH connection
If you are like me, you don't want to run risk of commands breaking because the connection drop. Therefore, install tmux.
emerge --ask app-misc/tmux
Now you can start a tmux session as root, execute emerge and detach it.
tmux new-session -s portage
# Install something
emerge --ask app-misc/colordiff
# Hit Ctrl-b d to detach the session
tmux ls
tmux attach -t portage
Oh, speaking of colordiff
. You'll quickly run into situations, where you will need to update config files.
If you use a modern tool like dispatch-conf
instead of etc-update
, bring some colour in by editing its conf file.
nano /etc/dispatch-conf.conf
# Update the following line
diff="colordiff -Nu '%s' '%s'"
Now if emerge tells you, that there are config files in need of update, run dispatch-conf
and edit it to your liking.
Conclusion
That was a fun exercise!
I learnt a bunch of new things like the inode-per-byte ratio and alternatives to solve conf conflicts.
If I run into some other interesting problems, be sure I'll write a blog post!