AMZSpiceOx is an educational Linux distribution project focused on boot flow, root filesystem assembly, and cloud-oriented systems engineering.
The project started as a Linux-from-scratch style exercise. The current direction is more practical:
- keep the custom kernel and initramfs flow
- keep the persistent ext4 root filesystem image
- stop compiling the whole userspace locally by default
- assemble the rootfs from upstream binary packages
- add AmazonSpiceOx overlays on top
That gives us a project that is still low-level and educational, but much faster to iterate on.
AmazonSpiceOx now uses Debian Stable as its upstream package base.
Why Debian instead of Alpine or Arch:
- Debian Stable has a large package archive
glibccompatibility is friendlier for AWS tooling and common server softwaredebootstrapgives us a clean, official rootfs bootstrap path- Debian is easier to keep reproducible than a rolling-release base
- the package model matches the goal of "assemble, overlay, boot, validate"
The default suite in this repo is currently:
trixie
You can change it through DEBIAN_SUITE in the Makefile or on the command
line.
Current boot and image flow:
Debian mirror
-> package download cache
-> debootstrap rootfs assembly
-> AmazonSpiceOx overlays
-> custom initramfs
-> ext4 root disk
-> QEMU
Current runtime flow:
Linux kernel
-> initramfs /init
-> mount /dev/vda
-> switch_root
-> /sbin/init
-> arrakis:/#
amazonspiceox/
|- configs/
| `- debian/
|- docs/
|- initramfs/
|- kernel/
|- manifests/
|- overlays/
|- packages/
|- qemu/
|- rootfs/
|- scripts/
|- build/
|- downloads/
`- out/
Important directories:
rootfs/: base overlay copied into the generated Debian rootfsoverlays/: optional profile-specific overlaysinitramfs/: stage-1 boot userspacemanifests/: package lists for rootfs compositionconfigs/debian/: Debian package source configurationscripts/: reproducible build helpers
Implemented:
- vanilla Linux kernel build in QEMU
- custom initramfs with stage-1
/init - persistent ext4 root filesystem
- stage-2
/sbin/init - boot logging and basic network bring-up
- Debian Stable rootfs assembly through
debootstrap - manifest-driven package selection
- composable
base,debug,ops,aws,awscli,ssm,terraform,kubectl, anddockerprofile building - optional
guiprofile for Chromium, X11 app launch, and desktop Python runtimes - optional
xpraprofile for cross-platform forwarding of individual guest GUI apps to WSL or macOS hosts - optional
ssm-powerconnectprofile for the Tkinter-based AWS SSM desktop tool - interactive login shells now prefer
/bin/bashwhen it is present in the guest rootfs
Still intentionally small:
- no systemd dependency
- no installer
- no package manager replacement yet
- no AWS-specific overlay profile enabled by default
On Debian or Ubuntu hosts, install:
sudo apt update
sudo apt install -y \
build-essential \
bc \
bison \
flex \
libssl-dev \
libelf-dev \
cpio \
curl \
xz-utils \
bzip2 \
gzip \
make \
qemu-system-x86 \
debootstrap \
binutils \
file \
ca-certificates \
e2fsprogs \
gnupg \
unzip \
patchRun a host check with:
make depsNotes:
make fetchcan run unprivilegedmake rootfsrequiressudobecausedebootstrapcreates a real Debian filesystem treemake imageis safest undersudoas well, because the generated rootfs can contain root-owned paths such as/root- the ext4 image builder auto-grows the image when the requested size is too small for the generated Debian rootfs
From WSL or Linux:
make profile-info
make fetch
make verify-packages
make initramfs
sudo -E make rootfs
sudo -E make image
make run
make run-gui
make xpra-attachAvoid sudo -E make all for regular local work. It can leave source trees in
build/src/ owned by root, which then breaks later non-root rebuilds.
Build initramfs before the sudo-only rootfs/image steps when you are running
the commands separately.
Expected boot marker:
AMZSpiceOx 1.0.0
AMAZONSPICEOX_PHASE3_BOOT_OK
arrakis:/#
To exit QEMU cleanly from inside the guest:
poweroff
In the normal interactive shell, exit or Ctrl+D also asks the guest to
power off.
The serial console passes Ctrl+C through to the guest, so it behaves like a
normal Linux interrupt instead of closing QEMU. If the guest is not responding,
close the host terminal or stop the QEMU process from another terminal.
Main targets:
make deps
make fetch
make verify-packages
make rootfs
make initramfs
make image
make run
make run-only
make run-gui
make run-gui-only
make xpra-attach
make release
make release-package-only
make smoke
make smoke-net
make smoke-awscli
make smoke-ssm
make smoke-ssm-powerconnect
make smoke-terraform
make smoke-kubectl
make smoke-docker
make smoke-apt
Useful extras:
make profile-info
make run-only
make smoke-only
make smoke-net-only
make smoke-awscli-only
make smoke-ssm-only
make smoke-ssm-powerconnect-only
make smoke-terraform-only
make smoke-kubectl-only
make smoke-docker-only
make smoke-apt-only
make run-gui-only
make legacy-rootfs
make clean
make distclean
legacy-rootfs keeps the older BusyBox-compiled rootfs flow around as
educational reference. It is also still useful for the tiny initramfs build.
run-only, smoke-only, smoke-net-only, smoke-awscli-only,
smoke-ssm-only, smoke-docker-only, and smoke-apt-only reuse the current
artifacts without rebuilding the rootfs or ext4 image. They are useful after a
sudo -E make rootfs / sudo -E make image cycle when you only want to re-run
QEMU-side validation.
The first complete release profile is:
base ops aws awscli ssm terraform kubectl docker ssm-powerconnect
ssm-powerconnect also automatically implies gui, so the full resolved
profile includes the browser/Tkinter GUI runtime, AWS CLI, Session Manager
plugin, Terraform, kubectl, kubeconfig helpers, Docker, and SSM-PowerConnect.
Build and package it locally:
ASOX_PROFILES="base ops aws awscli ssm terraform kubectl docker ssm-powerconnect" make fetch
ASOX_PROFILES="base ops aws awscli ssm terraform kubectl docker ssm-powerconnect" make verify-packages
ASOX_PROFILES="base ops aws awscli ssm terraform kubectl docker ssm-powerconnect" make initramfs
sudo -E ASOX_PROFILES="base ops aws awscli ssm terraform kubectl docker ssm-powerconnect" make rootfs
sudo -E ASOX_PROFILES="base ops aws awscli ssm terraform kubectl docker ssm-powerconnect" make image
sudo -E ASOX_PROFILES="base ops aws awscli ssm terraform kubectl docker ssm-powerconnect" make release-package-onlyThe release package is written under:
out/release/
Release artifacts use a short flavor name by default, for example:
amzspiceox-1.0.0-amd64-full.tar.gz
The full resolved profile is recorded inside BUILDINFO.
The packager refuses to publish images containing common local AWS state paths
such as /root/.aws/config, /root/.aws/credentials, or /root/.aws/sso.
To run an unpacked release:
tar -xf amzspiceox-1.0.0-amd64-*.tar.gz
cd amzspiceox-1.0.0-amd64-*
sh run-gui.shInside the guest:
ASOX_GUI_BACKEND=local-x11 ssm-powerconnectRelease packaging also emits a sibling WSL rootfs archive and installer:
amzspiceox-1.0.0-amd64-full-wsl-rootfs.tar.gz
amzspiceox-1.0.0-amd64-full-install-wsl.ps1
Import it from PowerShell:
.\amzspiceox-1.0.0-amd64-full-install-wsl.ps1
wsl -d AMZSpiceOxOr manually:
wsl --import AMZSpiceOx "$env:LOCALAPPDATA\AMZSpiceOx\wsl" .\amzspiceox-1.0.0-amd64-full-wsl-rootfs.tar.gz --version 2
wsl -d AMZSpiceOxIn WSL mode, AmazonSpiceOx uses the host WSL kernel instead of the bundled QEMU
kernel/initramfs. On Windows with WSLg, GUI apps such as chromium and
ssm-powerconnect can open directly without run-gui.sh.
The rootfs is package-driven and profile-aware.
Current manifests:
manifests/base.txtmanifests/aws.txtmanifests/awscli.txtmanifests/ops.txtmanifests/ssm.txtmanifests/terraform.txtmanifests/kubectl.txtmanifests/xpra.txtmanifests/ssm-powerconnect.txtmanifests/gui.txtmanifests/debug.txt
Default build:
ASOX_PROFILES=base
Examples:
make fetch ASOX_PROFILES="base debug"
sudo -E make rootfs ASOX_PROFILES="base debug"
make run ASOX_PROFILES="base debug"make fetch ASOX_PROFILES="base ops"
sudo -E make rootfs ASOX_PROFILES="base ops"
make run ASOX_PROFILES="base ops"make fetch ASOX_PROFILES="base aws"
sudo -E make rootfs ASOX_PROFILES="base aws"
make run ASOX_PROFILES="base aws"make fetch ASOX_PROFILES="base aws awscli"
sudo -E make rootfs ASOX_PROFILES="base aws awscli"
make run ASOX_PROFILES="base aws awscli"make fetch ASOX_PROFILES="base aws awscli ssm"
sudo -E make rootfs ASOX_PROFILES="base aws awscli ssm"
make run ASOX_PROFILES="base aws awscli ssm"make fetch ASOX_PROFILES="base ops terraform"
sudo -E make rootfs ASOX_PROFILES="base ops terraform"
make run ASOX_PROFILES="base ops terraform"make fetch ASOX_PROFILES="base ops kubectl" KUBECTL_VERSION=v1.36.1
sudo -E make rootfs ASOX_PROFILES="base ops kubectl" KUBECTL_VERSION=v1.36.1
make run ASOX_PROFILES="base ops kubectl" KUBECTL_VERSION=v1.36.1make fetch ASOX_PROFILES="base ops docker"
sudo -E make rootfs ASOX_PROFILES="base ops docker"
make run ASOX_PROFILES="base ops docker"make fetch ASOX_PROFILES="base gui"
make initramfs
sudo -E make rootfs ASOX_PROFILES="base gui"
sudo -E make image ASOX_PROFILES="base gui"
make run-gui-only ASOX_PROFILES="base gui"make fetch ASOX_PROFILES="base gui xpra"
make initramfs
sudo -E make rootfs ASOX_PROFILES="base gui xpra"
sudo -E make image ASOX_PROFILES="base gui xpra"
make run-only ASOX_PROFILES="base gui xpra"make fetch ASOX_PROFILES="base ssm-powerconnect"
make verify-packages
make initramfs
sudo -E make rootfs ASOX_PROFILES="base ssm-powerconnect"
sudo -E make image ASOX_PROFILES="base ssm-powerconnect"
make smoke-ssm-powerconnect-only ASOX_PROFILES="base ssm-powerconnect"
make run-gui-only ASOX_PROFILES="base ssm-powerconnect"Package names are standard Debian package names.
base is always included automatically.
The current aws profile is intentionally lightweight and keeps the first
Debian bootstrap focused on packages that behave well under debootstrap.
The ops profile is the main place for day-to-day operator tools that map
cleanly to Debian packages.
awscli and the heavy Docker daemon package currently live in post-bootstrap
manifests:
manifests-post/awscli.txt
manifests-post/docker.txt
That means:
ASOX_PROFILES="base ops"gives you the general-purpose operator toolkitASOX_PROFILES="base aws"gives you the light AWS-oriented sliceASOX_PROFILES="base aws awscli"adds the AWS CLI on topASOX_PROFILES="base aws awscli ssm"adds the AWS Session Manager plugin on top of the AWS CLI layerASOX_PROFILES="base ops terraform"adds a version-pinned Terraform binaryASOX_PROFILES="base ops kubectl"adds a version-pinnedkubectlclient plus kubeconfig helpersASOX_PROFILES="base ops docker"adds Debiandocker-cli,docker.io, Docker helpers, and guest-side cgroup setup for manual daemon startupASOX_PROFILES="base gui"adds a minimal X11-capable guest with Chromium and desktop Python launch helpersASOX_PROFILES="base gui xpra"adds an Xpra server path for forwarding individual guest windows to WSL or macOS hostsASOX_PROFILES="base ssm-powerconnect"adds the SSM-PowerConnect Tkinter app and automatically pulls ingui,aws,awscli, andssmcloud-initstays as a later Phase VI candidate
Current package mapping:
bind-utilson RPM-based distros maps tobind9-dnsutilsheretelnetis provided byinetutils-telnetvimis now the fullvimpackage in theopsprofile rather thanvim-tinycurl,git,jq, andtmuxare straight Debian packagesterraformis an externally fetched HashiCorp release archive with explicit version pinning throughTERRAFORM_VERSIONkubectlis an externally fetched upstream Kubernetes client with explicit version pinning throughKUBECTL_VERSION- Docker is provided by Debian's split
docker-clianddocker.iopackages, installed after the base bootstrap, and launched manually withdocker-startbecause AmazonSpiceOx does not use systemd chromium,xinit,Xorg, and Python GUI bits live in the opt-inguiprofilexpralives in its own opt-in profile so the forwarding path stays explicit and releasable across WSL and macOS- on Debian
trixie, thexpraprofile installsxprafrom the official Xpra repository after the base bootstrap, while keepingxvfbin the normal Debian package set - the post-bootstrap
xprainstall also includesxpra-x11, which upstream recommends on Debian for seamless X11 app forwarding ssm-powerconnectfetches theAmazonSpiceOx/app folder fromhttps://github.com/Hugo-BerC/SSM-PowerConnectand installs it into/opt/ssm-powerconnectwith a/usr/local/bin/ssm-powerconnectlauncher
Terraform example:
make fetch ASOX_PROFILES="base ops terraform" TERRAFORM_VERSION=1.15.5
sudo -E make rootfs ASOX_PROFILES="base ops terraform" TERRAFORM_VERSION=1.15.5
make smoke-terraform-only ASOX_PROFILES="base ops terraform" TERRAFORM_VERSION=1.15.5Implementation detail:
terraformis fetched fromreleases.hashicorp.com- the
SHA256SUMSfile is verified against HashiCorp's signing key - the selected archive checksum is verified before the binary is copied into
/usr/local/bin/terraform
kubectl example:
make fetch ASOX_PROFILES="base ops kubectl" KUBECTL_VERSION=v1.36.1
sudo -E make rootfs ASOX_PROFILES="base ops kubectl" KUBECTL_VERSION=v1.36.1
make smoke-kubectl-only ASOX_PROFILES="base ops kubectl" KUBECTL_VERSION=v1.36.1Implementation detail:
kubectlis fetched fromdl.k8s.io- the upstream
kubectl.sha256file is used for validation before the binary is copied into/usr/local/bin/kubectl - AmazonSpiceOx also includes
kubeconfigand exportsKUBECONFIG=/root/.kube/configwhen thekubectlprofile is active
Docker example:
make fetch ASOX_PROFILES="base ops docker"
sudo -E make rootfs ASOX_PROFILES="base ops docker"
sudo -E make image ASOX_PROFILES="base ops docker"
make smoke-docker-only ASOX_PROFILES="base ops docker"
make run-only ASOX_PROFILES="base ops docker"Inside arrakis:
docker-status
docker-start
docker run --rm hello-worldImplementation detail:
- Docker comes from Debian's split
docker-clianddocker.iopackages - it is installed in the post-bootstrap package phase so service start attempts are blocked cleanly during image assembly
- AmazonSpiceOx mounts cgroup v2 during stage-2 init when the kernel supports it
docker-startrunsdockerdmanually and logs to/var/log/docker.log- if daemon startup fails on iptables setup while tuning the kernel, retry with
DOCKER_IPTABLES=false docker-start - the default storage driver is
vfsfor broad QEMU compatibility; override it withDOCKER_STORAGE_DRIVER=overlay2 docker-startwhen the kernel/image combination supports overlayfs cleanly
Example with the optional AWS CLI manifest:
make fetch DEBIAN_MANIFESTS="manifests/base.txt manifests/aws.txt"
sudo -E make rootfs DEBIAN_MANIFESTS="manifests/base.txt manifests/aws.txt" DEBIAN_POST_MANIFESTS="manifests-post/awscli.txt"
make run DEBIAN_MANIFESTS="manifests/base.txt manifests/aws.txt" DEBIAN_POST_MANIFESTS="manifests-post/awscli.txt"That optional manifest flow still works, but the preferred path is now the profile form:
make fetch ASOX_PROFILES="base aws awscli"
sudo -E make rootfs ASOX_PROFILES="base aws awscli"
make smoke-awscli-only ASOX_PROFILES="base aws awscli"Implementation detail:
awscliis installed after the base Debian bootstrap withapt, not throughdebootstrap --include- this avoids a current
trixiebootstrap failure aroundpython3-cryptographyand versionedcffivirtual dependencies ssmis fetched from the official AWS Session Manager plugin Debian package URL, validated against the official AWS signing key and detached signature, and then installed post-bootstrap
The active profile also changes the generated rootfs and image paths. For example:
build/rootfs-base-debug/
out/rootfs-base-debug.ext4
AmazonSpiceOx can now launch guest GUI apps without committing to a full desktop environment.
The gui profile installs:
chromiumxinitXorgopenboxxtermasox-terminalx11-xkb-utilspython3python3-pippython3-venvpython3-tk
When the gui profile is active, AmazonSpiceOx now defaults QEMU memory to
2048M instead of 512M, because Chromium is not happy in a half-gig guest.
There are two GUI modes:
- host-forwarded X11, where guest apps open directly on your desktop
- guest-local X11, where QEMU opens a graphical VM window
There is now a third mode aimed at release portability:
xpra, where the guest app is exported as an individual remote window and attached from the host with an Xpra client
For host-forwarded X11, run an X server on the Windows host that listens on TCP and then boot the guest normally:
make fetch ASOX_PROFILES="base gui"
make verify-packages
make initramfs
sudo -E make rootfs ASOX_PROFILES="base gui"
sudo -E make image ASOX_PROFILES="base gui"
make run-only ASOX_PROFILES="base gui"Inside the guest:
gui-doctor
chrome
python-gui
python-gui /root/my-app.py
gui-run xtermBy default, gui-run and the wrappers built on top of it return your shell
prompt immediately and leave the GUI process running in the background. For a
foreground debugging run, prefix the command with:
ASOX_GUI_WAIT=1The guest defaults DISPLAY to 10.0.2.2:0, so the only missing piece in
that mode is the host X server.
If you want the fallback mode with a QEMU window instead, use:
make run-gui-only ASOX_PROFILES="base gui"chrome is intentionally a thin wrapper around Debian's chromium package so
we can keep the workflow package-driven and reproducible while still giving you
a Chrome-like browser inside the VM.
Graphical QEMU boots default to a Spanish keyboard layout:
QEMU_KEYBOARD_LAYOUT=es make run-gui-only ASOX_PROFILES="base gui"Inside guest X11 sessions, AmazonSpiceOx also applies:
ASOX_KEYBOARD_LAYOUT=esOverride either variable if you need another layout. The serial run.sh
console is different: it receives characters from the host terminal, so its
keyboard behavior is controlled mostly by Windows Terminal, WSL, macOS
Terminal, or whatever terminal is running QEMU.
For graphical terminal windows, use asox-terminal or gui-run without
arguments. It wraps xterm with a visible scrollbar and larger scrollback:
gui-run
gui-run asox-terminalIf mouse wheel scrolling in the serial console repeats shell history instead
of moving through scrollback, use the host terminal scrollbar or start a
graphical terminal with ASOX_GUI_BACKEND=local-x11 gui-run asox-terminal.
asox-terminal defaults to a dark xterm theme, larger geometry, and
xterm-256color, which improves full-screen tools such as Vim.
If Vim keys behave strangely, run:
asox-termcheckAmazonSpiceOx defaults to TERM=xterm-256color, disables XON/XOFF flow control
so Ctrl+S does not freeze the terminal, and ships Vim defaults for Backspace,
Escape timing, and terminal key handling.
For a better serial-console buffer, run:
asox-consoleThat attaches to a tmux session with mouse support and a larger scrollback.
Inside tmux, use Ctrl+b then [ for copy/scroll mode, or the mouse wheel
when your host terminal forwards mouse events.
scripts/run-qemu.sh defaults QEMU_ACCEL=auto:
- Linux/WSL uses KVM when
/dev/kvmis available to the current user. - macOS Intel uses HVF.
- everything else falls back to multi-threaded TCG emulation.
Check acceleration from the host with:
ls -l /dev/kvmIf /dev/kvm is missing or not writable in WSL, QEMU will be much slower. You
can add your Linux user to the kvm group, then restart WSL:
sudo usermod -aG kvm "$USER"From PowerShell:
wsl --shutdownAfter reopening WSL, confirm that id shows kvm. You can force behavior with:
QEMU_ACCEL=kvm make run-only ASOX_PROFILES="base ops aws awscli ssm terraform kubectl docker ssm-powerconnect"
QEMU_ACCEL=tcg make run-only ASOX_PROFILES="base ops aws awscli ssm terraform kubectl docker ssm-powerconnect"QEMU user-mode networking exposes the host gateway at 10.0.2.2. AmazonSpiceOx
also writes common aliases into /etc/hosts:
host.qemu.internal
host.local
host.docker.internal
host.containers.internal
When QEMU runs from WSL, the launcher also detects the Windows host IP from WSL's resolver and adds:
host.os.internal
host.windows.internal
host.wsl.internal
For a host service listening on port 8000, test from arrakis with:
curl http://host.qemu.internal:8000/
curl http://host.windows.internal:8000/The service must listen on an address reachable from QEMU, not only on an
unreachable loopback namespace. On Windows, prefer binding test services to
0.0.0.0 or the Windows host IP instead of only 127.0.0.1, and allow the
port through the firewall.
For host-to-guest access, use QEMU port forwarding:
QEMU_HOSTFWD_EXTRA="tcp:127.0.0.1:2222-:22" make run-only ASOX_PROFILES="base ops"Run asox-netcheck inside arrakis to print all detected host aliases and basic
connectivity checks.
Serial console paste is controlled by the host terminal. In graphical mode,
AmazonSpiceOx installs spice-vdagent, and QEMU enables the vdagent clipboard
channel automatically when the host QEMU supports qemu-vdagent.
Clipboard support applies to GUI sessions launched with make run-gui-only and
guest X11 apps. It does not make the raw serial console behave like a desktop
terminal emulator.
Inside a GUI session, diagnose the channel with:
asox-clipboard doctorFallback for password fields when host clipboard sync is not working: open an
asox-terminal inside the guest GUI and run:
asox-clipboard setPaste the secret into the hidden prompt, press Enter, then focus Chromium and
press Ctrl+V. This sets the guest X11 clipboard without echoing the value
back to the terminal.
The xpra profile is the recommended release path for WSL and macOS hosts.
Build and boot:
make fetch ASOX_PROFILES="base gui xpra"
make verify-packages
make initramfs
sudo -E make rootfs ASOX_PROFILES="base gui xpra"
sudo -E make image ASOX_PROFILES="base gui xpra"
make run-only ASOX_PROFILES="base gui xpra"Inside the guest:
xpra-info
chrome
python-gui
python-gui /root/my-app.py
ssm-powerconnectFrom the host, attach with:
make xpra-attach ASOX_PROFILES="base gui xpra"or directly:
xpra attach tcp://127.0.0.1:14500/This works because QEMU forwards host port 14500 to the guest xpra server
when the xpra profile is active.
ssm-powerconnect is a composite profile for the Tkinter AWS SysOps tool.
It implies:
guiawsawsclissm
Build and validate:
make fetch ASOX_PROFILES="base ssm-powerconnect"
make verify-packages
make initramfs
sudo -E make rootfs ASOX_PROFILES="base ssm-powerconnect"
sudo -E make image ASOX_PROFILES="base ssm-powerconnect"
make smoke-ssm-powerconnect-only ASOX_PROFILES="base ssm-powerconnect"Run it inside the guest:
ssm-powerconnectThe app is installed in /opt/ssm-powerconnect and launched through
python-gui, so it follows the same GUI backend rules as chrome and other
Tkinter apps.
AWS SSO browser flows use the same browser plumbing. The GUI profile exports
BROWSER=/usr/local/bin/asox-browser, and the guest provides xdg-open,
x-www-browser, and sensible-browser wrappers that launch Chromium.
AmazonSpiceOx no longer treats local userspace compilation as the default path.
The preferred workflow is:
- download packages from a public Debian mirror
- cache them locally
- assemble a minimal rootfs with
debootstrap - apply AmazonSpiceOx overlays from
rootfs/and optional profile overlays - boot and validate in QEMU
This keeps the project understandable while removing a lot of unnecessary compiler bootstrap friction.
The current rootfs overlay expects a simple Debian-style network config:
- loopback enabled
eth0via DHCPifupdownpreferred- fallback logic in
/sbin/initfor simpler environments
Hostname defaults to:
arrakis
When bash is present in the guest, AmazonSpiceOx now prefers a login
/bin/bash session for the interactive shell. If bash is missing, it falls
back to /bin/sh.
For the kubectl profile, the kubeconfig helper works like this:
kubeconfig status
kubeconfig init
kubeconfig install /path/to/config
cat my-kubeconfig.yaml | kubeconfig install-stdinStart here:
- docs/boot-process.md
- docs/overlay-profiles.md
- docs/release.md
- docs/mirror-rootfs.md
- docs/persistent-rootfs.md
- docs/roadmap.md
- CHANGELOG.md
If you ever see source extraction errors like:
tar: ... Cannot open: File exists
tar: ... Cannot change mode ... Operation not permitted
that usually means a previous build path ran with sudo and left parts of
build/, downloads/, or out/ owned by root.
Fix it in WSL with:
sudo chown -R "$USER:$USER" build downloads outThen rerun the normal flow without sudo except for make rootfs and
make image.
If apt-get update reports repository signatures like:
Not live until ...
The repository ... InRelease is not signed
the WSL or VM clock is behind the timestamp on Debian's signed metadata. Restarting WSL normally refreshes the clock:
wsl --shutdownThen open WSL again and rerun the build. The post-bootstrap package installer
also uses a temporary base-only Debian source list during image assembly to
avoid trixie-security and trixie-updates clock skew blocking packages such
as awscli and docker.io.
Inside AmazonSpiceOx, check guest/host clock drift with:
asox-timecheckQEMU launches pass the host UTC epoch to the guest and use an UTC RTC by default. To override the RTC manually:
QEMU_RTC="base=utc,clock=host" make run-only ASOX_PROFILES="$PROFILE"If DNS resolution fails inside AmazonSpiceOx, repair the resolver with:
asox-dns-fix
asox-netcheckThe default resolver order is Google DNS, Cloudflare DNS, then QEMU's user-mode
DNS proxy when running under QEMU. WSL release images disable automatic
resolv.conf regeneration so the fallback resolver remains persistent.
If WSL itself drifts after suspend or around midday, restart the WSL VM from PowerShell:
wsl --shutdown
wsl -d AMZSpiceOxIf Bash prints locale warnings such as:
setlocale: LC_CTYPE: cannot change locale (en_US.UTF-8)
rebuild the rootfs with the current base manifest. The image now includes
locales and generates both en_US.UTF-8 and es_ES.UTF-8 during rootfs
assembly.
PROFILE="base ops aws awscli ssm terraform kubectl docker ssm-powerconnect"
sudo -E make rootfs ASOX_PROFILES="$PROFILE"
sudo -E make image ASOX_PROFILES="$PROFILE"The repo still contains the earlier toolchain bootstrap work:
make toolchain-sysrootmake binutilsmake gcc-stage1make muslmake gcc-stage2
That work remains useful for learning, but it is no longer the main path for building the distro rootfs.
AmazonSpiceOx aims to stay:
- explicit
- reproducible
- small enough to understand
- close to the boot process
- useful for AWS and systems learning
Avoid by default:
- hidden build abstractions
- large framework layers
- systemd-specific assumptions
- source-based rebuilds of the whole userspace
- rolling-release instability in the base distro
Near-term goals:
- add AWS-focused packages from Debian where practical
- introduce custom package/install tooling only where it genuinely adds value
- validate
aptbehavior inside the guest with the profile-based rootfs flow
Longer-term goals:
- cloud-init support
- AMI-friendly image outputs
- immutable or semi-immutable rootfs variants
- a clearer AmazonSpiceOx package and profile model
