Alpine on RPI1B - hpaluch/hpaluch.github.io GitHub Wiki

Installing Alpine Linux on Raspberry PI 1.B

Alpine Linux (Alpine) is fastest Linux on x86 architecture I know (thanks to not using systemd, using musl instead of glibc and single busybox binary for base system commands).

So it is natural to try it on RPi - I have old model 1B purchased around 2013.

Hardware requirements:

  • Host PC with SD Card reader
  • RPi 1.B
  • SD Card - I use 4GB card
  • optional: USB <-> TTL Serial cable (in my case mandatory - I have only VGA monitor but RPi has only HDMI output - I have also HDMI -> VGA converter but it is sometimes tricky

There are two guides on:

In case of Model PI 1.B we need armhf (ARM with Hardware Float support - math coprocessor) in my case:

Downloaded .img contains only boot FAT partition (boot is defined by Broadcom firmware - using MBR partitioning and having FAT partition with specified files).

Preparing SD card

Insert card to SD reader of your Host Linux (I use openSUSE LEAP 15.6 amd64). Verify proper device name (important!):

$ lsblk -S

NAME
    HCTL       TYPE VENDOR   MODEL                        REV SERIAL            TRAN
sda 0:0:0:0    disk ATA      Samsung SSD 870 EVO 1TB SVT03B6Q S75CNX0WB29571B   sata
sdb 2:0:0:0    disk Generic- SD/MMC/MS PRO               1.00 20120926571200000 usb

In my case target device with SD card is /dev/sdb

WARNING! If you have any "smart" desktop system on your Host PC and card already has FAT partition it will be automatically mounted - you have to unmount it from your File Manager (Thunar in case of Xfce).

Now write Alpine Linux with just boot partition - REPLACE /dev/sdb with your SD card device!

sudo dd if=alpine-rpi-3.20.3-armhf.img of=/dev/sdb bs=1024k status=progress

In case of Desktop with Thunar the new FAT partition will be again automatically mounted - we can use it to make important changes.

Next edit /run/media/USERNAME/disk/cmdline.txt and append at the end of line console=ttyAMA0 and remove quiet

Now Unmount and then Eject your SD card from Thunar manager or using commands like:

udisksctl unmount -b /dev/sdb1
udisksctl power-off -b /dev/sdb

Booting

I connected USB <-> TTL Serial adapter to both RPi and PC. On PC with SUSE it appears as /dev/ttyUSB0 I use following command on Host PC to run Minicon on serial console with logging:

$ minicom -C logs/alpine-`date '+%s'`.log -b 115200 -8 -D /dev/ttyUSB0

Cannot create lockfile for /dev/ttyUSB0: Permission denied

I have verified that I have proper permissions:

$ ls -l /dev/ttyUSB0

crw-rw---- 1 root dialout 188, 0 Sep  7 08:57 /dev/ttyUSB

$ groups

users libvirt wireshark dialout wheel

Using strace -f -o xx COMMAND and grepping for = - I found:

13266 openat(AT_FDCWD, "/var/lock/LCK...13265", O_WRONLY|O_CREAT|O_TRUNC, 0666) = -1 EACCES (Permission denied)

So:

$ ls -ld /var/lock

lrwxrwxrwx 1 root root 9 Dec 26  2023 /var/lock -> /run/lock

$ ls -ld /run/lock

drwxrwxr-x 5 root root 140 Sep  7 08:37 /run/lock

So thanks to systemd we have to run minicom as root.

Now power-up RPi 1.b - after few seconds you should see kernel messages on serial console and Alpine setup messages:

    0.000000] Booting Linux on physical CPU 0x0
[    0.000000] Linux version 6.6.49-0-rpi (buildozer@build-3-20-armhf) (gcc (Alpine 13.2.1_git20240309) 13.2.1 202403094
[    0.000000] CPU: ARMv6-compatible processor [410fb767] revision 7 (ARMv7), cr=00c5387d
[    0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT nonaliasing instruction cache
[    0.000000] OF: fdt: Machine model: Raspberry Pi Model B Rev 2
...
[    5.649022] Loading boot drivers...
 * Loading boot drivers: [    5.701332] squashfs: version 4.0 (2009/01/31) Phillip Lougher
[    5.720787] Loading boot drivers: ok.
ok.
[    5.751832] Mounting boot media...
 * Mounting boot media: [    5.873024] usb 1-1.1: new high-speed USB device number 3 using dwc_otg
[    6.085430] usb 1-1.1: New USB device found, idVendor=0424, idProduct=ec00, bcdDevice= 2.00
[    6.099270] usb 1-1.1: New USB device strings: Mfr=0, Product=0, SerialNumber=0
...
 * Starting firstboot ... [ ok ]

Welcome to Alpine Linux 3.20
Kernel 6.6.49-0-rpi on an armv6l (/dev/ttyAMA0)

localhost login:

Use root without password.

Persistent disk install

I want to have standard installation on SD card (with read-write filesystem). In that case we have to follow semi-manual process (similar to manual disk setup etc):

First I will add target partitions:

fdisk /dev/mmcblk0

Disk /dev/mmcblk0: 3859 MB, 4046454784 bytes, 7903232 sectors
7840 cylinders, 16 heads, 63 sectors/track
Units: sectors of 1 * 512 = 512 bytes

Device       Boot StartCHS    EndCHS        StartLBA     EndLBA    Sectors  Size Id Type
/dev/mmcblk0p1 *  0,0,1       146,15,63            0     148175     148176 72.3M  6 FAT16

# Adding root filesystem partition:

Command (m for help): n
Partition type
   p   primary partition (1-4)
   e   extended
p
Partition number (1-4): 2
First sector (148176-7903231, default 148176):
Using default value 148176
Last sector or +size{,K,M,G,T} (148176-7903231, default 7903231): +3g

Command (m for help): p
Disk /dev/mmcblk0: 3859 MB, 4046454784 bytes, 7903232 sectors
7840 cylinders, 16 heads, 63 sectors/track
Units: sectors of 1 * 512 = 512 bytes

Device       Boot StartCHS    EndCHS        StartLBA     EndLBA    Sectors  Size Id Type
/dev/mmcblk0p1 *  0,0,1       146,15,63            0     148175     148176 72.3M  6 FAT16
/dev/mmcblk0p2    147,0,1     1023,15,63      148176    6439631    6291456 3072M 83 Linux

# Adding swap partition (just as reserve):

Command (m for help): n
Partition type
   p   primary partition (1-4)
   e   extended
p
Partition number (1-4): 3
First sector (6439632-7903231, default 6439632):
Using default value 6439632
Last sector or +size{,K,M,G,T} (6439632-7903231, default 7903231):
Using default value 7903231

Command (m for help): p
Disk /dev/mmcblk0: 3859 MB, 4046454784 bytes, 7903232 sectors
7840 cylinders, 16 heads, 63 sectors/track
Units: sectors of 1 * 512 = 512 bytes

Device       Boot StartCHS    EndCHS        StartLBA     EndLBA    Sectors  Size Id Type
/dev/mmcblk0p1 *  0,0,1       146,15,63            0     148175     148176 72.3M  6 FAT16
/dev/mmcblk0p2    147,0,1     1023,15,63      148176    6439631    6291456 3072M 83 Linux
/dev/mmcblk0p3    1023,15,63  1023,15,63     6439632    7903231    1463600  714M 83 Linux

Command (m for help): t
Partition number (1-4): 3
Hex code (type L to list codes): 82
Changed system type of partition 3 to 82 (Linux swap)

Command (m for help): p
Disk /dev/mmcblk0: 3859 MB, 4046454784 bytes, 7903232 sectors
7840 cylinders, 16 heads, 63 sectors/track
Units: sectors of 1 * 512 = 512 bytes

Device       Boot StartCHS    EndCHS        StartLBA     EndLBA    Sectors  Size Id Type
/dev/mmcblk0p1 *  0,0,1       146,15,63            0     148175     148176 72.3M  6 FAT16
/dev/mmcblk0p2    147,0,1     1023,15,63      148176    6439631    6291456 3072M 83 Linux
/dev/mmcblk0p3    1023,15,63  1023,15,63     6439632    7903231    1463600  714M 82 Linux swap

Command (m for help): v
Total allocated sectors 7903233 greater than CHS size 7902720

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table
fdisk: WARNING: rereading partition table failed, kernel still uses old table: Resource busy

WARNING! Because kernel was unable to re-read partition we have to issue reboot...

After reboot verify that there are new partitions:

fdisk -l
Disk /dev/mmcblk0: 3859 MB, 4046454784 bytes, 7903232 sectors
7840 cylinders, 16 heads, 63 sectors/track
Units: sectors of 1 * 512 = 512 bytes

Device       Boot StartCHS    EndCHS        StartLBA     EndLBA    Sectors  Size Id Type
/dev/mmcblk0p1 *  0,0,1       146,15,63            0     148175     148176 72.3M  6 FAT16
/dev/mmcblk0p2    147,0,1     1023,15,63      148176    6439631    6291456 3072M 83 Linux
/dev/mmcblk0p3    1023,15,63  1023,15,63     6439632    7903231    1463600  714M 82 Linux swap
Disk /dev/mmcblk0p1: 72 MB, 75866112 bytes, 148176 sectors
147 cylinders, 16 heads, 63 sectors/track
Units: sectors of 1 * 512 = 512 bytes

Device         Boot StartCHS    EndCHS        StartLBA     EndLBA    Sectors  Size Id Type
/dev/mmcblk0p1p1 *  0,0,1       146,15,63            0     148175     148176 72.3M  6 FAT16
/dev/mmcblk0p1p2    147,0,1     1023,15,63      148176    6439631    6291456 3072M 83 Linux
Partition 2 has different physical/logical end:
     phys=(1023,15,63) logical=(6388,8,24)
/dev/mmcblk0p1p3    1023,15,63  1023,15,63     6439632    7903231    1463600  714M 82 Linux swap
Partition 3 has different physical/logical start (non-Linux?):
     phys=(1023,15,63) logical=(6388,8,25)
Partition 3 has different physical/logical end:
     phys=(1023,15,63) logical=(7840,8,8)

You may safely ignore CHS mismatch warnings because it is ignored on Raspberry PI - it always uses LBA Addresses (CHS is leftover from old PC BIOS and IDE disks era).

To avoid out of memory, I recommend to format and activate swap:

mkswap -L alpine-swap /dev/mmcblk0p3
swapon /dev/mmcblk0p3
free -m

              total        used        free      shared  buff/cache   available
Mem:            429          15         352           9          62         394
Swap:           715           0         715

WARNING! I will now try my own setup for lazy people (trying to avoid as much manual steps as possible):

apk add e2fsprogs
mkfs.ext4 -L alpine-root /dev/mmcblk0p2
mount /dev/mmcblk0p2 /mnt
# we must fix date to avoid https errors

setup-interfaces

  Available interfaces are: eth0.
  Enter '?' for help on bridges, bonding and vlans.
  Which one do you want to initialize? (or '?' or 'done') [eth0]
  Ip address for eth0? (or 'dhcp', 'none', '?') [dhcp]
  Do you want to do any manual network configuration? (y/n) [n]

apk add dhcpcd
/sbin/ifup eth0

# now we have working network and can set proper date/time:
ntpd -dnqp ntp.cesnet.cz

  Sat Sep  7 07:42:30 UTC 2024

Now run installer (hoping it will not crash):

FORCE_BOOTFS=1 DISKOPTS=/mnt setup-alpine

FORCE_BOOTFS is required because we fake that /boot is just directory on ext4 root filesystem but RPi can boot from FAT only. The problem is that SD card is both Source device (system booted from it and actively is using its FAT partition) and also Target device (where we want to install new boot configuration). Thus `FORCE_BOOTFS' is needed until some better solution will be possible.

Quick and dirty way to boot installed with minimal changes:

# alpine mounted FAT there as read-only:
mount -o rw,remount /media/mmcblk0p1
vi /media/mmcblk0p1/cmdline.txt
# append to line:  root=/dev/mmcblk0p2

# reboot with: reboot

NOTE: Please read https://wiki.alpinelinux.org/wiki/Classic_install_or_sys_mode_on_Raspberry_Pi for clean solution.

After reboot Login as root - and you have to enter also root's password (it is sign that we are really booting installed system).

  • after power-up you have to sync clock with ntpd -nqp ntp.cesnet.cz (I should add it to post-up of /etc/network/interfaces
  • now edit /etc/apk/repositories and uncomment community line.
  • and try to install favorite programs:
    apk add vim tmux mc curl lynx wget
    

If you plan SSH access you can also setup regular user:

adduser -G wheel USRNAME
# will be asked for password

To become root from USERNAME issue command su - and enter root's password. I found that enough so I don't use sudo or doas (it is just another layer).

Summary

Alpine Linux again confirmed its fame as very fast and low footprint system. Whole system has really good response and it uses just 20MB of memory to run (including SSH server):

$ free -m
              total        used        free      shared  buff/cache   available
Mem:            429          20         322           0          87         398
Swap:             0           0           0

Disk overview:

apk add lsblk
lsblk -f -o+size

NAME        FSTYPE FSVER LABEL       UUID                                 FSAVAIL FSUSE% MOUNTPOINTS   SIZE
mmcblk0     vfat                                                                                       3.8G
├─mmcblk0p1 vfat                                                                                      72.4M
├─mmcblk0p2 ext4         alpine-root 78b30ca7-46a1-49d7-b1d2-c26e785d9237    2.4G    12% /               3G
└─mmcblk0p3 swap         alpine-swap 96e0886c-de36-4656-bbf5-11fc4f16bdd5                            714.6M

Although setup requires few manual steps (unlike NetBSD or other Linux distributions) - it is so far worth it.

Overall, Linux now has reputation of slow and bloated system - and it is mostly true, but Alpine Linux is definitely positive exception - both its disk footprint and speed very well compares to tuned FreeBSD or any other Unix like system. I'm really glad that there are still good examples in Linux world that not just follow rot business crowd (with its systemd and container crap that clashes with interests of community), but rather uses reasonable and sensible solutions.

--hp