Skip to content

Repository files navigation

SpaceOS SpaceOS

SpaceOS is a personal image-based Linux distribution built on Fedora Bootc 44. It uses Sway as its graphical environment, is delivered as an OCI image, and receives transactional system updates through bootc. This repository contains the system definition, desktop configuration, GHCR publishing automation, and a script for building an Anaconda installer ISO locally.

For the story behind the project, see How and why I built my own bootc-based Linux distribution. The article covers the path from the initial idea to an encrypted dual-boot installation, DisplayLink support, and the CI/CD update pipeline used by SpaceOS.

Important

SpaceOS is built specifically for my hardware, workflow, and personal preferences. I do not recommend using it directly as a general-purpose distribution. You are, however, encouraged to fork this repository and use it as a starting point for building your own bootc-based distribution.

Highlights

  • Fedora Bootc 44 base image.
  • Transactional system images published to GitHub Container Registry.
  • Lightweight desktop built around Sway, Waybar, Rofi, and Alacritty.
  • Graphical installer based on Anaconda.
  • Background updates without forced restarts.
  • Previous deployment available for rollback.
  • DisplayLink support with an EVDI module built for the image kernel.
  • Custom Plymouth branding for the boot and LUKS unlock screens.
  • A consistent visual style based on Ayu Dark and Ayu Light across the desktop and supported applications.

Installation

Installing from an ISO

Installer images are not published as GitHub Release assets because the complete ISO exceeds GitHub's per-file size limit. Build the installer locally from the repository instead. The script requires Podman, root access through sudo, and enough free disk space for the container images and resulting ISO.

  1. Clone the repository and check out the release tag to install:

    git clone https://github.com/SpaceShaman/spaceos.git
    cd spaceos
    git checkout vX.Y.Z
  2. Build the ISO. By default, the script reads the latest local release tag for the installer version and embeds the ghcr.io/spaceshaman/spaceos:auto image so that the installed system continues tracking the automatic update channel:

    ./scripts/build-installer-iso.sh

    To select a version explicitly, use VERSION without the leading v:

    VERSION=X.Y.Z ./scripts/build-installer-iso.sh

    BASE_IMAGE, PAYLOAD_IMAGE, BUILDER_IMAGE, and OUTPUT_DIR can also be overridden when testing a different image or build environment.

  3. Verify the generated checksum:

    cd output/installer-vX.Y.Z
    sha256sum --check SpaceOS-vX.Y.Z-x86_64.iso.sha256
  4. Write the ISO to a USB drive using a tool such as Fedora Media Writer.

  5. Boot the computer from the prepared installation media.

  6. Complete the installation using the graphical Anaconda installer.

The SpaceOS image used for installation is embedded in the ISO. After installation, the system tracks the auto channel in GHCR, so future updates do not require the installer media.

Switching an existing bootc system

An existing bootc-compatible system can switch directly to SpaceOS:

sudo bootc switch ghcr.io/spaceshaman/spaceos:auto
sudo reboot

Use the stable channel if the system should receive official SpaceOS releases only:

sudo bootc switch ghcr.io/spaceshaman/spaceos:stable
sudo reboot

Back up important data before switching. SpaceOS contains configuration tailored to specific hardware and may change assumptions about services, the desktop, drivers, or the target system layout.

Installing to prepared filesystems

Use bootc install to-filesystem to install SpaceOS on filesystems that have already been created and formatted. Replace the device paths below, verify them carefully, and run:

set -euo pipefail

ROOT_DEVICE="/dev/ROOT_DEVICE"
BOOT_DEVICE="/dev/BOOT_DEVICE"
EFI_DEVICE="/dev/EFI_DEVICE"
TARGET="/mnt/spaceos"
IMAGE="ghcr.io/spaceshaman/spaceos:auto"

sudo mkdir -p "$TARGET"
sudo mount "$ROOT_DEVICE" "$TARGET"
sudo mkdir -p "$TARGET/boot"
sudo mount "$BOOT_DEVICE" "$TARGET/boot"
sudo mkdir -p "$TARGET/boot/efi"
sudo mount "$EFI_DEVICE" "$TARGET/boot/efi"

findmnt -R "$TARGET"

ROOT_UUID="$(sudo blkid -s UUID -o value "$ROOT_DEVICE")"
BOOT_UUID="$(sudo blkid -s UUID -o value "$BOOT_DEVICE")"

sudo podman pull "$IMAGE"
sudo podman run --rm --privileged \
  --pid=host \
  --ipc=host \
  --security-opt label=type:unconfined_t \
  -v /dev:/dev \
  -v /var/lib/containers:/var/lib/containers \
  -v "${TARGET}:/target" \
  "$IMAGE" \
  bootc install to-filesystem \
    --bootloader=grub \
    --root-mount-spec="UUID=${ROOT_UUID}" \
    --boot-mount-spec="UUID=${BOOT_UUID}" \
    /target

The mounts select the root, /boot, and EFI filesystems, while the UUID options tell the installed system how to find root and /boot during startup. This example uses a separate /boot; other storage layouts may require different mount options or additional --karg arguments. Change auto to stable to follow official releases only.

GHCR images and tags

Images are published as:

ghcr.io/spaceshaman/spaceos
Tag Meaning Retention
v0.1.3 Immutable image for a specific release Kept indefinitely
stable Latest official SpaceOS release Moving tag
latest Alias for the latest official release Moving tag
auto Latest release or latest rebuild following a Fedora update Moving tag
auto-v0.1.3-20260920-abcdef123456 A specific automatic rebuild Latest five

Publishing a new vX.Y.Z tag moves stable, latest, and auto to the new release. Once a week, GitHub Actions checks the digest of quay.io/fedora/fedora-bootc:44. If the base changed, the source of the latest SpaceOS release is rebuilt and auto is moved to the resulting image. GitHub Actions does not build or publish installer ISOs.

All vX.Y.Z images remain in the registry. Only the five newest dated automatic rebuilds are retained.

System updates

SpaceOS does not use an update mechanism that automatically reboots the computer after finding a new image. A custom systemd timer checks for updates every hour, with a randomized delay of up to 10 minutes.

The update process works as follows:

  1. The system checks the channel selected during installation or the latest bootc switch.
  2. The update is deferred on a metered connection, when the battery is below 30%, or while the system load is high.
  3. A new image is downloaded and prepared as a staged deployment.
  4. The running system is neither restarted nor modified.
  5. Waybar displays an indicator when a new deployment is ready.
  6. The update is applied during a normal restart initiated by the user.

Updates can also be inspected and managed directly with bootc:

bootc status
sudo bootc upgrade --check
sudo bootc upgrade

bootc status shows the currently booted image, any staged update, and the rollback deployment. bootc upgrade --check checks registry metadata without downloading and staging the complete update. A regular bootc upgrade downloads the new image and stages it for the next restart, but does not restart the computer.

Automatic updater logs are available through:

journalctl -u spaceos-update.service

Inspect the current, staged, and rollback deployments with:

bootc status

Included software

The following tables list the main applications and tools added by SpaceOS. They do not include system-level dependencies inherited from the Fedora base image.

Desktop environment

Software Description
Sway Tiling Wayland compositor compatible with the i3 configuration model.
swayidle Turns displays off after 5 minutes of inactivity and restores them on input.
Waybar Status bar showing workspaces, network, audio, battery, and update state.
Rofi Application launcher.
Alacritty GPU-accelerated terminal emulator.
greetd + tuigreet Lightweight login manager used to start the Sway session.
Ayu Dark / Ayu Light Matching GTK, terminal, Waybar, and Rofi themes.
Plymouth Graphical boot screen, including the LUKS unlock prompt.

Applications

Software Description
Firefox Web browser.
Thunderbird Email and calendar client.
Signal Desktop Signal messenger distributed as an AppImage.
Teams for Linux Unofficial Microsoft Teams client.
ChatGPT ChatGPT desktop application for Linux.
Bruno API client for designing and testing HTTP requests.
qBittorrent BitTorrent client.
VLC Multimedia player.
GIMP Raster graphics editor.
imv Wayland image viewer.
FileZilla FTP, FTPS, and SFTP client.
GNOME Disks Utility for inspecting and managing storage devices and disk images.
Foliate eBook reader supporting EPUB, MOBI, AZW3, and PDF formats.
LibreOffice Calc Spreadsheet application.
LibreOffice Writer Word processor.
ZAP Security testing tool for web applications.

Terminal and development

Software Description
Fish Interactive shell with rich suggestions and completions.
Neovim Text editor with the SpaceOS development configuration.
tmux Terminal multiplexer.
Midnight Commander Two-panel terminal file manager.
Git Version control system.
lazygit Terminal user interface for Git.
wlctl Terminal interface for Wi-Fi and VPN connections managed by NetworkManager.
bluetui Terminal interface for managing Bluetooth devices through BlueZ.
Go Go compiler and development toolchain.
Zig Zig compiler and development toolchain.
uv Fast Python project and package manager.
rclone Command-line sync tool for cloud storage and remote filesystems.
rsync Efficient local and remote file synchronization utility.
zk Plain-text note-taking assistant with a Zettelkasten workflow.
jq Command-line JSON processor.
SOPS Command-line editor for encrypted secrets in configuration files.
age Simple, modern and secure encryption tool.
fzf Fuzzy finder for filtering and selecting items in the terminal.
fd Fast command-line tool for finding files and directories.
bat cat clone with syntax highlighting and Git integration.
htop Interactive process viewer and system monitor.
Codex OpenAI coding agent for the terminal.
GitHub Copilot CLI GitHub coding assistant for the terminal.
opencommit Generates commit messages from staged changes.
Translate Shell Command-line translator using various translation engines.
Newsboat Terminal-based RSS/Atom feed reader.

Containers and system tools

Software Description
Podman Daemonless OCI container runtime and image builder.
Docker Container environment compatible with the Docker ecosystem.
Docker Compose Definition and orchestration of multi-container environments.
Docker Buildx Extended Docker image builder with multi-platform build support.
BlueZ Bluetooth stack and system service.
Wiremix Terminal mixer for PipeWire.
brightnessctl Display brightness control.
grim + slurp + swappy Wayland screenshot capture, region selection, and annotation.
DisplayLink / EVDI Support for DisplayLink adapters and docking stations.
Netcat (nc) Command-line utility for TCP and UDP connections.

Fish aliases

I love aliases. Life is too short to type the same long command over and over, and my fingers have better things to do. These shortcuts are defined in config.fish for interactive Fish sessions:

Alias Runs What I use it for
o open Open files and URLs with the default application.
w, b wlctl, bluetui Open the Wi-Fi/VPN and Bluetooth terminal interfaces.
c oco Generate a commit message with opencommit.
wiremix, mix, m wiremix --config /etc/wiremix/wiremix.toml Open the PipeWire mixer with my configuration.
lazygit, l lazygit --use-config-dir /etc/lazygit Open lazygit with my configuration.
v, vim nvim Edit files in Neovim.
p python3 Run Python.
d, du, dd, dr docker compose, docker compose up -d, docker compose down, docker compose restart Manage Compose projects.
dev, devd, devr docker compose -f docker-compose.dev.yml with up -d, down, or restart Manage the development Compose file.
t, tp trans -b :en, trans -b :pl Translate text to English or Polish.
box rclone mount box: ~/box --vfs-cache-mode full --daemon Mount my Box remote at ~/box.
syncbox rsync -av --size-only --delete --progress -e ssh box:Muzyka/ Muzyka/ Sync music from box into the local Muzyka/ directory.
newsboat, n newsboat --config-file /etc/newsboat/config --url-file /etc/newsboat/urls Open Newsboat with the system feed list and configuration.
g codex exec --ephemeral --skip-git-repo-check --sandbox read-only Run a prompt with Codex in a read-only sandbox; pass the prompt as arguments or through standard input. Defined as a Fish function.

Keyboard shortcuts

Mod refers to the Super/Windows key.

Applications and session

Shortcut Action
Mod + Enter Open Alacritty.
Mod + R Open the Rofi application launcher.
Mod + B Open Firefox.
Mod + G Open ChatGPT.
Mod + T Toggle the light/dark theme.
Mod + Escape Show or hide Waybar.
Mod + Q Close the focused window.
Mod + Shift + Q Power off the system.
Mod + Shift + R Reload the Sway configuration.

Windows and workspaces

Shortcut Action
Mod + A / Mod + F Focus the previous/next window.
Mod + Shift + A / Mod + Shift + F Swap the focused window with the previous/next one.
Mod + Ctrl + J / Mod + Ctrl + ; Shrink/grow the focused window's width by 50 px.
Mod + Ctrl + K / Mod + Ctrl + L Shrink/grow the focused window's height by 50 px.
Mod + S / Mod + D Focus the previous/next workspace.
Mod + Shift + S / Mod + Shift + D Move the focused window to the previous/next workspace.
Mod + J / Mod + ; Focus the output to the left/right.
Mod + L / Mod + K Focus the output above/below.
Mod + Shift + J / Mod + Shift + ; Move the focused window to the output on the left/right.
Mod + Shift + L / Mod + Shift + K Move the focused window to the output above/below.

Screenshots and media

Shortcut Action
Print Screen Select a region, capture it, and open it in Swappy.
Shift + Print Screen Capture the full screen and open it in Swappy.
XF86AudioRaiseVolume / XF86AudioLowerVolume Increase/decrease audio volume.
XF86AudioMute Toggle audio mute.
XF86MonBrightnessUp / XF86MonBrightnessDown Increase/decrease display brightness.

Dynamic window and workspace management

Workspaces are independent on each output and numbered consecutively from 1. Moving backward from the first workspace inserts a new first workspace and shifts the existing ones; empty workspaces are removed by Sway, then the remaining workspaces are renumbered immediately. Forward and backward navigation creates a workspace only when the current workspace contains a window, and moving a window never leaves an unnecessary empty workspace behind.

Window focus and swapping cycle through the windows on the focused workspace. A background Sway listener adjusts the next tiling split after each window opens or closes: it uses the longer screen axis for one or an odd number of windows, and the other axis for an even number, so the layout alternates automatically with the window count.

Releases

Packages

Contributors

Languages