Skip to content

Repository Management

A repository is a borg backup destination — an SSH-accessible path where archives are stored. Each repository has its own encryption passphrase, compression settings, and access controls.

SSH Setup Prerequisites

Assimilate connects to borg repositories over SSH using the server's Ed25519 key pair. Before creating a repository, the server's public key must be authorized on the repository host.

View the server's public key under System in the admin UI, or retrieve it via:

ssh-add -L

Add the key to ~/.ssh/authorized_keys on the borg repository host:

echo "<server-public-key>" >> ~/.ssh/authorized_keys

For append-only access, use a command= restriction in authorized_keys:

command="borg serve --append-only --restrict-to-path /backup/repos",restrict ssh-ed25519 AAAA...

Once the key is in place, use the Test Connection button in the repository form to verify SSH connectivity and confirm that borg is installed on the remote host.

On the first successful borg connection, Assimilate records the repository host's SSH key against the repository and pins it to a dedicated, per-repository known_hosts file for all server-side borg operations. If the repository host's key later changes, syncs fail with a host-identification-changed error until an admin reviews the new key's fingerprint and accepts it from the repository's page.

For the full SSH agent forwarding setup — including Docker and systemd configurations — see SSH Agent Forwarding.

Creating a Repository

There are two paths for adding a repository:

Path When to use
Init new The remote path does not yet exist — Assimilate runs borg init
Import existing A borg repository already exists at the path — register it without reinitializing

Both paths are available from Repositories → New Repository in the UI.

Repositories

The Repositories list page shows all registered repositories with:

  • Text filter — search by repository name
  • Tag filter — filter by one or more tags
  • Quota filter chips — narrow the list to At risk repositories (at or above their own warning threshold) or repositories with No quota configured; the All chip always shows the total count
  • Group by tag — organize repositories into tag groups
  • Group by host — organize repositories that share an SSH host under a shared storage pool (see Quota by Host below); this is the default view
  • Sort buttons — sort by Name, Size, Last Backup, or Quota (utilization of each repository's own quota; repositories with no quota sort last). Sorting applies to the flat list — while grouped by host, each group orders its own repositories by size instead

Each repository card shows the name, SSH target, encryption type, compression algorithm, archive count, deduplicated size, and last backup time. A disabled repository tints the card and adds a Disabled pill; a repository with unmatched imported archives shows an N unmatched chip — click it to jump to the Archives tab. A repository with its own storage quota configured also shows a compact usage bar with its current size, threshold, and health.

Repository Detail

The repository detail page opens with a header naming the repository, its SSH target, its status and what it holds, with Sync now as its primary action and Show passphrase behind the overflow menu. Four tabs follow:

  • Overview — archives, deduplicated and original size, last write and disk-sync cadence, plus the repository's schedules
  • Archives — the archive list and the file browser
  • Schedules — every schedule writing to this repository
  • Settings — the repository's own connection fields, its storage quota, its tags, the borg console, and the danger zone (Confirm relocation, Break lock, Remove repository, Delete repository, Reset and re-import)

Break lock

Break lock clears a stale borg lock on the repository. It also detects and clears a stale local cache lock left behind by a backup process that was crashed, OOM-killed, or forcibly terminated (e.g. a killed container) — something plain borg break-lock does not do, since it only ever clears the repository's own lock. Only use Break lock when you are certain no backup is currently running against the repository; breaking a lock during an active backup will corrupt it.

Init New Repository

Use this path when the remote directory is empty or does not exist yet.

  1. Enter the SSH connection details: host, user, port (default 22), and repository path.
  2. Use the Browse button to navigate the remote filesystem and select a path (see Folder Browser).
  3. Select an encryption type (see Encryption Types).
  4. Enter a passphrase. Choose a strong, unique passphrase — it cannot be recovered if lost.
  5. Optionally select a compression algorithm (see Compression).
  6. Click Initialize. The server runs borg init on the remote host and registers the repository.

The borg output is shown after initialization. If the remote path already contains a borg repository, the server returns a conflict error — use Import Existing instead.

Import Existing Repository

Use this path when a borg repository already exists at the remote path and you want to register it in Assimilate without reinitializing.

  1. Enter the SSH connection details and the exact path to the existing repository.
  2. Enter the passphrase that was used when the repository was originally initialized.
  3. Click Save. The repository is registered and will appear in the repository list.

No borg init is run. The passphrase is stored encrypted at rest and used for all future backup and archive operations.

Import Progress

After saving, the server runs borg info and borg list in the background to sync existing archives. While this is in progress:

  • The repository card shows an Importing spinner badge.
  • The repository detail page shows an importing indicator.
  • If the import fails (e.g. SSH timeout, wrong passphrase), the error is displayed on the repository card and detail page.

During a full repository sync, Assimilate also prunes archives that no longer exist in borg from the database. The scheduled disk sync uses the same full reimport path, so it refreshes the complete archive list instead of only adding new entries.

Full resync and content indexing

The Sync now action on the repository detail page re-reads every archive from borg and then builds the browsable content index (the file tree used for archive browsing, search, diff, and restore). Because borg archives are immutable:

  • Archives whose content index is already complete are skipped — a resync never re-scans an archive it has already indexed.
  • Stats are only re-fetched for archives that don't have them yet.

Indexing runs in the background and the repository badge shows live progress: the bar advances as each archive finishes (so it never sits at 100% while work remains), and the status line shows the archive currently being scanned together with a running file count and the file being processed, e.g. Indexing 'host-2026-06-10T02:00:00' (3/84) — 12,345 files · home/user/project/main.rs. You can navigate away — indexing continues and the UI updates automatically via WebSocket.

For large repositories with many archives, the initial import and first full index may take several minutes.

Archive-to-Host Matching

During import, each archive's hostname is resolved to a registered agent:

  1. Exact match — the archive hostname matches an agent's hostname directly.
  2. Pattern match — the hostname matches a glob pattern configured on an agent (see Agent Management — Hostname Aliases).
  3. Unmatched — a placeholder agent is created with an "(imported)" badge.

Unmatched archives can be resolved later by adding hostname patterns and running a re-scan.

Re-scanning Unmatched Archives

After adding hostname aliases to agents, you can re-scan a repository to match previously unmatched archives against the updated patterns.

  1. Open the repository detail page.
  2. Click Re-scan Archives (admin only).
  3. The server evaluates all unmatched archives against current hostname patterns.
  4. A toast shows how many archives were matched and how many remain unmatched.
  5. Placeholder agents with no remaining archives are automatically cleaned up.

Encryption Migration

Admins can migrate a repository to a different encryption mode (e.g. from repokey to repokey-blake2).

  1. Open the repository detail page.
  2. Click Migrate Encryption and select the target encryption mode.
  3. Click Confirm.

The server:

  1. Renames the existing repository to <path>.migrated-<date> on the remote host.
  2. Runs borg init at the original path with the new encryption mode.
  3. Updates the database record.

The old repository is preserved at the .migrated-* path and can be removed manually once you've confirmed the migration is successful. This operation is audit-logged.

Warning

Migration creates a new empty repository. Existing archives remain in the old (renamed) repository. You will need to run new backups to populate the migrated repository.

Folder Browser

The built-in folder browser lets you navigate the remote filesystem over SFTP to select a repository path without typing it manually.

Click the Browse button next to the repository path field. The browser connects to the SSH host using the server's key and lists directories. Navigate to the desired parent directory and either select an existing directory or type a new subdirectory name.

The selected path is written back into the repository path field.

The folder browser requires the SSH host and user fields to be filled in first.

Encryption Types

Assimilate supports all borg encryption modes. The encryption type is set at borg init time and cannot be changed afterwards.

Mode Description
repokey Passphrase-protected key stored in the repository
repokey-blake2 Same as repokey with BLAKE2b MAC — recommended
keyfile Passphrase-protected key stored on the agent machine
keyfile-blake2 Same as keyfile with BLAKE2b MAC
authenticated No encryption, HMAC authentication only
authenticated-blake2 No encryption, BLAKE2b authentication only
none No encryption, no authentication

Recommendation: Use repokey-blake2. It stores the key in the repository (no separate key file to manage), uses the faster and more secure BLAKE2b MAC, and is the most common choice for server-managed backups.

Avoid none for any data that should remain confidential. For details on borg encryption internals, see the BorgBackup documentation.

Compression

Compression is applied per-archive at backup time. It can be changed on an existing repository — the new setting applies to future archives only.

Algorithm Trade-off
lz4 Very fast, low CPU, moderate ratio — default, good for most cases
zstd (level 1–22) Balanced speed and ratio; level 3 is a good starting point
zlib (level 1–9) Slower than lz4, similar ratio; legacy option
none No compression — useful when data is already compressed (e.g., media files)

For general-purpose backups, lz4 is the default and works well. Use zstd,3 when storage space is a priority and CPU overhead is acceptable.

Repository Tags

Tags are short labels that help organize repositories when managing many agents. A repository can have multiple tags.

Tags are set in the repository edit form and are visible in the repository list. They have no effect on backup behavior — they are purely organizational.

Quota by Host

The Repositories page groups repositories sharing an SSH host under one section by default — visually separated from other hosts by a shaded panel — so it's clear at a glance which repositories belong to which backup destination. Toggle Group by host off to switch back to a flat, sortable list.

Each section header shows a storage pool bar scaled to that host's server quota — when one is configured and you have admin access — with one segment per repository, sized to its share of the combined usage, and a mark at the server quota's warning threshold.

Repositories page grouped by host, showing a shared storage pool bar and repository cards

Inside a group, a repository without its own quota shows a usage bar on the same scale as the pool header, so its segment's position and width reflect its share of the host. A repository that has its own storage quota configured instead shows a usage bar on its own scale (current size, threshold, and health) — mixing the two scales in one bar made a repository's slice look almost full purely because of its position in the pool, which was confusing next to a "% of own quota" label describing a different number entirely.

Combining a quota filter chip with Group by host dims — rather than removes — repositories that don't match the filter, so the pool bar always reflects the host's true combined usage; the header notes how many of the group's repositories are currently shown.

A host with no configured server quota, or when viewing as a non-admin user, still groups its repositories together, but every card in that group falls back to showing its own quota (if any) on its own scale instead of the shared pool.

Passphrase Management

The passphrase is required by borg to encrypt and decrypt archives. Assimilate stores it encrypted at rest using AES-256-GCM, derived from the ASSIMILATE_SECRET_KEY environment variable.

Viewing the passphrase is restricted to admins. Navigate to the repository detail page and choose Show passphrase from the header’s overflow menu. The decrypted passphrase is fetched from the server and displayed once.

The passphrase is never logged or transmitted in plaintext. See Security for details on the encryption scheme.

Passphrase is irrecoverable

If you lose the passphrase, the repository contents are permanently inaccessible. Assimilate cannot recover it. Store the passphrase in a secure location (e.g., a password manager) independent of Assimilate. If ASSIMILATE_SECRET_KEY is changed or lost, all stored passphrases become unreadable. Keep this value stable and back it up separately. See Configuration for details.

Editing and Deleting

Editing a repository updates its host, SSH user, path, compression, and enabled state. The passphrase and encryption type cannot be changed after initialization — borg does not support re-encrypting an existing repository.

The Host picker lists the known repository hosts; a host's port comes with it. Add a new host... takes a hostname and port no other repository uses yet. Moving a repository to another host takes that host's SSH host key, power and availability settings. To change a host itself — its hostname, port or key — edit it on the host's own page, which moves every repository on it.

Changing the host or path does not move or modify the remote repository. It only updates the connection details Assimilate uses to reach it.

Toggling Disk sync on schedules a periodic borg info/borg list resync of this repository, independent of any backup schedule, using the same cron expression and visual Cron Expression Builder that backup schedules use.

Repository Relocation Safety

When you change a repository's path, SSH host, or SSH port, borg needs to accept that the repository has moved. Assimilate handles this securely:

  1. On edit: The server marks the repository as "relocation pending."
  2. Next backup: The agent sets BORG_RELOCATED_REPO_ACCESS_IS_OK=yes for that single backup run, allowing borg to accept the new location.
  3. After success: The relocation flag is cleared automatically. Subsequent backups no longer accept relocations.

This means borg will only accept a repository relocation once, immediately after an admin changes the connection details. If an attacker swaps the remote repository at any other time, borg will refuse to operate on it.

Note

No manual action is required. The relocation acceptance is automatic and one-shot. If the first backup after a path change fails for an unrelated reason, the flag remains set until a backup succeeds.

Deleting a repository removes it from Assimilate — the database record, stored passphrase, and associated schedules are deleted. The remote borg repository and its archives are not deleted. You must remove the remote data manually if desired.

Deletion requires admin privileges.

Power

Waking a powered-down machine, shutting it back down, and whether it is expected to be online are facts about the machine, so they are set on its repository host, once for every repository on it. The repository's Settings → Power pane shows its host's settings read-only, with Edit on host for admins, and lists the schedules currently waiting on this repository. See Power Management for the full behavior, and When the Host Is Offline for what an unreachable host means.

Repository Permissions

By default, repository visibility follows the owner model. Admins can grant per-user access to specific repositories using the permissions panel on the repository detail page.

Permission Effect
can_view User can see the repository and its archives
can_backup User can trigger manual backups
can_modify_schedules User can create, edit, and delete backup schedules for this repository
can_extract User can browse and extract files from archives
can_delete User can delete archives

Admins always have full access regardless of per-user permissions. For a broader overview of access control, see Security.