commit 1bc83085c6d7218f75e57cef078985e10db048e1 Author: Andreas Schulte <0x0001f346@pm.me> Date: Mon Sep 22 23:12:44 2025 +0200 first commit diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..379ec1c --- /dev/null +++ b/LICENSE @@ -0,0 +1,18 @@ +MIT License + +Copyright (c) 2025 Andreas Schulte + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO +EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..44d3084 --- /dev/null +++ b/README.md @@ -0,0 +1,56 @@ +# Boot-to-Firefox (Minimal Arch Linux Live System) + +This repository is a **proof-of-work** project — more of a "I always wanted to try this" kind of thing. +The goal is to demonstrate how one can reproducibly build a **minimal live system** based on **Arch Linux** and its **LTS kernel**. + +Once booted, the system skips the usual bells and whistles and goes straight into a graphical environment where the only real application of interest is: **Firefox**. + +## Why? + +In the age of increasingly complex software stacks, this project explores the opposite philosophy: +a lean, hardened live system that is **ephemeral by design**. + +- **No persistence**: Each boot is a clean slate. +- **Up-to-date**: Rebuild, PXE-boot, and users always start with the latest packages. +- **Reduced attack surface**: Minimal packages, minimal services, minimal surprises. +- **Reproducible**: The build pipeline ensures you know exactly what goes into the image. + +This makes it a neat candidate for: + +- **PXE deployments** in organizations where users only need a browser. +- **Security-conscious environments** where diskless, hardened endpoints reduce risks. +- **Training & demonstrations** where reproducible minimalism is key. + +## Features + +- Boots directly into **Firefox** under a Wayland compositor (Hyprland). +- Uses **Arch Linux LTS kernel** for stability. +- Automatically sets a **random root password** on each boot. +- Automatically sets a **random hostname** on each boot. +- Boots fast and quietly — no cluttered boot messages, no menu prompts. +- Network connectivity via DHCP out-of-the-box. + +## Future Directions + +- Integrating **pre-configured Firefox policies** (bookmarks, addons, homepage). +- Providing optional **Waybar** or minimal panels for usability. +- Exploring additional **hardening mechanisms** (AppArmor, sandboxing, etc.). + +## Disclaimer + +This project is for **educational and demonstration purposes only**. +Do not rely on it as-is for production use — but do feel free to tinker, adapt, and extend. + +## Build it + +Building requires an Arch Linux system with the `archiso` package installed. + +```bash +./build.sh +``` + +# Resources + +- https://wiki.archlinux.org/title/Archiso +- https://gitlab.archlinux.org/archlinux/archiso/-/blob/master/docs/README.profile.rst +- https://github.com/archlinux/archiso/blob/master/configs/releng/profiledef.sh diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..4482a62 --- /dev/null +++ b/build.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +PROFILEPATH="$(realpath "$(dirname "$0")/profiles/boot-to-firefox")" + +IMAGEPATH="/tmp/boot-to-firefox" +WORKPATH="$IMAGEPATH/work" +OUTPATH="$IMAGEPATH/out" + +if [ -d "$IMAGEPATH" ]; then + sudo rm -R "$IMAGEPATH" +fi + +mkdir -p "$WORKPATH" +mkdir -p "$OUTPATH" + +sudo mkarchiso -v -w "$WORKPATH" -o "$OUTPATH" "$PROFILEPATH" diff --git a/profiles/boot-to-firefox/airootfs/etc/group b/profiles/boot-to-firefox/airootfs/etc/group new file mode 100644 index 0000000..39375d7 --- /dev/null +++ b/profiles/boot-to-firefox/airootfs/etc/group @@ -0,0 +1,5 @@ +root:x:0:root +adm:x:4:liveuser +wheel:x:10:liveuser +uucp:x:14:liveuser +liveuser:x:1000:liveuser diff --git a/profiles/boot-to-firefox/airootfs/etc/gshadow b/profiles/boot-to-firefox/airootfs/etc/gshadow new file mode 100644 index 0000000..7cd1f45 --- /dev/null +++ b/profiles/boot-to-firefox/airootfs/etc/gshadow @@ -0,0 +1,3 @@ +root:!*::root +liveuser:!*:: + diff --git a/profiles/boot-to-firefox/airootfs/etc/hostname b/profiles/boot-to-firefox/airootfs/etc/hostname new file mode 100644 index 0000000..884d909 --- /dev/null +++ b/profiles/boot-to-firefox/airootfs/etc/hostname @@ -0,0 +1 @@ +boot-to-firefox \ No newline at end of file diff --git a/profiles/boot-to-firefox/airootfs/etc/locale.conf b/profiles/boot-to-firefox/airootfs/etc/locale.conf new file mode 100644 index 0000000..8ee5464 --- /dev/null +++ b/profiles/boot-to-firefox/airootfs/etc/locale.conf @@ -0,0 +1 @@ +LANG=de_DE.utf8 diff --git a/profiles/boot-to-firefox/airootfs/etc/localtime b/profiles/boot-to-firefox/airootfs/etc/localtime new file mode 120000 index 0000000..622b45b --- /dev/null +++ b/profiles/boot-to-firefox/airootfs/etc/localtime @@ -0,0 +1 @@ +/usr/share/zoneinfo/Europe/Berlin \ No newline at end of file diff --git a/profiles/boot-to-firefox/airootfs/etc/mkinitcpio.conf.d/archiso.conf b/profiles/boot-to-firefox/airootfs/etc/mkinitcpio.conf.d/archiso.conf new file mode 100644 index 0000000..ec1796f --- /dev/null +++ b/profiles/boot-to-firefox/airootfs/etc/mkinitcpio.conf.d/archiso.conf @@ -0,0 +1,3 @@ +HOOKS=(base udev microcode modconf kms memdisk archiso archiso_loop_mnt archiso_pxe_common archiso_pxe_nbd archiso_pxe_http archiso_pxe_nfs block filesystems keymap keyboard plymouth) +COMPRESSION="xz" +COMPRESSION_OPTIONS=(-9e) diff --git a/profiles/boot-to-firefox/airootfs/etc/mkinitcpio.d/linux.preset b/profiles/boot-to-firefox/airootfs/etc/mkinitcpio.d/linux.preset new file mode 100644 index 0000000..15eadc4 --- /dev/null +++ b/profiles/boot-to-firefox/airootfs/etc/mkinitcpio.d/linux.preset @@ -0,0 +1,8 @@ +# mkinitcpio preset file for the 'linux' package on archiso + +PRESETS=('archiso') + +ALL_kver='/boot/vmlinuz-linux-lts' +archiso_config='/etc/mkinitcpio.conf.d/archiso.conf' + +archiso_image="/boot/initramfs-linux-lts.img" diff --git a/profiles/boot-to-firefox/airootfs/etc/pacman.conf b/profiles/boot-to-firefox/airootfs/etc/pacman.conf new file mode 100644 index 0000000..200629e --- /dev/null +++ b/profiles/boot-to-firefox/airootfs/etc/pacman.conf @@ -0,0 +1,97 @@ +# +# /etc/pacman.conf +# +# See the pacman.conf(5) manpage for option and repository directives + +# +# GENERAL OPTIONS +# +[options] +# The following paths are commented out with their default values listed. +# If you wish to use different paths, uncomment and update the paths. +#RootDir = / +#DBPath = /var/lib/pacman/ +#CacheDir = /var/cache/pacman/pkg/ +#LogFile = /var/log/pacman.log +#GPGDir = /etc/pacman.d/gnupg/ +#HookDir = /etc/pacman.d/hooks/ +HoldPkg = pacman glibc +#XferCommand = /usr/bin/curl -L -C - -f -o %o %u +#XferCommand = /usr/bin/wget --passive-ftp -c -O %o %u +#CleanMethod = KeepInstalled +Architecture = auto + +# Pacman won't upgrade packages listed in IgnorePkg and members of IgnoreGroup +#IgnorePkg = +#IgnoreGroup = + +#NoUpgrade = +#NoExtract = + +# Misc options +#UseSyslog +#Color +#NoProgressBar +CheckSpace +#VerbosePkgLists +#ParallelDownloads = 5 + +# By default, pacman accepts packages signed by keys that its local keyring +# trusts (see pacman-key and its man page), as well as unsigned packages. +SigLevel = Required DatabaseOptional +LocalFileSigLevel = Optional +#RemoteFileSigLevel = Required + +# NOTE: You must run `pacman-key --init` before first using pacman; the local +# keyring can then be populated with the keys of all official Arch Linux +# packagers with `pacman-key --populate archlinux`. + +# +# REPOSITORIES +# - can be defined here or included from another file +# - pacman will search repositories in the order defined here +# - local/custom mirrors can be added here or in separate files +# - repositories listed first will take precedence when packages +# have identical names, regardless of version number +# - URLs will have $repo replaced by the name of the current repo +# - URLs will have $arch replaced by the name of the architecture +# +# Repository entries are of the format: +# [repo-name] +# Server = ServerName +# Include = IncludePath +# +# The header [repo-name] is crucial - it must be present and +# uncommented to enable the repo. +# + +# The testing repositories are disabled by default. To enable, uncomment the +# repo name header and Include lines. You can add preferred servers immediately +# after the header, and they will be used before the default mirrors. + +#[core-testing] +#Include = /etc/pacman.d/mirrorlist + +[core] +Include = /etc/pacman.d/mirrorlist + +#[extra-testing] +#Include = /etc/pacman.d/mirrorlist + +[extra] +Include = /etc/pacman.d/mirrorlist + +# If you want to run 32 bit applications on your x86_64 system, +# enable the multilib repositories as required here. + +#[multilib-testing] +#Include = /etc/pacman.d/mirrorlist + +[multilib] +Include = /etc/pacman.d/mirrorlist + +# An example of a custom package repository. See the pacman manpage for +# tips on creating your own repositories. +#[custom] +#SigLevel = Optional TrustAll +#Server = file:///home/custompkgs diff --git a/profiles/boot-to-firefox/airootfs/etc/passwd b/profiles/boot-to-firefox/airootfs/etc/passwd new file mode 100644 index 0000000..02fc90a --- /dev/null +++ b/profiles/boot-to-firefox/airootfs/etc/passwd @@ -0,0 +1,2 @@ +root:x:0:0:root:/root:/usr/bin/bash +liveuser:x:1000:1000::/home/liveuser:/usr/bin/bash diff --git a/profiles/boot-to-firefox/airootfs/etc/plymouth/plymouthd.conf b/profiles/boot-to-firefox/airootfs/etc/plymouth/plymouthd.conf new file mode 100644 index 0000000..26d5384 --- /dev/null +++ b/profiles/boot-to-firefox/airootfs/etc/plymouth/plymouthd.conf @@ -0,0 +1,2 @@ +[Daemon] +Theme=bgrt diff --git a/profiles/boot-to-firefox/airootfs/etc/shadow b/profiles/boot-to-firefox/airootfs/etc/shadow new file mode 100644 index 0000000..65f56dd --- /dev/null +++ b/profiles/boot-to-firefox/airootfs/etc/shadow @@ -0,0 +1,2 @@ +root::14871:::::: +liveuser::14871:::::: diff --git a/profiles/boot-to-firefox/airootfs/etc/systemd/logind.conf.d/do-not-suspend.conf b/profiles/boot-to-firefox/airootfs/etc/systemd/logind.conf.d/do-not-suspend.conf new file mode 100644 index 0000000..f3ecb39 --- /dev/null +++ b/profiles/boot-to-firefox/airootfs/etc/systemd/logind.conf.d/do-not-suspend.conf @@ -0,0 +1,4 @@ +[Login] +HandleSuspendKey=ignore +HandleHibernateKey=ignore +HandleLidSwitch=ignore diff --git a/profiles/boot-to-firefox/airootfs/etc/systemd/network/20-ethernet.network b/profiles/boot-to-firefox/airootfs/etc/systemd/network/20-ethernet.network new file mode 100644 index 0000000..d3a3271 --- /dev/null +++ b/profiles/boot-to-firefox/airootfs/etc/systemd/network/20-ethernet.network @@ -0,0 +1,24 @@ +[Match] +# Matching with "Type=ether" causes issues with containers because it also matches virtual Ethernet interfaces (veth*). +# See https://bugs.archlinux.org/task/70892 +# Instead match by globbing the network interface name. +Name=en* +Name=eth* + +[Link] +RequiredForOnline=routable + +[Network] +DHCP=yes +MulticastDNS=yes + +# systemd-networkd does not set per-interface-type default route metrics +# https://github.com/systemd/systemd/issues/17698 +# Explicitly set route metric, so that Ethernet is preferred over Wi-Fi and Wi-Fi is preferred over mobile broadband. +# Use values from NetworkManager. From nm_device_get_route_metric_default in +# https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/main/src/core/devices/nm-device.c +[DHCPv4] +RouteMetric=100 + +[IPv6AcceptRA] +RouteMetric=100 diff --git a/profiles/boot-to-firefox/airootfs/etc/systemd/network/20-wlan.network b/profiles/boot-to-firefox/airootfs/etc/systemd/network/20-wlan.network new file mode 100644 index 0000000..8b70a95 --- /dev/null +++ b/profiles/boot-to-firefox/airootfs/etc/systemd/network/20-wlan.network @@ -0,0 +1,20 @@ +[Match] +Name=wl* + +[Link] +RequiredForOnline=routable + +[Network] +DHCP=yes +MulticastDNS=yes + +# systemd-networkd does not set per-interface-type default route metrics +# https://github.com/systemd/systemd/issues/17698 +# Explicitly set route metric, so that Ethernet is preferred over Wi-Fi and Wi-Fi is preferred over mobile broadband. +# Use values from NetworkManager. From nm_device_get_route_metric_default in +# https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/main/src/core/devices/nm-device.c +[DHCPv4] +RouteMetric=600 + +[IPv6AcceptRA] +RouteMetric=600 diff --git a/profiles/boot-to-firefox/airootfs/etc/systemd/network/20-wwan.network b/profiles/boot-to-firefox/airootfs/etc/systemd/network/20-wwan.network new file mode 100644 index 0000000..6e1c8dd --- /dev/null +++ b/profiles/boot-to-firefox/airootfs/etc/systemd/network/20-wwan.network @@ -0,0 +1,19 @@ +[Match] +Name=ww* + +[Link] +RequiredForOnline=routable + +[Network] +DHCP=yes + +# systemd-networkd does not set per-interface-type default route metrics +# https://github.com/systemd/systemd/issues/17698 +# Explicitly set route metric, so that Ethernet is preferred over Wi-Fi and Wi-Fi is preferred over mobile broadband. +# Use values from NetworkManager. From nm_device_get_route_metric_default in +# https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/main/src/core/devices/nm-device.c +[DHCPv4] +RouteMetric=700 + +[IPv6AcceptRA] +RouteMetric=700 diff --git a/profiles/boot-to-firefox/airootfs/etc/systemd/networkd.conf.d/ipv6-privacy-extensions.conf b/profiles/boot-to-firefox/airootfs/etc/systemd/networkd.conf.d/ipv6-privacy-extensions.conf new file mode 100644 index 0000000..0e9ceb4 --- /dev/null +++ b/profiles/boot-to-firefox/airootfs/etc/systemd/networkd.conf.d/ipv6-privacy-extensions.conf @@ -0,0 +1,2 @@ +[Network] +IPv6PrivacyExtensions=yes diff --git a/profiles/boot-to-firefox/airootfs/etc/systemd/resolved.conf.d/archiso.conf b/profiles/boot-to-firefox/airootfs/etc/systemd/resolved.conf.d/archiso.conf new file mode 100644 index 0000000..636f3bd --- /dev/null +++ b/profiles/boot-to-firefox/airootfs/etc/systemd/resolved.conf.d/archiso.conf @@ -0,0 +1,4 @@ +# Default systemd-resolved configuration for archiso + +[Resolve] +MulticastDNS=yes diff --git a/profiles/boot-to-firefox/airootfs/etc/systemd/system-generators/systemd-gpt-auto-generator b/profiles/boot-to-firefox/airootfs/etc/systemd/system-generators/systemd-gpt-auto-generator new file mode 120000 index 0000000..dc1dc0c --- /dev/null +++ b/profiles/boot-to-firefox/airootfs/etc/systemd/system-generators/systemd-gpt-auto-generator @@ -0,0 +1 @@ +/dev/null \ No newline at end of file diff --git a/profiles/boot-to-firefox/airootfs/etc/systemd/system/getty@tty1.service.d/autologin.conf b/profiles/boot-to-firefox/airootfs/etc/systemd/system/getty@tty1.service.d/autologin.conf new file mode 100644 index 0000000..b10ceb2 --- /dev/null +++ b/profiles/boot-to-firefox/airootfs/etc/systemd/system/getty@tty1.service.d/autologin.conf @@ -0,0 +1,3 @@ +[Service] +ExecStart= +ExecStart=-/sbin/agetty -o '-p -f -- \\u' --noclear --autologin liveuser - $TERM diff --git a/profiles/boot-to-firefox/airootfs/etc/systemd/system/multi-user.target.wants/dbus.service b/profiles/boot-to-firefox/airootfs/etc/systemd/system/multi-user.target.wants/dbus.service new file mode 120000 index 0000000..47b81fa --- /dev/null +++ b/profiles/boot-to-firefox/airootfs/etc/systemd/system/multi-user.target.wants/dbus.service @@ -0,0 +1 @@ +/usr/lib/systemd/system/dbus.service \ No newline at end of file diff --git a/profiles/boot-to-firefox/airootfs/etc/systemd/system/multi-user.target.wants/random-hostname.service b/profiles/boot-to-firefox/airootfs/etc/systemd/system/multi-user.target.wants/random-hostname.service new file mode 120000 index 0000000..764903a --- /dev/null +++ b/profiles/boot-to-firefox/airootfs/etc/systemd/system/multi-user.target.wants/random-hostname.service @@ -0,0 +1 @@ +../random-hostname.service \ No newline at end of file diff --git a/profiles/boot-to-firefox/airootfs/etc/systemd/system/multi-user.target.wants/random-root-password.service b/profiles/boot-to-firefox/airootfs/etc/systemd/system/multi-user.target.wants/random-root-password.service new file mode 120000 index 0000000..bd78042 --- /dev/null +++ b/profiles/boot-to-firefox/airootfs/etc/systemd/system/multi-user.target.wants/random-root-password.service @@ -0,0 +1 @@ +../random-root-password.service \ No newline at end of file diff --git a/profiles/boot-to-firefox/airootfs/etc/systemd/system/multi-user.target.wants/seatd.service b/profiles/boot-to-firefox/airootfs/etc/systemd/system/multi-user.target.wants/seatd.service new file mode 120000 index 0000000..43968b5 --- /dev/null +++ b/profiles/boot-to-firefox/airootfs/etc/systemd/system/multi-user.target.wants/seatd.service @@ -0,0 +1 @@ +/usr/lib/systemd/system/seatd.service \ No newline at end of file diff --git a/profiles/boot-to-firefox/airootfs/etc/systemd/system/random-hostname.service b/profiles/boot-to-firefox/airootfs/etc/systemd/system/random-hostname.service new file mode 100644 index 0000000..aa4d52b --- /dev/null +++ b/profiles/boot-to-firefox/airootfs/etc/systemd/system/random-hostname.service @@ -0,0 +1,10 @@ +[Unit] +Description=Set random hostname +Before=systemd-logind.service + +[Service] +Type=oneshot +ExecStart=/bin/sh -c 'hostnamectl set-hostname "client-$(tr -dc a-z0-9