Skip to content

feat(backup): Add remote S3-compatible backup destinations#168

Merged
nfebe merged 5 commits into
mainfrom
feat/backup-remote-s3
Jul 9, 2026
Merged

feat(backup): Add remote S3-compatible backup destinations#168
nfebe merged 5 commits into
mainfrom
feat/backup-remote-s3

Conversation

@nfebe

@nfebe nfebe commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

FlatRun backups were local-only, so a lost host meant lost backups. This adds remote S3-compatible object storage as a backup target on top of the always-local copy, and lays the foundation for treating object stores as a first-class concept.

Closes #105.

Why it is shaped this way (things the diff will not tell you):

  • The local copy stays primary and remote uploads are best-effort, so a remote outage degrades to local-only instead of failing the backup.
  • Object-storage secrets live in the credential manager (written 0600, masked in API responses) and are referenced by id, so no secret ever lands in the flat-file config.
  • Local retention prunes only the on-disk copies; a remote's lifecycle is left to the bucket.
  • Listing, download, and restore fall back to a remote when the local archive has been pruned.

It also seeds the object-store abstraction: a store records its kind (external, which FlatRun only connects to, or managed, which FlatRun runs from a template), and a MinIO template lets FlatRun host its own S3 endpoint. The object browser, deployment consumption, and replication are later slices, described in docs/OBJECT_STORES.md.

nfebe added 5 commits July 7, 2026 18:20
Backups can now be mirrored to remote S3-compatible object storage
(AWS S3, Cloudflare R2, Backblaze B2, MinIO) on top of the always-local
copy. A remote outage never fails a backup: the local copy is primary and
uploads are best-effort.

Object-storage credentials are held by the credential manager, written to a
private file and masked in API responses, and referenced by destinations so
no secret ever lands in the agent config. Destinations are configured through
the existing config API and applied live.

Listing, download, and restore transparently fall back to a remote copy when
the local archive has been pruned, and local retention no longer deletes remote
copies. A destination connectivity check is available, and what/how/where a
deployment is backed up is now documented.
Introduces a MinIO app template so an S3-compatible object store can be
deployed and run by FlatRun itself, with a per-deployment root credential and
its data in a flat-file mount.

Adds a spec defining the object store abstraction: one concept with two kinds,
external (a store FlatRun only connects to) and managed (a store FlatRun runs
from a template), which backup destinations fold into. Later slices cover an
object browser, deployment consumption, and replication.
@sourceant

sourceant Bot commented Jul 9, 2026

Copy link
Copy Markdown

Code Review Summary

This PR adds S3-compatible remote backup destinations to FlatRun. It introduces a generic credential manager for S3 secrets and an 'Object Store' abstraction that supports both external and managed (MinIO) stores. Remote uploads are best-effort, ensuring local backups succeed even if the network is down.

🚀 Key Improvements

  • Added internal/backup/remotes.go to handle multi-destination mirroring.
  • Introduced Credential model with custom JSON marshaling to prevent secret leakage.
  • Implemented a MinIO template for self-hosted object storage.

💡 Minor Suggestions

  • Use parallel execution for remote listings to improve UI responsiveness.
  • Propagate request contexts to remote storage operations instead of using Background().

@sourceant sourceant Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review complete. See the overview comment for a summary.

prefix = filter.DeploymentName + "/"
}
for _, r := range m.getRemotes() {
objs, err := r.List(context.Background(), prefix)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Passing context.Background() ignores the request context. While listing remotes is best-effort, using the passed context (if available) or a timeout-bounded context is preferred.

Suggested change
objs, err := r.List(context.Background(), prefix)
objs, err := r.List(ctx, prefix)

@nfebe nfebe merged commit eedaba9 into main Jul 9, 2026
5 checks passed
@nfebe nfebe deleted the feat/backup-remote-s3 branch July 9, 2026 00:20
@nfebe nfebe mentioned this pull request Jul 9, 2026
38 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: Add support for s3 compatible backup

1 participant