Files
AlvinArch/README.md
T
alvinlolloandClaude Opus 5.5 da26e88147 fix(localrepo): Drop stale packages so update.sh can't re-add them
f06bfd1 and a940d91 removed eternalterminal-client/-server,
illogical-impulse-quickshell-git, meshy-git and pacserve from
packages.x86_64, but their .pkg.tar.zst files stayed in localrepo/ and
in local-aur.db. update.sh appends every localrepo package name back to
the list, which would bring the eternalterminal conflict back, and CI
shipped the conflicting packages into the image's /opt/localrepo.

Remove the files and their repo DB entries, re-sort the vulkan-* lines
in packages.x86_64, and drop the names from README.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 11:39:06 +11:00

448 lines
21 KiB
Markdown

# Complete Guide to Creating a Custom Arch Linux ISO
[![Scheduled ArchISO Build](https://git.vilaythong.us/alvinlollo/AlvinArch/actions/workflows/build-iso.yaml/badge.svg?branch=main)](https://git.vilaythong.us/alvinlollo/AlvinArch/actions?workflow=build-iso.yaml) [![Tests](https://git.vilaythong.us/alvinlollo/AlvinArch/actions/workflows/tests.yaml/badge.svg?branch=main)](https://git.vilaythong.us/alvinlollo/AlvinArch/actions?workflow=tests.yaml)
DistroTube: <https://www.youtube.com/watch?v=tSGGBbJBgvk&t=1228s>
Dotfiles install file structure:
```bash
AlvinArch/
├── airootfs/
│ ├── etc/skel/
│ │ ├── .config/bat/ # bat + catppuccin theme
│ │ ├── .config/fish/ # 20 files, quickshell guard
│ │ ├── .config/nvim/ # LazyVim (14 files)
│ │ ├── .config/hypr/custom/ # 8 files (kdeconnectd + cursor only)
│ │ ├── .config/starship.toml
│ │ ├── .zshrc # adapted (no hardcoded paths)
│ │ └── .fzf.zsh
│ └── root/customize_airootfs.sh # pre-installs oh-my-zsh, lazy.nvim, plugins
├── localrepo/
│ ├── build-end4-deps.sh # non-interactive AUR build (all deps)
│ ├── end4-pkgbuilds/ # microtex-git, quickshell-git, bibata
│ ├── illogical-impulse-bibata-modern-classic-bin-*.pkg.tar.zst
│ └── update.sh # existing, regenerates repo db
└── packages.x86_64 # 420 packages (65+ end-4 deps added)
```
## Table of Contents
1. [Overview](#overview)
2. [Prerequisites](#prerequisites)
3. [Directory Structure](#directory-structure)
4. [Core Configuration Files](#core-configuration-files)
5. [User Configuration (skel/)](#user-configuration-skel)
6. [System Services & Networking](#system-services--networking)
7. [Local Repository (localrepo/)](#local-repository-localrepo)
8. [Boot Configuration](#boot-configuration)
9. [Automated Installer (alvin-install)](#automated-installer-alvin-install)
10. [Build & Test](#build--test)
11. [Planned Additions](#planned-additions)
12. [Troubleshooting](#troubleshooting)
---
## Overview
**AlvinArch** is a custom Arch Linux live ISO built on the [archiso](https://wiki.archlinux.org/title/Archiso) framework. It ships a Hyprland desktop with [end-4 dots-hyprland](https://github.com/end-4/dots-hyprland), a curated set of ~400 packages, and a local repository of pre-built AUR packages for packages not available in official repos. The ISO targets both real hardware and VMs (VirtualBox/Hyper-V/VMware guest services are enabled out of the box).
### Key Features
- **Hyprland + end-4** — Wayland compositor with illogical-impulse dotfiles (quickshell, bibata cursors, microtex)
- **Automated installer (`alvin-install`)** — gum TUI: LUKS with systemd initramfs or experimental touchscreen unl0kr, optional TPM2 auto-unlock, GitHub SSH key import, login manager choice (none/greetd/sddm/gdm), optional sshd (on by default), autologin; the build stamp identifies the live ISO via its `/etc/motd`
- **LazyVim** — Pre-configured Neovim with lazy.nvim and curated plugins
- **Fish + Zsh + Starship** — Dual shell setup with oh-my-zsh and a cross-shell prompt
- **Local AUR repo** — Pre-built packages (end-4 deps, wallust, grub-customizer, etc.) that aren't in official repos
- **Curated packages** — ~400 packages across ccache, networking, dev tools, and desktop utilities
- **Guest VM support** — VirtualBox, Hyper-V, and VMware tools auto-enabled
---
## Prerequisites
### Required Tools
```bash
# Install archiso and dependencies
sudo pacman -S archiso git base-devel
# Optional but recommended
sudo pacman -S arch-install-scripts squashfs-tools
```
### Knowledge Requirements
- Basic Linux system administration
- Understanding of Arch Linux package management
- Shell scripting basics
- Git version control (for managing your project)
---
## Directory Structure
### Complete Project Layout
```
AlvinArch/
├── profiledef.sh # ISO metadata, compression, boot modes, file permissions
├── packages.x86_64 # ~400 live-environment packages (Hyprland, end-4, dev tools)
├── bootstrap_packages # Minimal build-time packages (base, arch-install-scripts)
├── pacman.conf # Repos: cachyos → core → extra → multilib → chaotic-aur → local-aur
├── airootfs/ # Root filesystem overlay (copied into live ISO)
│ ├── etc/
│ │ ├── os-release # NAME="Alvin Arch Linux", ID=arch
│ │ ├── hostname # Default hostname: archiso
│ │ ├── motd # Welcome text with install instructions and color bar
│ │ ├── locale.conf # LANG=en_AU.UTF-8
│ │ ├── locale.gen # Locale generation file
│ │ ├── localtime → ../usr/share/zoneinfo/... # Timezone symlink
│ │ ├── resolv.conf # DNS resolver config
│ │ ├── passwd # System user accounts
│ │ ├── shadow # Password hashes (mode 400)
│ │ ├── clamav/ # ClamAV antivirus config (certs, clamd, freshclam, milter)
│ │ ├── skel/ # Home directory template for new users
│ │ │ ├── .config/
│ │ │ │ ├── bat/ # bat + Catppuccin Macchiato theme
│ │ │ │ ├── fish/ # Fish shell config (~20 files, nvm, fisher, hyprland helper)
│ │ │ │ ├── nvim/ # LazyVim setup (init.lua, plugins/, config/)
│ │ │ │ ├── hypr/custom/ # Hyprland dotfiles (keybinds, rules, execs, env, general, scripts)
│ │ │ │ └── starship.toml # Starship cross-shell prompt
│ │ │ ├── .zshrc # Zsh config (oh-my-zsh compatible)
│ │ │ └── .fzf.zsh # Fzf shell integration
│ │ ├── systemd/
│ │ │ ├── system/ # Service files and enablement symlinks
│ │ │ │ ├── choose-mirror.service # Auto mirror selection
│ │ │ │ ├── pacman-init.service # Keyring initialization
│ │ │ │ ├── livecd-alsa-unmuter.service # Unmute ALSA on boot
│ │ │ │ ├── livecd-talk.service # LiveCD talk helper
│ │ │ │ ├── multi-user.target.wants/ # Enabled services (iwd, NetworkManager, sshd, vboxservice,
│ │ │ │ │ # hv_kvp/vss/fcopy, vmtoolsd, ModemManager, etc.)
│ │ │ │ ├── sysinit.target.wants/ # systemd-timesyncd, systemd-time-wait-sync
│ │ │ │ ├── sockets.target.wants/ # systemd-networkd, pcscd
│ │ │ │ ├── network-online.target.wants/ # systemd-networkd-wait-online
│ │ │ │ └── sound.target.wants/ # livecd-alsa-unmuter
│ │ │ ├── networkd.conf.d/ # IPv6 privacy extensions
│ │ │ ├── resolved.conf.d/ # systemd-resolved config
│ │ │ ├── journald.conf.d/ # Volatile journal storage
│ │ │ └── logind.conf.d/ # Do-not-suspend policy
│ │ ├── pacman.d/
│ │ │ ├── hooks/
│ │ │ │ ├── uncomment-mirrors.hook # Enable mirrors after install
│ │ │ │ └── zzzz99-remove-custom-hooks-from-airootfs.hook
│ │ │ ├── chaotic-mirrorlist # Chaotic AUR mirrors
│ │ │ └── cachyos-mirrorlist # CachyOS mirrors
│ │ ├── ssh/sshd_config.d/ # SSH live-environment config (10-archiso.conf)
│ │ ├── modprobe.d/ # broadcom-wl.conf (Broadcom WiFi driver)
│ │ └── mkinitcpio.conf.d/ # archiso initramfs config
│ ├── usr/
│ │ ├── lib/os-release # usr-merge os-release
│ │ ├── local/bin/ # alvin-install, choose-mirror, Installation_guide, livecd-sound
│ │ ├── local/share/livecd-sound/ # ALSA config (asound.conf.in)
│ │ └── share/pacman/keyrings/ # CachyOS GPG keyring + trust data
│ └── root/
│ ├── .automated_script.sh # Automated install entry point
│ ├── .zlogin # Zsh login hook
│ ├── .gnupg/scdaemon.conf # GPG smartcard config
│ ├── .live-pacman.conf # Pacman config for live session
│ └── customize_airootfs.sh # Build-time chroot script (oh-my-zsh, lazy.nvim, plugins)
├── localrepo/ # Pre-built AUR packages (indexed as local-aur repo)
│ ├── build-end4-deps.sh # Non-interactive AUR builder for end-4 dependencies
│ ├── update.sh # Regenerates repo DB + syncs names to packages.x86_64
│ ├── end4-pkgbuilds/ # PKGBUILDs: quickshell-git, microtex-git, bibata-modern-classic-bin
│ ├── *.pkg.tar.zst # Pre-built packages (illogical-impulse-*, wallust, grub-customizer,
│ │ # snapd, upscayl, eternalterminal, etc.)
│ └── local-aur.db{,.tar.gz} # Repo database files
├── efiboot/ # UEFI boot (systemd-boot)
│ └── loader/
│ ├── loader.conf
│ └── entries/
│ ├── 01-archiso-linux.conf
│ ├── 02-archiso-speech-linux.conf
│ └── 03-archiso-memtest86+x64.conf
├── grub/ # GRUB boot (BIOS + UEFI)
│ ├── grub.cfg
│ └── loopback.cfg
└── syslinux/ # BIOS boot (syslinux)
├── syslinux.cfg
├── archiso_head.cfg
├── archiso_pxe-linux.cfg
├── archiso_sys.cfg
├── archiso_sys-linux.cfg
├── archiso_tail.cfg
└── splash.png
```
## Core Configuration Files
### **profiledef.sh**
Defines the entire ISO build. Key settings: `iso_label="AlvinArch_..."`, `bootmodes` (BIOS syslinux + UEFI systemd-boot), `airootfs_image_type="squashfs"` with xz compression. Edit first to change branding or compression.
### **packages.x86_64**
The main package list (~400 packages). Packages from allowed repos (`cachyos`, `extra`, `multilib`, `chaotic-aur`) are installed directly. Packages in `localrepo/*.pkg.tar.zst` are pulled from the `[local-aur]` repo. Keep sorted alphabetically.
### **bootstrap_packages**
Minimal packages for the mkarchiso bootstrap phase: `base` and `arch-install-scripts`.
### **pacman.conf**
Defines the repo order: **cachyos → core → extra → multilib → chaotic-aur → local-aur**. The `[local-aur]` repo points to the local `localrepo/` directory for pre-built AUR packages.
---
## User Configuration (skel/)
Dotfiles in `airootfs/etc/skel/` are copied into every new user's home directory on the live ISO.
### **.config/bat/**
[bat](https://github.com/sharkdp/bat) with a Catppuccin Macchiato color theme. Provides `bat` as a `cat` replacement.
### **.config/fish/**
Fish shell configuration (~20 files). Includes nvm integration, fisher plugin manager, Hyprland auto-detection (`auto-Hypr.fish`), frozen theme/keybindings, and custom functions (`edit`, `update`, `lzd`).
### **.config/nvim/**
Full LazyVim setup powered by lazy.nvim. Includes `init.lua`, plugin specs for Obsidian, Arduino, and Harper (grammar), plus standard LazyVim config/options/keymaps/autocmds.
### **.config/hypr/custom/**
Hyprland dotfiles from [end-4 dots-hyprland](https://github.com/end-4/dots-hyprland):
| File | Purpose |
|------|---------|
| `keybinds.lua` | Window manager keybindings |
| `general.lua` | Appearance, gaps, border settings |
| `rules.lua` | Window rules (floating, size, class matching) |
| `execs.lua` | Autostart commands |
| `env.lua` | Environment variables |
| `variables.lua` | Shared variable definitions |
| `scripts/` | Helper scripts (video wallpaper restore, paste-as-type) |
### **.config/starship.toml**
Cross-shell prompt config for [Starship](https://starship.rs/). Works with both Fish and Zsh.
### **.zshrc / .fzf.zsh**
Zsh configuration adapted for oh-my-zsh (installed by `customize_airootfs.sh`) and fzf shell integration.
---
## System Services & Networking
### Services (enabled via symlinks)
| Service | Purpose |
|---------|---------|
| `iwd` | WiFi management |
| `NetworkManager` | Network connections |
| `sshd` | SSH access to live environment |
| `vboxservice` | VirtualBox guest additions |
| `hv_kvp_daemon`, `hv_vss_daemon`, `hv_fcopy_daemon` | Hyper-V integration |
| `vmtoolsd`, `vmware-vmblock-fuse` | VMware guest tools |
| `ModemManager` | Mobile broadband |
| `pacman-init` | Initializes GPG keyring before package operations |
| `choose-mirror` | Auto mirror selection (triggered by `mirror` kernel param) |
| `livecd-alsa-unmuter` | Unmutes audio on live boot |
### Network Config
- **systemd-networkd** with IPv6 privacy extensions enabled
- **systemd-resolved** for DNS
- DHCP auto-configured for wired (ethernet) and wireless (iwd)
### Other System Config
- **ClamAV** — Antivirus daemon config included in `airootfs/etc/clamav/`
- **mkinitcpio** — Archiso-specific initramfs config
- **logind** — No-suspend policy for live session
- **journald** — Volatile (in-memory) log storage
---
## Local Repository (localrepo/)
Pre-built AUR packages that aren't available in any allowed repo. The `local-aur` repo is configured in `pacman.conf` and picked up automatically by mkarchiso.
### Scripts
- **`build-end4-deps.sh`** — Non-interactive AUR build for all end-4 (illogical-impulse) dependencies. Run `--quick` to skip large packages.
- **`update.sh`** — Regenerates the repo database and syncs new package names to `packages.x86_64`.
### end4-pkgbuilds/
Custom PKGBUILDs for end-4 metapackages:
- `quickshell-git` — Quickshell (Qt6/QML shell for Wayland)
- `microtex-git` — LaTeX previewer
- `bibata-modern-classic-bin` — Bibata cursor theme
### Pre-built Packages
Packages like `illogical-impulse-bibata-modern-classic-bin`, `wallust`, `grub-customizer`, `snapd`, `upscayl-bin`, `xwaylandvideobridge`, `eternalterminal`, etc.
---
## Boot Configuration
### UEFI — systemd-boot (`efiboot/`)
Three boot entries: standard Arch Linux, speech/accessibility, and MemTest86+.
### BIOS — GRUB (`grub/`)
`grub.cfg` for BIOS/CSM boot, `loopback.cfg` for booting the ISO from a mounted image.
### BIOS — syslinux (`syslinux/`)
Legacy BIOS boot with custom splash screen. Includes PXE network boot config.
---
## Automated Installer (alvin-install)
The ISO ships an interactive installer at `/usr/local/bin/alvin-install` (source:
`airootfs/usr/local/bin/alvin-install`, ~1,880 lines of bash; the live `/etc/motd`
advertises it). It partitions, encrypts, installs, and fully configures a system —
including the end-4 dotfiles — without network access to this repo.
### Running it
```bash
alvin-install # as root on the live medium (root autologins on tty1)
```
Requirements: **UEFI boot** (it exits if `/sys/firmware/efi` is missing — BIOS/CSM
is not supported by the installer) and `gum`. A network connection is required and
verified by pinging `archlinux.org` before any disk is touched; the network screen
can open `nmtui` for WiFi. Every step is logged to `/var/log/alvin-install.log`,
which is copied into the installed system.
### What it asks (gum TUI screens)
Keymap → network → target disk (the live USB is hidden from the list) → LUKS
encryption (optional; **the LUKS passphrase is the same as your login password**)
→ experimental unl0kr touchscreen unlock → filesystem (`ext4`/`btrfs`) →
username/password/hostname → git identity + GitHub username (both optional) →
timezone/locale → login manager → SSH server (enabled by default) → summary.
### What it does
1. GPT partitioning (1 GiB ESP) on the chosen disk, optional LUKS2 on the rest,
format + mount at `/mnt`
2. `pacstrap` with the package list derived from the medium's
`pkglist.x86_64.txt` (`pacman -Q` of the live ISO) — `archiso`, `syslinux`,
`memtest86+` etc. are dropped, hardcoded essentials (kernel, GRUB,
NetworkManager, cryptsetup, microcode) always appended
3. User account, sudo, git config, GitHub SSH keys (`ssh-import-id`, falling
back to `github.com/<user>.keys`)
4. end-4 dotfiles from the staged `/opt/dots-hyprland` via
`./setup install -f -s --skip-alldeps`
5. Initramfs in one of two modes: **Mode A** — systemd initramfs + `sd-encrypt`
(default); **Mode B** — busybox hooks + unl0kr touchscreen unlock
(experimental, mutually exclusive with TPM2; falls back to Mode A on failure)
6. Optional **TPM2 auto-unlock** (`systemd-cryptenroll`, PCR 0+7; passphrase
slot kept as fallback; warns if Secure Boot is off)
7. GRUB (UEFI, boot entry `ALVIN`), login manager — `none` (plain tty, Hyprland
autostarts), `greetd`+tuigreet, `sddm`, or `gdm` — falls back to `none` only
if the **package** can't be resolved/installed; a failed `systemctl enable`
keeps `getty@tty1` as the login path (the summary still reports the chosen
manager). Optional autologin (forced off when TPM2 is enrolled), and sshd
enabled at boot when selected (default: on) — Arch's stock config allows
**password login with the same password as LUKS**, so only accept the default
on networks you trust (or harden `sshd_config` afterwards). The final banner
reports whether the enable actually succeeded, not just what was selected
On failure an `EXIT` trap unmounts `/mnt` and closes the `cryptroot` mapping, so
re-running is safe. If the end-4 step reports "incomplete", see the repository's
`AGENTS.md` Gotchas for the chroot/systemd limitations that cause it.
---
## Build & Test
### Building the ISO
```bash
# Build the ISO (repo root IS the profile directory)
sudo mkarchiso -v -w work -o out/ .
# Build AUR deps for end-4 (run locally before ISO build if localrepo/ is stale)
./localrepo/build-end4-deps.sh # build all
./localrepo/build-end4-deps.sh --quick # skip large AUR pkgs
# Refresh localrepo DB after adding/moving .pkg.tar.zst files
./localrepo/update.sh # re-indexes existing packages
./localrepo/update.sh pkg1.pkg.tar.zst # add files, then re-index
```
### CI Checks (must pass before merge)
- **ShellCheck**: all `.sh` files checked with `shellcheck -x -s bash`
- **yamllint**: all `.yml`/`.yaml` files (relaxed config)
- **packages.x86_64 syntax**: one package per line, no trailing whitespace, `[a-zA-Z0-9._@+\-]+` only
- **Package repo check**: every package in `packages.x86_64` must be resolvable via `pacman -Si` in allowed repos (`cachyos`, `extra`, `multilib`, `chaotic-aur`), OR have a pre-built `.pkg.tar.zst` in `localrepo/`, OR appear in `localrepo/build-end4-deps.sh`
### Recommended VirtualBox Settings (for testing)
- RAM: 4GB minimum, 8GB recommended
- Video Memory: 128MB
- 3D Acceleration: Enabled
- Storage: 40GB minimum
Guest additions (`vboxservice`), Hyper-V (`hv_*`), and VMware (`vmtoolsd`) tools are all auto-enabled in the live environment.
---
## Planned Additions
The following dotfiles are not yet included but are planned for future versions:
| Component | Status | Notes |
|-----------|--------|-------|
| **Alacritty** terminal config | 🚧 Planned | Catppuccin Macchiato theme to match bat |
| **GTK 3.0/4.0** theme config | 🚧 Planned | Consistent theming across GTK apps |
| **Fontconfig** custom settings | 🚧 Planned | Font rendering and fallback rules |
| **Dunst** notification daemon | 🚧 Planned | Notification appearance and behavior |
---
## Troubleshooting
### ISO won't boot
- Verify the ISO was built with `sudo mkarchiso` (not as a regular user)
- Check that UEFI or BIOS/CSM is correctly set in VM firmware settings
- For Ventoy: use the `.iso` directly, don't extract
### No network in live environment
- `iwd` handles WiFi — run `iwctl` to connect manually if NetworkManager doesn't detect networks
- Ethernet via systemd-networkd with DHCP should work automatically
### Package installation fails during build
- Run `./localrepo/update.sh` to refresh the localrepo database
- Ensure `localrepo/*.pkg.tar.zst` files are valid and not corrupted
- Check that the package name in `packages.x86_64` matches exactly
### LazyVim / oh-my-zsh not installed
- `customize_airootfs.sh` clones repos at build time — requires network access during `mkarchiso`
- Check build logs for git clone failures
---
## Acknowledgements
- [Arch Linux](https://archlinux.org/) and the [archiso](https://wiki.archlinux.org/title/Archiso) project
- [end-4 dots-hyprland](https://github.com/end-4/dots-hyprland) for the illogical-impulse Hyprland config
- [LazyVim](https://www.lazyvim.org/) for the Neovim starter config
- [DistroTube](https://www.youtube.com/watch?v=tSGGBbJBgvk&t=1228s) for the archiso walkthrough that inspired this project