Self-Hosting Securely
InterGenOS is built from source and ships with a package manager (pkm) that
trusts a signed index, not a transport layer. That design is what makes
self-hosting your own binary mirror practical: you can stand up a repository
your machines pull from, sign it with keys you control, and let every client
verify it the same way the official mirror is verified.
A self-hosted mirror should leave you with a machine you understand, can modify, and can trust, which means the trust boundary has to be something you can inspect by hand, not a black box.
The trust model
The integrity boundary is the GPG signature on the package index
(InterGenOS.db), not TLS. TLS protects the transport; it does not prove
who built the index. A self-hosted mirror inherits this model:
pkm syncfetchesInterGenOS.dband its detached signature (InterGenOS.db.sig), verifies the signature against the public key in the client’s trust store, and only then trusts the per-package SHA-256 hashes inside the index.pkm installdownloads an archive and verifies its SHA-256 against that trusted index before deploying anything.
Because the signature is the boundary, a mirror can sit behind any web server or CDN. A compromised transport can withhold or stale an index, but it cannot forge one without the signing key.
Key handling
Keep the signing material off the mirror host. The recommended posture, and the one the official mirror uses, is:
- An offline master key that certifies signing subkeys and never touches a networked machine.
- One or more signing subkeys held on hardware tokens. Signing requires the token to be physically present and unlocked (PIN plus touch), so a remote compromise of either your workstation or the mirror host cannot produce a signature on its own.
- A backup signer on a second token, so loss of the primary does not lock you out of publishing.
Publishing writes the signed tree to the mirror over SSH using a key authorized only for that account, with no root step. The signing step happens on your workstation, where the token lives; the mirror host only ever receives already-signed files.
Building the index
pkm reads a gzipped-JSON index that lists each package and its SHA-256.
Generating it is a single operation against your directory of built
.igos.tar.gz archives, producing InterGenOS.db. The signature is then a
detached, armored GPG signature over that file
(gpg --detach-sign --armor), written as InterGenOS.db.sig.
Index generation is not byte-stable: regenerating the index produces a new
file, which voids any prior signature. Sign the exact InterGenOS.db you
intend to publish, and never regenerate after signing. If you need to re-sign
without rebuilding, sign the existing file directly with the subkey
fingerprint and skip the regenerate step.
Publishing without a downtime window
The official publish flow is worth copying because it never exposes a half-written repository:
- Stage. Rsync the signed tree into a fresh, per-publish staging directory (timestamped) under the architecture path, alongside the source archives.
- Promote atomically. Repoint the
currentsymlink with a single atomic rename (ln -sfnto a.newname, thenmv -T). On a journaling filesystem this is one syscall, so there is no 404 window: in-flight clients finish against the old target or restart against the new one. No web-server restart is needed; the server serves the swapped symlink on the next request. - Keep the previous set. Archive the prior target rather than deleting it, so a bad publish can be rolled back by flipping the symlink back.
Always dry-run first. A dry run validates that the signing key is available, generates the index in place, and prints the rsync and promote it would perform, without writing to the mirror. Confirm the archive count and staging path look right before the real run.
Pointing clients at your mirror
Clients read repository settings from /etc/pkm/repos.conf. Two settings
govern the security posture:
gpg_verifycontrols whetherpkm syncrequires a valid signature on the index. A fresh install ships with verification off so a first sync against an empty, not-yet-signed mirror does not fail closed. Once your mirror serves a signed index, setgpg_verify = trueso clients fail-closed on any unsigned or tampered index.- The client’s trust store holds the public key your index is verified against
(
/etc/pkm/trusted.gpg). Distribute only the public key; the private signing material stays on your token.
For installs, pkm also exposes archive-trust modes (strict / repo-only)
that check each downloaded archive’s SHA-256 against the synced index before
installation. Self-hosters should run a strict mode so a mirror that serves a
mismatched archive is rejected at the client.
Verifying your own mirror
A self-hosted mirror is only as trustworthy as your ability to audit it. Two layers:
Automated, ongoing. Run a periodic verification pass on the mirror host
that checks the index signature, walks every file’s SHA-256 against the index,
and scans for stray files not listed in the index, alerting on any drift. Run
it manually right after your first publish to confirm the live set verifies;
it stays red until a current/ target exists.
Manual, by anyone. Every step is reproducible by hand against your published public key, with no opaque steps:
curl -O https://<your-mirror>/x86_64/current/InterGenOS.db
curl -O https://<your-mirror>/x86_64/current/InterGenOS.db.sig
gpg --verify InterGenOS.db.sig InterGenOS.db # signed by your subkey, certified by your master
# then sha256sum any archive against its entry in the index
If those two commands succeed, the index is authentic and any archive you pull can be checked against it. That is the whole trust chain, and it is the same chain whether you pull from the official mirror or your own.
Append-only audit log
A publish can append the signed index to an append-only transparency log, so the history of what you published, and when, is auditable after the fact, independent of the live mirror state. Self-hosters operating a mirror for more than one machine should keep such a log; it turns “what did I serve last Tuesday” from a guess into a record.
Where this fits
- For how
pkminstalls, verifies, and supersedes packages on a client, see the package manager component documentation. - For installing InterGenOS itself with Forge, see ../install/forge-guide.md.
- For common questions, see ../start-here/faq.md.