Skip to content

Linux setup

A setup guide for programmers, etc., on Linux and the Windows Linux Subsystem. Alternatives for Ubuntu/Debian-like and Fedora/RedHat-like are shown.

Install

Follow the instructions that show up to install. In Ubuntu, select “Default installation” and check “Install third-party software for graphics and Wi-Fi hardware” and “Download and install support for additional media formats”.

If you need encryption, TPM-backed FDE is a potential option. Support in Ubuntu and Fedora is experimental (as of October 2023). I have not tested it.

UEFI troubleshooting

If you get an error installing GRUB, try these steps:

  • Disable Fast Boot.
  • Disable Secure Boot. Also, check to see if CSM/Legacy options is disabled.
  • Manually install the bootloader (not recommended).
  • Read about Linux and UEFI for more troubleshooting.

Choose a partition scheme

Use Btrfs.

Btrfs is a copy-on-write option and is now much more robust than ext4. See the btrfs documentation.

Use a swap partition the same size as your RAM.

There’s an adage that it’s important for emergency memory – in case your main memory runs out. Meanwhile, mavericks insist on skipping it altogether, pointing out that using it for emergency memory would render a system excessively slow. Linux uses swap space as a complement to memory by swapping out infrequently used pages. You should definitely use it, but it probably doesn’t need to fit more than your memory.

For single-user systems, skip /home in favor of /files.

/home will probably fill with miscellaneous configuration and even temp data that doesn’t need to be backed up. It’s probably even best to discard such files when upgrading or installing a new distro. So, leave /home in the root partition and use another mount point like /data or /files instead.

Skip the /boot partition.

It’s not needed on a modern UEFI system.

For workstations, consider separate /tmp and /var/tmp.

Things like an inefficient SQL query can quickly take hundreds of gigabytes in /tmp. If /tmp is in your root partition, this can brick your system, and you might have to boot to a flash drive to clean up the system. If /tmp is a separate partition, filling it up won’t leave your system unbootable. Of course, consider the tradeoff. The same goes for /var/tmp (more or less). If mounted as separate partitions, mount with noexec.

Example scheme 1 – single-user workstation
drive(s) mount point size (GB) filesystem purpose
nvme0 (efi) 1 FAT32
nvme0 (swap) 64 swap
nvme0 / 256 btrfs
nvme0 /tmp 128 btrfs
nvme0 /var/tmp 256 btrfs
nvme0 /data 1308 btrfs Working data
nvme1 /docs 1024 btrfs Documents
sda /bak 4096 btrfs External backup (HDD)
Example scheme 2 – multi-user server

Context: nvme0 and nvme1 are ultra-fast drives (CPU chipset and 4 PCIe lanes, respectively), while nvme2 and nvme3 are slower. sda and sdb are SATA SSDs, and sdc is a spinning disk.

drive(s) mount point size (GB) filesystem purpose
nvme0 (efi) 1 FAT32
nvme0 (swap) 128 swap
nvme0 / 1408 btrfs
nvme0 /tmp 256 btrfs
nvme0 /var/tmp 256 btrfs Only system temp files
nvme1 /scratch 2048 btrfs Ultra-fast scratch
nvme2 /lake 2048 btrfs Fast shared data
nvme3 /home 2048 btrfs User files
sda,sdb /stock 8192 btrfs Frozen data (raid 0)
sdc1 /bakroot 2048 btrfs dd of /
sdc2 /baklake 2048 btrfs dd of /lake
sdc3 /bakhome 2048 btrfs dd of /home

Update and reboot

sudo apt update && reboot
sudo dnf update && reboot

Enable kernel modules

Run

sudo modprobe sha256

Set mount options

  • Add noatime everywhere. Access timestamps (atime) are written using the default option, relatime. This makes a lot of otherwise-unnecessary writes, degrading performance.
  • Add noacl everywhere. There’s probably no performance gain to disable ACL, but you almost definitely don’t need it.
  • Add noexec, nodev, and nosuid to /tmp and /var/tmp (if they exist).

Consider compression.

btrfs can compress data at rest and in transit. Whether to use lzo, zstd, or no compression depends primarily on the (uncompressed) throughput: Use heavier compression to compensate for slow IO, and use lighter compression for fast IO. Use no compression if the CPU is already the bottleneck. See benchmarks for btrfs compression. Here are my recommendations:

  • compression=off for NVMe 2.0 drives connected directly to CPU lanes.
  • compression=lzo for all other NVMe drives.
  • compression=lzo for SATA-connected SSDs.
  • compression=zstd:3 for SATA-connected HDDs.
  • compression=zstd:3 for USB-connected drives.

Bug

Sometimes filesystems cannot be mounted with compress, presumably for any number of reasons.

Warning

Make sure to follow the steps below to verify that your fstab is valid and useable.

Edit fstab

Following these rules, the fstab for “Example scheme 1 – single-user workstation” might look like this:

# filesystem     mount      type   options                            d p
.../by-uuid/...  none       swap   sw                                 0 1
.../by-uuid/...  /boot/efi  vfat   defaults                           0 1
.../by-uuid/...  /tmp       btrfs  noatime,noacl,noexec,nodev,nosuid  0 1
.../by-uuid/...  /var/tmp   btrfs  noatime,noacl,noexec,nodev,nosuid  0 1
.../by-uuid/...  /          btrfs  noatime,noacl                      0 1
.../by-uuid/...  /data      btrfs  noatime,noacl                      0 1
.../by-uuid/...  /docs      btrfs  noatime,noacl,compress=lzo         0 1
.../by-uuid/...  /bak       btrfs  noatime,noacl,compress=zstd:3      0 1

Before rebooting, verify that your changes are probably ok by running

mount --fake --all --verbose

and

sudo systemctl daemon-reload
sudo findmnt --fstab --verify --verbose

Then reboot and see the results by running

cat /etc/mtab

Install packages

Open a terminal and enter the following commands to install the necessary packages:

First, enable the Universe repository:

sudo add-apt-repository universe -y
sudo apt install -y git vim curl wget xz-utils brotli lzma zstd iotop exa
  sudo apt install libncurses-dev
  sudo apt install -y build-essential cmake
sudo apt install -y zsh
sudo dnf update && upgrade
sudo dnf install -y git vim curl wget xz-utils brotli lzma zstd iotop exa
  sudo dnf install -y ncurses-devel
  sudo dnf install -y make automake gcc gcc-c++ kernel-devel cmake
sudo dnf install -y zsh

Install the GitHub CLI per the official GH Linux install instructions.

Set up firewall

sudo ufw enable

Fedora should come with firewalld installed and enabled by default.

Allow SSH login

Install ssh to allow for remote logins.

sudo apt update
sudo apt install openssh-server
sudo ufw allow 22

Cosmetics/UI

Exa and Nerd fonts

Download one or more Nerd fonts. Then run

cd ~/Downloads  # (1)!
for f in *.zip; do sudo unzip $f -d /usr/local/share/fonts; done
fc-cache
  1. Or wherever your downloaded Nerd fonts are

Set your terminal font to the Nerd font. (In Tilix, this is a per-profile setting called “Custom font”.) Now you can run

exa --icons

GNOME

In GNOME’s settings, set the time format to 24-hour and make sure Automatic Data and Time is selected. Also install extensions:

sudo apt install gnome-browser-connector
sudo dnf install gnome-browser-connector

Then open https://extensions.gnome.org/ and install the browser extension. I recommend installing:

  • Force Quit
  • Panel Date Format After installing, run
    dconf write /org/gnome/shell/extensions/panel-date-format/format "'%Y-%m-%d %H:%M'"
    

Install Oh My Zsh

You’ll thank me later. (You’ll need ZSH installed for this to work.)

sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"

You should be prompted to change your shell. If you are not, run

chsh -s $(which zsh)

Make sure it is set by running

sudo cat /etc/passwd | grep ${USER}

You may need to reboot for the change to your login shell to take effect. You should now have a colorful shell, complete with a plugin for Git.

.commonrc file

To keep the config for ZSH and Bash consistent, add a file called .commonrc in your home directory:

echo 'export PATH=/usr/local/sbin:$PATH\n' > ~/.commonrc
echo 'source ~/.commonrc\n' >> ~/.zshrc
echo 'source ~/.commonrc\n' >> ~/.bashrc

From here on, only modify .commonrc so that both Bash and ZSH have the same environment.

Git, SSH, and GPG

See this guide.

Install Java and Rust

First, Install the Rust toolchain.

Then, download JDK 21 from Temurin. Do not use Java 8, java.com, or OpenJDK. Make sure it’s on your $PATH by running java --version in a new shell.

Generate a certificate

If you need a certificate, set a static IP address and generate a certificate with certbot. Choose “None of the above” for Software. Then follow the instructions exactly, including the “Automating renewal” section. This may not work through some company and university firewalls.

Sudoers

The easiest way is to run

su  #(1)!
usermod -aG sudo $USER
  1. This will require you to enter the root password.

See this sudoers guide for more info.

Dotfiles

See awesome-dotfiles. Here are some I used:

# xdg-open occasionally assumed in scripts,
# so aliasing it to macOS's `open` is a good idea
# alias xdg-open=open

# These improve safety
# Accidentally running `chown -R xx . /` (on root) can brick your system
# The same goes for chmod and chgrp
alias chown='chown --preserve-root'
alias chmod='chmod --preserve-root'
alias chgrp='chgrp --preserve-root'

alias wgetc='wget -c'
alias grep='grep --color=auto'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'

# list open file handles for the current shell session (also see lsof)
alias handles='ls -la /proc/$$/fd'

# Check free memory
alias fre='free --human'

# Check CPU, memory, and swap usage
alias usg='vmstat --active'

# Check IO usage
alias iousg='sudo iotop --only --batch'

# List listening sockets
alias lssockets='sudo --listening --processes'
alias lstcp='sudo --listening --processes --tcp'
alias lsudp='sudo --listening --processes --udp'

# List threads
# -A == all processes
# -f == full listing (show args)
# -L == show threads
# -l == long format
# -y == Hide flags and show resident set size (RSS; memory used) instead of addr
# --headers == repeat header line once per page
# In the output:
# - NLWP is # of threads
# - LWP is "light-weight process"
alias threads='ps -A -f -L -l -y -S --headers'

# Normal grid exa (--created, --modified, and --git have no effect unless we pass --list)
alias e='exa --all --sort=name --group-directories-first --icons --created --modified --git'
# Detailed view with --list
alias el='exa --all --sort=name --group-directories-first --icons --created --modified --git --list'
# Detailed view in a grid (for wide monitors)
alias elg='exa --all --sort=name --group-directories-first --icons --created --modified --git --list --grid'

# These are nice as navigation shorthands
alias cd..='cd ..'
alias ..='cd ..'
alias ...='cd ../../../'
alias ....='cd ../../../../'
alias .....='cd ../../../../'

# make a dir and cd to it
function mkcd {
    mkdir "$1" && cd "$1"
}

# This one chowns recursively for you
function grab() {
    sudo chown -R ${USER}:${USER} ${1:-.}
}

# This one's modified from https://serverfault.com/questions/3743/what-useful-things-can-one-add-to-ones-bashrc
function extract () {
   if [[ ! -f "$1" ]] ; then
       >&2 echo "'$1' is not a file"
       exit 2
   fi
   case "$1" in
       *.tar.bz2)   tar xvjf "$1"    ;;
       *.tar.gz)    tar xvzf "$1"    ;;
       *.bz2)       bunzip2 "$1"     ;;
       *.rar)       unrar x "$1"     ;;
       *.gz)        gunzip "$1"      ;;
       *.tar)       tar xvf "$1"     ;;
       *.tbz2)      tar xvjf "$1"    ;;
       *.tgz)       tar xvzf "$1"    ;;
       *.zip)       unzip "$1"       ;;
       *.Z)         uncompress "$1"  ;;
       *.snappy)    snunzip "$1"     ;;
       *.sz)        snunzip "$1"     ;;
       *.br)        brotli -d "$1"   ;;
       *.xz)        unxz "$1"        ;;
       *.lz4)       unlz4 "$1"       ;;
       *.lzma)      unlzma  "$1"     ;;
       *.zst)       unzstd "$1"      ;;
       *.7z)        7z x "$1"        ;;
       *)           >&2 echo "I don't know how to extract '$1'"; exit 1 ;;
   esac
 }

Thanks

Thank you to Cole Helsell for drafting this guide with me.