The rename was justified partly by an anticipated second `libreportal-regen` unit — which we then decided not to create (the poll rides the existing task processor). What's left is cosmetic, and it isn't worth a footprint_version bump (which forces a root re-install on every existing box) plus the dual-name migration cruft. Reverting also means the rename was the ONLY footprint change in the regen work, so the whole regen system now ships as a plain manager-owned code deploy — no root re-install needed. footprint_version stays 2. Kept only the accurate FOOTPRINT.md note that the service also drives the poll. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> Signed-off-by: librelad <librelad@digitalangels.vip>
4.6 KiB
LibrePortal system footprint (outside the data roots)
LibrePortal's own data lives in three independently-relocatable roots, chosen at install (defaults shown) and owned by exactly one principal each:
| Root (default) | Owner | Holds |
|---|---|---|
/libreportal-system |
the manager user | configs, logs, the install tree, the database, ssl/ssh |
/libreportal-containers |
the container user | live app data (one dir per app) |
/libreportal-backups |
the container user | backup repositories |
This file catalogues the few things LibrePortal must place outside those roots
to integrate with the host. The OS dictates where most of these live — sudoers,
systemd units, sysctl, and $PATH entries can only be read from their fixed
locations, so they can't sit inside a relocatable root. What we control, we keep
together in /usr/local/lib/libreportal/; everything else is named
libreportal* so the whole footprint is greppable and removable.
The three roots and the manager username are chosen at install and baked into the helpers / systemd unit / CLI wrapper below (sed placeholders, like the manager name has always been) — never read at runtime from a manager-writable config. That immutability is the privilege boundary: a root helper can't be redirected at, say,
/etcby editing config. This footprint itself stays at fixed paths by design; only the data roots relocate.
Executables — /usr/local/lib/libreportal/ (root:root, our own dir)
| File | Owner | Purpose |
|---|---|---|
libreportal |
root | the CLI wrapper (symlinked onto $PATH, see below) |
uninstall.sh |
root | the uninstaller (symlinked onto $PATH as libreportal-uninstall) |
libreportal-ownership |
root | reconcile the three-root ownership model |
libreportal-dns |
root | edit /etc/resolv.conf (nameservers) |
libreportal-ssh-access |
root | manage admin authorized_keys + sshd PasswordAuthentication |
libreportal-socket |
root | docker-socket read perms (type switcher) |
libreportal-svc |
root | generate/install the task-processor systemd unit |
libreportal-bininstall |
root | install the restic/kopia backup-engine binaries |
libreportal-appcfg |
root | rewrite AdGuard/CrowdSec/ownCloud config files |
These are the scoped-sudoers trust boundary: root-owned in a root-owned dir, so the
manager can sudo them but can't modify them. Each bakes the three roots + the
manager name at install. Source of truth: scripts/system/ in the repo; installed
by init.sh → initRootHelpers (re-installed only on a reinstall, not by the
quick-deploy).
OS-mandated locations (must live where the OS reads them)
| Path | Owner | Purpose |
|---|---|---|
/usr/local/bin/libreportal |
root | symlink → /usr/local/lib/libreportal/libreportal (puts the CLI on $PATH) |
/usr/local/bin/libreportal-uninstall |
root | symlink → /usr/local/lib/libreportal/uninstall.sh (location-agnostic uninstall command) |
/etc/sudoers.d/<manager> |
root | scoped least-privilege grant for the manager (drop-in named after the manager user) |
/etc/systemd/system/libreportal.service |
root | the task-processor service (User=<manager>; bakes the roots as Environment=LP_*_DIR; also drives the periodic regen poll) |
/etc/sysctl.d/99-libreportal-hardening.conf |
root | kernel LPE-surface hardening |
/etc/sysctl.d/99-libreportal-rootless.conf |
root | rootless sysctl settings + "rootless configured" marker |
Third-party tools we install (not ours, conventional home)
/usr/local/bin/{restic,kopia,ufw-docker,docker-compose} — installed on demand
(restic/kopia via the libreportal-bininstall helper). /usr/local/bin is the
correct home for these; left under their own names.
System users
The manager (default libreportal, configurable via --manager-user= /
LP_MANAGER_USER) and the container user (default dockerinstall, from
CFG_DOCKER_INSTALL_USER) — each with a home under /home/. The rootless daemon
config lives at ~<container-user>/.config/docker/daemon.json.
Uninstall sketch
init.sh uninstall does all of this; the sketch (with default roots/manager):
sudo systemctl disable --now libreportal.service
sudo rm -f /etc/systemd/system/libreportal.service /etc/sudoers.d/libreportal
sudo rm -f /etc/sysctl.d/99-libreportal-*.conf
sudo rm -rf /usr/local/lib/libreportal /usr/local/bin/libreportal /usr/local/bin/libreportal-uninstall
sudo rm -rf /libreportal-system /libreportal-containers /libreportal-backups
# optional: the backup-engine binaries and the two users