- 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 Cacule Linux Kernel
- Preemptive Full Tickless Kernel at 500Hz w/ Tuned CPU Core Scheduler.
- RCU Boost for better responsiveness and lower overall system latency.
- Full multi-core block layer runqueue requests for high I/O throughput.
- Caching, Virtual Memory Manager and CPUFreq Governor improvements.
- BBR TCP Congestion Control + FQ-PIE Packet Scheduling and AQM Algorithm [5.10].
- ORC Unwinder for Kernel Stack Traces (debuginfo) implementation.
- Third-party patchset available: BBRv2 TCP Congestion [5.10][as module], ZSTD kernel, initrd and modules support [5.10], Clear Linux [partial], CK's Hrtimer patchset, Proton Fsync support, PCIe ACS Override, Aufs [5.4] and Graysky's GCC patchset.
- Btrfs Checksum hardware acceleration
- High responsiveness CacULE scheduler (SCHED_NORMAL) based on ULE interactivity score mechanism build available [5.10-cacule]
- Each CPU has its own runqueue.
- NORMAL runqueue is a linked list of sched_entities (instead of RB-Tree).
- RT and other runqueues are just the same as the CFS's.
- Wake up tasks preempt currently running tasks if its interactivity score value is higher
- Miscellaneous
- Secureboot
- Udev rule for faster IO performance from NVME and SSD
- Hooks for zsh and secureboot
- Improved laptop battery life
- Zram
- Btrfs
- Profile-sync-daemon
- 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)
- Profile-sync-daemon, faster web browsing experience and 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
- Docker using IPV6
- 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
- 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-cacule
- Only wayland login manager
- Can unlock gnome-keyring on automatic login when password is set to LUKS password
This means after I unlock LUKS I don't need to enter any more password. SSH, git, and GPG passwords are automatically used without me entering them(after you enter them the first time).
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
iwctl
Get your IP address
ip a
cfdisk /dev/nvme0n1 # replace nvme0n1 with your drive
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 /dev/nvme0n1p2
cryptsetup --allow-discards --perf-no_read_workqueue --perf-no_write_workqueue --persistent open /dev/nvme0n1p2 crypt
mkfs.vfat -F32 -n "EFI" /dev/nvme0n1p1
mkfs.btrfs -L Arch -f /dev/mapper/crypt
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
btrfs sub create /mnt/@ && \
btrfs sub create /mnt/@home && \
btrfs sub create /mnt/@abs && \
btrfs sub create /mnt/@tmp && \
btrfs sub create /mnt/@srv && \
btrfs sub create /mnt/@snapshots && \
btrfs sub create /mnt/@btrfs && \
btrfs sub create /mnt/@log && \
btrfs sub create /mnt/@cache
umount /mnt
Mount the subvolumes
mount -o noatime,compress-force=zstd,commit=120,space_cache=v2,ssd,discard=async,autodefrag,subvol=@ /dev/mapper/crypt /mnt
mkdir -p /mnt/{boot,home,var/cache,var/log,.snapshots,btrfs,var/tmp,var/abs,srv}
mount -o noatime,compress-force=zstd,commit=120,space_cache=v2,ssd,discard=async,autodefrag,subvol=@home /dev/mapper/crypt /mnt/home && \
mount -o nodev,nosuid,noexec,noatime,compress-force=zstd,commit=120,space_cache=v2,ssd,discard=async,autodefrag,subvol=@abs /dev/mapper/crypt /mnt/var/abs && \
mount -o nodev,nosuid,noexec,noatime,compress-force=zstd,commit=120,space_cache=v2,ssd,discard=async,autodefrag,subvol=@tmp /dev/mapper/crypt /mnt/var/tmp && \
mount -o noatime,compress-force=zstd,commit=120,space_cache=v2,ssd,discard=async,autodefrag,subvol=@srv /dev/mapper/crypt /mnt/srv && \
mount -o nodev,nosuid,noexec,noatime,compress-force=zstd,commit=120,space_cache=v2,ssd,discard=async,autodefrag,subvol=@log /dev/mapper/crypt /mnt/var/log && \
mount -o nodev,nosuid,noexec,noatime,compress-force=zstd,commit=120,space_cache=v2,ssd,discard=async,autodefrag,subvol=@cache /dev/mapper/crypt /mnt/var/cache && \
mount -o noatime,compress-force=zstd,commit=120,space_cache=v2,ssd,discard=async,autodefrag,subvol=@snapshots /dev/mapper/crypt /mnt/.snapshots && \
mount -o noatime,compress-force=zstd,commit=120,space_cache=v2,ssd,discard=async,autodefrag,subvolid=5 /dev/mapper/crypt /mnt/btrfs
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
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}
Mount the EFI partition
mount -o nodev,nosuid,noexec /dev/nvme0n1p1 /mnt/boot
(this is the time where you change the mirrorlist, if that's your thing) The following assumes you have an AMD CPU & GPU
pacstrap /mnt base base-devel linux linux-firmware amd-ucode btrfs-progs git go \
kanshi zstd iwd networkmanager mesa vulkan-radeon libva-mesa-driver openssh \
mesa-vdpau xf86-video-amdgpu docker libvirt qemu refind rustup wl-clipboard \
zsh sshguard npm bc ripgrep bat tokei hyperfine rust-analyzer xdg-user-dirs \
systemd-swap pigz pbzip2 snapper chrony noto-fonts a52dec faac iptables-nft \
tlp faad2 flac jasper grim libdca libdv libmad libmpeg2 libtheora libvorbis \
waybar wavpack xvidcore libde265 gstreamer gst-libav gst-plugins-bad breeze \
gst-plugins-base gst-plugins-good gst-plugins-ugly gstreamer-vaapi seahorse \
sway lollypop alacritty wofi polkit-gnome mako slurp xdg-desktop-portal-wlr \
gvfs libxv libsecret gnome-keyring nautilus nautilus-image-converter gdm fd \
xarchiver arj cpio lha udiskie nautilus-share nautilus-sendto imv mpv lrzip \
unrar zip chezmoi powertop brightnessctl lastpass-cli sbsigntools x264 lzip \
xorg-xwayland apparmor ttf-roboto ttf-roboto-mono ttf-dejavu ttf-liberation \
ttf-fira-code ttf-hanazono ttf-fira-mono seahorse-nautilus exa ttf-opensans \
pulseaudio lzop p7zip ttf-hack noto-fonts noto-fonts-emoji ttf-font-awesome \
ttf-droid adobe-source-code-pro-fonts firefox-decentraleyes libva-utils man \
firefox-dark-reader lame network-manager-applet unarj blueman yarn npm code \
firefox-ublock-origin irqbalance swayidle haveged profile-sync-daemon shfmt \
compsize pipewire-pulse pipewire-jack pipewire-alsa gnome-boxes wf-recorder \
dbus-broker wireplumber skim youtube-dl nftables python-nautilus celluloid \
entr reflector postgresql tmux gnome-podcasts
generate the fstab
genfstab -U /mnt > /mnt/etc/fstab
Use timedatectl(1) to ensure the system clock is accurate
timedatectl set-ntp true
Add some zsh configs for a nicer experience
cp /etc/zsh/zprofile /mnt/root/.zprofile && \
cp /etc/zsh/zshrc /mnt/root/.zshrc
Add pacman mirrorlist
cp /etc/pacman.d/mirrorlist /mnt/etc/pacman.d/mirrorlist
Chroot into the new system
arch-chroot /mnt /bin/zsh
Export some variables
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
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 && \
withecho "$USER ALL=(ALL) ALL" >> /etc/sudoers && \
to have sudo only with passwd
WARNING Anyone added to the docker group is root equivalent because they can use the docker run --privileged command to start containers with root privileges. For more information see 3 and 4.
useradd -m -G docker,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
- docker - Members of docker group are able to run the docker CLI command as a non-root user
- 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
sed -i 's/BINARIES=()/BINARIES=("\/usr\/bin\/btrfs")/' /etc/mkinitcpio.conf && \
sed -i 's/MODULES=()/MODULES=(amdgpu)/' /etc/mkinitcpio.conf && \
sed -i 's/#COMPRESSION="lz4"/COMPRESSION="lz4"/' /etc/mkinitcpio.conf && \
sed -i 's/#COMPRESSION_OPTIONS=()/COMPRESSION_OPTIONS=(-9)/' /etc/mkinitcpio.conf && \
sed -i 's/^HOOKS.*/HOOKS=(base systemd autodetect modconf block sd-encrypt filesystems keyboard fsck)/' /etc/mkinitcpio.conf
# if you have more than 1 btrfs drive
# sed -i 's/^HOOKS.*/HOOKS=(base systemd autodetect modconf block sd-encrypt resume btrfs filesystems keyboard fsck)/' mkinitcpio.conf
mkinitcpio -p linux
Laptop Power Saving Improvements
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_ac97_codec
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
By default, PulseAudio suspends any audio sources that have become idle for too long. When using an external USB microphone, recordings may start with a pop sound. As a workaround, comment out load-module module-suspend-on-idle
in /etc/pulse/default.pa
sed -i 's/load-module module-suspend-on-idle/#load-module module-suspend-on-idle/' /etc/pulse/default.pa
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
Here are some sensible default settings for TLP
cat << EOF > /etc/tlp.conf
SATA_LINKPWR_ON_AC="max_performance"
SATA_LINKPWR_ON_BAT="med_power_with_dipm"
RADEON_POWER_PROFILE_ON_AC="high"
RADEON_POWER_PROFILE_ON_BAT="low"
RESTORE_DEVICE_STATE_ON_STARTUP="1"
EOF
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
Autosign Kernel
mkdir /etc/pacman.d/hooks && cat << EOF > /etc/pacman.d/hooks/999-sign_kernel_for_secureboot.hook
[Trigger]
Operation = Install
Operation = Upgrade
Type = Package
Target = linux
Target = linux-lts
Target = linux-hardened
Target = linux-zen
Target = linux-xanmod
Target = linux-xanmod-cacule
Target = linux-xanmod-git
Target = linux-xanmod-lts
Target = linux-xanmod-rt
Target = linux-xanmod-anbox
[Action]
Description = Signing kernel with Machine Owner Key for Secure Boot
When = PostTransaction
Exec = /usr/bin/fd vmlinuz /boot -d 1 -x /usr/bin/sbsign --key /etc/refind.d/keys/refind_local.key --cert /etc/refind.d/keys/refind_local.crt --output {} {}
Depends = sbsigntools
Depends = fd
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 --shim /usr/share/shim-signed/shimx64.efi --localkeys
EOF
Zsh hook
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/swap.conf
# This file is part of systemd-swap.
#
# Entries in this file show the systemd-swap defaults as
# specified in /usr/share/systemd-swap/swap-default.conf
# You can change settings by editing this file.
# Defaults can be restored by simply deleting this file.
#
# See swap.conf(5) and /usr/share/systemd-swap/swap-default.conf for details.
zram_enabled=1
zswap_enabled=0
swapfc_enabled=0
zram_size=\$(( RAM_SIZE / 4 ))
EOF
Optimize Makepkg
sed -i 's/^CFLAGS.*/CFLAGS="-march=native -mtune=native -O2 -pipe -fstack-protector-strong --param=ssp-buffer-size=4 -fno-plt"/' /etc/makepkg.conf && \
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/#TotalDownload/TotalDownload/' /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
Docker use IPV6 & Btrfs
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
Prepare gnome-keyring-daemon
cat <<EOF > /etc/pam.d/login
#%PAM-1.0
auth required pam_securetty.so
auth requisite pam_nologin.so
auth include system-local-login
auth optional pam_gnome_keyring.so
account include system-local-login
session include system-local-login
session optional pam_gnome_keyring.so auto_start
EOF
cat <<EOF > /etc/pam.d/passwd
#%PAM-1.0
#password required pam_cracklib.so difok=2 minlen=8 dcredit=2 ocredit=2 retry=3
#password required pam_unix.so sha512 shadow use_authtok
password required pam_unix.so sha512 shadow nullok
password optional pam_gnome_keyring.so
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
Setup 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
Install AUR helper
su $USER
cd ~ && \
git clone https://aur.archlinux.org/yay.git && \
cd yay && \
makepkg -si && \
cd .. && \
sudo rm -dR yay
Sign bootloader & kernel for Secure Boot
yay --noremovemake --nodiffmenu -S shim-signed && \
sudo refind-install --shim /usr/share/shim-signed/shimx64.efi --localkeys && \
sudo sbsign --key /etc/refind.d/keys/refind_local.key --cert /etc/refind.d/keys/refind_local.crt --output /boot/vmlinuz-linux /boot/vmlinuz-linux
Add some user niceties whiler you are there
rustup default stable && \
yay --noremovemake --nodiffmenu --batchinstall -S otf-san-francisco fedora-firefox-wayland-bin \
otf-san-francisco pamac-aur starship-bin firefox-extension-amazon-container \
gst-plugin-libde265 firefox-extension-privacybadger poweralertd zoxide-bin \
firefox-extension-https-everywhere firefox-extension-facebook-container wob \
firefox-extension-containerise ananicy-git lastpass nwg-launchers persway \
neovim-nightly-git swaylock-effects-git lazygit-bin grimshot memavaild \
prelockd nohang-git auto-cpufreq-git otf-nerd-fonts-monacob-mono refind-btrfs \
bat-extras-git opennic-up ttf-wps-office-fonts wps-office wps-office-mime \
neovim-remote git-delta-bin git-journal just gitui-bin procs-bin smug \
nushell-bin
yay --noremovemake --nodiffmenu --editmenu -S linux-xanmod-cacule linux-xanmod-cacule-headers
export PATH=/usr/bin/ && yay -S nerd-fonts-jetbrains-mono
# Now is a good time to install dotfiles
# Example 1 (bare git repo)
# git clone --bare https://github.com/Th3Whit3Wolf/.dots.git $HOME/.dots
# git --git-dir=$HOME/.dots/ --work-tree=$HOME checkout
# Example 2 (chezmoi)
# chezmoi init https://github.com/Th3Whit3Wolf/dots.git
exit
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
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
initrd /initramfs-linux.img
options "rd.luks.name=$(blkid /dev/nvme0n1p2 | cut -d " " -f2 | cut -d '=' -f2 | sed 's/\"//g')=crypt root=/dev/mapper/crypt rootflags=subvol=@ 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=\amd-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-cacule
initrd /initramfs-linux-xanmod-cacule.img
options "rd.luks.name=$(blkid /dev/nvme0n1p2 | cut -d " " -f2 | cut -d '=' -f2 | sed 's/\"//g')=crypt root=/dev/mapper/crypt rootflags=subvol=@ 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=\amd-ucode.img"
submenuentry "Boot - terminal" {
add_options "systemd.unit=multi-user.target"
}
}
include themes/refind-dreary/theme.conf
EOF
Edit refing-btrfs
sed -i 's/^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
rd.luks.name=$(blkid /dev/nvme0n1p2 | cut -d " " -f2 | cut -d '=' -f2 | sed 's/\"//g')=crypt root=/dev/mapper/crypt
- This will expand tord.luks.name=device-UUID=crypt root=/dev/mapper/crypt
, this is required when using the sd-encrypt hook in mkinitcpiorootflags=subvol=@
- This is how to specifty the subvolume to use as the root mountpointrw
- Allows the mountpoint to both read from and written toquiet
- Prevents unneccesary infor being written to stdout durring boot.nmi_watchdog=0
- Disables NMI watchdog from early bootkernel.unprivileged_userns_clone=0
- Allows unpriviledged containers on linux-hardened and custom kernelsnet.core.bpf_jit_harden=2
- The kernel includes a hardening feature for JIT-compiled BPF which can mitigate some types of JIT spraying attacks at the cost of performance and the ability to trace and debug many BPF programsapparmor=1 lsm=lockdown,yama,apparmor
- Enables AppArmor as default security model on every bootsystemd.unified_cgroup_hierarchy=1
- Enables unified cgroup hierarchy, AKA cgroups v2. Click here for more information.add_efi_memmap
- According to this reddit post, this parameter may be required if the UEFI implementation on the system fails to correctly report the amount of available physical memory to the kernel. You may not need it.initrd=\amd-ucode.img
- This is how to set the cpu microcode in refind (inside options \ is used a path separator)
Make scripts to start service & setup snapshots
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 --now systemd-timesyncd.service
sudo systemctl mask systemd-rfkill.socket systemd-rfkill.service
sudo systemctl enable --now NetworkManager
sudo systemctl enable --now NetworkManager-wait-online
sudo systemctl enable --now NetworkManager-dispatcher
sudo systemctl enable --now nftables
sudo systemctl enable --now opennic-up.timer
sudo systemctl enable --now sshd
sudo systemctl enable --now chronyd
sudo systemctl enable --now reflector
sudo systemctl enable --now apparmor
sudo systemctl enable --now sshguard
sudo systemctl enable --now tlp
sudo systemctl enable --now memavaild
sudo systemctl enable --now haveged
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
sudo systemctl enable --now postgresql
sudo systemctl enable --now refind-btrfs
systemctl --user start psd
sudo systemctl enable --now gdm
rm /home/$USER/init.sh
EOF
chown $USER /home/$USER/init.sh
exit
umount -R /mnt && \
reboot
Run script
bash init.sh
Connect to wifi
nmcli -a device wifi connect
SSID
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