apiscp-borg/docs/DESIGN.md
Laurence Horrocks-Barlow 2f0d93a0ae Initial scaffold: Borg engine + docs (Layer 1 milestone)
apiscp-borg is a sibling of apiscp-kopia built on BorgBackup. This first
milestone lands the project scaffold and the Layer 1 engine:
- borg-apiscp-backup: per-site named archives (siteN-shadow/info/db), fresh
  per-site DB dumps via ApisCP site-context export, system + custom archives,
  borg prune retention per prefix, Prometheus metrics, email notifications.
- apiscp-borg-common.sh: logging, mail, site/owner helpers.
- config example, systemd service+timer, install.sh, README, DESIGN.

Borg preserves POSIX ACLs and xattrs natively, so (unlike the kopia engine) no
metadata sidecar is required; DESIGN.md records how Borg reshapes the design.
Repository/restore tools, Layer 2 panel integration, hooks, uninstall, and the
full reference are the next milestones.
2026-07-24 22:33:37 +01:00

5.6 KiB

Design

apiscp-borg is a sibling of apiscp-kopia: the same ApisCP integration architecture, but built on BorgBackup instead of kopia. This document records how Borg changes the design.

What is the same as apiscp-kopia

  • Two upgrade-safe layers. Layer 1 is a standalone POSIX-sh engine plus tools, driven by a systemd timer, with zero coupling to ApisCP's PHP. Layer 2 is an ApisCP module, GUI apps, and account hooks under /usr/local/apnscp/config/custom (git-ignored, so they survive upcp).
  • Runs backup_dbs.php first so per-site logical database dumps are current before they are archived. A plain cron job that runs before ApisCP's own 10backup_dbs captures day-stale dumps; running it in the engine fixes that.
  • Per-site granularity. Each site is archived as its own named set so a single site can be restored and retention can be reasoned about per site.
  • Per-site database handling through ApisCP's site-context API. Host mysqldump cannot see per-site databases, so the engine dumps each site's databases with cpcmd -d <domain> mysql:export (and pgsql), which resolves the target path INSIDE the site filesystem namespace, then archives the dump from its real host location under the site's fst tree and removes it. Import is the guarded native mysql:import / pgsql:import.
  • Security boundary. The panel runs the module as the unprivileged apnscp user; a scoped /etc/sudoers.d/apiscp-borg lets it run only the plugin binaries as root, and the binaries validate their own input. Site-owner verbs derive the site from the ApisCP auth context and never trust a site parameter.
  • Editions. An appliance-admin edition and a site-owner ("My Backups") edition scoped to a single account.
  • Retention, schedule, maintenance/verify, email notifications, one-time key backup, and lifecycle hooks, mirroring apiscp-kopia.

What Borg changes (and why the rationale differs)

  1. ACLs and extended attributes are preserved natively. This is the single biggest difference from kopia. borg create stores POSIX ACLs and xattrs by default on Linux, and borg extract restores them (use --numeric-ids for servers so ownership maps by id, matching ApisCP's account model). apiscp-kopia exists largely because kopia drops that metadata and needs ACL/xattr sidecars; Borg needs no sidecars. The plugin's value here is instead: correct ordering (fresh DB dumps), per-site archives, retention (borg prune), encryption and passphrase safety, and native ApisCP GUI/CLI integration. (An optional sidecar capture remains available as belt-and-braces but is off by default because Borg already preserves the metadata.)

  2. Archives, not tags. Borg has named archives in a repository rather than kopia's tagged snapshots. The engine names archives with a structured prefix so per-site operations are glob-addressable: siteN-shadow-{now}, siteN-info-{now}, siteN-db-{now}, _system-{now}, _custom-<slug>-{now} (timestamps in Borg's {now} placeholder). Restore picks an archive by name; borg list enumerates them; per-site retention is borg prune --glob-archives 'siteN-*' --keep-*.

  3. Retention is borg prune. Retention runs as an explicit borg prune after each backup (and can be run on demand), with keep-within/keep-daily/ weekly/monthly/annual rules from the config, applied per site prefix so one site's churn cannot expire another's history.

  4. Maintenance is borg compact; integrity is borg check (repository and archive consistency, optionally --verify-data to read everything back).

  5. Transport and backends. Borg speaks its own protocol over SSH. Backends are a local path (/mnt/...) or a remote ssh://user@host/path (with a dedicated SSH key and, ideally, an append-only borg serve restriction on the server). There is no kopia-style repository server or sftp backend; ssh is the remote story.

  6. Encryption and the key. Repositories are created with --encryption=repokey-blake2 by default, so the encryption key lives inside the repository and only the passphrase is needed to use it. That makes recovery simpler than keyfile mode (which stores the key under ~/.config/borg and must be backed up separately). The one-time key backup exports the passphrase plus borg key export output and stores it off the machine; losing it makes the encrypted repository unrecoverable, exactly as with kopia.

  7. Single-writer locking. A Borg repository is locked to one operation at a time. The engine holds a local lock and relies on Borg's own repository lock; concurrent site-owner actions queue rather than run in parallel.

Layer 1 (this scaffold)

  • bin/borg-apiscp-backup: the engine (this milestone).
  • bin/borg-apiscp-repo: repository init/connect, key backup, retention/prune, maintenance (compact), check, schedule, notifications. (Next.)
  • bin/borg-apiscp-restore: per-site, subpath, whole-account, and system restore via borg extract, plus site-owner-scoped variants. (Next.)
  • lib/apiscp-borg-common.sh: shared helpers (logging, mail, site helpers, optional metadata sidecar).

Layer 2 (next)

The ApisCP module (Borg_Module_Surrogate), the admin GUI app, the site-owner GUI app ("My Backups"), the menu templates, and the account hooks, mirroring apiscp-kopia verb-for-verb where it makes sense.

Status

Scaffold and Layer 1 engine. The repository tools, restore tool, Layer 2 panel integration, hooks, uninstall, and the full reference are being built out next, tracking the apiscp-kopia feature set.