Skip to main content

Overview

Borg UI provides comprehensive repository management with support for multiple storage backends, encryption modes, and compression algorithms. Create new repositories or import existing ones with a streamlined workflow.

Storage Backends

Store repositories directly on the filesystem where Borg UI is running.Path Examples:
  • /data/backups/my-repo - Container storage
  • /local/home/user/backups - Host filesystem via Docker mount
Paths starting with /local/ access your host filesystem through Docker volume mounts. Paths without this prefix are stored inside the container.

Encryption Modes

Borg UI supports all Borg encryption modes:
1

Choose Encryption Mode

Select from available encryption modes based on your security requirements:
ModeDescriptionKey Storage
repokeyEncryption key stored in repositoryRepository config
keyfileEncryption key stored separately~/.config/borg/keys/
repokey-blake2Repokey with BLAKE2 hashRepository config
keyfile-blake2Keyfile with BLAKE2 hash~/.config/borg/keys/
noneNo encryption (not recommended)N/A
repokey modes are convenient for single-user setups. keyfile modes allow sharing keys across multiple machines.
2

Set Passphrase

For encrypted repositories, provide a strong passphrase:
# From repositories.py:468-473
if repo_data.encryption in ["repokey", "keyfile", "repokey-blake2", "keyfile-blake2"]:
    if not repo_data.passphrase or repo_data.passphrase.strip() == "":
        raise HTTPException(
            status_code=400,
            detail=f"Passphrase is required for encryption mode '{repo_data.encryption}'"
        )
Store your passphrase securely! Lost passphrases cannot be recovered and will make your backups inaccessible.
3

Manage Keyfiles (Optional)

For keyfile-based encryption, Borg UI automatically manages keys:
  • Upload Keyfile: Import existing keyfiles via API endpoint
  • Download Keyfile: Export keys for backup or sharing
  • Automatic Storage: Keys stored in ~/.config/borg/keys/
# Keyfile naming convention from repositories.py:51-66
# /local/Users/foo/backups/repo → local_Users_foo_backups_repo
# ssh://user@host:22/backups → user_host_22_backups

Compression Algorithms

Choose compression based on your performance vs. storage requirements:
Fast compression with minimal CPU overhead
  • Compression ratio: ~2:1 to 3:1
  • Speed: Very fast (300+ MB/s)
  • Best for: General use, modern hardware
  • CPU usage: Low
# Default compression from repositories.py:306
compression: str = "lz4"
Balanced compression with good ratio
  • Compression ratio: ~3:1 to 5:1
  • Speed: Fast (100-200 MB/s)
  • Best for: Balance of speed and storage
  • CPU usage: Medium
  • Supports compression levels (1-22)
Good compression ratio, slower speed
  • Compression ratio: ~3:1 to 6:1
  • Speed: Moderate (50-100 MB/s)
  • Best for: Storage-constrained environments
  • CPU usage: Medium-High
  • Supports compression levels (1-9)
Maximum compression ratio
  • Compression ratio: ~5:1 to 10:1
  • Speed: Slow (20-50 MB/s)
  • Best for: Archival storage, rarely accessed data
  • CPU usage: High
  • Supports compression levels (0-9)
Borg auto-detectionBorg automatically selects compression based on file type:
  • Already compressed files: No compression
  • Compressible files: lz4 compression
Data obfuscation without compression
  • Makes data patterns less obvious
  • No compression benefit
  • Same size as original data

Creating a Repository

1

Navigate to Repositories

Click Repositories in the sidebar, then Create Repository.
2

Configure Basic Settings

Fill in repository details:
interface RepositoryCreate {
  name: string;                    // Display name
  path: string;                    // Storage path
  encryption: string;              // Encryption mode
  compression: string;             // Compression algorithm
  passphrase?: string;             // Required for encrypted repos
  source_directories: string[];    // Directories to backup
  exclude_patterns?: string[];     // File patterns to exclude
}
3

Set Source Directories

Specify which directories to backup:
{
  "source_directories": [
    "/local/home/user/documents",
    "/local/var/www",
    "/local/etc/nginx"
  ]
}
Source directories are required for repositories in full mode. Observability-only repositories don’t need source directories.
4

Configure Exclusions (Optional)

Use exclude patterns to skip files:
{
  "exclude_patterns": [
    "*.log",
    "*.tmp",
    "node_modules",
    "__pycache__",
    ".git"
  ]
}
5

Advanced Options

Configure optional settings:
  • Remote Path: Custom borg binary path (e.g., /usr/local/bin/borg)
  • Custom Flags: Additional borg create flags
  • Bypass Lock: Read-only access for observe-only mode
  • Pre/Post Scripts: Hooks to run before/after backups

Importing Existing Repositories

Import repositories created outside Borg UI:
# From repositories.py:704-950
@router.post("/import")
async def import_repository(
    repo_data: RepositoryImport,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """Import an existing Borg repository"""
1

Verify Repository

Borg UI validates the repository using borg info:
# Verification from repositories.py:831-838
verify_result = await verify_existing_repository(
    repo_path,
    repo_data.passphrase,
    ssh_key_id_for_verify,
    repo_data.remote_path,
    repo_data.bypass_lock
)
2

Import Keyfile (If Needed)

For keyfile encryption, upload your existing keyfile:
# Keyfile handling from repositories.py:819-828
if repo_data.keyfile_content:
    keyfile_dir = os.path.expanduser("~/.config/borg/keys")
    os.makedirs(keyfile_dir, exist_ok=True)
    keyfile_name = _borg_keyfile_name(repo_path)
    keyfile_path = os.path.join(keyfile_dir, keyfile_name)
    with open(keyfile_path, 'w') as f:
        f.write(repo_data.keyfile_content)
    os.chmod(keyfile_path, 0o600)
3

Update Statistics

Archive count and size are automatically updated:
# From repositories.py:913-920
try:
    await update_repository_stats(repository, db)
except Exception as e:
    logger.warning("Failed to update repository stats after import",
                  repository=repository.name,
                  error=str(e))

Repository Modes

Complete backup and observability
  • Create new backups
  • Browse and restore archives
  • Schedule automated backups
  • Full repository management
# From repositories.py:318
mode: str = "full"  # full: backups + observability

SSH Path Prefix

For remote storage with non-standard paths (e.g., Synology NAS):
# From repositories.py:529-541
ssh_path_prefix = connection_details.get("ssh_path_prefix")
if ssh_path_prefix:
    ssh_path_prefix = ssh_path_prefix.strip()
    if ssh_path_prefix and not ssh_path_prefix.startswith("/"):
        ssh_path_prefix = f"/{ssh_path_prefix}"
    repo_path_for_ssh = f"{ssh_path_prefix}/{repo_path.lstrip('/')}"
    logger.info("Applying SSH path prefix",
               original_path=repo_path,
               prefix=ssh_path_prefix,
               final_path=repo_path_for_ssh)
Example Use Case:
  • Synology NAS with /volume1 prefix
  • Custom chroot environments
  • Restricted SSH shells

Repository Statistics

Borg UI automatically tracks repository metrics:
# From repositories.py:165-283
async def update_repository_stats(repository: Repository, db: Session) -> bool:
    """Update archive count and repository size stats by querying Borg"""
    
    # Get archive list and count
    list_result = await borg.list_archives(
        repository.path,
        remote_path=repository.remote_path,
        passphrase=repository.passphrase,
        bypass_lock=use_bypass_lock
    )
    
    # Update repository size from borg info
    info_data = json.loads(stdout.decode())
    cache = info_data.get("cache", {}).get("stats", {})
    unique_csize = cache.get("unique_csize", 0)
Tracked Metrics:
  • Archive count
  • Total repository size
  • Last backup timestamp
  • Compression effectiveness
  • Deduplication ratio

Lock Configuration

Borg UI configures repository locks to prevent conflicts:
# From repositories.py:94-119
def setup_borg_env(base_env=None, passphrase=None, ssh_opts=None):
    """Setup Borg environment variables with lock and timeout configuration"""
    
    # Configure lock behavior to prevent timeout issues
    env["BORG_LOCK_WAIT"] = "180"  # Wait up to 3 minutes for locks
    env["BORG_HOSTNAME_IS_UNIQUE"] = "yes"  # Mark hostname as unique
    env["BORG_RELOCATED_REPO_ACCESS_IS_OK"] = "yes"  # Allow relocated repos

Best Practices

  • Encryption: Always use encryption for sensitive data
  • Passphrases: Use strong, unique passphrases (20+ characters)
  • Keyfile Backup: Store keyfile backups in a secure location
  • Test Restores: Regularly verify backups are recoverable
  • Remote Backups: Use SSH for off-site disaster recovery
  • Compression: Start with lz4, adjust based on storage needs

API Reference

Create Repository

POST /api/repositories/
Request Body:
{
  "name": "Production Backups",
  "path": "/local/backups/prod",
  "encryption": "repokey-blake2",
  "compression": "zstd",
  "passphrase": "your-secure-passphrase",
  "source_directories": ["/local/var/www", "/local/etc"],
  "exclude_patterns": ["*.log", "*.tmp"],
  "mode": "full"
}

Import Repository

POST /api/repositories/import
Request Body:
{
  "name": "Imported Repo",
  "path": "/local/backups/existing",
  "passphrase": "existing-passphrase",
  "compression": "lz4",
  "mode": "observe",
  "bypass_lock": true
}

Upload Keyfile

POST /api/repositories/{repo_id}/keyfile
Multipart Form Data:
keyfile: <binary file>

Build docs developers (and LLMs) love