PR 3: borg-ui web frontend with PocketID OIDC
Created by: jedmund
Summary
Third PR in the backup series. Adds borg-ui (the most actively-maintained Borg web UI as of 2026) as a sidecar service in the same stack as borgmatic. Routed at https://backup.atelier.house behind PocketID native OIDC, no TinyAuth middleware.
This PR is stacked on PR 2 (jedmund/backup-db-hooks). When PR 2 merges, GitHub auto-rebases this onto main.
What it does
- New
borg-uiservice in the backup compose stack, imageghcr.io/karanhudia/borg-ui:latest - Mounts the local repo at
/reporead-only. borgmatic remains the only writer; borg-ui only browses and restores. - Named volume
borg-ui-datafor borg-ui's own SQLite app database (auth state, saved repo definitions) - Traefik labels for
backup.atelier.house, native OIDC means notinyauth@filemiddleware - README documents the one-time OIDC bootstrap
Why bootstrap is manual
Borg-ui's OIDC configuration lives in the in-app Settings panel rather than env vars (verified against the docs). That means the role can't template the OIDC values directly. The bootstrap procedure is:
- Register the OIDC client in PocketID (one-time, by hand)
- Log into borg-ui with the default
admin/admin123(one-time, by hand) - Paste issuer/client_id/secret into Settings -> Auth -> OIDC
- Add the local repo at
/repowith theborg_passphrase - Future users authenticate via PocketID
This violates strict "everything must be Ansible-templated" but respects the rule "use PocketID for any service that supports native OIDC." TinyAuth would be env-var clean but loses identity propagation, so we accept the manual step.
Commits
backup: add borg-ui web frontend with PocketID OIDC
(Single cohesive change; compose addition and README bootstrap procedure ship together.)
Test plan
-
After merge of PR 2 + this PR, make deploy-backupbrings up bothborgmaticandborg-uicontainers -
https://backup.atelier.houseresolves, serves the borg-ui login page with a valid cert -
Log in once with admin/admin123, configure OIDC per README, log out, log back in via PocketID -
Add the /repolocal repository with the borg_passphrase, confirm it lists existing archives -
Browse a recent archive in the UI and download a single file (e.g. an Ansible env file) to verify read access works -
Confirm borg-ui has no write access to /repo by attempting a delete from the UI (should fail or be hidden)