Unofficial, automated Docker multi-platform images of Arch Linux for the following architectures:
| Architecture | Docker Platform | Distribution |
|---|---|---|
| x86_64 | linux/amd64 |
Arch Linux |
| aarch64 | linux/arm64 |
Arch Linux ARM |
| armv7h | linux/arm/v7 |
Arch Linux ARM |
| loongarch64 | linux/loong64 |
Arch Linux loong64 |
| riscv64 | linux/riscv64 |
Arch Linux RISC-V |
| ppc | linux/ppc |
ArchPOWER |
| ppc64 | linux/ppc64 |
ArchPOWER |
| ppc64le | linux/ppc64le |
ArchPOWER |
The same images are published to two registries under two organisation names. Both are live and both stay working.
ghcr.io/pkgforge-dev/archlinux
docker.io/pkgforge/archlinux# --rm deletes the container on exit
# --net=host and --privileged are not required, but --privileged often works
# around host DNS and networking problems
# --platform runs another architecture under QEMU, for example
# --platform=linux/arm64 runs the aarch64 image on an x86_64 host
# drops you in a bash shell
docker run --rm -it docker.io/pkgforge/archlinux:latest
# the same image from GHCR
docker run --rm -it ghcr.io/pkgforge-dev/archlinux:latest
# a specific architecture, under emulation
docker run --rm -it --platform=linux/arm64 docker.io/pkgforge/archlinux:aarch64More in examples/.
Five families. latest and v<date> are multi-architecture indexes. The other
three name one architecture each.
| tag | resolves to | moves |
|---|---|---|
latest |
an index over every platform | every build |
v2026.08.26 |
an index over every platform, that day's build | never |
x86_64 |
one platform, newest | every build |
x86_64-v2026.08.26 |
one platform, that day's build | never |
x86_64-7.1.0.r9.g54d9411-2 |
one platform, that pacman version |
never |
Each architecture answers to more than one spelling. The names share one
manifest, so x86_64 and amd64 are two names for one digest.
| Docker platform | tag names |
|---|---|
linux/amd64 |
x86_64, amd64 |
linux/arm64 |
aarch64, arm64 |
linux/arm/v7 |
armv7l, armv7h, armv7 |
linux/loong64 |
loongarch64, loong64 |
linux/riscv64 |
riscv64 |
linux/ppc |
ppc, powerpc |
linux/ppc64 |
ppc64, powerpc64 |
linux/ppc64le |
ppc64le, powerpc64le |
The uname -m spellings follow the sibling images in the organisation. ⚠ The
Docker platform spellings (amd64, arm64, armv7) are this repository's
extension and are not an organisation convention.
⚠ On the three PowerPC ports uname -m and the Docker platform agree, so the
second name in each pair is neither: it is the spelling ArchPOWER uses in its
repository paths and in Architecture.
⚠ A single-architecture tag still records its platform, so pulling one for a
foreign architecture needs --platform. Without it the runtime looks for the
host architecture and finds nothing:
docker pull ghcr.io/pkgforge-dev/archlinux:aarch64
# no image found in image index for architecture "amd64", variant "", OS "linux"
docker pull --platform=linux/arm64 ghcr.io/pkgforge-dev/archlinux:aarch64x86_64-7.1.0.r9.g54d9411-2 names the version of pacman that image contains.
Arch is rolling. No port publishes a VERSION_ID, so there is no distribution
version to name a tag after. pacman is used because it exists on every port
and its version already carries the upstream tag, the commits since it, and the
commit hash it was built from.
⚠ The ports are not in lockstep and pacman has differed by pkgrel between
them, so the anchor is resolved per architecture. Two architectures can carry
different anchor versions in the same build, and the index tags cover both.
# what an image is anchored on
docker run --rm docker.io/pkgforge/archlinux:x86_64 pacman -Q pacmanThere is no NoExtract rule. Man pages, info pages, documentation and every
locale are extracted as upstream ships them, so pacman -Ql and the filesystem
agree: every path the package database lists is on disk.
⚠ That is a change. Earlier images withheld usr/share/man, and one build also
withheld documentation, info pages and the locales. A consumer whose tooling
validates the paths in a package's file list broke on the second of those. See
HISTORY/noextract-reverted.md.
A locale needs only locale-gen.
echo "de_DE.UTF-8 UTF-8" >> /etc/locale.gen
locale-gen⚠ The image sets LANG, LC_ALL and LANGUAGE, and they do not have equal
weight. LC_ALL beats LANG, and LANGUAGE beats LC_ALL for translated
messages. Setting LANG alone changes nothing here. Override all three.
docker run --rm -it -e LANG=de_DE.UTF-8 -e LC_ALL=de_DE.UTF-8 -e LANGUAGE=de ghcr.io/pkgforge-dev/archlinux:latestexamples/04-add-a-locale.sh shows both.
Arch puts perl scripts in /usr/bin/vendor_perl, /usr/bin/site_perl and
/usr/bin/core_perl. None is on PATH. The perl package adds them through
/etc/profile.d/perlbin.sh, which only a login shell reads, so an installed
command is not callable without one.
docker run --rm ghcr.io/pkgforge-dev/archlinux:latest sh -c 'pacman -Sy --noconfirm perl-image-exiftool >/dev/null 2>&1; exiftool -ver'That prints a version here. A pacman hook symlinks such a command into
/usr/local/bin, which is on PATH.
⛔ PATH is unchanged. It is byte for byte the official image's, and nothing
that resolved before resolves anywhere new: a name already claimed under
/usr/bin is never linked, and a link goes as soon as its target does.
Undo it with:
rm /etc/pacman.d/hooks/bindir-links.hook
find /usr/local/bin -lname '/usr/bin/*_perl/*' -deleteEvery image carries a build provenance attestation and an SBOM. Each build also publishes an evidence file per platform recording every package, its version, its download size, its sha256 and its build date.
docker buildx imagetools inspect docker.io/pkgforge/archlinux:latest --format '{{ json .Provenance }}'See examples/ for consuming the evidence file.
A statically linked pacman is built from source for every architecture above.
It carries its own libc, so it runs on a system whose own libc is missing or
broken, and it can build an Arch root on a host that has no pacman, no
libalpm and no Arch keyring.
scripts/build-pacman-static amd64⛔ Built here, never downloaded. Every input is pinned by sha256 or by commit
in bootstrap/pacman-static/sources.pin,
and pacman itself is pinned at the commit the images above are built from.
docs/bootstrap-with-pacman-static.md
is the walkthrough: build the binary, build a root with it in two passes, and
end with an image that passes this repository's image suite.
Every release carries the same images as plain files, so a consumer that never runs a registry client can still use them.
| asset | what it is |
|---|---|
rootfs-<arch>.tar.gz |
the image filesystem, one gzipped tar. Untar it and chroot, or podman import it |
oci-<arch>.tar.gz |
the same image with its metadata, for podman load with no network |
bootstrap-set-<arch>.txt |
the resolved package set as name version sha256, so the root can be rebuilt with no tooling from here |
rootfs-<arch>.json |
the evidence file for that image: every package, version, size, sha256 and release date |
pacman-static-<arch> |
the static pacman below, and its evidence file |
manifest.json |
every published tag with its digest, platforms and anchor version |
SHA256SUMS |
covers all of the above |
⚠ Only manifest.json has a URL that does not change. The rest are under
releases/download/<tag>/, so a consumer who wants the current set resolves the
latest release first. ⚠ A rootfs tarball carries /etc/os-release, which dates
it; the commit it was built from is in rootfs-<arch>.json beside it and
nowhere else on this path.
curl -sSfL --connect-timeout 15 --max-time 120 \
https://github.com/pkgforge-dev/docker-archlinux/releases/latest/download/manifest.json \
| jq -r '.tags[] | select(.anchor) | "\(.tag) \(.digest)"'⚠ A git tag here is a version of this repository's tooling and assets,
v0.1.0 shape. It is not an image version. Images are tagged by date.
The build was rewritten from scratch to get reproducible inputs, pinned dependencies, signed packages and published provenance. Tags, registries and image names are unchanged.
History before the rewrite is kept on the
history-archive
branch. HISTORY/ records what changed and why.
docker build --platform linux/amd64 --build-arg IMAGE_VERSION="$(date -u +%Y.%m.%d)" -t archlinux:amd64 .
tests/run.sh static
IMAGE=archlinux:amd64 PLATFORM=linux/amd64 tests/run.sh imageIMAGE_VERSION is required. An image that does not record its version cannot be
tagged by it. tests/README.md lists what every test asserts.