The Pros and Cons of Arch Linux

My Linux distro of choice for my main computer is Arch Linux (btw.™). I love its approach of being lightweight and shipping the latest software with (almost) default configuration as intended by the developers. For me this is perfect as I like to try out new software and I am also forced to configure some packages myself. The ArchWiki is a great resource helping me on my learning journey. There is also the large Arch User Repository (AUR) where even more software packages can be found. Personally, I don't need any packages from the AUR at the moment but it's nice to have the option.

As with most things in life there are tradeoffs of using a rolling release distro like Arch. The benefit of having access to the latest software comes with the occasional bug or breaking change where user intervention is necessary. Sometimes, a clean reinstall is the easiest way to get up and running again. Wouldn't it be cool to replicate the configuration automatically? That's what this article is about.

Package Management with Ansible

Ansible is an automation tool for managing system configurations mainly on remote machines via SSH but it can also be used locally. By using playbooks you can declare the desired state you want the system to be in. Ansible will check the current state and will only perform actions when necessary. This means that playbooks are idempotent in the general case so running it twice is the same as running it once.

Setting up Ansible

The first configuration step is to create a inventory.ini file within a project directory where we tell Ansible to execute the playbook locally.

[localhost]
127.0.0.1 ansible_connection=local

The (optional) second step is to configure default parameters in the ansible.cfg file. This saves you from specifying the options -K -i inventory.ini every time you run a playbook.

[defaults]
inventory = inventory.ini

[privilege_escalation]
become_ask_pass = true

Writing a Playbook

Ansible playbooks are defined as YAML files which can be executed with ansible-playbook playbook.yaml. We start by giving the play a name and referencing the localhost group from the inventory. become: true ensures privileges are escalated by default for all tasks.

---
- name: Arch Linux setup
  hosts: localhost
  become: true

Installing regular Packages

Regular packages can simply be installed by listing their names below the pacman module.

  tasks:
    - name: Install packages
      community.general.pacman:
        name:
          - kitty
          - fish
          - zoxide
          - starship

Enabling Systemd Services

Some packages need a systemd service running in the background, e.g. Ollama1. They can be enabled using the systemd_service module. I use block statements to organize related tasks into groups.

    - name: Setup Ollama
      block:
      - name: Install Ollama
        community.general.pacman:
          name:
            - ollama
            - ollama-cuda
      - name: Enable ollama.service
        ansible.builtin.systemd_service:
          name: ollama
          enabled: true

Managing Users and Groups

Other packages need the user to be in a certain group in order to work properly, e.g. Wireshark2. Group memberships can be managed with the user module. The task below also uses a template to dynamically determine the user name on execution.

    - name: Setup Wireshark
      block:
        - name: Install Wireshark
          community.general.pacman:
            name: wireshark-qt
        - name: Add to wireshark group
          ansible.builtin.user:
            name: "{{ lookup('ansible.builtin.env', 'USER') }}"
            groups:
              - wireshark
            append: true

Configuration Management with Chezmoi

Chezmoi is a tool called a dotfile manager. It keeps track of user configuration files e.g. in the ~/.config directory.

Configuring Fish

Fish is a great shell for interactive use. It has builtin syntax highlighting and suggestions based on a program's man pages. Recently, its core has been rewritten in Rust. Using it as the default shell can cause problems because fish is not POSIX compliant.3 So instead I configured my terminal emulator Kitty to drop into fish on startup using this line in ~/.config/kitty/kitty.conf.

shell fish

Next, I set up zoxide, a cd replacement, and Starship, a shell promt, in ~/.config/fish/config.fish.

if status is-interactive
    # Commands to run in interactive sessions can go here
    zoxide init fish | source
    starship init fish | source
end

To initialize chezmoi, execute chezmoi init. Both config files can now be added to chezmoi using chezmoi add [file]. To check the files tracked by chezmoi into git, switch to its source directory using chezmoi cd and add, commit, and push them to a repository. You can now replicate the configuration on a new machine using the command:

chezmoi init --apply [repo]