# Design apiscp-borg is a sibling of apiscp-kopia: the same ApisCP integration architecture, but built on [BorgBackup](https://www.borgbackup.org/) 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 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--{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.