Skip to main content

Native install (systemd)

AURCache runs on the host without Docker, as two systemd services. This is often the better choice for the worker: several things the container images do exist only because they are containers, and drop away here.

  • systemd-nspawn needs a systemd manager, which a container lacks — the image ships a wrapper for it. A real host has one.
  • pacman 7's Landlock download sandbox needs syscalls that some runtimes block or do not implement (older seccomp profiles, qemu emulation), so the images set DisableSandbox to work everywhere. Natively those syscalls are normally available, so it stays on.
  • No privileged container, and no qemu/binfmt for the machine's own architecture.

Packages​

paru -S aurcache-server # the build server and web UI
paru -S aurcache-worker # a build machine

They live in the AUR, not the official repositories, so install them with an AUR helper (paru, yay, …).

They are separate because their dependencies are: the server needs no devtools, base-devel or sudo, and most build machines do not want a server. Both may be installed together on one host; they share the aurcache user. See Native packages for what the packages contain and how to build them yourself.

Server​

$EDITOR /etc/aurcache/server.env
systemctl enable --now aurcache

It listens on 8080 (API and web UI), 8081 (the pacman repository) and 8083 (workers). State lives in /var/lib/aurcache: the repository, the database, the worker CA and the build logs.

Build logs​

Each build's log is build_logs/<pkgbase>/<number>.log under the server's working directory, overridable with AURCACHE_BUILD_LOG_PATH — named after the build's public identity, the same <pkgbase>/<number> the API, the CLI and the web UI use.

Two things worth knowing:

  • A database backup does not contain build logs. Back up the log directory alongside the database if the logs matter to you.
  • A log whose file is missing is not an error. The build page shows "no log for this build" rather than failing, which is also what you get for a build that never produced output.

Every PKGBUILD the server reads is sourced through a sandbox — see Package parsing. That holds for every install method, not just this one.

Everything is optional in server.env; the defaults work for a single machine. Two worth setting before anything else reaches it:

  • AURCACHE_TLS_SANS — the host names workers dial this server by, which its worker certificate must be valid for, and AURCACHE_PUBLIC_URL — where pacman clients fetch the repository.
  • The OAUTH_* block. With all of them unset there is no authentication, which is only sensible on a machine nothing else can reach. See Authentication, and note OAUTH_ALLOWED_USERS if your provider is a public one.

Worker​

$EDITOR /etc/aurcache/worker.env # AURCACHE_URL: the server's https://<host>:8083
systemctl enable --now aurcache-worker

The worker then waits for approval on the server's Workers page. To skip that, give the worker the secret the server has as AURCACHE_ENROLLMENT_TOKEN. Once approved, it authenticates with its own certificate.

What the package sets up​

Two users, and the split between them is the security model rather than tidiness:

aurcacheruns the worker process; owns the mTLS identity and build credentials, and is the only user that can read them
builderruns each package build, named explicitly by makechrootpkg -U, so a build never inherits the worker's user and cannot reach its secrets by file permissions

builder's primary group is aurbuild. That is load-bearing, not incidental: makechrootpkg carries only the build user's primary uid/gid into the chroot, so a supplementary group does not exist in there and group-write on the caches fails from inside the chroot, after every host-side check has already passed.

Directories, with ownership that matters for the same reason:

/var/lib/aurcache-worker aurcache worker state
/var/lib/aurcache-worker/secrets aurcache 0700, build credentials
/var/lib/aurcache-worker/work builder 2775, shared to the worker by group
/var/lib/aurcache-worker/chroot aurcache the storage pool: its image and mount point

Everything that grows -- the base chroot, each build, the source and package caches -- lives in the storage pool, a btrfs filesystem the worker creates in chroot/pool.img and mounts at chroot/pool, with a disk quota per build and one over the whole worker. A zvol, a partition or a dedicated btrfs filesystem can back it instead of the image, set with WORKER_POOL. On a btrfs root, make /var/lib/aurcache-worker/chroot a subvolume of its own before the first start, so host snapshots leave the image alone. See Storage pool.

Why the worker's unit is not hardened​

aurcache.service takes the full set of systemd hardening directives. aurcache-worker.service deliberately does not, and the unit says so inline. Its whole job is sudo mkarchroot and sudo makechrootpkg, which mount, unshare and chroot. NoNewPrivileges=yes alone stops every build before it starts; ProtectSystem=strict makes the chroot and pacman's cache read-only; RestrictNamespaces=yes forbids what systemd-nspawn is.

The isolation that matters here is not systemd's. Each build runs in its own devtools chroot as a different unprivileged user, and the two places a PKGBUILD is executed outside that chroot are confined with Landlock.

aurcache-build, the patched makechrootpkg​

makechrootpkg executes the PKGBUILD twice outside the chroot — once for makepkg --verifysource, once to read pkgbase/pkgname. A PKGBUILD is bash, so unconfined either one lets a build write another build's files. Checksums are no defence: they are declared by the PKGBUILD being run.

The package installs a copy of it as /usr/lib/aurcache/bin/aurcache-build with those two sites wrapped in aurcache-sandbox, and the worker names that path absolutely. The copy also takes a leading --interface=N that the stock script rejects, so the two cannot stand in for each other: the worker checks the copy at startup and refuses to start without it. It is derived at install time from the devtools on this machine rather than shipped pre-patched, because makechrootpkg sources six files from /usr/share/devtools/lib and /usr/share/makepkg/util at runtime — a copy taken against one devtools release would end up running against another's libraries.

A pacman hook re-derives it whenever devtools is installed or upgraded. If a future devtools moves one of those two call sites the hook fails the transaction and removes the stale copy, so the worker refuses to start rather than quietly building with two steps unconfined. If that happens, please report it with your devtools version.

Nothing is installed into /usr/local, and nothing shadows makechrootpkg for other users: running it yourself gets the packaged one.

Both on one machine​

Install both packages. They share the aurcache user and their state directories are separate, so no extra configuration is needed — point AURCACHE_URL in worker.env at https://localhost:8083, which is also its default.

Building the packages yourself​

See Native packages.