I am trying out Pi-hole on a Raspberry Pi, but more on the specifics in another post. Alpine Linux is not one of the supported Linux distributions, so instead I use the offical Docker image with Pi-hole.
I have previously written about installing Alpine Linux on a Raspberry Pi, but now I use the default Alpine approach of running the OS from memory. I use the rest of the SD card as cache and storage.
Installing Alpine Linux
I prepare the SD card on another computer running Ubuntu.
Format SD card
The first thing is to identify the SD card. With a new SD card I see something like this:
$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
mmcblk0 179:0 0 14,9G 0 disk
└─mmcblk0p1 179:2 0 14,9G 0 part /media/robert/3636-3339
When the SD card is formatted as described below I see this instead (with mount points for mmcblk0p2
for mmcblk0p3
):
$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
mmcblk0 179:0 0 14,9G 0 disk
├─mmcblk0p1 179:1 0 255M 0 part
├─mmcblk0p2 179:2 0 1,8G 0 part
└─mmcblk0p3 179:3 0 12,9G 0 part
If some partitions are mounted, they should be unmounted with sudo umount /path/to/mountpoint
.
Inspired by https://vincentserpoul.github.io/post/alpine-linux-rpi0 I create three partitions:
- The boot partition with Alpine Linux itself.
- A partition for cache and config files.
- A “storage” partition for e.g. Docker images.
This can be achieved with GNU parted(8)
:
sudo parted --script -a optimal /dev/mmcblk0 \
mklabel msdos \
mkpart primary fat32 0% 256MiB \
mkpart primary ext4 256MiB 1GiB \
mkpart primary ext4 1GiB 100% \
set 1 boot on
Afterwards the result can be inspected with fdisk(8)
:
$ sudo fdisk -l /dev/mmcblk0
Device Boot Start End Sectors Size Id Type
/dev/mmcblk0p1 * 2048 524287 522240 255M c W95 FAT32 (LBA)
/dev/mmcblk0p2 524288 2097151 1572864 768M 83 Linux
/dev/mmcblk0p3 2097152 31115263 29018112 13,9G 83 Linux
If the boot partition does not have a *
in the Boot
column the Raspberry Pi does not boot.
This happens if the parted
command has e.g. mklabel gpt
instead of mklabel msdos
and the result is visible with fdisk
:
$ sudo fdisk -l /dev/mmcblk0
Device Start End Sectors Size Type
/dev/mmcblk0p1 2048 524287 522240 255M EFI System
/dev/mmcblk0p2 524288 4194303 3670016 1,8G Linux filesystem
/dev/mmcblk0p3 4194304 31115263 26920960 12,9G Linux filesystem
When the partitions are created successfully they must be formatted:
sudo mkfs.vfat -F 32 /dev/mmcblk0p1
sudo mkfs.ext4 /dev/mmcblk0p2
sudo mkfs.ext4 /dev/mmcblk0p3
Install Alpine Linux
Download a suitable tar ball from Alpine’s web page. At the time of writing the latest version is 3.13.3. The tar ball has to be extracted onto the boot partition of the SD card, which we do by mounting this partition.
sudo mkdir /mnt/alpine
sudo mount /dev/mmcblk0p1 /mnt/alpine
sudo tar -xzf /path/to/alpine-rpi-3.13.3-armhf.tar.gz --no-same-owner -C /mnt/alpine
sudo umount /mnt/alpine
sudo rmdir /mnt/alpine
On the Pi
When the Pi is turned on you should soon see the login prompt.
Login as root
with an empty password.
First we mount the second and third partition.
This ensures that the upcoming setup can use mmcblk0p2
.
mkdir /media/mmcblk0p2
mkdir /media/mmcblk0p3
mount /dev/mmcblk0p2 /media/mmcblk0p2
mount /dev/mmcblk0p3 /media/mmcblk0p3
Run the setup and remember to set config and cache partition to mmcblk0p2
:
setup-alpine
To keep the installation small all changes has to be explicitly persisted using the lbu
command – known as Alpine local backup.
Run lbu commit
to persist the settings so far.
There are some shell commands that I use constantly when navigating.
I set these system wide in /etc/profile
to ensure that they also work for root
.
alias ll='ls -l'
alias la='ls -la'
alias ..='cd ..'
(To enable the system wide settings when changing to root
from another user we use su -
. Notice the dash.)
Finally, I want to auto mount mmcblk0p3
by editing the file /etc/fstab
.
In my case it should look like this by adding the last line:
/dev/cdrom /media/cdrom iso9660 noauto,ro 0 0
/dev/usbdisk /media/usb vfat noauto,ro 0 0
/dev/mmcblk0p1 /media/mmcblk0p1 vfat ro,relatime,fmask=0022,dmask=0022,errors=remount-ro 0 0
/dev/mmcblk0p2 /media/mmcblk0p2 ext4 rw,relatime 0 0
/dev/mmcblk0p3 /media/mmcblk0p3 ext4 rw,relatime 0 0
Non-root user
I prefer to have a non-root user that has permission to change to root
.
The user is named robert
, has its own group named robert
and is also a member of the wheel
group:
addgroup robert
adduser robert robert
adduser robert wheel
This creates the home folder for robert
in /home/robert
.
To allow users in the wheel
group to change to root, we must edit the file /etc/sudoers
.
The safe way to do this is with visudo
that we get with sudo
.
apk update
apk add sudo
Run visudo
and uncomment the line wheel ALL=(ALL) ALL
.
To make SSH access easier I setup SSH keys.
First create ~/.ssh
.
On another computer I setup the Pi as pihole
in ~/.ssh/config
.
Then I can copy the relevant public key to the Pi with scp
:
scp ~/.ssh/id_rsa.pub pihole:~/.ssh/authorized_keys
Note from https://wiki.alpinelinux.org/wiki/Alpine_local_backup that by default lbu
only cares about /etc
.
To persist the changes in elsewhere we must add this to lbu
’s watch list.
I do not include the entire home dir since this will also include shell history.
lbu include /home/robert/.ssh/authorized_keys
Docker
Docker is available for Alpine in a “community” repository.
Edit /etc/apk/repositories
to include:
http://dl-cdn.alpinelinux.org/alpine/latest-stable/community
Now Docker (and here also Docker Compose) can be installed:
apk update
apk add docker
apk add docker-compose
The user robert
should also have permission to run docker
commands, here achieved by adding robert
to the docker
group.
adduser robert docker
rc-update add docker boot
service docker start
Docker image location
Docker images are big and I want store them on the “storage” partition of the SD card.
By default, Docker images are stored in /var/lib/docker
.
This folder can be moved in the following manner as root
:
service docker stop
cp --archive /var/lib/docker /media/mmcblk0p3/
Create the file /etc/docker/daemon.json
with the content
{
"data-root": "/media/mmcblk0p3/docker"
}
Finally, Docker can be started again:
service docker start
Remember to persist the changes.
If this works as intended the folder /var/lib/docker
can be removed.