Installing ArchLinux the opinionated way
Similar to official instructions, but with some opinionated decisions. This is a work-in-progress manual on the things I did during my last ArchLinux installation. I will try to keep it updated as my system evolves.
These instructions follow the official ArchLinux installation instructions, but divert in an opinionated way in some steps. Follow with caution, and only if you know what you are doing!
Installation system, partitioning and formatting
Booting from installation medium
Boot from installation iso, set up keymap and font for installation environment:
loadkeys de-latin1
setfont ter-132b
It’s recommended to use a Ventoy boot stick, as we’ll also rely on using a rEFInd boot loader later on. For that, you can just put the official refind boot img on the Ventoy stick you have.
Partitioning
For partition#ing, we use gdisk:
# gdisk /dev/nvme0n1
- Delete all partitions by creating a new GPT partition table with
o. - Then create partitions with this layout:
Number Start (sector) End (sector) Size Code Name 1 2048 2099199 1024.0 MiB EF00 EFI system partition 2 2099200 4196351 1024.0 MiB EA00 XBOOTLDR partition 3 4196352 3907028991 1.8 TiB 8304 ArchLinux-Crypt - Note new partitions can be created with
n, printing works withp, andcallows to rename a partition. - Finally, write out the table with
w. - Note that 8304 is required even for crypted volume to allow for GPT automounting.
Formatting disks
mkfs.fat -F 32 /dev/nvme0n1p1
mkfs.ext4 /dev/nvme0n1p2
# Takes good defaults into account, may want to check sector size via https://wiki.archlinux.org/title/Advanced_Format#NVMe_solid_state_drives ...
cryptsetup luksFormat -s 512 /dev/nvme0n1p3
# Check with:
cryptsetup luksDump /dev/nvme0n1p3
cryptsetup open /dev/nvme0n1p3 ArchLinux
mkfs.btrfs -O block-group-tree /dev/mapper/ArchLinux
Setup BTRFS
Setup BTRFS with separate volumes for rootfs and home for usage of btrbk:
mount --mkdir -t btrfs -o defaults,noatime,compress-force=zstd:6,ssd /dev/mapper/ArchLinux /mnt/btrfs_pool
btrfs subvol create /mnt/btrfs_pool/rootfs
btrfs subvol create /mnt/btrfs_pool/home
mkdir /mnt/btrfs_pool/_btrbk_snap
mount --mkdir -t btrfs -o defaults,noatime,compress-force=zstd:6,ssd,subvol=rootfs /dev/mapper/ArchLinux /mnt/rootfs
btrfs subvolume set-default /mnt/rootfs
mount --mkdir -t btrfs -o defaults,noatime,compress-force=zstd:6,ssd,subvol=home /dev/mapper/ArchLinux /mnt/rootfs/home
btrfs subvolume list /mnt/btrfs_pool
mount --mkdir /dev/nvme0n1p1 /mnt/rootfs/efi
mount --mkdir /dev/nvme0n1p2 /mnt/rootfs/boot
Bootstrapping Arch and initial config
Initial pacstrap
pacman-key --init
pacman-key --populate
pacman -Sy archlinux-keyring
pacstrap -K /mnt/rootfs base linux linux-lts sof-firmware linux-firmware intel-ucode wireless-regdb networkmanager nano man-db man-pages texinfo btrfs-progs dosfstools e2fsprogs openssh gdisk
Initial config
Follow usual manual for initial config, basically:
genfstab -U /mnt >> /mnt/rootfs/etc/fstab
arch-chroot /mnt/rootfs
ln -sf /usr/share/zoneinfo/Europe/Berlin /etc/localtime
hwclock --systohc
“Savepoint”
In case you break off here, you can continue by booting from the installation medium again and setting up keys etc. (see Booting from the Installation medium), then issue:
cryptsetup open /dev/nvme0n1p3 ArchLinux
mount --mkdir -t btrfs -o defaults,noatime,compress-force=zstd:6,ssd /dev/mapper/ArchLinux /mnt/rootfs
mount -t btrfs -o defaults,noatime,compress-force=zstd:6,ssd,subvol=home /dev/mapper/ArchLinux /mnt/rootfs/home
mount /dev/nvme0n1p1 /mnt/rootfs/efi
mount /dev/nvme0n1p2 /mnt/rootfs/boot
arch-chroot /mnt/rootfs
Set up locales
In /etc/locale.gen, uncomment
en_US.UTF-8 UTF-8
de_DE.UTF-8 UTF-8
Then, run locale-gen.
Finally, in /etc/locale.conf, set:
LANG=de_DE.UTF-8
and in /etc/vconsole.conf, set:
KEYMAP=de-latin1
Prepare the network setup
Edit /etc/hostname, set:
myhostname-i-have-though-about
Then, enable NetworkManager:
systemctl enable NetworkManager
In case you need eduroam, remember to install python-dbus so the CAT tool works:
pacman -S python-dbus
For IPv6 with working DNS with most home routers, you may need:
pacman -S avahi-daemon
systemctl enable avahi-daemon
You may want to enable privacy extensions by creating /etc/sysctl.d/ipv6-priv.conf with content (adapt to interface names!):
# Enable ipv6 privacy extensions
net.ipv6.conf.wlp0s20f3.use_tempaddr = 2
net.ipv6.conf.all.use_tempaddr = 2
net.ipv6.conf.default.use_tempaddr = 2
You might also want to install dhcpcd:
pacman -S dhcpcd
and tell NetworkManager to use it instead of it’s integrated implementation by adding these lines to /etc/NetworkManager/NetworkManager.conf:
[main]
dhcp=dhcpcd
Set up initrd
Edit /etc/mkinitcpio.conf, ensure sd-encrypt is added:
HOOKS=(base systemd autodetect microcode modconf kms keyboard keymap sd-vconsole block sd-encrypt filesystems fsck)
Run mkinitcpio -P.
Set root password
passwd
Add refind_linux.conf for boot configuration
Create the file /boot/refind_linux.conf with content:
"Boot with standard options no EHT" "zswap.enabled=0 splash rw iwlwifi.disable_11be=1"
"Boot with standard options" "zswap.enabled=0 splash rw"
"Boot without plymouth" "zswap.enabled=0 plymouth.enable=0 disablehooks=plymouth rw"
"Boot to terminal" "zswap.enabled=0 rw systemd.unit=multi-user.target"
"Boot with full UUIDs" "rd.luks.name=9f26906e-7603-4735-91e4-81f412f089cc=ArchLinux root=/dev/mapper/ArchLinux zswap.enabled=0 rw"
"Boot to single user mode" "zswap.enabled=0 splash ro single"
"Boot with minimal options" "ro"
Note the special iwlwifi setting is due to problems with EHT/MLO support in case of my hardware, the UUID of course needs to be adapted, and zswap is turned off since we are using zram which will be set up later.
Test booting
At this point, refind is not installed yet. As outlined in Booting from the Installation medium, we’ll now use a rEFInd boot loader from an external medium, e.g. a Ventoy boot stick. You should be able to boot with that by now.
This should work fine, if yes, you are ready to continue to the next stage!
Creating a user and making system self-bootable
Activate sshd
systemctl enable --now sshd
Create user
useradd -m olifre
passwd olifre
Remote login
For more comfort (e.g. to set up a system with small screen or keyboard), you may now want to log in via ssh remotely.
Securing SSH
Configure sshd, i.e. copy over pubkey with ssh-copy-id, then set in /etc/ssh/sshd_config:
PasswordAuthentication no
and restart service:
systemctl restart sshd
Install yay
Install yay, see GitHub project (will be needed for easier installation of bootloader / shim-signed):
pacman -Sy vi vim
Need to grant sudo permissions to regular user so yay can be used:
visudo
There, allow wheel users with password to use sudo. Then:
usermod -a -G wheel olifre
Then, as user (ensure to re-login to get group membership!):
sudo pacman -S --needed git base-devel
mkdir AUR
cd AUR
git clone https://aur.archlinux.org/yay.git
cd yay
makepkg -si
yay -Y --devel --save
Configure for speed, create /etc/makepkg.conf.d/multicore.conf with content:
NPROC=8
MAKEFLAGS="-j8"
Adapt the /etc/fstab
In preparation for btrbk and more, you should adapt the /etc/fstab. It should look like this:
# <file system> <dir> <type> <options> <dump> <pass>
# /dev/mapper/root
UUID=8fae96ce-42b0-4933-88ac-f4cdb41155ad / btrfs rw,noatime,compress-force=zstd:6,ssd,space_cache=v2,subvol=/rootfs 0 0
# /dev/mapper/root
UUID=8fae96ce-42b0-4933-88ac-f4cdb41155ad /home btrfs rw,noatime,compress-force=zstd:6,ssd,space_cache=v2,subvol=/home 0 0
# /dev/mapper/root pool directory
UUID=8fae96ce-42b0-4933-88ac-f4cdb41155ad /mnt/btrfs_pool btrfs rw,noatime,compress-force=zstd:6,ssd,space_cache=v2,subvolid=5,noauto 0 0
# /dev/nvme0n1p1
UUID=1542-2E81 /efi vfat noauto,x-systemd.automount,x-systemd.idle-timeout=1min,rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=ascii,shortname=mixed,utf8,errors=remount-ro 0 2
# /dev/nvme0n1p2
UUID=8fae96ce-42b0-4933-88ac-f4cdb41155ad /boot ext4 noauto,x-systemd.automount,x-systemd.idle-timeout=1min,rw,relatime 0 2
The important things we added here are the /mnt/btrfs_pool mountpoint and the automount settings for /efi amnd /boot such that they should only be mounted when actually accessed. You may want to regenerate the initrd at this point:
mkinitcpio -P
and you should for sure generate the /mnt/btrfs_pool mountpoint:
mkdir /mnt/btrfs_pool
and of course make sure the UUIDs match your system (use blkid to check)!
Set up discard for crypto devices, and increase performance for SSDs
Be sure you are aware of the security implications! We do this to increase the SSD lifetime. For the performance trick, see the ArchWiki for more details.
cryptsetup --allow-discards --perf-no_read_workqueue --perf-no_write_workqueue --persistent refresh root
Install the bootloader
We can finally install the boot loader. We will be using Secure Boot, with MOK (Machine-Owner Keys), so do as user:
yay refind sbsigntools
yay shim-signed
Then, as root, run:
refind-install --shim /usr/share/shim-signed/shimx64.efi --localkeys
Configure refind by editing /efi/EFI/refind/refind.conf. Notably, comment out all those dummy menuentry a the bottom, and make sure to add those settings:
timeout 15
use_nvram false
banner dell_logo.bmp
use_graphics_for osx,linux,windows
showtools shell, bootorder, gdisk, memtest, mok_tool, apple_recovery, windows_recovery, about, hidden_tags, reboot, exit, firmware, fwupdate
fold_linux_kernels false
extra_kernel_version_strings "linux-hardened,linux-rt-lts,linux-zen,linux-lts,linux-rt,linux"
write_systemd_vars true
For ease of maintainability, you may want to add these below to the existing descriptions. Note the write_systemd_vars is critical for GPT automounting (i.e. this will cause the partitions to be detected and mounted automatically from the same disk which holds the ESP), extra_kernel_version_strings is important for the Arch kernel naming scheme, and fold_linux_kernels is helpful in case you also want to install the LTS kernel later on.
Copy over an icon from UEFI BGRT for themeing and a kernel icon:
cp /sys/firmware/acpi/bgrt/image /efi/EFI/refind/dell_logo.bmp
cp /efi/EFI/refind/icons/os_arch.png /boot/vmlinuz-linux.png
cp /efi/EFI/refind/icons/os_arch.png /boot/vmlinuz-linux-lts.png
Now, follow the ArchWiki on how to set up kernel signing, and put the following in the hook file:
keypairs=(/etc/refind.d/keys/refind_local.key /etc/refind.d/keys/refind_local.crt)
Do not forget to make the hook executable! Then, as user:
yay linux
This will reinstall the kernel and sign it.
Also, add a refind update hook, create /etc/pacman.d/hooks/refind.hook with content:
[Trigger]
Operation=Upgrade
Type=Package
Target=refind
[Action]
Description = Updating rEFInd on ESP
When=PostTransaction
Exec=/usr/bin/refind-install --shim /usr/share/shim-signed/shimx64.efi --localkeys
Now, a reboot should show a Secure Boot warning and MokManager should pop up. In there, enroll the MOK from:
esp/EFI/refind/keys/refind_local.cer
If this works as expected, you will have a booting system! You can unenroll the key of your Ventoy medium (if used) at this point.
System services and base system installation
Set up some base services
pacman -S reflector
pacman -S pacman-contrib
systemctl enable --now systemd-timesyncd.service
systemctl enable --now paccache.timer
systemctl enable --now fstrim.timer
systemctl enable --now reflector.timer
Install some basic tools
Some tools from Arch repos:
powertop
guvcview
chromium
firefox
thunderbird
nextcloud-client
fwupd
stress-ng
mpv
libreoffice-fresh
power-profiles-daemon
keepassxc
wl-clipboard
xclip
waypipe
rsync
biber
python-pygments
xorg-xlsclients
inkscape
screen
strace
iftop
iotop-c
htop
tcpdump
compsize
scrcpy
emacs
wireshark-qt
tcpdump
gimp
Then, the groups:
texlive
and from AUR:
syncthingtray-qt6
Install the desktop environment with apps
plasma-meta
kde-applications-meta
sddm
Then, execute:
systemctl enable --now sddm
Configure SDDM
Set it up to use wayland (rootless):
mkdir /etc/sddm.conf.d/
cd /etc/sddm.conf.d/
Create /etc/sddm.conf.d/05-base.conf with content:
[Theme]
# Current theme name
Current=breeze
# Cursor theme used in the greeter
CursorTheme=breeze_cursors
Create 10-wayland.conf with content:
[General]
DisplayServer=wayland
GreeterEnvironment=QT_WAYLAND_SHELL_INTEGRATION=layer-shell
[Wayland]
CompositorCommand=kwin_wayland --drm --no-lockscreen --no-global-shortcuts --locale1
Finally, restart it:
systemctl restart sddm.service
Set up Plymouth
yay plymouth
yay plymouth-kcm
Then, in /etc/mkinitcpio.conf, add plymouth to HOOKS after systemd, but before sd-encrypt, then:
mkinitcpio -P
Set up firewalld
Install firewalld, firewall-applet and firewall-config. Note that the integration into KDE is not too helpful at this point, it does not support zones.
After installation, activate:
systemctl enable --now firewalld
For further configuration, you can start firewall-config (GUI) and allow syncthing, kdeconnect. Alternatively, you can run:
firewall-cmd --zone=public --add-service syncthing
firewall-cmd --zone=public --add-service kdeconnect
firewall-cmd --runtime-to-permanent
Note ssh and dhcpv6-client are already on by default, see:
firewall-cmd --info-zone=public
Set up zram
Install zram-generator, then edit /etc/systemd/zram-generator.conf, should contain (swap and personal scratch space):
[zram0]
zram-size = min(ram / 2, 16384)
compression-algorithm = zstd
[zram1]
zram-size = min(ram / 2, 16384)
mount-point = /var/tmp/olifre
options = X-mount.owner=1000,X-mount.group=1000
Create /etc/sysctl.d/99-vm-zram-parameters.conf with content:
vm.swappiness = 180
vm.watermark_boost_factor = 0
vm.watermark_scale_factor = 125
vm.page-cluster = 0
Set up locate
Install package plocate.
Edit /etc/updatedb.conf and set (to include btrfs filesystems):
PRUNE_BIND_MOUNTS = "no"
You may want to enable the timer (but also happens on reboot) or trigger the service for an initial indexing:
systemctl start plocate-updatedb.timer
systemctl start plocate-updatedb.service
Set up logrotate
Install package logrotate. Note we already set up things here for the backup we’ll set up later.
Create file /etc/logrotate.d/restic with content:
/var/log/restic/*.log {
weekly
missingok
rotate 100
copytruncate
minsize 1M
compress
}
You’ll also want to create this:
mkdir /var/log/restic
Create file /etc/logrotate.d/btrbk with content:
/var/log/btrbk.log {
weekly
missingok
rotate 100
copytruncate
minsize 1M
compress
}
Enable timer and trigger once:
systemctl enable --now logrotate.timer
systemctl start logrotate
Set up cronie
systemctl enable --now cronie
Set up dnsmasq
Install package dnsmasq, then, edit /etc/NetworkManager/NetworkManager.conf and add:
[main]
dns=dnsmasq
For more safe and easy usage of VPNs, you may want to create /etc/NetworkManager/dnsmasq.d/fritzbox with content:
server=/fritz.box/192.168.22.1
(assuming this is your home router hostname and IP). Finally, apply:
systemctl restart NetworkManager
Tinc VPN
Install tinc-pre (from AUR).
Execute:
tinc -n homeroute init myhostname
Note that this does 2048 RSA, we want 4096, so:
tinc -n homeroute generate-keys 4096
Now, clean out the old keys, i.e. the commented parts of:
/etc/tinc/homeroute/{ed25519_key,rsa_key}.priv/etc/tinc/homeroute/hosts/myhostname
Copy over config parts from existing tinc cluster, i.e. up/down scripts, other hosts, tinc.conf parts.
If you use static addressing, do not forget to adapt IPs in up/down scripts and add a static Address to this host’s config!
Finally, copy over the host config file to all other nodes.
Set up Backup
We use a two-fold backup, one is btrbk for local snapshotting and versioning (self-protection) and one is an external backup with restic.
btrbk
Create /usr/local/bin/run-btrbk.sh with content:
#!/bin/bash
UMOUNTAFTER=1
if grep -qs '/mnt/btrfs_pool' /proc/mounts; then
# Already mounted by user, do not umount after!
echo "/mnt/btrfs_pool already mounted."
UMOUNTAFTER=0
else
echo "Mounting /mnt/btrfs_pool."
mount /mnt/btrfs_pool
UMOUNTAFTER=1
fi
if [ $# -eq 0 ]; then
btrbk --progress -v run
else
btrbk $@
fi
if [ $UMOUNTAFTER -eq 1 ]; then
echo "Unmounting /mnt/btrfs_pool."
umount -l /mnt/btrfs_pool
else
echo "NOT unmounting /mnt/btrfs_pool."
fi
and make it executable:
chmod +x /usr/local/bin/run-btrbk.sh
Then, install btrbk and mbuffer and copy over the example config:
cp /etc/btrbk/btrbk.conf.example /etc/btrbk/btrbk.conf
and adapt it, uncomment all the “complex examples” and “retention policy” at the end, then add:
snapshot_preserve_min 2d
snapshot_preserve 12h 7d
snapshot_create always
timestamp_format long-iso
volume /mnt/btrfs_pool
subvolume rootfs
subvolume home
Then, create /etc/systemd/system/btrbk.service with content:
[Unit]
Description=btrbk backup
[Service]
Type=oneshot
ExecStart=/usr/local/bin/run-btrbk.sh
Then, create /etc/systemd/system/btrbk.timer with content:
[Unit]
Description=btrbk hourly backup
[Timer]
OnCalendar=hourly
AccuracySec=5min
Persistent=true
[Install]
WantedBy=multi-user.target
Enable all that:
systemctl daemon-reload
systemctl enable --now btrbk.timer
Restic
Install and setup restic for backup.
pacman -S restic
Create dir for configs:
mkdir -p /etc/restic
Within, create /etc/restic/restic_root.conf and /etc/restic/restic_home.conf, follow this scheme:
RESTIC_PASSWORD="secret"
RESTIC_COMPRESSION="max"
AWS_ACCESS_KEY_ID="secret"
AWS_SECRET_ACCESS_KEY="secret"
RESTIC_REPOSITORY="s3:rgw.example.com:7480/my-machine-home"
PRE_BACKUP_COMMAND=""
POST_BACKUP_COMMAND=""
KEEP_WITHIN="2d"
KEEP_LAST=""
KEEP_HOURLY=""
KEEP_DAILY="28"
KEEP_WEEKLY="26"
KEEP_MONTHLY="12"
KEEP_YEARLY="2"
VERBOSITY=1
ONE_FILE_SYSTEM=1
EXCLUDE_CACHES=1
PATH_TO_BACKUP="/home"
EXCLUDE_PATTERNS="'/home/olifre/.cache'"
IEXCLUDE_PATTERNS=""
EXCLUDE_IF_PRESENT_LIST=""
You will of course want to change the secrets and backup server address.
For the EXCLUDE_PATTERNS you may want to set for the home backup:
EXCLUDE_PATTERNS="'/home/olifre/.cache' '/home/olifre/some_cloud_sync'"
and for the root backup:
EXCLUDE_PATTERNS="'/home' '/var/cache/pacman' '/root/.cache' '/mnt/btrfs_pool'"
Make sure the repository names contain different bucket names, e.g. myhostname-home and myhostname-root!
Finally, make sure the files have permissions 0640 for security, and also protect the directory:
chmod 0750 /etc/restic
chmod 0640 /etc/restic/*
Then, create the log directory:
mkdir -p /var/log/restic/
Create two service files, first is /etc/systemd/system/restic-backup@.service with content:
[Unit]
Description=restic backup
[Service]
Type=oneshot
ExecStart=/bin/bash -c "/usr/local/bin/restic_backup.sh backup /etc/restic/restic_%i.conf 2>&1 | cat -v | tee -a /var/log/restic/restic_%i.log > /dev/null"
Second is /etc/systemd/system/restic-check-and-prune@.service:
[Unit]
Description=restic check-and-prune
[Service]
Type=oneshot
ExecStart=/bin/bash -c "/usr/local/bin/restic_backup.sh check-and-prune /etc/restic/restic_%i.conf 2>&1 | cat -v | tee -a /var/log/restic/restic_%i.log > /dev/null"
The actual script in /usr/local/bin/restic_backup.sh should be created with the following content:
#!/bin/bash
# Check provided parameters
if [ ${#*} -ne 2 ]; then
echo "Usage: $(basename $0) <mode> <config_file>"
exit 1
fi
MODE=$1
CONFIG_FILE=$2
if [ "$MODE" != "backup" ] && [ "$MODE" != "check-and-prune" ]; then
echo "Error, you passed mode = ${MODE}, but be one of: backup, check-and-prune!"
exit 1
fi
echo "########## START - $(date) ##########"
if [ ! -r ${CONFIG_FILE} ]; then
echo "Config file ${CONFIG_FILE} can not be accessed / does not exist!"
exit 1
fi
set -o allexport
. ${CONFIG_FILE}
set +o allexport
# Ensure HOME is set (needed for cache).
export HOME=/root
# Init repo if absent.
restic snapshots > /dev/null 2> /dev/null
if [ ! $? -eq 0 ]; then
restic init
echo "Restic repository created at \"${RESTIC_REPOSITORY}\"."
else
echo "Using existing restic repository at \"${RESTIC_REPOSITORY}\"."
fi
if [ "$MODE" = "backup" ]; then
# Handle actual backup commandline arguments.
RESTIC_BACKUP_PARS=()
if [ "x${ONE_FILE_SYSTEM}" = "x1" ]; then
RESTIC_BACKUP_PARS+=("--one-file-system")
fi
if [ "x${EXCLUDE_CACHES}" = "x1" ]; then
RESTIC_BACKUP_PARS+=("--exclude-caches")
fi
if [ -n "${EXCLUDE_PATTERNS}" ]; then
eval "excl_dir_array=($EXCLUDE_PATTERNS)"
for excl_dir in "${excl_dir_array[@]}"; do
RESTIC_BACKUP_PARS+=("--exclude")
RESTIC_BACKUP_PARS+=("${excl_dir}")
done
fi
if [ -n "${IEXCLUDE_PATTERNS}" ]; then
eval "iexcl_dir_array=($IEXCLUDE_PATTERNS)"
for iexcl_dir in "${iexcl_dir_array[@]}"; do
RESTIC_BACKUP_PARS+=("--iexclude")
RESTIC_BACKUP_PARS+=("${iexcl_dir}")
done
fi
if [ -n "${EXCLUDE_IF_PRESENT_LIST}" ]; then
eval "excl_if_present_array=($EXCLUDE_IF_PRESENT_LIST)"
for excl_if_present in "${excl_if_present_array[@]}"; do
RESTIC_BACKUP_PARS+=("--exclude-if-present")
RESTIC_BACKUP_PARS+=("${excl_if_present}")
done
fi
# Now finally the actual backup.
SECONDS=0
echo "Starting backup of \"${PATH_TO_BACKUP}\" to \"${RESTIC_REPOSITORY}\" at $(date)..."
if [ -n "${PRE_BACKUP_COMMAND}" ]; then
echo "Running pre-backup-command \"${PRE_BACKUP_COMMAND}\"..."
$PRE_BACKUP_COMMAND
echo "Done!"
fi
echo "Running restic..."
restic --verbose=${VERBOSITY} backup "${RESTIC_BACKUP_PARS[@]}" ${PATH_TO_BACKUP}
echo "Done!"
if [ -n "${POST_BACKUP_COMMAND}" ]; then
echo "Running post-backup-command \"${POST_BACKUP_COMMAND}\"..."
$POST_BACKUP_COMMAND
echo "Done!"
fi
echo "Backup finished at $(date) (after ${SECONDS} seconds)."
# Forget metadata for old snapshots.
RESTIC_FORGET_PARS=()
if [ -n "${KEEP_WITHIN}" ]; then
RESTIC_FORGET_PARS+=("--keep-within" "${KEEP_WITHIN}")
fi
if [ -n "${KEEP_LAST}" ]; then
RESTIC_FORGET_PARS+=("--keep-last" "${KEEP_LAST}")
fi
if [ -n "${KEEP_HOURLY}" ]; then
RESTIC_FORGET_PARS+=("--keep-hourly" "${KEEP_HOURLY}")
fi
if [ -n "${KEEP_DAILY}" ]; then
RESTIC_FORGET_PARS+=("--keep-daily" "${KEEP_DAILY}")
fi
if [ -n "${KEEP_WEEKLY}" ]; then
RESTIC_FORGET_PARS+=("--keep-weekly" "${KEEP_WEEKLY}")
fi
if [ -n "${KEEP_MONTHLY}" ]; then
RESTIC_FORGET_PARS+=("--keep-monthly" "${KEEP_MONTHLY}")
fi
if [ -n "${KEEP_YEARLY}" ]; then
RESTIC_FORGET_PARS+=("--keep-yearly" "${KEEP_YEARLY}")
fi
SECONDS=0
echo "Starting forgetting of old snapshots at $(date)..."
restic --verbose=${VERBOSITY} forget --cleanup-cache "${RESTIC_FORGET_PARS[@]}"
echo "Forgetting of old snapshots finished at $(date) (after ${SECONDS} seconds)."
fi
if [ "$MODE" = "check-and-prune" ]; then
SECONDS=0
echo "Start of checking at $(date)."
restic --verbose=${VERBOSITY} check --retry-lock 1h --read-data
CHECK_RES=$?
if [ $CHECK_RES -ne 0 ]; then
echo "Error: Check was not successful, exiting here, not pruning!"
exit 1
fi
echo "End of successful check at $(date). Duration: $SECONDS seconds."
SECONDS=0
echo "Start of pruning at $(date)."
restic --verbose=${VERBOSITY} prune --repack-small
echo "End of pruning at $(date). Duration: $SECONDS seconds."
fi
echo "########## STOP - $(date) ##########"
Afterwards, make it executable:
chmod +x /usr/local/bin/restic_backup.sh
Note the following assumes we will call the restic-backup@.service once every day via a timer (created below), which also marks snapshots for forgetting, but never prunes, as this might destroy data e.g. in case of bad RAM or otherwise corrupted backups.
For that, there is restic-check-and-prune@.service which can be one-shotted manually when there is a stable connection. This will likely not be used on the road with a laptop, as it reads back all data before pruning. Make sure to check the logs when running this.
Now, create the timer for the backup, i.e. /etc/systemd/system/restic-backup@.timer:
[Unit]
Description=restic daily backup
[Timer]
OnCalendar=*-*-* 23:15:00
AccuracySec=5min
Persistent=true
[Install]
WantedBy=multi-user.target
Enable things:
systemctl daemon-reload
systemctl enable --now restic-backup@root.timer
systemctl enable --now restic-backup@home.timer
You may want to trigger the service units manually for the initial backup.
Set up user environment
Set up shell
yay zsh
chsh
Choose /usr/bin/zsh.
Then, install oh-my-zsh (see (upstream docs)[https://ohmyz.sh/#install]).
FIXME: May want to adjust theme and plugins and such!
Keep extended ZSH history
Create ~/.oh-my-zsh/custom/history.zsh with content:
HISTFILE=~/.histfile
HISTSIZE=2000000
SAVEHIST=2000000
## Extended history.
## Instead of just a list of commands, append it with this:
## `:<beginning time since epoch>:<elapsed seconds>:<command>'.
setopt extended_history
You may want to save ZSH history periodically, e.g. via Syncthing, useful for easier recovery or to search through history from other machines you use.
Run crontab -e as user, and add a line like:
*/30 * * * * cp -a /home/olifre/.histfile /home/olifre/Sync/Sync/ZSH-History/histfile-myhostname
Set up ssh-agent
systemctl enable --user ssh-agent
Edit ~/.zshrc, set:
export SSH_AUTH_SOCK=$XDG_RUNTIME_DIR/ssh-agent.socket
Also, edit ~/.config/plasma-workspace/env/ssh-agent.sh (may need to create directory) and add the same line.
Re-login after this.
WireGuard VPN
yay wireguard-tools
nmcli conn import type wireguard file somefilewithoutspaces.conf
Note that you may want to adapt the config in NetworkManager graphically afterwards, as VPNs imported this way are autoconnect / always-on by default.
Regular system maintenance
Installing updates and purging things
yay
yay -Qtdq | yay -Rns -
The last line will for example remove build-only dependencies.
Prune old Restic backups
As outlined in Set up Backup: Restic, you should regularly run the following (when there is a good and stable connection, as this will read back all data):
systemctl start restic-check-and-prune@root.service
systemctl start restic-check-and-prune@home.service
Check logs after this!