On this page
Installation
A build farm is a single host running peipkg-manager as a long-lived daemon. The daemon shells out to peipkg-build and peipkg-repo, so all three binaries need to be on PATH.
Host requirements
Any modern Linux distribution. Tested on Debian 12. Required runtime tools:
git(for source clones andls-remote)bash(forbuild.shinvocation)coreutils(forcp -a,find,sha256sum, etc.)rcloneif you're hosting on R2/S3-style object storage
Storage: enough room for the source clones, build outputs, and the published repository state. For the official Peios repo at v1 scale (~100 packages, hundreds of MB each, retention forever), a 50–100 GB volume is sufficient and won't fill up for years. Logs go to systemd's journal; size them per your normal log retention.
Memory: peak usage is bounded by the largest single .peipkg (typically ≤100 MB) plus build process overhead. 1–2 GB of RAM is enough; 4 GB is plenty.
Install the binaries
The three tools each publish a latest GitHub release with static linux-amd64 and linux-arm64 binaries. They have no shared library dependencies.
ARCH=$(dpkg --print-architecture 2>/dev/null || uname -m) # amd64 or arm64
case "$ARCH" in
x86_64) ARCH=amd64 ;;
aarch64) ARCH=arm64 ;;
esac
for tool in peipkg-build peipkg-repo peipkg-manager; do
curl -sSL -o /usr/local/bin/$tool \
https://github.com/peios/$tool/releases/download/latest/$tool-linux-$ARCH
chmod +x /usr/local/bin/$tool
done
peipkg-build help
peipkg-repo help
peipkg-manager -h
Create the directory layout
peipkg-manager reads from one directory tree and writes to another. By convention:
/etc/peipkg-manager/
├── config.toml # the operator's environment
├── farm.ed25519 # signing key (mode 0600)
├── webhook-secret # GitHub webhook HMAC secret (mode 0600)
└── recipes/ # one subdirectory per package
├── libfoo/
│ ├── peipkg.toml
│ └── build.sh
└── nginx/
├── peipkg.toml
└── build.sh
/var/lib/peipkg-manager/ # state directory; manager owns this
├── sources/ # ephemeral per-build source clones
├── stage/ # ephemeral per-build output dirs
├── publish/ # outputs awaiting peipkg-repo publish
└── repo/ # the published repository state (peipkg-repo's domain)
Create the empty layout:
sudo install -d -o root -g root -m 0755 /etc/peipkg-manager
sudo install -d -o root -g root -m 0755 /etc/peipkg-manager/recipes
sudo install -d -o root -g root -m 0755 /var/lib/peipkg-manager
peipkg-manager creates the subdirectories of state_dir itself on first run, so no need to pre-create sources/, stage/, etc.
Generate a signing key
sudo openssl genpkey -algorithm ed25519 -out /etc/peipkg-manager/farm.ed25519
sudo chmod 600 /etc/peipkg-manager/farm.ed25519
The detailed discussion is in Signing keys, including how to publish the public-key fingerprint so consumers can add the trust anchor.
Generate a webhook secret
If you'll be using GitHub webhooks for any recipe, generate a strong random secret:
openssl rand -hex 32 | sudo tee /etc/peipkg-manager/webhook-secret > /dev/null
sudo chmod 600 /etc/peipkg-manager/webhook-secret
The same value goes into each upstream's GitHub webhook configuration.
Write the config
A minimum config.toml:
[manager]
id = "peios-build-1"
recipes_dir = "/etc/peipkg-manager/recipes"
state_dir = "/var/lib/peipkg-manager"
[repo]
name = "peios-official"
description = "Official Peios package repository"
[signing]
key_file = "/etc/peipkg-manager/farm.ed25519"
[upload]
backend = "rclone"
remote = "r2:pkgs.peios.org"
[http]
addr = ":8080"
webhook_secret_file = "/etc/peipkg-manager/webhook-secret"
[poll]
default_interval = "1h"
Configuration is the field-by-field reference.
Configure rclone (R2 example)
If you're using [upload].backend = "rclone", create the remote rclone will sync to:
sudo rclone config create r2 s3 \
provider=Cloudflare \
endpoint=https://<account-id>.r2.cloudflarestorage.com \
access_key_id=<key> \
secret_access_key=<secret>
Hosting on R2 covers the bucket, custom domain, and access policies in detail. Other backends are documented as siblings.
Install the systemd service
# /etc/systemd/system/peipkg-manager.service
[Unit]
Description=peipkg-manager build farm
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/local/bin/peipkg-manager --config /etc/peipkg-manager/config.toml
Restart=on-failure
RestartSec=10s
# Soft hardening — adjust as appropriate for your threat model.
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
ReadWritePaths=/var/lib/peipkg-manager
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now peipkg-manager
sudo journalctl -u peipkg-manager -f
Verify
# Daemon up and listening
curl -fsSL http://localhost:8080/healthz
# Status endpoint shows the loaded recipe roster
curl -fsSL http://localhost:8080/status | jq
You should see structured logs scrolling past as peipkg-manager polls each recipe's upstream. The first poll for a new repo emits one trigger per upstream tag matching tag_pattern — the manager dedups against the (currently empty) archive index, builds anything new, and publishes.
Where to go from here
- Configuration — the
peipkg-config.tomlreference, field by field. - Signing keys — what to do with the key beyond
chmod 600, and how rotation works. - Hosting — pick the backend that fits your situation: R2 (recommended), GitHub Pages (simple), or VPS (full control).
- Monitoring — what the
/statusendpoint says and what to alert on.