Alpine Linux on a Laptop How-To
A few notes before we get started, we’re going to partition and install by-hand
with minimal help from the installer. This is so you can easily have Alpine
co-exist with other operating systems on the same disk, so as long as you have
another ef00
and 8e00
partition for it to reside. We won’t be using any
bootloader tools either, just the kernel’s built in EFI stub and efibootmgr
to
tell the UEFI where to look.
Once your done with the main sections you should have an Xfce desktop, from there you can pick and choose the other pieces, if any, that you want.
Boot into the Alpine Linux ISO:
You will probably want to start form the extended image, though this method works just fine from the standard image as well.
# setup-interfaces
# /etc/init.d/networking start
# setup-apkrepos
# apk add cryptsetup lvm2 gptfdisk xfsprogs btrfs-progs efibootmgr
Now let’s partition the disk:
# gdisk /dev/<device>
Command (? for help): n
Partition number (1-128, default 1):
First sector : 2048
Last sector : +500M
Current type is 8300 (Linux filesystem)
Hex code or GUID (L to show codes, Enter = 8300): ef00
Changed type of partition to 'EFI system partition'
Command (? for help): n
Partition number (2-128, default 2):
First sector : <hit enter>
Last sector : <hit enter>
Current type is 8300 (Linux filesystem)
Hex code or GUID (L to show codes, Enter = 8300): 8e00
Changed type of partition to 'Linux LVM'
Command (? for help): w
Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
PARTITIONS!!
Do you want to proceed? (Y/N): y
OK; writing new GUID partition table (GPT) to /dev/<device>.
The operation has completed successfully.
#
Where <device>
is probably sda
or nvme0n1
, but double check. Instead
of +500M
for the uEFI partition, you could also do 1, or 2gb even if you’re
going to be sharing /boot
with multiple operating systems.
# cryptsetup luksFormat /dev/<device>
WARNING!
========
This will overwrite data on /dev/<device> irrevocably.
Are you sure? (Type 'yes' in capital letters): YES
Enter passphrase for /dev/<device>:
Verify passphrase:
#
# cryptsetup luksOpen /dev/<device> crypt
Enter passphrase for /dev/<device>:
# lvm pvcreate /dev/mapper/crypt
Physical volume "/dev/mapper/crypt" successfully created.
# lvm vgcreate vg /dev/mapper/crypt
Volume group "vg" successfully created
# lvm lvcreate vg --name root --size=<size>
Logical volume "root" created.
# lvm lvcreate vg --name home --size=<size>
Logical volume "home" created.
# mkfs.xfs /dev/vg/root
# mkfs.xfs /dev/vg/home
# mkfs.vfat -f32 /dev/<device>1
I’ve used xfs
above, you can use ext4
or btrfs
as well.
Mount the filesystems and install
# modprobe xfs
# mount /dev/vg/root /mnt
# mkdir /mnt/boot /mnt/home
# modprobe vfat
# mount /dev/<device>1 /mnt/boot
# mkdir -p /mnt/etc/apk
# cp -a /etc/apk/keys /mnt/etc/apk/
# cp /etc/apk/repositories /mnt/etc/apk/
# apk -p /mnt --initdb -U add $(cat /etc/apk/world)
# cp /etc/resolv.conf /mnt/etc/
# cd /mnt
# mount -o bind --rbind /dev dev
# mount -o bind --rbind /sys sys
# mount -t proc none proc
# chroot . /bin/ash
# export PS1="(CHROOT)# "
(CHROOT)# apk add linux-lts tzdata
(CHROOT)# apk add wpa_supplicant # If you need wifi
(CHROOT)# grep -E 'xfs|vfat|btrfs|ext4' /proc/mounts >> /etc/fstab
(CHROOT)# echo none /tmp tmpfs rw,defaults 0 0 >> /etc/fstab
(CHROOT)# echo 'auto lo
iface lo inet loopback' > /etc/network/interfaces
(CHROOT)# setup-sshd
(CHROOT)# setup-ntp
(CHROOT)# for svc in devfs dmesg hwdrivers mdev ; do rc-update add $svc sysinit ; done
(CHROOT)# for svc in bootmisc hostname hwclock lvm modules networking \
seedrng swap sysctl syslog ; do rc-update add $svc boot ; done
(CHROOT)# for svc in acpid crond klogd local ; do rc-update add $svc default ; done
(CHROOT)# sed -i.bak -e's/ext4/ext4 xfs btrfs lvm cryptsetup/' \
/etc/mkinitfs/mkinitfs.conf
(CHROOT) # mkinitfs $(ls -t /lib/modules | sed 1q) # Note if `ls` is aliased, use `command ls` to avoid a trailing slash
(CHROOT) # efibootmgr -c -p 1 -d /dev/<device>1 -L Alpine -l /vmlinuz-lts \
-u 'initrd=/initramfs-lts cryptroot=/dev/<device>2 cryptdm=crypt root=/dev/vg/root rootfstype=xfs rootflags=rw' \
(CHROOT) # passwd
(CHROOT) # exit
# sync && reboot
You may wish to replace cryptroot=/dev/<device>2
with
cryptroot=/dev/disk/by-uuid/<uuid>
for that particular partition.
Now, if all goes well, you should be able to reboot into your new Alpine Linux system.
# ln -s /usr/share/zoneinfo/America/New_York /etc/localtime
# adduser <username>
# adduser <username> wheel
# apk add doas
# echo "permit :wheel as root" >> /etc/doas.d/wheel.conf
# setup-xorg-base
# apk add xfce4 lightdm lightdm-gtk-greeter dbus xfce4-terminal \
xfce4-screensaver firefox openssh git gpg gnupg-scdaemon libfido2 \
openssh-sk-helper pcsc-lite fido2 pulseaudio pulseaudio-alsa \
alsa-plugins-pulse pavucontrol pinentry-gnome
# adduser <username> plugdev
# adduser <username> gnupg
# adduser <username> audio
# adduser <username> pulse-access
# addgroup autologin
# adduser <username> autologin
# sed -i.bak 's/^#autologin-user=.*/autologin-user=<username>/' /etc/lightdm/lightdm.conf
# /etc/init.d/lightdm start
Now, if all has gone well you should be greeted with a login screen. Once
you’ve logged in the first time, subsequent starts of lightdm
will have you
automatically logged in. ( Which is fine, considering we have an encrypted root
)
From the terminal you can now have the login manager start on boot:
Congrats, you can stop here if you’d like.
$ doas rc-update add lightdm default
(Optional) Switching to the dwm
window manager
There are a lot of tutorials on dwm
out there,
I’m not to make one here, just to simply outline how I compile and set it up
on Alpine Linux ( and, the process is very similar on most linux distros )
First let’s install the required packages:
$ doas apk add build-base xorg-server-dev libxft-dev libxinerama-dev
The easiest way to retain automatic login and all of that is to simply add a session to lightdm:
$ git clone https://git.riedstra.dev/x/session
$ cd session
$ make install
Now you have a custom session that can execute your ~/.xinitrc
on login,
just as if you used startx
.
A basic ~/.xinitrc
example:
$ echo '#!/bin/sh
# If you'd like, you can source other files here.
# . ~/.kshrc
# Useful if you're running oksh
# export ENV=$HOME/.kshrc
$(eval ssh-agent)
# See https://git.riedstra.dev/x/dmenu for the patch and script
export SSH_ASKPASS=dmenu_askpass
# Add SSH keys if you'd like.
# ssh-add ~/.ssh/keys/<key>
# Optional, compositor. You'll have to install it yourself
picom --config /dev/null &
# Start a program to update the status bar, I just use a short shell
# script with `xsetroot`
status-bar &
# You can use `feh` directly or similar. This is just a shell script that
# sets the wallpaper every 15 seconds, so when I change screen resolutions it
# goes back to normal.
wallpaper ~/.wallpaper.jpg &
# If you want to inherit xfce settings
# xfsettingsd &
# Alternatively you can set the gtk themes and such directly.
# Finally, do not forget that all of the commands above either need to finish
# or fork to the background (`&`) otherwise we don't get here and it appears
# that your login "hangs"
exec dwm' > ~/.xinitrc
$ chmod +x ~/.xinitrc
Finally, fetch and make dwm:
$ git clone https://git.suckless.org/dwm
$ cd dwm
$ doas make clean install
If you’d like my version of dmenu
which includes dmenu_askpass
for SSH keys:
$ git clone https://git.riedstra.dev/x/dmenu
$ cd dmenu
$ doas make clean install
Now you should be able logout, and login under the custom
session and
be greeted with dwm.
Some additional packages you may like to add:
$ doas apk add slock xsetroot lm-sensors feh slock st # dmenu, if you didn't install mine
(Optional) System suspend without pm-utils and root/sudo/doas
If you want to be able to quickly suspend, say from dmenu
I have a useful
c shim for that:
$ doas apk add build-base
$ cd $(mktemp -d)
$ curl https://git.riedstra.dev/mitch/dotfiles/plain/bin/zzz.c > zzz.c
$ # This may be where you wish to read the file you just downloaded :-)
$ cc -o zzz zzz.c
$ export dest=/sbin/zzz
$ doas sh -c "cp zzz $dest && chown root:wheel $dest && chmod 6750 $dest"
Once you’re done, zzz
should work to suspend the system for any user
in the wheel
group
If you’re interested, you could also clone down the entire git repo and use the makefile in bin/
(Optional) Backlight control without root/sudo/doas
In a similar vein to the zzz
program:
$ doas apk add build-base
$ cd $(mktemp -d)
$ curl https://git.riedstra.dev/mitch/dotfiles/plain/bin/backlight.c > backlight.c
$ # This may be where you wish to read the file you just downloaded :-)
$ cc -o backlight backlight.c
$ export dest=/sbin/backlight
$ doas sh -c "cp backlight $dest && chown root:wheel $dest && chmod 6750 $dest"
Once you’re done, backlight <percentage>
should work to suspend the system for
any user in the wheel
group.
It simply tries to deciver backlights in /sys/class/backlight
, out of
the box this should work on most intel and amd systems.
If you’re interested, you could also clone down the entire git repo and use the makefile in bin/
(Optional) Bluetooth
# apk add bluez bluez-alsa
# rc-update add bluetooth default
# /etc/init.d/bluetooth start
From there interacting with bluetooth is pretty straightforward:
# bluetoothctl
[bluetooth]# scan on
[bluetooth]# pair <MACADDR>
[bluetooth]# connect <MACADDR>
[bluetooth]# scan off
[bluetooth]# <c-d>
#
Optionally you can also issue a trust <MACADDR>
, useful for keyboards
and such.
Bluetooth audio should work out of the box.
(Optional) Enable Network Manager
From just about any point in our install process you can install NetworkManager if you’re having troubple with manual network configuration
# apk add networkmanager networkmanager-tui
# /etc/init.d/networking stop
# /etc/init.d/networkmanager start
# nmtui
# rc-update del networking boot
# rc-update add networkmanager boot
(Optional) Disable SSH
If you’re not going to be logging into your system remotely, you might as well disable the SSH service.
# rc-update del sshd default
(Optional) Setup WiFi with wpa_supplicant
Create a configuration file:
network={
ssid="<your network name>"
scan_ssid=1
key_mgmt=WPA-PSK
psk="<your network password>"
}
Then run:
# wpa_supplicant -i wlan0 -c /path/to/conf &
That should spit out a few messages, and return you to your terminal.
From there, get a DHCP lease:
# udhcpc -i wlan0
Now you should be hooked up to the wifi by-hand for now.