Skip to content

Instantly share code, notes, and snippets.

@ptr1337
Created February 10, 2022 03:04
Show Gist options
  • Save ptr1337/dfb1a9c30bd3750afad118ccb711c100 to your computer and use it in GitHub Desktop.
Save ptr1337/dfb1a9c30bd3750afad118ccb711c100 to your computer and use it in GitHub Desktop.
My install instruction for a secure Arch Linux (sway) laptop workstation

WARNING from TellyO3 WORK IN PROGRESS

I am a novice Linux user, please take all my edits with a grain of salt. I wanted it to work a bit better for a number of reasons. The original guide was written early 2021, it is February 2022 as of now. Some of the utilities, like the original custom kernel are deprecated. Additionally some AUR repos are not up to date, as is the case with auto-cpufreq which was last updated months ago. I also included some troubleshooting tips, based on issues I encountered. Feel free to leave any suggestions or tips, it would be greatly appreciated.

My goal is also to have a more template like setup, give you the utilities you need but not anything else. Especially the first setup had a lot of extra's which were absolutely not necessary and it took me a lot of time to disect some of that from what is actually used in the setup.

  • No GDM, because I don't want its gnome dependencies if I don't use them
  • Many packages were changed or made optional
  • Xanmod-TT

I don't currently use docker, I will leave in the instructions but I cannot test it The same counts for PostgreSQL and Secure Boot.

What's Cool

  • Encrypted root partition
    • AES-256 bit cipher
    • Argon2id variant for PBKDF
    • Sha3-512 bit hash
  • rEFInd bootloader
    • With dreary theme
    • Optimal Settings (optimized for aesthetics, and boot time)
    • Boot into backups thanks to refind-btrfs
  • Optimized Settings
    • pacman.conf (optimized for aesthetics and use)
    • makepkg.conf (optimized for faster binaries)
  • Xanmod TT Linux Kernel
  • Miscellaneous
    • Udev rule for faster IO performance from NVME and SSD
    • Hooks for zsh and secureboot
    • Improved laptop battery life
      • Zram-generator
      • Btrfs
    • Automatic CPU frequency scaling depending on load
    • Improved system responsiveness in low memory situations
      • Nohang, an OOM prevention daemon
      • Prelockd, a daemon that locks memory mapped executables & shared libraries in memory to improve system responsiveness
      • Memavaild, improve responsiveness during heavy swapping
    • Zram, compressed swap in ram - Faster swap & less drive writes (longer ssd lifespan)
    • Improved security
      • Nftables Firewall
      • Apparmor
      • SSHGuard
      • Stricter Mount Options
      • Stricter File access permissions
      • Enforce a delay after a failed login attempt
      • Restricting access to kernel pointers in the proc filesystem
      • BPF hardening
      • Restrict access to kernel logs
      • Disable kexec
      • Intitialize lsm (required to set lockdown mode)
      • Disabled Unprivileged user namespace usage
      • TCP SYN cookie protection
      • Protect against tcp time-wait assassination hazards
      • Reverse path filtering (helps protect against attackers that are using IP spoofing methods to do harm)
      • Disable ICMP redirects
      • Automatic logout for vtconsole
      • Wayland (unlike x11 applications have GUI-Level isolation)
    • Cgroups V2
    • Most responsive DNS autoupdater (lower latency network connections)
    • Fastest Arch Linux mirror list autoupdater
    • Automount USB
    • All the codecs, encryption, and archive formats you could want
    • Wayland
    • Chrony for NTP (Best NTP for laptops)
    • Btrfs filesystem
      • Optimized mount settings (optimized for IO, storage, and drive lifespan)
      • Snapshots
        • On initial install
        • Pre/Post package install/uninstall/updates
        • Daily

Changelog

The following changes were made in comparsion with Th3Whit3Wolf's gist:

  • Make it easier to mount partitions with the appropriate options
  • Add subvolume prefix for multi OS support
  • Changed some packages from pacstrap (some packages were kept as optional)
  • Using Booster as initramfs generator
  • Using pipewire as jack replacement (may have issues with some audio softwares)
  • Using systemd's zram-generator instead of zram-swap
  • Using paru instead of yay

To see changes made in comparison to Sixel's gist Look at the warning at the top of the document

What this is not

  • A minimal or generic arch linux install

This guide should allow you to make an optimized, complete, secure Arch Linux install with out having to touch an editor except for when editing PKGBUILD for linux-xanmod-tt

Why NOT GDM

Because I hate the fact that it depends on a bunch of gnome stuff I don't want. And there are alternatives available now, they didn't exist or were underdeveloped at the time of writing the original guide.

Prologue

If possible you'll have much nicer experience installing arch if you ssh into the machine you want to install arch onto from another machine

In the desired arch laptop after booting up the archiso set the password.

passwd

Start the ssh daemon

systemctl start sshd.service

Connect to wifi using iwctl

iwctl

Get your IP address

ip a

Step 1 - Partitioning

Create an EFI partition (IF YOU DON'T HAVE ONE) which should be ~200-500mb and set its type to EFI

Create a main partition with the remaining space, you can leave its type as the default

cfdisk /dev/sda # replace sda with your drive
# replace with the respective partions you created
export BOOT_PARTITION=/dev/sda1
export ROOT_PARTITION=/dev/sda2

Step 2 Encrypt Partition

While this is very safe, it might take a while (10-20 sec) to unlock on weaker machines. If this concerns you, consider using weaker cryptography.

cryptsetup luksFormat --perf-no_read_workqueue --perf-no_write_workqueue --type luks2 --cipher aes-xts-plain64 --key-size 512 --iter-time 2000 --pbkdf argon2id --hash sha3-512 $ROOT_PARTITION
cryptsetup --allow-discards --perf-no_read_workqueue --perf-no_write_workqueue --persistent open $ROOT_PARTITION crypt

Step 3 - Formatting the partitions

mkfs.vfat -F32 -n "EFI" $BOOT_PARTITION
mkfs.btrfs -L Arch -f /dev/mapper/crypt

Step 4 - Create and Mount Subvolumes

Create subvolumes for root, home, snapshots, swap, the entire Btrfs file system, and for things that are not worth being snapshotted, like /var/cache, /var/abs, /var/tmp, and /srv.

mount /dev/mapper/crypt /mnt
mkdir /mnt/arch

btrfs sub create /mnt/arch/@          && \
btrfs sub create /mnt/arch/@home      && \
btrfs sub create /mnt/arch/@abs       && \
btrfs sub create /mnt/arch/@tmp       && \
btrfs sub create /mnt/arch/@srv       && \
btrfs sub create /mnt/arch/@snapshots && \
btrfs sub create /mnt/@btrfs          && \
btrfs sub create /mnt/arch/@log       && \
btrfs sub create /mnt/arch/@cache

# Extra subvolumes (not necessary)
mkdir /mnt/common
btrfs sub create /mnt/common/@devel && \
btrfs sub create /mnt/common/@games && \

# Remember to umount
umount /mnt

Set MOUNT_OPTIONS according to your drive type

export HDD_MOUNT_OPTIONS="noatime,compress-force=zstd,autodefrag" 
export SSD_MOUNT_OPTIONS="$HDD_MOUNT_OPTIONS,space_cache=v2,ssd,commit=120,discard=async"

export MOUNT_OPTIONS=$SSD_MOUNT_OPTIONS

NOTE

  • nodev - Do not interpret character or block special devices on the file system
  • nosuid - Do not allow set-user-identifier or set-group-identifier bits to take effect
  • noexec - Do not allow direct execution of any binaries on the mounted file system
  • discard=async - Freed extents are not discarded immediately, but grouped together and trimmed later by a separate worker thread, improving commit latency
  • compress-force=zstd - empirical testing on multiple mixed-use systems showed a significant improvement of about 10% disk compression from using compress-force=zstd over just compress=zstd (which also had 10% disk compression), resulting in a total effective disk space saving of 20%.
  • noatime - The noatime option is known to improve performance of the filesystem. It also disables disk writes when a file is read, prolongin the lifespan of SSDs.
  • commit - The resolution at which data are written to the filesystem is dictated by Btrfs itself and by system-wide settings. This means less writes (prolongs SSD lifespan) and better performance (multiple writes are combined into one single larger write, updates to previous writes within the commit time frame are cancelled out).
  • space_cache - Btrfs stores the free space data ondisk to make the caching of a block group much quicker.
  • autodefrag – will detect random writes into existing files and kick off background defragging. It is well suited to bdb or sqlite databases, but not virtualization images or big databases (yet). Once the developers make sure it doesn’t defrag files over and over again, they’ll move this toward the default
  • ssd - tells btrfs to use SSD Specific options

Mount the subvolumes

export STRICT_MOUNT_OPTIONS="noexec,nodev,nosuid,$MOUNT_OPTIONS"

mount -o $MOUNT_OPTIONS,subvol=arch/@     /dev/mapper/crypt /mnt      && \
mkdir -p /mnt/{boot,home,var/cache,var/log,.snapshots,btrfs,var/tmp,var/abs,srv}

mount -o $MOUNT_OPTIONS,subvol=arch/@home /dev/mapper/crypt /mnt/home && \
mount -o $MOUNT_OPTIONS,subvol=arch/@srv  /dev/mapper/crypt /mnt/srv

strict_mount_targets="cache log abs tmp"
for target in $(echo $strict_mount_targets); do mount /dev/mapper/crypt -o $STRICT_MOUNT_OPTIONS,subvol=arch/@$target /mnt/var/$target; done

mount -o $MOUNT_OPTIONS,subvol=arch/@snapshots /dev/mapper/crypt /mnt/.snapshots && \
mount -o $MOUNT_OPTIONS,subvolid=5 /dev/mapper/crypt /mnt/btrfs

# Extra subvolumes
mkdir -p /mnt/media/{devel,games}
mount /dev/mapper/crypt -o $MOUNT_OPTIONS,subvol=common/@devel /mnt/media/devel
mount /dev/mapper/crypt -o $MOUNT_OPTIONS,subvol=common/@games /mnt/media/games

It's recommended if we have VMs or databases, to disable copy-on-write (COW).

mkdir -p /mnt/var/lib/{docker,machines,mysql,postgres} && \
chattr +C /mnt/var/lib/{docker,machines,mysql,postgres}

chattr +C /mnt/media/games

Mount the EFI partition

mount -o nodev,nosuid,noexec $BOOT_PARTITION /mnt/boot

Step 5 - Base System and /etc/fstab

If your ArchISO is a bit older some of the keys might not be up to date

In that case:

pacman -Sy 
pacman -S archlinux-keyring

Don't try to -Syu as it might give you errors on the ArchISO

(this is the time where you change the mirrorlist, if that's your thing) -The following assumes you have an Intel CPU & GPU

pacstrap /mnt base base-devel linux-lts linux-lts-headers booster intel-ucode        \
    zstd iwd networkmanager mesa vulkan-intel libva-mesa-driver openssh wf-recorder  \
    mesa-vdpau libvirt qemu refind rustup wl-clipboard zsh sshguard neovim nano      \
    rust-analyzer xdg-user-dirs zram-generator pigz pbzip2 snapper a52dec            \
    faac iptables-nft git faad2 flac jasper grim swayidle                            \
    libmad libmpeg2 libtheora libvorbis compsize nftables reflector tmux             \
    waybar wavpack xvidcore libde265 gstreamer gst-libav gst-plugins-bad             \
    gst-plugins-base gst-plugins-good gst-plugins-ugly gstreamer-vaapi 		     \
    sway alacritty polkit-gnome mako slurp xdg-desktop-portal-wlr           	     \
    gvfs libxv nautilus nautilus-image-converter noto-fonts btrfs-progs   	     \
    udiskie imv mpv lrzip unrar zip powertop brightnessctl linux-firmware            \
    x264 lzip xorg-xwayland apparmor lz4 wireplumber             		     \
    lzop p7zip noto-fonts-emoji ttf-font-awesome libva-utils man chrony dbus-broker  \
    lame blueman irqbalance pipewire{,-pulse,-jack,-alsa}

Optional:

  • profile-sync-daemon - Used to increase performance with some browsers
  • xf86-video-linux - Discouraged by some distros, evaluate on a case to case basis
  • hyperfine - Used to benchmark the command-line
  • flatpak - Alternative package solution
  • yadm - Yet Another Dotfiles Manager (Literally)
  • fd - Alternative to find
  • exa - Alternative to ls
  • tlp - Power saving tool, auto-cpufreq aims to succeed it and recommends not using it
  • ripgrep - Tool to search directories using RegEx, which respects your gitignore
  • bat - Cat clone with useful tools
  • skim - Fuzzy finder written in rust
  • shfmt - Shell script formatter

What is all of this?

Core

  • base base-devel git linux-firmware - Base Arch package, development tools, and drivers.
  • linux-lts linux-lts-headers - Linux kernel, I am using LTS because the main kernel is a custom kernel, it functions as a backup.
  • booster - Initial ram generator, necessary for booting.
  • intel-ucode - Microcode for intel processors, your system might not function correctly without this.
  • mesa vulkan-intel libva-mesa-driver mesa-vdpau libva-utils - Graphics drivers for intel systems, research what you need for AMD or Nvidia yourself. Nvidia has terrible Linux support and will probably not work in Wayland the software responsible for giving us a graphical interface.
  • zram-generator - Utility that creates optimized swap/ram relations.
  • snapper - Responsible for managing BTRFS snapshots.
  • refind - Bootloader, this is what starts our system. It is capable of booting many different systems including Windows if you decide to dual boot. It should automatically detect and add this if you decide to dual boot.
  • rustup rust-analyzer - Rust language utilities, it is a common language for writing utilities.
  • xdg-user-dirs xdg-desktop-portal-wlr - Adds support for the common Downloads, Desktop etc folders. Should work out of the box.
  • zsh - Alternative shell which is much cooler. Allows for better peformance and a ton of cosmetic and utilitarian modifications.
  • xorg-xwayland - Allows you to run xorg programs inside of wayland if they do not support it
  • sway - Window Manager
  • gvfs nautilus udiskie nautilus-image-converter - File manager and utilities
  • btrfs-progs - Essential for BTRFS
  • noto-fonts noto-fonts-emoji ttf-font-awesome - Fonts

Audio/Video

  • a52dec faac faad2 flac jasper libmad libmpeg2 libtheora libvorbis wavpack xvidcore libde265 gstreamer gst-libav gst-plugins-bad gst-plugins-base gst-plugins-good gst-plugins-ugly gstreamer-vaapi libxv x264 lame - Audio/Video tools
  • pipewire{,-pulse,-jack,-alsa} - Audio service

Programs/Tools

  • zstd pigz pbzip2 lrzip unrar zip lzip lz4 lzop p7zip - Compression and archiving tools
  • iwd networkmanager - Networking utilities for both wired and wireless. IWD is responsible for iwctl which we used earlier.
  • wf-recorder wl-clipboard grim slurp swayidle waybar mako - These are all addons to our desktop, wf-recorder records the desktop, wl-clipboard is a clipboard, grim and slurp are used for screenshots, swayidle is for an idle menu, waybar is a replacement for the default bar at the top of your screen, and mako is for notifications.
  • libvirt qemu - Virtual machine technology, allows for high performance virtual machines. Technically not mandatory but it is a commonly used tool and it is easier to configure it now and not worry about it later.
  • neovim nano - File editing tools, neovim is very powerful but also complex. It might be easier to use nano for small edits until you familiarize yourself with neovim.
  • compsize - Compression checker for BTRFS
  • reflector - Updates your pacman mirrorlist
  • tmux - Used for splitting the terminal and other useful things
  • wireplumber - Networking diagnostics tool
  • man - View the manual for a program
  • chrony - Time utility specialized in laptops and other devices that move around a lot
  • blueman - Bluetooth utility
  • irqbalance - Performance utility
  • imv mpv - Image viewer and audio/video player
  • powertop brightnessctl - Power and backlight utilities
  • alacritty - Terminal

Security

  • openssh sshguard - Allows for SSHing in and out of the machine, as you are probably doing right now. SSHGuard attempts to make this safer by blocking potential vulnerabilities.
  • iptables-nft nftables - Firewall utilities
  • apparmor - Security
  • polkit-gnome dbus-broker - Security essential, what commands can you run without permission?

generate the fstab

genfstab -U /mnt > /mnt/etc/fstab

Step 6 - System Configuration

Use timedatectl(1) to ensure the system clock is accurate

timedatectl set-ntp true

Export some variables to chroot environment

cat << EOF >> /mnt/env.sh
export USER=username       # Replace username with the name for your new user
export HOST=hostname       # Replace hostname with the name for your host
export TZ="Europe/London"  # Replace Europe/London with your Region/City

export ROOT_PARTITION="$ROOT_PARTITION"
EOF

Chroot into the new system

arch-chroot /mnt /bin/zsh

Source the environment

source /env.sh && rm /env.sh

Set root password & shell

passwd && \
chsh -s /bin/zsh

Set locale

echo "en_US.UTF-8 UTF-8" > /etc/locale.gen && \
locale-gen && \
echo "LANG=\"en_US.UTF-8\"" > /etc/locale.conf && \
echo "KEYMAP=us" > /etc/vconsole.conf && \
export LANG="en_US.UTF-8" && \
export LC_COLLATE="C"

Set timezone

ln -sf /usr/share/zoneinfo/$TZ /etc/localtime  && \
hwclock -uw # or hwclock --systohc --utc

Set Hostname

echo $HOST > /etc/hostname

Add user

WARNING Giving a user passwordless sudo is not safe, I put it in only for my own convenience. You may replace echo "$USER ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers && \ with echo "$USER ALL=(ALL) ALL" >> /etc/sudoers && \ to have sudo only with passwd

useradd -m -G  input,kvm,libvirt,storage,video,wheel -s /bin/zsh $USER && \
passwd $USER && \
echo "$USER ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers && \
echo "Defaults timestamp_timeout=0" >> /etc/sudoers

NOTE

  • input - Access to input devices.
  • kvm - Access to virtual machines using KVM.
  • libvirt - Members of the libvirt group have passwordless access to the RW daemon socket by default
  • storage - Used to gain access to removable drives such as USB hard drives, flash/jump drives, MP3 players; enables the user to mount storage devices.
  • video - Access to video capture devices, 2D/3D hardware acceleration, framebuffer
  • wheel - Administration group, commonly used to give privileges to perform administrative actions. It has full read access to journal files and the right to administer printers in CUPS. Can also be used to give access to the sudo and su utilities (neither uses it by default).

Set hosts

cat << EOF >> /etc/hosts
# <ip-address>	<hostname.domain.org>	<hostname>
127.0.0.1	localhost
::1		localhost
127.0.1.1	$HOST.localdomain	$HOST
EOF

Step 6 - Configure Booster.

I have run into issues running /usr/lib/booster/regenerate_images because of a too many files open error. This can be circumvented by temporarily increasing the max amount of open files.

# ONLY IF YOU HAVE THIS ERROR
ulimit -n 4096

It is also possible to do this permanently, just incase. link

cat << EOF >> /etc/booster.yaml
universal: true
compression: lz4
strip: true
modules_force_load: i915
EOF

/usr/lib/booster/regenerate_images

Step 7 - Quality of Life Improvements

Laptop Power Saving Improvements

Audio

By default, audio power saving is turned off by most drivers. It can be enabled by setting the power_save parameter; a time (in seconds) to go into idle mode.

If lspci -k | grep snd_hda_intel returns Kernel driver in use: snd_hda_intel, then run the following command to idle the audio card after one second.

echo "options snd_hda_intel power_save=1" > /etc/modprobe.d/audio_powersave.conf

Otherwise

echo "options snd_ac97_codec power_save=1" > /etc/modprobe.d/audio_powersave.conf

Wifi

Additional power saving functions of Intel wireless cards with iwlwifi driver can be enabled by passing the correct parameters to the kernel module. Making them persistent can be achieved by adding the lines below to the /etc/modprobe.d/iwlwifi.conf file.

echo "options iwlwifi power_save=1" >> /etc/modprobe.d/iwlwifi.conf

This option will probably increase your median latency:

options iwlwifi uapsd_disable=0 >> /etc/modprobe.d/iwlwifi.conf

If lsmod | grep '^iwl.vm' returns iwlmvm

echo "options iwlmvm power_scheme=3" >> /etc/modprobe.d/iwlwifi.conf

If lsmod | grep '^iwl.vm' returns iwlmvm

echo "options iwldvm force_cam=0" >> /etc/modprobe.d/iwlwifi.conf

SATA Active Link Power Management

Since Linux 4.15 there is a new setting called med_power_with_dipm that matches the behaviour of Windows IRST driver settings and should not cause data loss with recent SSD/HDD drives. The power saving can be significant, ranging from 1.0 to 1.5 Watts (when idle).

echo 'ACTION=="add", SUBSYSTEM=="scsi_host", KERNEL=="host*", ATTR{link_power_management_policy}="med_power_with_dipm"' > /etc/udev/rules.d/hd_power_save.rules

Set Network Manager iwd backend

cat << EOF >> /etc/NetworkManager/conf.d/nm.conf
[device]
wifi.backend=iwd
EOF

Preventing snapshot slowdowns

echo 'PRUNENAMES = ".snapshots"' >> /etc/updatedb.conf

Set reflector up

cat << EOF > /etc/xdg/reflector/reflector.conf
# Set the output path where the mirrorlist will be saved (--save).
--save /etc/pacman.d/mirrorlist
# Select the transfer protocol (--protocol).
--protocol https
# Use only the  most recently synchronized mirrors (--latest).
--latest 100
# Sort the mirrors by MirrorStatus score
--sort score
EOF

Update rEFInd ESP on update

cat << EOF > /etc/pacman.d/hooks/refind.hook
[Trigger]
Operation=Upgrade
Type=Package
Target=refind

[Action]
Description = Updating rEFInd on ESP
When=PostTransaction
Exec=/usr/bin/refind-install
EOF

Zsh hook

What this does is refresh the known programs if you install new programs. link

cat << EOF > /etc/pacman.d/hooks/zsh.hook
[Trigger]
Operation = Install
Operation = Upgrade
Operation = Remove
Type = Path
Target = usr/bin/*
[Action]
Depends = zsh
When = PostTransaction
Exec = /usr/bin/install -Dm644 /dev/null /var/cache/zsh/pacman
EOF

Reflector hook

cat << EOF > /etc/pacman.d/hooks/mirrorupgrade.hook
[Trigger]
Operation = Upgrade
Type = Package
Target = pacman-mirrorlist

[Action]
Description = Updating pacman-mirrorlist with reflector and removing pacnew...
When = PostTransaction
Depends = reflector
Exec = /bin/sh -c 'systemctl start reflector.service; if [ -f /etc/pacman.d/mirrorlist.pacnew ]; then rm /etc/pacman.d/mirrorlist.pacnew; fi'
EOF

Better IO Scheduler

cat << EOF > /etc/udev/rules.d/60-ioschedulers.rules
# set scheduler for NVMe
ACTION=="add|change", KERNEL=="nvme[0-9]*", ATTR{queue/scheduler}="none"
# set scheduler for SSD and eMMC
ACTION=="add|change", KERNEL=="sd[a-z]|mmcblk[0-9]*", ATTR{queue/rotational}=="0", ATTR{queue/scheduler}="mq-deadline"
# set scheduler for rotating disks
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="1", ATTR{queue/scheduler}="bfq"
EOF

Create zram

cat << EOF > /etc/systemd/zram-generator.conf
# This file is part of the zram-generator project
# https://github.com/systemd/zram-generator

# Edit the values as appropriate

# This section describes the settings for /dev/zram0.
[zram0]

# The size of the zram device, as a function of MemTotal, both in MB.
# For example, if the machine has 1 GiB, and zram-size=ram/4,
# then the zram device will have 256 MiB.
# Fractions in the range 0.1–0.5 are recommended.
#
# The default is "min(ram / 2, 4096)".
zram-size = ram / 4

# The compression algorithm to use for the zram device,
# or leave unspecified to keep the kernel default.
# compression-algorithm = lzo-rle

EOF

Optimize Makepkg

sed -i 's/^CXXFLAGS.*/CXXFLAGS="-march=native -mtune=native -O2 -pipe -fstack-protector-strong --param=ssp-buffer-size=4 -fno-plt"/' /etc/makepkg.conf && \
sed -i 's/^#RUSTFLAGS.*/RUSTFLAGS="-C opt-level=2 -C target-cpu=native"/' /etc/makepkg.conf && \
sed -i 's/^#BUILDDIR.*/BUILDDIR=\/tmp\/makepkg/' /etc/makepkg.conf && \
sed -i 's/^#MAKEFLAGS.*/MAKEFLAGS="-j$(getconf _NPROCESSORS_ONLN) --quiet"/' /etc/makepkg.conf && \
sed -i 's/^COMPRESSGZ.*/COMPRESSGZ=(pigz -c -f -n)/' /etc/makepkg.conf && \
sed -i 's/^COMPRESSBZ2.*/COMPRESSBZ2=(pbzip2 -c -f)/' /etc/makepkg.conf && \
sed -i 's/^COMPRESSXZ.*/COMPRESSXZ=(xz -T "$(getconf _NPROCESSORS_ONLN)" -c -z --best -)/' /etc/makepkg.conf && \
sed -i 's/^COMPRESSZST.*/COMPRESSZST=(zstd -c -z -q --ultra -T0 -22 -)/' /etc/makepkg.conf && \
sed -i 's/^COMPRESSLZ.*/COMPRESSLZ=(lzip -c -f)/' /etc/makepkg.conf && \
sed -i 's/^COMPRESSLRZ.*/COMPRESSLRZ=(lrzip -9 -q)/' /etc/makepkg.conf && \
sed -i 's/^COMPRESSLZO.*/COMPRESSLZO=(lzop -q --best)/' /etc/makepkg.conf && \
sed -i 's/^COMPRESSZ.*/COMPRESSZ=(compress -c -f)/' /etc/makepkg.conf && \
sed -i 's/^COMPRESSLZ4.*/COMPRESSLZ4=(lz4 -q --best)/' /etc/makepkg.conf

Pacman

sed -i 's/#UseSyslog/UseSyslog/' /etc/pacman.conf && \
sed -i 's/#Color/Color\\\nILoveCandy/' /etc/pacman.conf && \
sed -i 's/Color\\/Color/' /etc/pacman.conf && \
sed -i 's/#CheckSpace/CheckSpace/' /etc/pacman.conf

Chrony

cat <<EOF > /etc/chrony.conf
# Use public NTP servers from the pool.ntp.org project.
server 0.pool.ntp.org offline
server 1.pool.ntp.org offline
server 2.pool.ntp.org offline
server 3.pool.ntp.org offline

# Record the rate at which the system clock gains/losses time.
driftfile /etc/chrony.drift

# In first three updates step the system clock instead of slew
# if the adjustment is larger than 1 second.
makestep 1.0 3

# Enable kernel synchronization of the real-time clock (RTC).
rtcsync

rtconutc
EOF

Chrony work with Network Manager

cat << EOF > /etc/NetworkManager/dispatcher.d/10-chrony
#!/bin/sh

INTERFACE=\$1
STATUS=\$2

# Make sure we're always getting the standard response strings
LANG='C'

CHRONY=\$(which chronyc)

chrony_cmd() {
    echo "Chrony going \$1."
    exec \$CHRONY -a \$1
}

nm_connected() {
    [ "\$(nmcli -t --fields STATE g)" = 'connected' ]
}

case "\$STATUS" in
    up)
        chrony_cmd online
    ;;
    vpn-up)
        chrony_cmd online
    ;;
    down)
        # Check for active interface, take offline if none is active
        nm_connected || chrony_cmd offline
    ;;
    vpn-down)
        # Check for active interface, take offline if none is active
        nm_connected || chrony_cmd offline
    ;;
EOF
chmod +x /etc/NetworkManager/dispatcher.d/10-chrony

(OPTIONAL) Docker use IPV6 & Btrfs

pacman -S docker
mkdir /etc/docker && cat << EOF > /etc/docker/daemon.json
{
  "ipv6": true,
  "fixed-cidr-v6": "fd00::/80",
  "storage-driver": "btrfs"
}
EOF

Security & Performance

sed -i 's/^umask.*/umask\ 077/' /etc/profile && \
chmod 700 /etc/{iptables,arptables,nftables.conf} && \
echo "auth optional pam_faildelay.so delay=4000000" >> /etc/pam.d/system-login && \
echo "tcp_bbr" > /etc/modules-load.d/bbr.conf && \
echo "write-cache" > /etc/apparmor/parser.conf
cat << EOF >/etc/sysctl.d/99-sysctl-performance-tweaks.conf
# The swappiness sysctl parameter represents the kernel's preference (or avoidance) of swap space. Swappiness can have a value between 0 and 100, the default value is 60. 
# A low value causes the kernel to avoid swapping, a higher value causes the kernel to try to use swap space. Using a low value on sufficient memory is known to improve responsiveness on many systems.
vm.swappiness=10

# The value controls the tendency of the kernel to reclaim the memory which is used for caching of directory and inode objects (VFS cache). 
# Lowering it from the default value of 100 makes the kernel less inclined to reclaim VFS cache (do not set it to 0, this may produce out-of-memory conditions)
vm.vfs_cache_pressure=50

# This action will speed up your boot and shutdown, because one less module is loaded. Additionally disabling watchdog timers increases performance and lowers power consumption
# Disable NMI watchdog
#kernel.nmi_watchdog = 0

# Contains, as a percentage of total available memory that contains free pages and reclaimable
# pages, the number of pages at which a process which is generating disk writes will itself start
# writing out dirty data (Default is 20).
vm.dirty_ratio = 5

# Contains, as a percentage of total available memory that contains free pages and reclaimable
# pages, the number of pages at which the background kernel flusher threads will start writing out
# dirty data (Default is 10).
vm.dirty_background_ratio = 5

# This tunable is used to define when dirty data is old enough to be eligible for writeout by the
# kernel flusher threads.  It is expressed in 100'ths of a second.  Data which has been dirty
# in-memory for longer than this interval will be written out next time a flusher thread wakes up
# (Default is 3000).
#vm.dirty_expire_centisecs = 3000

# The kernel flusher threads will periodically wake up and write old data out to disk.  This
# tunable expresses the interval between those wakeups, in 100'ths of a second (Default is 500).
vm.dirty_writeback_centisecs = 1500

# Enable the sysctl setting kernel.unprivileged_userns_clone to allow normal users to run unprivileged containers.
kernel.unprivileged_userns_clone=1

# To hide any kernel messages from the console
kernel.printk = 3 3 3 3

# Restricting access to kernel logs
kernel.dmesg_restrict = 1

# Restricting access to kernel pointers in the proc filesystem
kernel.kptr_restrict = 2

# Disable Kexec, which allows replacing the current running kernel. 
kernel.kexec_load_disabled = 1

# Increasing the size of the receive queue.
# The received frames will be stored in this queue after taking them from the ring buffer on the network card.
# Increasing this value for high speed cards may help prevent losing packets: 
net.core.netdev_max_backlog = 16384

# Increase the maximum connections
#The upper limit on how many connections the kernel will accept (default 128): 
net.core.somaxconn = 8192

# Increase the memory dedicated to the network interfaces
# The default the Linux network stack is not configured for high speed large file transfer across WAN links (i.e. handle more network packets) and setting the correct values may save memory resources: 
net.core.rmem_default = 1048576
net.core.rmem_max = 16777216
net.core.wmem_default = 1048576
net.core.wmem_max = 16777216
net.core.optmem_max = 65536
net.ipv4.tcp_rmem = 4096 1048576 2097152
net.ipv4.tcp_wmem = 4096 65536 16777216
net.ipv4.udp_rmem_min = 8192
net.ipv4.udp_wmem_min = 8192

# Enable TCP Fast Open
# TCP Fast Open is an extension to the transmission control protocol (TCP) that helps reduce network latency
# by enabling data to be exchanged during the sender’s initial TCP SYN [3]. 
# Using the value 3 instead of the default 1 allows TCP Fast Open for both incoming and outgoing connections: 
net.ipv4.tcp_fastopen = 3

# Enable BBR
# The BBR congestion control algorithm can help achieve higher bandwidths and lower latencies for internet traffic
net.core.default_qdisc = cake
net.ipv4.tcp_congestion_control = bbr

# TCP SYN cookie protection
# Helps protect against SYN flood attacks. Only kicks in when net.ipv4.tcp_max_syn_backlog is reached: 
net.ipv4.tcp_syncookies = 1

# Protect against tcp time-wait assassination hazards, drop RST packets for sockets in the time-wait state. Not widely supported outside of Linux, but conforms to RFC: 
net.ipv4.tcp_rfc1337 = 1

# By enabling reverse path filtering, the kernel will do source validation of the packets received from all the interfaces on the machine. This can protect from attackers that are using IP spoofing methods to do harm. 
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.all.rp_filter = 1

# Disable ICMP redirects
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0

# To use the new FQ-PIE Queue Discipline (>= Linux 5.6) in systems with systemd (>= 217), will need to replace the default fq_codel. 
net.core.default_qdisc = fq_pie
EOF

Nftables Firewall

cat << EOF > /etc/nftables.conf
flush ruleset

table ip filter {
  chain DOCKER-USER {
    mark set 1
  }
}

table inet my_table {
	chain my_input {
		type filter hook input priority 0; policy drop;

		iif lo accept comment "Accept any localhost traffic"
		ct state invalid drop comment "Drop invalid connections"
		
		meta l4proto icmp icmp type echo-request limit rate over 10/second burst 4 packets drop comment "No ping floods"
		meta l4proto ipv6-icmp icmpv6 type echo-request limit rate over 10/second burst 4 packets drop comment "No ping floods"

		ct state established,related accept comment "Accept traffic originated from us"

		meta l4proto ipv6-icmp icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, mld-listener-query, mld-listener-report, mld-listener-reduction, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, ind-neighbor-solicit, ind-neighbor-advert, mld2-listener-report } accept comment "Accept ICMPv6"
		meta l4proto ipv6-icmp icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, mld-listener-query, mld-listener-report, mld-listener-reduction, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, ind-neighbor-solicit, ind-neighbor-advert, mld2-listener-report } accept comment "Accept ICMPv6"
		meta l4proto icmp icmp type { destination-unreachable, router-solicitation, router-advertisement, time-exceeded, parameter-problem } accept comment "Accept ICMP"
		ip protocol igmp accept comment "Accept IGMP"

		tcp dport ssh ct state new limit rate 15/minute accept comment "Avoid brute force on SSH"

		udp dport mdns ip6 daddr ff02::fb accept comment "Accept mDNS"
		udp dport mdns ip daddr 224.0.0.251 accept comment "Accept mDNS"

		udp sport 1900 udp dport >= 1024 ip6 saddr { fd00::/8, fe80::/10 } meta pkttype unicast limit rate 4/second burst 20 packets accept comment "Accept UPnP IGD port mapping reply"
		udp sport 1900 udp dport >= 1024 ip saddr { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16 } meta pkttype unicast limit rate 4/second burst 20 packets accept comment "Accept UPnP IGD port mapping reply"

		udp sport netbios-ns udp dport >= 1024 meta pkttype unicast ip6 saddr { fd00::/8, fe80::/10 } accept comment "Accept Samba Workgroup browsing replies"
		udp sport netbios-ns udp dport >= 1024 meta pkttype unicast ip saddr { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16 } accept comment "Accept Samba Workgroup browsing replies"

		counter comment "Count any other traffic"
	}

	chain my_forward {
		type filter hook forward priority security; policy drop;
  		mark 1 accept
		# Drop everything forwarded to that's not from docker us. We do not forward. That is routers job.
	}

	chain my_output {
		type filter hook output priority 0; policy accept;
		# Accept every outbound connection
	}

}

table inet dev {
    set blackhole {
        type ipv4_addr;
        flags dynamic, timeout;
        size 65536;
    }

    chain input {
        ct state new tcp dport 443 \
                meter flood size 128000 { ip saddr timeout 10s limit rate over 10/second } \
                add @blackhole { ip saddr timeout 1m }

        ip saddr @blackhole counter drop
    }
}
EOF

SSHGuard

cat << EOF > /etc/sshguard.conf
# Full path to backend executable (required, no default)
BACKEND="/usr/lib/sshguard/sshg-fw-nft-sets"

# Log reader command (optional, no default)
LOGREADER="LANG=C /usr/bin/journalctl -afb -p info -n1 -t sshd -t vsftpd -o cat"

# How many problematic attempts trigger a block
THRESHOLD=20
# Blocks last at least 180 seconds
BLOCK_TIME=180
# The attackers are remembered for up to 3600 seconds
DETECTION_TIME=3600

# Blacklist threshold and file name
BLACKLIST_FILE=100:/var/db/sshguard/blacklist.db

# IPv6 subnet size to block. Defaults to a single address, CIDR notation. (optional, default to 128)
IPV6_SUBNET=64
# IPv4 subnet size to block. Defaults to a single address, CIDR notation. (optional, default to 32)
IPV4_SUBNET=24
EOF

Automatic logout

cat << EOF > /etc/profile.d/shell-timeout.sh
TMOUT="\$(( 60*30 ))";
[ -z "\$DISPLAY" ] && export TMOUT;
case \$( /usr/bin/tty ) in
	/dev/tty[0-9]*) export TMOUT;;
esac
EOF

Set ZDOTDIR (this will help declutter the home directory)

cat << EOF > /etc/zsh/zshenv
export ZDOTDIR=$HOME/.config/zsh
export HISTFILE="$XDG_DATA_HOME"/zsh/history
EOF

(OPTIONAL) Setup PostgreSQL

pacman -S postgresql

su -l postgres
initdb --locale=en_US.UTF-8 -E UTF8 -D /var/lib/postgres/data && \
exit

cat << EOF > /var/lib/postgres/data/postgresql.conf
stats_temp_directory = '/run/postgresql'
EOF

Step 8 - Setup the user & configure the bootloader

Install AUR helper

su $USER
cd ~  && \
git clone https://aur.archlinux.org/paru-bin.git && \
cd paru-bin && \
makepkg -si && \
cd .. && \
sudo rm -dR paru-bin

Install bootloader

sudo refind-install

Add some user niceties while you are there

rustup default stable && \
paru --noremovemake -S  memavaild prelockd nohang-git refind-btrfs just greetd greetd-gtkgreeter
paru --noremovemake -S linux-xanmod-tt linux-xanmod-tt-headers

exit

Add auto-cpu-freq

git clone https://github.com/AdnanHodzic/auto-cpufreq.git
cd auto-cpufreq && sudo ./auto-cpufreq-installer

Add rEFInd theme

mkdir /boot/EFI/refind/themes  && \
git clone https://github.com/dheishman/refind-dreary.git /boot/EFI/refind/themes/refind-dreary-git && \
mv /boot/EFI/refind/themes/refind-dreary-git/highres /boot/EFI/refind/themes/refind-dreary && \
rm -dR /boot/EFI/refind/themes/refind-dreary-git

Configure rEFInd

sed -i 's/#resolution 3/resolution 1920 1080/' /boot/EFI/refind/refind.conf && \
sed -i 's/#use_graphics_for osx,linux/use_graphics_for linux/' /boot/EFI/refind/refind.conf && \
sed -i 's/#scanfor internal,external,optical,manual/scanfor manual,external/' /boot/EFI/refind/refind.conf
sed -i 's/hideui.*/hideui singleuser,hints,arrows,badges/' /boot/EFI/refind/themes/refind-dreary/theme.conf

Add rEFInd Manual Stanza (make sure ROOT_PARITION is set)

cat << EOF >> /boot/EFI/refind/refind.conf

menuentry "Arch Linux" {
    icon     /EFI/refind/themes/refind-dreary/icons/os_arch.png
    volume   "Arch Linux"
    loader   /vmlinuz-linux-lts
    initrd   /booster-linux-lts.img
    options  "rd.luks.name=$(blkid $ROOT_PARTITION | cut -d " " -f2 | cut -d '=' -f2 | sed 's/\"//g')=crypt root=/dev/mapper/crypt rootflags=subvol=arch/@ rw quiet nmi_watchdog=0 kernel.unprivileged_userns_clone=0 net.core.bpf_jit_harden=2 apparmor=1 lsm=lockdown,yama,apparmor systemd.unified_cgroup_hierarchy=1 add_efi_memmap initrd=\intel-ucode.img"
    submenuentry "Boot - terminal" {
        add_options "systemd.unit=multi-user.target"
    }
}

menuentry "Arch Linux - Low Latency" {
    icon     /EFI/refind/themes/refind-dreary/icons/os_arch.png
    volume   "Arch Linux"
    loader   /vmlinuz-linux-xanmod-tt
    initrd   /booster-linux-xanmod-tt.img
    options  "rd.luks.name=$(blkid $ROOT_PARTITION | cut -d " " -f2 | cut -d '=' -f2 | sed 's/\"//g')=crypt root=/dev/mapper/crypt rootflags=subvol=arch/@ rw quiet nmi_watchdog=0 kernel.unprivileged_userns_clone=0 net.core.bpf_jit_harden=2 apparmor=1 lsm=lockdown,yama,apparmor systemd.unified_cgroup_hierarchy=1 add_efi_memmap initrd=\intel-ucode.img"
    submenuentry "Boot - terminal" {
        add_options "systemd.unit=multi-user.target"
    }
}

include themes/refind-dreary/theme.conf
EOF

Edit refind-btrfs

sed -i 's/^selection_count.*/count = "inf"/' /etc/refind-btrfs.conf
sed -i 's/^include_sub_menus.*/include_sub_menus = true/' /etc/refind-btrfs.conf

Add snap-pac for automatic pre/post backups for package install/uninstalls/updates

sudo pacman --noconfirm -S snap-pac

NOTE

Make scripts to start service & setup snapshots (uncomment the optional services as needed)

cat << EOF >> /home/$USER/init.sh
sudo umount /.snapshots
sudo rm -r /.snapshots
sudo snapper -c root create-config /
sudo mount -a
sudo chmod 750 -R /.snapshots
sudo chmod a+rx /.snapshots
sudo chown :wheel /.snapshots
sudo snapper -c root create --description "Fresh Install"
sudo sed -i 's/^TIMELINE_MIN_AGE.*/TIMELINE_MIN_AGE="1800"/' /etc/snapper/configs/root && \
sudo sed -i 's/^TIMELINE_LIMIT_HOURLY.*/TIMELINE_LIMIT_HOURLY="0"/' /etc/snapper/configs/root && \
sudo sed -i 's/^TIMELINE_LIMIT_DAILY.*/TIMELINE_LIMIT_DAILY="7"/' /etc/snapper/configs/root && \
sudo sed -i 's/^TIMELINE_LIMIT_WEEKLY.*/TIMELINE_LIMIT_WEEKLY="0"/' /etc/snapper/configs/root && \
sudo sed -i 's/^TIMELINE_LIMIT_MONTHLY.*/TIMELINE_LIMIT_MONTHLY="0"/' /etc/snapper/configs/root && \
sudo sed -i 's/^TIMELINE_LIMIT_YEARLY.*/TIMELINE_LIMIT_YEARLY="0"/' /etc/snapper/configs/root
sudo systemctl enable --now snapper-timeline.timer snapper-cleanup.timer
sudo systemctl disable NetworkManager-wait-online
sudo systemctl mask NetworkManager-wait-online
sudo systemctl enable --now NetworkManager 
sudo systemctl enable --now NetworkManager-dispatcher
sudo systemctl enable --now nftables
sudo systemctl enable --now sshd 
# uncomment if chronyd NOT is installed
#sudo systemctl disable --now systemd-timesyncd.service
sudo systemctl enable --now chronyd
sudo systemctl enable --now reflector
sudo systemctl enable --now apparmor
sudo systemctl enable --now sshguard
sudo systemctl enable --now memavaild 
sudo systemctl enable --now irqbalance 
sudo systemctl enable --now prelockd 
sudo systemctl enable --now systemd-swap 
sudo systemctl enable --now nohang-desktop 
sudo systemctl enable --now auto-cpufreq 
sudo systemctl enable --now dbus-broker
# uncomment if postgres is installed
#sudo systemctl enable --now postgresql
sudo systemctl enable --now refind-btrfs
sudo systemctl enable --now greetd
rm /home/$USER/init.sh
EOF
chown $USER /home/$USER/init.sh

Step 10 - Reboot into your new install

exit
umount -R /mnt && \
reboot

11 - Post Install

Run script

bash init.sh

Connect to wifi

nmcli -a device wifi connect SSID

(OPTIONAL) Finish setting up postgresql for user

sudo -iu postgres
createuser --interactive
# When asked name of role to add enter your username.
# When asked shall the new role be a superuser enter y

Optional: for asus laptops only

cat << EOF > /etc/systemd/system/battery-charge-threshold.service
[Unit]
Description=Set the battery charge threshold
After=multi-user.target
StartLimitBurst=0

[Service]
Type=oneshot
Restart=on-failure
ExecStart=/bin/bash -c 'echo 80 > /sys/class/power_supply/BAT0/charge_control_end_threshold'

[Install]
WantedBy=multi-user.target
EOF
sudo systemctl enable --now
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment