uechi.io/source/_posts/2021/installing-arch-linux.md

1589 lines
42 KiB
Markdown
Raw Permalink Normal View History

2021-01-21 21:45:05 +09:00
---
2022-12-24 03:20:02 +09:00
title: Installing Arch Linux on Bare-metal Server
2021-02-25 22:36:19 +09:00
date: 2021-02-12T00:00:00
2021-01-21 21:45:05 +09:00
---
2022-12-24 03:20:02 +09:00
This is all the commands I typed when I set up Arch Linux on my new compute server.
2021-01-21 21:45:05 +09:00
2022-12-24 03:20:02 +09:00
> PSA[1]: I published a toolchain for creating/testing PKGBUILD in a clean-room Docker container
2021-12-14 17:13:26 +09:00
> <https://github.com/uetchy/archpkgs>
2021-01-21 21:45:05 +09:00
2022-12-24 03:20:02 +09:00
> PSA[2]: Also published [cfddns](https://github.com/uetchy/cfddns) ([AUR](https://aur.archlinux.org/packages/cfddns)), a Cloudflare DDNS client written in Rust.
# Table of Contents
<!-- toc -->
# Goals
- /dev/sda - NVMe M.2 SSD
- /dev/sda1 - EFI system partition mounted on /boot (systemd-boot)
- /dev/sda2 - LUKS partition contains Btrfs subvolumes
- @ -> /
- @home -> /home
- @srv -> /srv
- Docker stacks directory (nginx-proxy, Mail, Nextcloud, Minio, JupyterHub, Weights & Biases, etc)
- @log -> /var/log
- @cache -> /var/cache
- /dev/sdb - HDD for data vault
- /dev/sdb1 - LUKS partition contains Btrfs mounted on /mnt/vault
- /dev/sdc - HDD for backups
- /dev/sdc1 - Btrfs mounted on /mnt/backups
- /dev/sde - SSD for analytical database (intensive write-ops)
- /dev/sde1 - XFS mounted on /mnt/analytics
Why XFS for analytical database storage? Refer to [Production Notes — MongoDB Manual](https://www.mongodb.com/docs/manual/administration/production-notes/#kernel-and-file-systems) and [Configure Scylla | Scylla Docs](https://docs.scylladb.com/stable/getting-started/system-configuration.html#set-up-raid-and-filesystem).
2021-06-06 21:56:40 +09:00
# Setup
2021-01-21 21:45:05 +09:00
2022-12-24 03:20:02 +09:00
## Wipe a disk
2021-01-21 21:45:05 +09:00
```bash
2022-12-24 03:20:02 +09:00
# Erase file-system magic strings (insecure but super fast, suitable when reusing a disk)
wipefs -a /dev/sdN
2022-02-05 13:41:25 +09:00
# or
2022-12-24 03:20:02 +09:00
# Write (random then zeroes) to the device (takes longer but more secure, suitable when selling a disk)
shred -v -n 1 -z /dev/sdN
2021-01-21 21:45:05 +09:00
```
2022-02-05 13:41:25 +09:00
## Create partitions
2021-01-21 21:45:05 +09:00
2022-12-24 03:20:02 +09:00
This command will calculate optimal sector alignments correctly. You can confirm it by running `sfdisk -d /dev/sda`.
2021-01-21 21:45:05 +09:00
2021-06-11 15:15:02 +09:00
```bash
2022-12-24 03:20:02 +09:00
# Overwrite new GPT
sgdisk -og /dev/sda
2021-01-21 21:45:05 +09:00
2022-12-24 03:20:02 +09:00
# Create 1GiB EFI system partition
sgdisk -n 1:0:+1G -c 1:boot -t 1:ef00 /dev/sda
2022-05-20 13:18:51 +09:00
2022-12-24 03:20:02 +09:00
# Fill the rest with a LUKS partition
sgdisk -n 2:0:0 -c 2:crypt -t 2:8308 /dev/sda
2022-03-04 15:03:48 +09:00
2022-12-24 03:20:02 +09:00
# Data disks
sgdisk -og /dev/sdb
sgdisk -n 1:0:0 -c 1:vault -t 1:8308 /dev/sdb # LUKS
2021-01-21 21:45:05 +09:00
2022-12-24 03:20:02 +09:00
sgdisk -og /dev/sdc
sgdisk -n 1:0:0 -c 1:backups /dev/sdb
sgdisk -og /dev/sde
sgdisk -n 1:0:0 -c 1:analytics /dev/sdb
# Verify the result
sgdisk -p /dev/sdN
2021-01-21 21:45:05 +09:00
```
2022-12-24 03:20:02 +09:00
> NOTE: Since my server has 128GB of physical memory, I would rather let OOM Killer do its job than creating a swap partition.
> Should the need for swap comes up later, consider swap file (no perf difference in general)
- [GPT fdisk - ArchWiki](https://wiki.archlinux.org/title/GPT_fdisk)
- [Swap file - ArchWiki](https://wiki.archlinux.org/title/Swap#Swap_file)
- [Swap file - Btrfs - ArchWiki](https://wiki.archlinux.org/title/btrfs#Swap_file)
## Write file systems
2021-01-21 21:45:05 +09:00
```bash
2022-12-24 03:20:02 +09:00
# VFAT32 ESP
mkfs.vfat -F 32 -n ESP /dev/sda1
# LUKS2
cryptsetup luksFormat /dev/sda2
cryptsetup \
--allow-discards \
--perf-no_read_workqueue \
--perf-no_write_workqueue \
--persistent \
open /dev/sda2 crypt
cryptsetup luksFormat /dev/sdb1
cryptsetup open /dev/sdb1 vault
# Verify the LUKS devices
cryptsetup luksDump /dev/sdN # Dump LUKS2 header
dmsetup table # Show flags for the currently opened devices
# Also, backup the LUKS headers to safe storage
cryptsetup luksHeaderBackup /dev/sdN --header-backup-file /path/to/luks_header_sdN
# Btrfs for root partition
mkfs.btrfs -L crypt /dev/mapper/crypt
mount /dev/mapper/crypt /mnt # Temporary mounted to create subvolumes
# btrfs [su]bvolume [cr]eate
btrfs su cr /mnt/@
btrfs su cr /mnt/@home
btrfs su cr /mnt/@cache
btrfs su cr /mnt/@log
btrfs su cr /mnt/@srv # Home for Docker Compose stacks
btrfs su set-default 256 /mnt # Required for remote unlocking
umount /mnt
# Btrfs
mkfs.btrfs -L vault /dev/mapper/vault
mkfs.btrfs -L backups /dev/sdc1
# XFS
mkfs.xfs -L analytics /dev/sde1
2021-01-21 21:45:05 +09:00
```
2022-12-24 03:20:02 +09:00
See [Discard/TRIM support for solid state drives (SSD) - Dm-crypt - ArchWiki](<https://wiki.archlinux.org/title/Dm-crypt/Specialties#Discard/TRIM_support_for_solid_state_drives_(SSD)>) for the reasoning behind these `cryptsetup` flags.
- [User:I2Oc9/Btrfs subvolumes - ArchWiki](https://wiki.archlinux.org/title/User:I2Oc9/Btrfs_subvolumes)
## Mount partitions
2021-01-21 21:45:05 +09:00
```bash
2022-12-24 03:20:02 +09:00
# Root partition
mount /dev/mapper/crypt /mnt
mount -m -o subvol=@home /dev/mapper/crypt /mnt/home
mount -m -o subvol=@cache /dev/mapper/crypt /mnt/var/cache
mount -m -o subvol=@log /dev/mapper/crypt /mnt/var/log
mount -m -o subvol=@srv /dev/mapper/crypt /mnt/srv
# EFI system partition
mount -m /dev/sda1 /mnt/boot
# Extra disks
mount -m /dev/mapper/vault /mnt/mnt/vault
mount -m /dev/sde1 /mnt/mnt/analytics
mount -m /dev/sdc1 /mnt/mnt/backups
2021-01-21 21:45:05 +09:00
```
2022-12-24 03:20:02 +09:00
## Install Linux kernel
2022-02-05 13:41:25 +09:00
2021-01-21 21:45:05 +09:00
```bash
2022-12-24 03:20:02 +09:00
# This is necessary for older Arch ISO image
pacman -Sy archlinux-keyring
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
# Choose between 'linux-lts' and 'linux'
pacstrap /mnt base linux-lts linux-firmware \
btrfs-progs xfsprogs vim man-db man-pages
2021-07-28 15:22:05 +09:00
```
2022-12-24 03:20:02 +09:00
## Generate fstab
2021-07-28 15:22:05 +09:00
```bash
2022-12-24 03:20:02 +09:00
# Generate fstab based on current /mnt structure
genfstab -U /mnt >> /mnt/etc/fstab
2021-07-28 15:22:05 +09:00
```
2022-12-24 03:20:02 +09:00
## Tweak pacman
2022-02-05 13:41:25 +09:00
```bash
2022-12-24 03:20:02 +09:00
# Optimize mirrorlist (replace `country` params with your nearest countries)
pacman -S --needed pacman-contrib
curl -s 'https://archlinux.org/mirrorlist/?use_mirror_status=on&protocol=https&country=JP&country=KR&country=HK' | sed -e 's/#//' -e '/#/d' | rankmirrors -n 10 - > /mnt/etc/pacman.d/mirrorlist
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
# Colorize output
sed '/#Color/a Color' -i /mnt/etc/pacman.conf
# Parallel downloads
sed '/#ParallelDownloads/a ParallelDownloads = 5' -i /mnt/etc/pacman.conf
# ILoveCandy
sed '/# Misc/a ILoveCandy' -i /mnt/etc/pacman.conf
2022-02-05 13:41:25 +09:00
```
2021-06-08 16:50:58 +09:00
2022-12-24 03:20:02 +09:00
## Chroot into the installation
2021-06-08 16:50:58 +09:00
2022-12-24 03:20:02 +09:00
```bash
# Chroot
arch-chroot /mnt
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
# Change root password
passwd
2021-06-08 16:50:58 +09:00
```
2022-12-24 03:20:02 +09:00
## Finish structuring file systems
2021-06-08 16:50:58 +09:00
```bash
2022-12-24 03:20:02 +09:00
# Verify fstab entries
findmnt --verify --verbose
2021-06-08 16:50:58 +09:00
```
2022-12-24 03:20:02 +09:00
### crypttab
2021-01-21 21:45:05 +09:00
```bash
2022-12-24 03:20:02 +09:00
echo "crypt UUID=$(blkid /dev/sda2 -s UUID -o value) none luks" >> /etc/crypttab
echo "vault UUID=$(blkid /dev/sdb1 -s UUID -o value) none luks" >> /etc/crypttab
2021-06-06 21:56:40 +09:00
2022-12-24 03:20:02 +09:00
cat /etc/crypttab
2021-01-21 21:45:05 +09:00
```
2022-12-24 03:20:02 +09:00
### Remote unlocking
2022-02-05 13:41:25 +09:00
```bash
2022-12-24 03:20:02 +09:00
pacman -S --needed mkinitcpio-systemd-tool openssh cryptsetup tinyssh busybox mc python3
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
# crypttab for initramfs
echo "crypt UUID=$(blkid /dev/sda2 -s UUID -o value) none luks" >> /etc/mkinitcpio-systemd-tool/config/crypttab
# [!] Add every other device whose password is different from `crypt` device
# to make sure that all the passwords will be asked during the remote unlocking
2021-01-21 21:45:05 +09:00
2022-12-24 03:20:02 +09:00
# fstab for initramfs
echo "UUID=$(blkid /dev/mapper/crypt -s UUID -o value) /sysroot auto x-systemd.device-timeout=9999h 0 1" >> /etc/mkinitcpio-systemd-tool/config/fstab
2021-01-21 21:45:05 +09:00
2022-12-24 03:20:02 +09:00
# Append 'systemd systemd-tool' to and remove 'udev' from mkinitcpio HOOKS
sed -r '/^HOOKS=/s/^/#/' -i /etc/mkinitcpio.conf
sed -r '/^#HOOKS=/a HOOKS=(base autodetect modconf block filesystems keyboard fsck systemd systemd-tool)' -i /etc/mkinitcpio.conf
2021-01-21 21:45:05 +09:00
2022-12-24 03:20:02 +09:00
# Change SSH port
mkdir -p /etc/systemd/system/initrd-tinysshd.service.d
cat > /etc/systemd/system/initrd-tinysshd.service.d/override.conf <<EOD
[Service]
Environment=
Environment=SSHD_PORT=12345
EOD
# Assign static IP because we are behind NAT
cat > /etc/mkinitcpio-systemd-tool/network/initrd-network.network <<EOD
2021-01-21 21:45:05 +09:00
[Match]
2022-12-24 03:20:02 +09:00
# [!] use kernel interface name, not udev name
Name=eth0
2021-01-21 21:45:05 +09:00
[Network]
2022-12-24 03:20:02 +09:00
Address=10.0.1.2
2021-01-21 21:45:05 +09:00
Gateway=10.0.1.1
2022-12-24 03:20:02 +09:00
DNS=9.9.9.9
EOD
2021-01-21 21:45:05 +09:00
2022-12-24 03:20:02 +09:00
# Enable required services
systemctl enable initrd-cryptsetup.path
systemctl enable initrd-tinysshd
systemctl enable initrd-debug-progs
systemctl enable initrd-sysroot-mount
2021-01-21 21:45:05 +09:00
2022-12-24 03:20:02 +09:00
# Generate host SSH key pair
ssh-keygen -A
2021-01-21 21:45:05 +09:00
2022-12-24 03:20:02 +09:00
# Download SSH public keys to use ([!] tinysshd only supports ed25519)
curl -s https://github.com/<username>.keys >> /root/.ssh/authorized_keys
2021-01-21 21:45:05 +09:00
2022-12-24 03:20:02 +09:00
# Build initramfs
mkinitcpio -P
2021-01-21 21:45:05 +09:00
2022-12-24 03:20:02 +09:00
# Verify initramfs contents
lsinitcpio -l /boot/initramfs-linux-lts.img
```
2021-01-21 21:45:05 +09:00
2022-12-24 03:20:02 +09:00
- [Case: Complete BTRFS Setup (step by step)](<https://github.com/random-archer/mkinitcpio-systemd-tool/wiki/Case:-Complete-BTRFS-Setup-(step-by-step)>)
### Periodic TRIM
```bash
systemctl enable fstrim.timer
2021-01-21 21:45:05 +09:00
```
2022-12-24 03:20:02 +09:00
Run `lsblk --discard` to see the TRIM-supported devices (it does if both `DISC-GRAN` and `DISC-MAX` have non-empty values).
[Solid state drive - ArchWiki](https://wiki.archlinux.org/title/Solid_state_drive#Periodic_TRIM)
## SSH
2021-01-21 21:45:05 +09:00
```bash
2022-12-24 03:20:02 +09:00
vim /etc/ssh/sshd_config
# Change port
sed '/#Port /a Port 12345' -i /etc/ssh/sshd_config
# Limit to pubkey auth
sed '/#PasswordAuthentication /a PasswordAuthentication no' -i /etc/ssh/sshd_config
systemctl enable sshd
2021-01-21 21:45:05 +09:00
```
2022-12-24 03:20:02 +09:00
## Bootloader (systemd-boot)
Because GRUB's LUKS2 support is still limited (It does not support cryptsetup's default Argon2id yet. I've tested in a VM and confirmed it doesn't work).
In the end, I end up liking systemd-boot (formerly Gummiboot) more. It's refreshingly simple and easier to understand, doesn't this sound like Arch Linux?
2021-01-21 21:45:05 +09:00
```bash
2022-12-24 03:20:02 +09:00
# Install AMD microcode updates (pick `intel-ucode` for Intel CPU)
pacman -S amd-ucode
# Install systemd-boot on /boot
bootctl install
# Add bootloader config
cat > /boot/loader/loader.conf <<EOD
default arch-lts.conf
timeout 3
console-mode max
editor no
EOD
2021-01-21 21:45:05 +09:00
2022-12-24 03:20:02 +09:00
# Add an entry for `linux-lts` (omit -lts for `linux`)
cat > /boot/loader/entries/arch-lts.conf <<EOD
title Arch Linux (LTS)
initrd /amd-ucode.img
initrd /initramfs-linux-lts.img
linux /vmlinuz-linux-lts
options root=/dev/mapper/crypt
EOD
2021-01-21 21:45:05 +09:00
```
2022-12-24 03:20:02 +09:00
`options` are kernel params.
2021-01-21 21:45:05 +09:00
2022-12-24 03:20:02 +09:00
- [systemd-boot - ArchWiki](https://wiki.archlinux.org/title/Systemd-boot)
2022-05-20 13:18:51 +09:00
2022-12-24 03:20:02 +09:00
## Network
### systemd-networkd
```ini /etc/systemd/network/wired.network
[Match]
# `ip l` to find the right interface
Name=enp5s0
[Network]
Address=10.0.1.2/24
Gateway=10.0.1.1
MulticastDNS=yes
#DHCP=yes
```
2022-05-20 13:18:51 +09:00
2022-12-24 03:20:02 +09:00
```bash
systemctl enable systemd-networkd
```
### systemd-resolved
2021-01-21 21:45:05 +09:00
```bash
2022-12-24 03:20:02 +09:00
mkdir /etc/systemd/resolved.conf.d
cat > /etc/systemd/resolved.conf.d/dns.conf <<EOD
[Resolve]
DNS=1.1.1.1 1.0.0.1
DNSOverTLS=yes
EOD
systemctl enable systemd-resolved
2021-01-21 21:45:05 +09:00
```
2022-12-24 03:20:02 +09:00
- [ArchWiki: systemd-networkd](https://wiki.archlinux.org/title/Systemd-networkd)
- [ArchWiki: systemd-resolved](https://wiki.archlinux.org/title/Systemd-resolved)
- [systemd.network](https://systemd.network/systemd.network.html)
- [Ivan Smirnov's blog](https://blog.ivansmirnov.name/set-up-pihole-using-docker-macvlan-network/).
2022-05-20 13:18:51 +09:00
## sysctl
```bash
2022-12-24 03:20:02 +09:00
# Increase max map count for Elasticsearch on Docker
# https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html#_linux
echo "vm.max_map_count=262144" > /etc/sysctl.d/96-map-count.conf
2022-06-23 16:24:02 +09:00
2022-12-24 03:20:02 +09:00
# Increase inotify limit to avoid "too many open files"
echo "fs.inotify.max_user_watches=1048576" > /etc/sysctl.d/97-inotify.conf
# Auto reboot after 60s of kernel panic
2022-06-23 16:24:02 +09:00
echo "kernel.panic=60" > /etc/sysctl.d/98-kernel-panic.conf
2022-05-20 13:18:51 +09:00
2022-12-24 03:20:02 +09:00
# Tweak swappiness value for memory-rich servers
# https://linuxhint.com/understanding_vm_swappiness/
2022-06-23 16:24:02 +09:00
echo "vm.swappiness=10" > /etc/sysctl.d/99-swappiness.conf
2022-05-20 13:18:51 +09:00
```
2022-12-24 03:20:02 +09:00
## faillock
2021-01-21 21:45:05 +09:00
2022-12-24 03:20:02 +09:00
Change `deny` from `3` to `5`:
2022-01-17 13:42:14 +09:00
2022-12-24 03:20:02 +09:00
```
sed '/^# deny/a deny = 5' -i /etc/security/faillock.conf
2022-01-17 13:42:14 +09:00
```
2022-12-24 03:20:02 +09:00
## NVIDIA driver
2021-01-21 21:45:05 +09:00
```bash
2022-12-24 03:20:02 +09:00
# 'nvidia' for 'linux'
pacman -S nvidia-lts
2021-01-21 21:45:05 +09:00
```
2022-12-24 03:20:02 +09:00
## Create operator user
2021-01-21 21:45:05 +09:00
```bash
2022-12-24 03:20:02 +09:00
# Install ZSH and sudo
pacman -S zsh sudo
2021-01-21 21:45:05 +09:00
2022-12-24 03:20:02 +09:00
# Add operator user (op) with wheel membership
useradd -m -s /bin/zsh -G wheel op
2021-01-21 21:45:05 +09:00
2022-12-24 03:20:02 +09:00
# Change operator user password
passwd op
2021-01-21 21:45:05 +09:00
2022-12-24 03:20:02 +09:00
# Populate SSH public keys
mkdir /home/op/.ssh
curl -s https://github.com/<username>.keys >> /home/op/.ssh/authorized_keys
chown -R op:op /home/op/.ssh
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
# [!] Don't put SSH key pairs on the server. Use SSH agent forwarding instead.
2021-01-21 21:45:05 +09:00
2022-12-24 03:20:02 +09:00
# Grant wheel group sudo priv
(umask 0337; echo "%wheel ALL=(ALL) ALL" > /etc/sudoers.d/wheel)
2021-01-21 21:45:05 +09:00
2022-12-24 03:20:02 +09:00
visudo -c # Verify sudoers
userdbctl # Verify users
userdbctl group # Verify groups
2021-01-21 21:45:05 +09:00
```
2022-12-24 03:20:02 +09:00
- [Octal codes - umask - Wikipedia](https://en.wikipedia.org/wiki/Umask#Octal_codes)
## Time and locales
2022-02-05 13:41:25 +09:00
```bash
2022-12-24 03:20:02 +09:00
# Set time zone
ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
# Enable NTP
systemctl enable systemd-timesyncd
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
# Sync system time to hardware clock
hwclock --systohc
2021-10-27 15:53:06 +09:00
```
2022-12-24 03:20:02 +09:00
```bash
sed '/#en_US.UTF-8 UTF-8/s/^#//' -i /etc/locale.gen
locale-gen
echo "LANG=en_US.UTF-8" >> /etc/locale.conf
2022-01-17 13:42:14 +09:00
```
2021-10-27 15:53:06 +09:00
2022-12-24 03:20:02 +09:00
## Leave chroot and reboot
2022-01-17 13:42:14 +09:00
2022-12-24 03:20:02 +09:00
```bash
exit # leave chroot
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
# Symlink stub resolver config (non-chroot required)
ln -rsf /run/systemd/resolve/stub-resolv.conf /mnt/etc/resolv.conf
umount -R /mnt # unmount /mnt recursively
reboot
```
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
**[!] From now on, run all commands as the operator user (use sudo if necessary)**
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
## Set hostname
2021-01-21 21:45:05 +09:00
```bash
2022-12-24 03:20:02 +09:00
hostnamectl set-hostname tako
hostnamectl set-chassis server
echo "127.0.0.1 tako" >> /etc/hosts
2021-01-21 21:45:05 +09:00
```
2022-12-24 03:20:02 +09:00
- [RFC 1178: Choosing a name for your computer](https://www.rfc-editor.org/rfc/rfc1178)
- [RFC 8117: Current Hostname Practice Considered Harmful](https://www.rfc-editor.org/rfc/rfc8117.html)
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
## Check-ups
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
```bash
# Check network status
networkctl status
resolvectl status
resolvectl query uechi.io
resolvectl query -p mdns tako.local
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
# Verify time and NTP status
timedatectl status
# Verify sysctl values
sysctl --system
2022-02-05 13:41:25 +09:00
```
2022-01-17 13:42:14 +09:00
2022-12-24 03:20:02 +09:00
> If `networkctl` keeps showing `enp5s0` as `degraded`, then run `ip addr add 10.0.1.2/24 dev enp5s0` to manually assign static IP address for the workaround.
2021-12-14 17:13:26 +09:00
## S.M.A.R.T.
2021-01-21 21:45:05 +09:00
```bash
2021-07-28 15:22:05 +09:00
pacman -S smartmontools
2022-12-24 03:20:02 +09:00
# Needed for sending email
pacman -S s-nail
2022-02-05 13:41:25 +09:00
```
2022-12-24 03:20:02 +09:00
### Automated disk health check-ups and reporting
2022-02-05 13:41:25 +09:00
```ini /etc/smartd.conf
2022-12-24 03:20:02 +09:00
# Scan all but removable devices and notify any test failures
# Also, start a short self-test every day around 1-2am, and a long self test every Saturday around 3-4am
2022-02-05 13:41:25 +09:00
DEVICESCAN -a -o on -S on -n standby,q -s (S/../.././02|L/../../6/03) -m me@example.com
```
2022-12-24 03:20:02 +09:00
> Tips: Add `-M test` immediately after `DEVICESCAN` to send test mail
2022-02-05 13:41:25 +09:00
```bash
2021-07-28 15:22:05 +09:00
systemctl enable --now smartd
2022-02-05 13:41:25 +09:00
```
### Manual testing
2021-01-21 21:45:05 +09:00
2022-02-05 13:41:25 +09:00
```bash
2021-07-28 15:22:05 +09:00
smartctl -t short /dev/sda
smartctl -l selftest /dev/sda
```
2021-01-21 21:45:05 +09:00
2022-12-24 03:20:02 +09:00
- [S.M.A.R.T. - ArchWiki](https://wiki.archlinux.org/title/S.M.A.R.T.)
- [S-nail - ArchWiki](https://wiki.archlinux.org/title/S-nail)
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
## AUR Helper (yay)
2021-01-21 21:45:05 +09:00
```bash
2022-12-24 03:20:02 +09:00
pacman -S base-devel git
git clone https://aur.archlinux.org/yay.git
cd yay
makepkg -si
2021-01-21 21:45:05 +09:00
```
2021-12-14 17:13:26 +09:00
## Docker
2021-01-21 21:45:05 +09:00
```bash
pacman -S docker docker-compose
2021-05-06 13:53:02 +09:00
yay -S nvidia-container-runtime
2021-01-21 21:45:05 +09:00
```
2021-02-25 22:36:19 +09:00
```json /etc/docker/daemon.json
2021-01-21 21:45:05 +09:00
{
2022-12-24 03:20:02 +09:00
"log-driver": "json-file", // default: "json-file"
2021-01-21 21:45:05 +09:00
"log-opts": {
2021-06-06 21:56:40 +09:00
"max-size": "10m", // default: -1 (unlimited)
"max-file": "3" // default: 1
2021-01-21 21:45:05 +09:00
},
"runtimes": {
2022-12-24 03:20:02 +09:00
// for Docker Compose
2021-01-21 21:45:05 +09:00
"nvidia": {
"path": "/usr/bin/nvidia-container-runtime",
"runtimeArgs": []
}
}
}
```
```bash
2022-02-05 13:41:25 +09:00
systemctl enable --now docker
2021-01-21 21:45:05 +09:00
2022-12-24 03:20:02 +09:00
# Allow operator user to run docker command without sudo (less secure)
# Re-login for the changes to take effect
usermod -aG docker op
2021-07-28 15:22:05 +09:00
2022-12-24 03:20:02 +09:00
# Enable Swarm
docker swarm init --advertise-addr $(curl -s https://ip.seeip.org)
# Create overlay network for Swarm stack
# docker network create --attachable -d overlay --subnet 10.11.0.0/24 <network>
2021-01-21 21:45:05 +09:00
2022-12-24 03:20:02 +09:00
# Verify installation
docker run --rm --gpus all nvidia/cuda:11.7.1-cudnn8-runtime-ubuntu20.04 nvidia-smi
2021-01-21 21:45:05 +09:00
```
2022-12-24 03:20:02 +09:00
- [NVIDIA/nvidia-container-runtime: NVIDIA container runtime](https://github.com/NVIDIA/nvidia-container-runtime)
### Cross-platform build support (BuildKit, QEMU)
```bash
docker run --rm --privileged multiarch/qemu-user-static --reset --persistent yes
# Verify
docker run --rm --platform linux/arm64/v8 -t arm64v8/ubuntu uname -m # => aarch64
```
### Tips: Use `journald` log driver in Docker Compose
This is particularly useful when you want to feed container logs to fail2ban through journald.
2021-06-06 21:56:40 +09:00
```yaml
services:
web:
logging:
driver: "journald"
options:
tag: "{{.ImageName}}/{{.Name}}/{{.ID}}" # default: "{{.ID}}"
```
- [Configure logging drivers | Docker Documentation](https://docs.docker.com/config/containers/logging/configure/)
2022-01-17 13:42:14 +09:00
- [Architecture Overview — NVIDIA Cloud Native Technologies documentation](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/arch-overview.html)
2021-06-06 21:56:40 +09:00
2022-12-24 03:20:02 +09:00
## DNS resolver (Pi-hole + unbound)
2022-02-05 13:41:25 +09:00
```bash
2022-12-24 03:20:02 +09:00
git clone https://github.com/uetchy/docker-dns /srv/dns
cd /srv/dns
rm -rf .git
cp .env.example .env
vim .env
mkdir -p data/unbound
cp examples/unbound/forward-records.conf data/unbound/
vim data/unbound/forward-records.conf # see below
docker compose up -d
```
> For Quad9 resolver, I chose [ECS-enabled resolver](https://www.quad9.net/service/service-addresses-and-features/#ecssec) because their nearest [anycast](https://en.wikipedia.org/wiki/Anycast#Domain_Name_System) server from Tokyo is in another country (Singapore), which could confuse CDN server selection and result in higher latency.
>
> If your favorite DNS resolver DOES have their anycast servers near your city, you don't need ECS at all.
>
> If you are in Japan, I would recommend [IIJ Public DNS](https://public.dns.iij.jp/). They offer secure DoT/DoH resolvers (actually, they don't support "normal" unencrypted DNS queries so there's no room for the "accidental fallback to an unencrypted query in [Opportunistic TLS](https://en.wikipedia.org/wiki/Opportunistic_TLS) configuration" scenario)
```ini /etc/systemd/network/dns-shim.netdev
# workaround to route local dns lookups to Docker managed MACVLAN interface
[NetDev]
Name=dns-shim
Kind=macvlan
[MACVLAN]
Mode=bridge
2022-02-05 13:41:25 +09:00
```
2022-12-24 03:20:02 +09:00
```ini /etc/systemd/network/dns-shim.network
# workaround to route local dns lookups to Docker managed MACVLAN interface
[Match]
Name=dns-shim
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
[Network]
IPForward=yes
[Address]
Address=10.0.1.103/32
Scope=link
[Route]
Destination=10.0.1.100/30
2022-02-05 13:41:25 +09:00
```
2022-12-24 03:20:02 +09:00
```bash
cat >> /etc/systemd/network/wired.network <<EOD
# workaround to route local dns lookups to Docker managed MACVLAN interface
MACVLAN=dns-shim
EOD
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
cat > /etc/systemd/resolved.conf.d/dns.conf <<EOD
[Resolve]
DNS=10.0.1.100
EOD
```
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
> If you want to do the same thing but using `ip`:
>
> ```bash
> ip link add dns-shim link enp5s0 type macvlan mode bridge # add macvlan shim interface
> ip a add 10.0.1.103/32 dev dns-shim # assign the interface an ip address
> ip link set dns-shim up # enable the interface
> ip route add 10.0.1.100/30 dev dns-shim # route macvlan subnet (.100 - .103) to the interface
> ```
## DDNS (cfddns)
Dynamic DNS for Cloudflare.
> Star [the GitHub repository](https://github.com/uetchy/cfddns) if you like it :)
```bash
yay -S cfddns
2022-02-05 13:41:25 +09:00
```
2022-12-24 03:20:02 +09:00
```yml /etc/cfddns/cfddns.yml
token: <token>
notification:
# You'll need local mail transfer agent such as Mailu/Mailcow
enabled: true
from: cfddns@localhost
to: me@example.com
server: localhost
2022-02-05 13:41:25 +09:00
```
2022-12-24 03:20:02 +09:00
```ini /etc/cfddns/domains
example.com
dev.example.com
example.org
```
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
```
systemctl enable --now cfddns
```
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
## Reverse proxy (nginx-proxy)
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
nginx-proxy serves as an ingress gateway for port 80 and 443, as well as a TLS terminal.
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
```bash
git clone --recurse-submodules https://github.com/evertramos/nginx-proxy-automation.git /srv/proxy
cd /srv/proxy/bin
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
./fresh-start.sh --yes -e your_email@domain --skip-docker-image-check
```
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
- [nginx-proxy-automation/docs at master · evertramos/nginx-proxy-automation · GitHub](https://github.com/evertramos/nginx-proxy-automation/tree/master/docs)
## ACME CA (step-ca)
With nginx-proxy, you can generate and auto-rotate self-signed ACME certificates for private Docker containers.
```yaml /srv/ca/docker-compose.yml
version: "3"
services:
step-ca:
image: smallstep/step-ca:0.22.1
restart: unless-stopped
ports:
- "9000:9000"
environment:
DOCKER_STEPCA_INIT_NAME: ${DOCKER_STEPCA_INIT_NAME}
DOCKER_STEPCA_INIT_DNS_NAMES: ${DOCKER_STEPCA_INIT_DNS_NAMES}
volumes:
- "./data/step-ca:/home/step"
dns:
# Split horizon DNS server for private web services (also point <domain> to the server)
- 10.0.1.100
```
```ini /srv/ca/.env
DOCKER_STEPCA_INIT_NAME=MySign Root CA
DOCKER_STEPCA_INIT_DNS_NAMES=localhost,<hostname>,<domain>
2022-02-05 13:41:25 +09:00
```
2022-12-24 03:20:02 +09:00
```bash
pacman -S step-cli
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
# Start step-ca
docker compose up -d
2021-06-06 21:56:40 +09:00
2022-12-24 03:20:02 +09:00
# Show CA password
docker compose exec step-ca cat secrets/password
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
# Enable ACME module
docker compose exec step-ca step ca provisioner add acme --type ACME
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
# Download root cert and CA configuration
CA_FINGERPRINT=$(docker compose exec step-ca step certificate fingerprint certs/root_ca.crt)
step-cli ca bootstrap --ca-url https://localhost:9000 --fingerprint $CA_FINGERPRINT
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
# Test installation
step-cli certificate inspect $(step-cli path)/certs/root_ca.crt
step-cli certificate inspect https://<domain>:9000
# Install root cert system-wide
step-cli certificate install $(step-cli path)/certs/root_ca.crt
2022-02-05 13:41:25 +09:00
```
2022-12-24 03:20:02 +09:00
## Auth gateway and identity provider (Authelia)
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
Authelia acts as:
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
- OIDC identity provider (single sign-on)
- Auth gateway for some self-hosted web apps lacking user authentication
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
```yml /srv/authelia/docker-compose.yml
version: "3.9"
secrets:
JWT_SECRET:
file: ./data/authelia/secrets/JWT_SECRET
SESSION_SECRET:
file: ./data/authelia/secrets/SESSION_SECRET
STORAGE_PASSWORD:
file: ./data/authelia/secrets/STORAGE_PASSWORD
STORAGE_ENCRYPTION_KEY:
file: ./data/authelia/secrets/STORAGE_ENCRYPTION_KEY
OIDC_HMAC_SECRET:
file: ./data/authelia/secrets/OIDC_HMAC_SECRET
PRIVATE_KEY:
file: ./data/authelia/keys/private.pem
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
services:
server:
container_name: authelia
image: authelia/authelia:4
restart: unless-stopped
networks:
- default
- webproxy
secrets:
- JWT_SECRET
- SESSION_SECRET
- STORAGE_PASSWORD
- STORAGE_ENCRYPTION_KEY
- OIDC_HMAC_SECRET
- PRIVATE_KEY
environment:
AUTHELIA_JWT_SECRET_FILE: /run/secrets/JWT_SECRET
AUTHELIA_SESSION_SECRET_FILE: /run/secrets/SESSION_SECRET
AUTHELIA_STORAGE_POSTGRES_PASSWORD_FILE: /run/secrets/STORAGE_PASSWORD
AUTHELIA_STORAGE_ENCRYPTION_KEY_FILE: /run/secrets/STORAGE_ENCRYPTION_KEY
AUTHELIA_IDENTITY_PROVIDERS_OIDC_HMAC_SECRET: /run/secrets/OIDC_HMAC_SECRET
AUTHELIA_IDENTITY_PROVIDERS_OIDC_ISSUER_PRIVATE_KEY_FILE: /run/secrets/PRIVATE_KEY
VIRTUAL_PROTO: https
VIRTUAL_HOST: ${VIRTUAL_HOST}
LETSENCRYPT_HOST: ${VIRTUAL_HOST}
volumes:
- ./data/authelia/config:/config
- ${AUTHELIA_CERTS}:/certs:ro
depends_on:
- redis
- postgres
redis:
image: redis:7-alpine
restart: unless-stopped
volumes:
- ./data/redis:/data
postgres:
image: postgres:11-alpine
restart: unless-stopped
secrets:
- STORAGE_PASSWORD
environment:
POSTGRES_USER: authelia
POSTGRES_PASSWORD_FILE: /run/secrets/STORAGE_PASSWORD
POSTGRES_DB: authelia
volumes:
- ./data/postgres:/var/lib/postgresql/data
networks:
webproxy:
external: true
```
```ini /srv/authelia/.env
VIRTUAL_HOST=auth.example.com
# Use nginx-proxy managed TLS cert
AUTHELIA_CERTS=/srv/proxy/data/certs/auth.example.com
```
## Mail server (Mailu)
See [Setup a new Mailu server — Mailu, Docker based mail server](https://mailu.io/1.9/setup.html)
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
## Nextcloud
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
```bash
git clone https://github.com/uetchy/docker-nextcloud.git /srv/cloud
cd /srv/cloud
cp .env.example .env
vim .env # fill the blank variables
make # pull, build, start
make applypatches # apply custom patches (run only once after the update)
2022-02-05 13:41:25 +09:00
```
2022-01-17 13:42:14 +09:00
2022-12-24 03:20:02 +09:00
## Monitor (Telegraf + InfluxDB + Grafana)
### Grafana + InfluxDB (Docker)
2022-01-17 13:42:14 +09:00
```bash
2022-12-24 03:20:02 +09:00
git clone https://github.com/uetchy/docker-monitor.git /srv/monitor
cd /srv/monitor
docker compose up -d
2022-01-17 13:42:14 +09:00
```
2022-12-24 03:20:02 +09:00
### Telegraf (Host)
```bash
yay -S telegraf
```
```ini /etc/telegraf/telegraf.conf
# Global tags can be specified here in key="value" format.
[global_tags]
# Configuration for telegraf agent
[agent]
interval = "15s"
round_interval = true
metric_batch_size = 1000
metric_buffer_limit = 10000
collection_jitter = "0s"
flush_interval = "10s"
flush_jitter = "0s"
precision = ""
hostname = "tako"
omit_hostname = false
# Read InfluxDB-formatted JSON metrics from one or more HTTP endpoints
[[outputs.influxdb]]
urls = ["http://127.0.0.1:8086"]
database = "<db>"
username = "<user>"
password = "<password>"
# Read metrics about cpu usage
[[inputs.cpu]]
percpu = true
totalcpu = true
collect_cpu_time = false
report_active = false
# Read metrics about disk usage by mount point
[[inputs.disk]]
ignore_fs = ["tmpfs", "devtmpfs", "devfs", "iso9660", "overlay", "aufs", "squashfs"]
# Read metrics about disk IO by device
[[inputs.diskio]]
# Get kernel statistics from /proc/stat
[[inputs.kernel]]
# Read metrics about memory usage
[[inputs.mem]]
# Get the number of processes and group them by status
[[inputs.processes]]
# Read metrics about system load & uptime
[[inputs.system]]
# Read metrics about network interface usage
[[inputs.net]]
interfaces = ["enp5s0"]
# Read metrics about docker containers, requires docker group membership for telegraf user
[[inputs.docker]]
endpoint = "unix:///var/run/docker.sock"
perdevice = false
total = true
[[inputs.fail2ban]]
interval = "15m"
use_sudo = true
# Pulls statistics from nvidia GPUs attached to the host
[[inputs.nvidia_smi]]
timeout = "30s"
[[inputs.http_response]]
interval = "5m"
urls = [
"https://example.com"
]
# Monitor sensors, requires lm-sensors package
[[inputs.sensors]]
interval = "60s"
remove_numbers = false
```
```ini /etc/sudoers.d/telegraf
Cmnd_Alias FAIL2BAN = /usr/bin/fail2ban-client status, /usr/bin/fail2ban-client status *
telegraf ALL=(root) NOEXEC: NOPASSWD: FAIL2BAN
Defaults!FAIL2BAN !logfile, !syslog, !pam_session
```
```bash
chmod 440 /etc/sudoers.d/telegraf
chown -R telegraf /etc/telegraf
usermod -aG docker telegraf
# Verify config
telegraf -config /etc/telegraf/telegraf.conf -test
systemctl enable --now telegraf
```
## Bruce-force attack mitigation (fail2ban)
```
pacman -S fail2ban
```
```ini /etc/fail2ban/jail.local
[DEFAULT]
ignoreip = 127.0.0.1/8 10.0.1.0/24 10.0.10.0/24
[sshd]
enabled = true
port = 12345
bantime = 1h
mode = aggressive
# https://mailu.io/1.9/faq.html?highlight=fail2ban#do-you-support-fail2ban
[mailu]
enabled = true
backend = systemd
filter = mailu
action = docker-action
findtime = 15m
maxretry = 10
bantime = 1w
[gitea]
enabled = true
backend = systemd
filter = gitea
action = docker-action
findtime = 30m
maxretry = 5
bantime = 1w
```
```ini /etc/fail2ban/filter.d/mailu.conf
[INCLUDES]
before = common.conf
[Definition]
__date = \d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}
__mailu_prefix = ^%(__prefix_line)s%(__date)s \[info\] \d+#\d+: \*\d+ client login failed:
__mailu_suffix = while in http auth state, client: <HOST>,
failregex =
%(__mailu_prefix)s "AUTH not supported" %(__mailu_suffix)s
%(__mailu_prefix)s "Authentication credentials invalid" %(__mailu_suffix)s
journalmatch = CONTAINER_NAME=mail-front-1
```
```ini /etc/fail2ban/filter.d/gitea.conf
[INCLUDES]
before = common.conf
[Definition]
failregex = ^%(__prefix_line)sDisconnected from invalid user \S+ <HOST> port \d+ \[preauth\]
journalmatch = CONTAINER_NAME=gitea
```
```ini /etc/fail2ban/action.d/docker-action.conf
[Definition]
actionstart = iptables -N f2b-bad-auth
iptables -A f2b-bad-auth -j RETURN
iptables -I DOCKER-USER -p tcp -j f2b-bad-auth
actionstop = iptables -D DOCKER-USER -p tcp -j f2b-bad-auth
iptables -F f2b-bad-auth
iptables -X f2b-bad-auth
actioncheck = iptables -n -L DOCKER-USER | grep -q 'f2b-bad-auth[ \t]'
actionban = iptables -I f2b-bad-auth 1 -s <ip> -j DROP
actionunban = iptables -D f2b-bad-auth -s <ip> -j DROP
```
```bash
# Test regex pattern or specific filter against journald logs
fail2ban-regex systemd-journal -m 'CONTAINER_NAME=gitea' ': Disconnected from invalid user .+ <HOST> port \d+ \[preauth\]'
fail2ban-regex systemd-journal -m 'CONTAINER_NAME=gitea' gitea --print-all-matched
# Test config
fail2ban-client --test
systemctl enable --now fail2ban
fail2ban-client status
```
- [Fail2ban - ArchWiki](https://wiki.archlinux.org/title/fail2ban)
- [Manual - Fail2ban](https://www.fail2ban.org/wiki/index.php/Manual)
- [Developing Filters — Fail2Ban documentation](https://fail2ban.readthedocs.io/en/latest/filters.html#developing-filter-regular-expressions)
- [Journald logging driver | Docker Documentation](https://docs.docker.com/config/containers/logging/journald/)
## Firewall (ufw)
```bash
pacman -S ufw
systemctl enable --now ufw
```
- [Uncomplicated Firewall - ArchWiki](https://wiki.archlinux.org/title/Uncomplicated_Firewall)
- [Introduction to Netfilter – To Linux and beyond !](https://home.regit.org/netfilter-en/netfilter/)
2022-02-05 13:41:25 +09:00
## VPN (WireGuard)
2022-01-17 13:42:14 +09:00
```bash
2022-02-05 13:41:25 +09:00
pacman -S wireguard-tools
# gen private key
(umask 0077; wg genkey > server.key)
# gen public key
wg pubkey < server.key > server.pub
# gen preshared key for each client
(umask 0077; wg genpsk > secret1.psk)
(umask 0077; wg genpsk > secret2.psk)
...
```
```ini /etc/wireguard/wg0.conf
[Interface]
Address = 10.0.10.1/24
2022-12-24 03:20:02 +09:00
ListenPort = 121212
2022-02-05 13:41:25 +09:00
PrivateKey = <content of server.key>
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o dns-shim -d 10.0.1.100/32 -j MASQUERADE; iptables -t nat -A POSTROUTING -o enp5s0 ! -d 10.0.1.100/32 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o dns-shim -d 10.0.1.100/32 -j MASQUERADE; iptables -t nat -D POSTROUTING -o enp5s0 ! -d 10.0.1.100/32 -j MASQUERADE
[Peer]
PublicKey = <public key>
PresharedKey = <content of secret1.psk>
AllowedIPs = 10.0.10.2/32
[Peer]
PublicKey = <public key>
PresharedKey = <content of secret2.psk>
AllowedIPs = 10.0.10.3/32
```
```bash
2022-12-24 03:20:02 +09:00
ufw allow 121212/udp # If ufw is running
2022-02-05 13:41:25 +09:00
sysctl -w net.ipv4.ip_forward=1
2022-12-24 03:20:02 +09:00
2022-02-05 13:41:25 +09:00
systemctl enable --now wg-quick@wg0
2022-01-17 13:42:14 +09:00
2022-12-24 03:20:02 +09:00
# Show active settings
wg show
```
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
- [https://wiki.archlinux.org/title/WireGuard](https://wiki.archlinux.org/title/WireGuard)
- [https://github.com/linuxserver/docker-wireguard](https://github.com/linuxserver/docker-wireguard)
- [https://philipdeljanov.com/posts/2019/03/21/setting-up-a-wireguard-vpn/](https://philipdeljanov.com/posts/2019/03/21/setting-up-a-wireguard-vpn/)
2021-01-21 21:45:05 +09:00
2022-12-24 03:20:02 +09:00
## Backup (restic)
2021-06-11 15:15:02 +09:00
2022-12-24 03:20:02 +09:00
```bash
pacman -S restic
2021-01-21 21:45:05 +09:00
```
2022-12-24 03:20:02 +09:00
```ini /etc/restic/systemd/restic.service
[Unit]
Description=Daily Backup Service
2021-01-21 21:45:05 +09:00
2022-12-24 03:20:02 +09:00
[Service]
Nice=19
IOSchedulingClass=idle
KillSignal=SIGINT
ExecStart=/etc/restic/cmd/run
2021-01-21 21:45:05 +09:00
```
2022-12-24 03:20:02 +09:00
```ini /etc/restic/systemd/restic.timer
[Unit]
Description=Daily Backup Timer
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
[Timer]
OnCalendar=*-*-* 0,6,12,18:0:0
RandomizedDelaySec=15min
Persistent=true
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
[Install]
WantedBy=timers.target
```
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
```bash /etc/restic/cmd/config
export RESTIC_REPOSITORY=/mnt/backups/restic
export RESTIC_PASSWORD_FILE=/etc/restic/key # a file contains password
export RESTIC_CACHE_DIR=/var/cache/restic
export RESTIC_PROGRESS_FPS=1
```
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
```bash /etc/restic/cmd/run
#!/bin/bash -ue
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
# https://restic.readthedocs.io/en/latest/040_backup.html#
2021-01-21 21:45:05 +09:00
2022-12-24 03:20:02 +09:00
DIR=$(dirname "$(readlink -f "$0")")
source "$DIR/config"
2021-01-21 21:45:05 +09:00
2022-12-24 03:20:02 +09:00
date
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
# system
echo "> system"
restic backup --tag system -v \
--one-file-system \
--exclude .cache \
--exclude .vscode-server \
--exclude TabNine \
--exclude /swapfile \
--exclude "/lost+found" \
--exclude "/var/lib/docker/overlay2/*" \
/ /boot /home /srv
# vault
echo "> vault"
restic backup --tag vault -v \
--one-file-system \
--exclude 'appdata_*/preview' \
--exclude 'appdata_*/dav-photocache' \
/mnt/vault
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
echo "! prune"
restic forget --prune --group-by tags \
--keep-last 4 \
--keep-within-daily 7d \
--keep-within-weekly 1m \
--keep-within-monthly 3m
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
echo "! check"
restic check
2022-02-05 13:41:25 +09:00
```
2022-12-24 03:20:02 +09:00
```bash /etc/restic/cmd/show
#!/bin/bash -ue
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
DIR=$(dirname "$(readlink -f "$0")")
source "$DIR/config"
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
TAG=${TAG:-system}
ID=$(restic snapshots --tag $TAG --json | jq -r ".[] | [.time, .short_id] | @tsv" | fzy | awk '{print $2}')
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
TARGET=${1:-$(pwd)}
MODE="ls -l"
if [[ -f $TARGET ]]; then
TARGET=$(realpath ${TARGET})
MODE=dump
fi
>&2 echo "Command: restic ${MODE} ${ID} ${TARGET}"
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
restic $MODE $ID ${TARGET}
2022-02-05 13:41:25 +09:00
```
2022-12-24 03:20:02 +09:00
```bash /etc/restic/cmd/restore
#!/bin/bash -ue
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
# https://restic.readthedocs.io/en/latest/050_restore.html
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
DIR=$(dirname "$(readlink -f "$0")")
source "$DIR/config"
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
TARGET=${1:?Specify TARGET}
TARGET=$(realpath ${TARGET})
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
TAG=$(restic snapshots --json | jq -r '[.[].tags[0]]|unique|.[]' | fzy)
ID=$(restic snapshots --tag $TAG --json | jq -r ".[] | [.time, .short_id] | @tsv" | fzy | awk '{print $2}')
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
>&2 echo "Command: restic restore ${ID} -i ${TARGET} -t /"
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
read -p "Press enter to continue"
restic restore $ID -i ${TARGET} -t /
```
2021-07-28 15:22:05 +09:00
```bash
2022-12-24 03:20:02 +09:00
(umask 0377; echo -n "<password>" > /etc/restic/key)
chmod 700 /etc/restic/cmd/config
ln -sf /etc/restic/systemd/restic.{service,timer} /etc/systemd/system/
systemctl enable --now restic.timer
systemctl status restic.timer
systemctl status restic
2021-07-28 15:22:05 +09:00
```
2022-12-24 03:20:02 +09:00
- [Restic Documentation — restic 0.12.1 documentation](https://restic.readthedocs.io/en/stable/)
2021-07-28 15:22:05 +09:00
2022-12-24 03:20:02 +09:00
# Miscellaneous stuff
2021-07-28 15:22:05 +09:00
2022-12-24 03:20:02 +09:00
## Kubernetes
2021-07-28 15:22:05 +09:00
2022-12-24 03:20:02 +09:00
```bash
pacman -S minikube
2021-07-28 15:22:05 +09:00
2022-12-24 03:20:02 +09:00
# see https://github.com/kubernetes/minikube/issues/4172#issuecomment-1267069635
# for the reason having `--kubernetes-version=v1.23.1`
minikube start \
--driver=docker \
--cpus=max \
--disable-metrics=true \
--subnet=10.100.0.0/16 \
--kubernetes-version=v1.23.1
2021-07-28 15:22:05 +09:00
2022-12-24 03:20:02 +09:00
alias kubectl="minikube kubectl --"
2021-07-28 15:22:05 +09:00
2022-12-24 03:20:02 +09:00
# Allow the control plane to allocate pods to itself
kubectl taint nodes --all node-role.kubernetes.io/control-plane:NoSchedule-
2021-07-28 15:22:05 +09:00
2022-12-24 03:20:02 +09:00
# NGINX Ingress
minikube addons enable ingress
minikube service list
2021-07-28 15:22:05 +09:00
2022-12-24 03:20:02 +09:00
# Verify
docker network inspect minikube
minikube ip # => should be 10.100.0.2
kubectl cluster-info
kubectl get cm -n kube-system kubeadm-config -o json | jq .data.ClusterConfiguration -r | yq
kubectl get nodes
kubectl get po -A
2021-07-28 15:22:05 +09:00
2022-12-24 03:20:02 +09:00
# Hello world
kubectl create deployment web --image=gcr.io/google-samples/hello-app:1.0
kubectl expose deployment web --type=NodePort --port=8080
kubectl get service web
curl $(minikube service web --url)
2021-07-28 15:22:05 +09:00
2022-12-24 03:20:02 +09:00
# Hello world through ingress
kubectl apply -f https://k8s.io/examples/service/networking/example-ingress.yaml
kubectl get ingress
curl -H "Host: hello-world.info" http://$(minikube ip)
```
2021-07-28 15:22:05 +09:00
2022-12-24 03:20:02 +09:00
- [Kubernetes - ArchWiki](https://wiki.archlinux.org/index.php/Kubernetes)
- [docker | minikube](https://minikube.sigs.k8s.io/docs/drivers/docker/)
- [Set up Ingress on Minikube with the NGINX Ingress Controller | Kubernetes](https://kubernetes.io/docs/tasks/access-application-cluster/ingress-minikube/)
2021-07-28 15:22:05 +09:00
2022-12-24 03:20:02 +09:00
## Install useful tools
2021-07-28 15:22:05 +09:00
2022-12-24 03:20:02 +09:00
```bash
# Tips: to find packages that provide specific command, say `pygmentize`:
pacman -Fy pygmentize # => python-pygments
2021-07-28 15:22:05 +09:00
2022-12-24 03:20:02 +09:00
yay -S --needed htop mosh tmux direnv ncdu fx jq yq fd ripgrep exa bat fzy peco fastmod rsync \
antibody-bin hub lazygit git-lfs git-delta difftastic ghq-bin ghq-gst iperf gptfdisk lsof lshw lostfiles \
ffmpeg yt-dlp prettier age gum pyenv neofetch pqrs tea
```
2021-07-28 15:22:05 +09:00
2022-12-24 03:20:02 +09:00
## Make SSH forwarding work with tmux + sudo
```bash /home/op/.ssh/rc
if [ ! -S ~/.ssh/ssh_auth_sock ] && [ -S "$SSH_AUTH_SOCK" ]; then
ln -sf $SSH_AUTH_SOCK ~/.ssh/ssh_auth_sock
fi
2021-07-28 15:22:05 +09:00
```
2022-12-24 03:20:02 +09:00
```bash /home/op/.tmux.conf
set -g update-environment -r
setenv -g SSH_AUTH_SOCK $HOME/.ssh/ssh_auth_sock
2021-07-28 15:22:05 +09:00
```
```bash
2022-12-24 03:20:02 +09:00
(umask 0337; echo "Defaults env_keep += SSH_AUTH_SOCK" > /etc/sudoers.d/ssh)
2021-07-28 15:22:05 +09:00
```
2022-12-24 03:20:02 +09:00
See also: [Happy ssh agent forwarding for tmux/screen · Reboot and Shine](https://werat.dev/blog/happy-ssh-agent-forwarding/)
## Temperature sensors
2021-01-21 21:45:05 +09:00
2021-12-14 17:13:26 +09:00
```bash
2022-12-24 03:20:02 +09:00
pacman -S lm_sensors
sensors-detect
systemctl enable --now lm_sensors
2021-12-14 17:13:26 +09:00
2022-12-24 03:20:02 +09:00
# Now you can configure htop to show the CPU temps
htop
2021-01-21 21:45:05 +09:00
```
2022-12-24 03:20:02 +09:00
- [lm_sensors - ArchWiki](https://wiki.archlinux.org/title/Lm_sensors)
2021-01-21 21:45:05 +09:00
2022-12-24 03:20:02 +09:00
## Telegram notifier
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
```bash /usr/local/bin/telegram-notifier
#!/bin/bash
BOT_TOKEN=<your bot token>
CHAT_ID=<your chat id>
PAYLOAD=$(ruby -r json -e "print ({text: ARGF.to_a.join, chat_id: $CHAT_ID}).to_json" </dev/stdin)
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
OK=$(curl -s -X "POST" \
-H "Content-Type: application/json; charset=utf-8" \
-d "$PAYLOAD" \
https://api.telegram.org/bot${BOT_TOKEN}/sendMessage | jq .ok)
2022-02-05 13:41:25 +09:00
2022-12-24 03:20:02 +09:00
if [[ $OK == true ]]; then
exit 0
else
exit 1
fi
```
2022-02-05 13:41:25 +09:00
2021-12-14 17:13:26 +09:00
## Audio
2021-01-21 21:45:05 +09:00
```bash
2022-02-05 13:41:25 +09:00
pacman -S alsa-utils # may require rebooting system
2021-06-06 21:56:40 +09:00
2022-12-24 03:20:02 +09:00
# Grant op user audio priv
usermod -aG audio op
# List devices as root
2021-06-06 21:56:40 +09:00
aplay -l
arecord -L
cat /proc/asound/cards
2022-12-24 03:20:02 +09:00
# Test speaker
2021-06-06 21:56:40 +09:00
speaker-test -c2
2022-12-24 03:20:02 +09:00
# Test mic
2021-06-06 21:56:40 +09:00
arecord -vv -Dhw:2,0 -fS32_LE mic.wav
aplay mic.wav
2022-12-24 03:20:02 +09:00
# GUI mixer
2021-06-06 21:56:40 +09:00
alsamixer
2022-12-24 03:20:02 +09:00
# For Mycroft.ai
2021-06-06 21:56:40 +09:00
pacman -S pulseaudio pulsemixer
pulseaudio --start
pacmd list-cards
```
```conf /etc/pulse/default.pa
# INPUT/RECORD
load-module module-alsa-source device="default" tsched=1
# OUTPUT/PLAYBACK
load-module module-alsa-sink device="default" tsched=1
# Accept clients -- very important
load-module module-native-protocol-unix
load-module module-native-protocol-tcp
2021-02-25 22:36:19 +09:00
```
2021-01-21 21:45:05 +09:00
2021-02-25 22:36:19 +09:00
```conf /etc/asound.conf
2021-06-06 21:56:40 +09:00
pcm.mic {
2021-01-21 21:45:05 +09:00
type hw
card M96k
rate 44100
format S32_LE
}
2021-06-06 21:56:40 +09:00
pcm.speaker {
2021-01-21 21:45:05 +09:00
type plug
2021-06-06 21:56:40 +09:00
slave {
pcm "hw:1,0"
}
2021-01-21 21:45:05 +09:00
}
2021-06-06 21:56:40 +09:00
pcm.!default {
type asym
capture.pcm "mic"
playback.pcm "speaker"
}
#defaults.pcm.card 1
#defaults.ctl.card 1
2021-01-21 21:45:05 +09:00
```
2021-06-06 21:56:40 +09:00
- [PulseAudio as a minimal unintrusive dumb pipe to ALSA](https://wiki.archlinux.org/title/PulseAudio/Examples#PulseAudio_as_a_minimal_unintrusive_dumb_pipe_to_ALSA)
2021-01-21 21:45:05 +09:00
- [SoundcardTesting - AlsaProject](https://www.alsa-project.org/main/index.php/SoundcardTesting)
- [Advanced Linux Sound Architecture/Troubleshooting - ArchWiki](https://wiki.archlinux.org/index.php/Advanced_Linux_Sound_Architecture/Troubleshooting#Microphone)
- [ALSA project - the C library reference: PCM (digital audio) plugins](https://www.alsa-project.org/alsa-doc/alsa-lib/pcm_plugins.html)
2021-06-06 21:56:40 +09:00
- [Asoundrc - AlsaProject](https://www.alsa-project.org/wiki/Asoundrc)
2021-01-21 21:45:05 +09:00
# Maintenance
2021-12-14 17:13:26 +09:00
## Quick checkups
2021-06-06 21:56:40 +09:00
2021-01-21 21:45:05 +09:00
```bash
2021-07-28 15:22:05 +09:00
htop # show task overview
2021-06-06 21:56:40 +09:00
systemctl --failed # show failed units
free -h # show memory usage
lsblk -f # show disk usage
networkctl status # show network status
userdbctl # show users
nvidia-smi # verify nvidia cards
2021-07-28 15:22:05 +09:00
ps aux | grep "defunct" # find zombie processes
2021-06-06 21:56:40 +09:00
```
2021-12-14 17:13:26 +09:00
## Delve into system logs
2021-06-06 21:56:40 +09:00
```bash
journalctl -p err -b-1 -r # show error logs from previous boot in reverse order
2021-07-28 15:22:05 +09:00
journalctl -u sshd -f # tail logs from sshd unit
journalctl --no-pager -n 25 -k # show latest 25 logs from the kernel without pager
2022-12-24 03:20:02 +09:00
journalctl --since="6 hours ago" --until "2020-07-10 15:10:00" # show logs within specific time range
2022-02-05 13:41:25 +09:00
journalctl CONTAINER_NAME=service_web_1 # show error from the docker container named 'service_web_1'
2021-07-28 15:22:05 +09:00
journalctl _PID=2434 -e # filter logs based on PID and jump to the end of the logs
2022-12-24 03:20:02 +09:00
journalctl -g 'timed out' # filter logs based on a regular expression. if the pattern is all lowercase, it will become case-insensitive mode
2021-07-28 15:22:05 +09:00
```
2022-12-24 03:20:02 +09:00
- `g` - go to the first line
- `G` - go to the last line
- `/` - search for the string
2021-07-28 15:22:05 +09:00
2021-12-14 17:13:26 +09:00
## Force overriding installation
2021-07-28 15:22:05 +09:00
```bash
pacman -S <pkg> --overwrite '*'
```
2021-12-14 17:13:26 +09:00
## Check memory modules
```bash
pacman -S lshw dmidecode
lshw -short -C memory # lists installed mems
dmidecode # shows configured clock speed
```
## File-system related issues checklist
2021-07-28 15:22:05 +09:00
```bash
2022-12-24 03:20:02 +09:00
smartctl -a /dev/sdN
# via USB bridge
smartctl -a -d sat /dev/sdN
```
### Ext4
```bash
# e2fsck with badblocks (non-destructive read-write test) and preen enabled
# [!] umount the drive before this ops
# [!] Never perform this on an unmounted LUKS partition, as it may lead to data loss
e2fsck -vcckp /dev/sdNn
```
- `-v`: Be verbose
- `-cc`: This option causes e2fsck to use badblocks(8) program to do a read-only scan of the device in order to find any bad blocks. If any bad blocks are found, they are added to the bad block inode to prevent them from being allocated to a file or directory. If this option is specified twice, then the bad block scan will be done using a non-destructive read-write test.
- `-k`: When combined with the -c option, any existing bad blocks in the bad blocks list are preserved, and any new bad blocks found by running badblocks(8) will be added to the existing bad blocks list.
- `-p`: Automatically repair ("preen") the file system. This option will cause e2fsck to automatically fix any file system problems that can be safely fixed without human intervention. If e2fsck discovers a problem which may require the system administrator to take additional corrective action, e2fsck will print a description of the problem and then exit with the value 4 logically or'ed into the exit code. This option is normally used by the system's boot scripts. It may not be specified at the same time as the -n or -y options.
2021-07-28 15:22:05 +09:00
2022-12-24 03:20:02 +09:00
### Fix broken file system headers
```bash
testdisk /dev/sdN
2021-01-21 21:45:05 +09:00
```
2021-06-06 21:56:40 +09:00
2022-02-05 13:41:25 +09:00
# Troubleshooting
2021-06-06 21:56:40 +09:00
## Longer SSH login (D-bus glitch)
```bash
systemctl restart systemd-logind
systemctl restart polkit
```
- [A comprehensive guide to fixing slow SSH logins – JRS Systems: the blog](https://jrs-s.net/2017/07/01/slow-ssh-logins/)
2022-12-24 03:20:02 +09:00
## Annoying `systemd-homed is not available` messages flooding journald logs
2021-06-06 21:56:40 +09:00
Move `pam_unix` before `pam_systemd_home`.
```ini /etc/pam.d/system-auth
#%PAM-1.0
auth required pam_faillock.so preauth
# Optionally use requisite above if you do not want to prompt for the password
# on locked accounts.
auth [success=2 default=ignore] pam_unix.so try_first_pass nullok
-auth [success=1 default=ignore] pam_systemd_home.so
auth [default=die] pam_faillock.so authfail
auth optional pam_permit.so
auth required pam_env.so
auth required pam_faillock.so authsucc
# If you drop the above call to pam_faillock.so the lock will be done also
# on non-consecutive authentication failures.
account [success=1 default=ignore] pam_unix.so
-account required pam_systemd_home.so
account optional pam_permit.so
account required pam_time.so
password [success=1 default=ignore] pam_unix.so try_first_pass nullok shadow
-password required pam_systemd_home.so
password optional pam_permit.so
session required pam_limits.so
session required pam_unix.so
session optional pam_permit.so
```
2022-12-24 03:20:02 +09:00
- [\[solved\] pam fails to find unit dbus-org.freedesktop.home1.service / Newbie Corner / Arch Linux Forums](https://bbs.archlinux.org/viewtopic.php?id=258297)
2021-06-06 21:56:40 +09:00
2022-12-24 03:20:02 +09:00
## Annoying `systemd-journald-audit` logs
2021-06-06 21:56:40 +09:00
```ini /etc/systemd/journald.conf
Audit=no
```
## Missing `/dev/nvidia-{uvm*,modeset}`
2022-02-05 13:41:25 +09:00
This usually happens right after updating the Linux kernel.
2021-06-11 15:15:02 +09:00
2021-10-11 12:24:57 +09:00
- Run `docker run --rm --gpus all --device /dev/nvidia0 --device /dev/nvidiactl --device /dev/nvidia-modeset --device /dev/nvidia-uvm --device /dev/nvidia-uvm-tools -it nvidia/cuda:10.2-cudnn7-runtime nvidia-smi` once.
2021-06-06 21:56:40 +09:00
2021-12-14 17:13:26 +09:00
## `[sudo] Incorrect password` while password is correct
```bash
faillock --reset
```
2021-06-06 21:56:40 +09:00
# Useful links
2022-12-24 03:20:02 +09:00
- [General recommendations - ArchWiki](https://wiki.archlinux.org/index.php/General_recommendations#Users_and_groups)
2021-07-28 15:22:05 +09:00
- [General troubleshooting - ArchWiki](https://wiki.archlinux.org/title/General_troubleshooting)
2022-12-24 03:20:02 +09:00
- [Security - ArchWiki](https://wiki.archlinux.org/title/Security)
- [Improving performance - ArchWiki](https://wiki.archlinux.org/index.php/Improving_performance#Know_your_system)
- [System maintenance - ArchWiki](https://wiki.archlinux.org/index.php/System_maintenance)
2021-07-28 15:22:05 +09:00
- [Stress testing - ArchWiki](https://wiki.archlinux.org/title/Stress_testing#Stressing_memory)
- [Archboot - ArchWiki](https://wiki.archlinux.org/title/Archboot)
2022-12-24 03:20:02 +09:00
- [udev - ArchWiki](https://wiki.archlinux.org/title/Udev#Debug_output)
- [Repair Broken system, system without a kernel / Forum & Wiki discussion / Arch Linux Forums](https://bbs.archlinux.org/viewtopic.php?id=18066)