LibrePortal/docs/FOOTPRINT.md
librelad 8cdf5fb294 revert(footprint): drop the libreportal.service rename
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>
2026-05-25 23:27:44 +01:00

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, /etc by 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.shinitRootHelpers (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