Storage Backends

PyRestServer supports multiple storage backends through a pluggable architecture.

Overview

All storage backends implement the StorageProvider interface, allowing PyRestServer to work with different storage systems transparently.

Available backends:

  • Local Filesystem - Store data on local disk (built-in)

  • Drime Cloud - Store data in Drime Cloud storage (requires pydrime)

Local Filesystem Backend

The local backend stores repository data in a directory structure on the local filesystem.

Configuration

Start with local backend:

pyrestserver serve --path /srv/restic

Or configure:

pyrestserver config add mylocal \
    --type local \
    --path /srv/restic

Directory Structure

The local backend creates the following structure:

/srv/restic/
├── repo1/
│   ├── config              # Repository configuration
│   ├── data/               # Data blobs
│   │   ├── 00/            # Subdirectory for blobs starting with 00
│   │   ├── 01/
│   │   ├── ...
│   │   └── ff/
│   ├── index/              # Index files
│   ├── keys/               # Encryption keys
│   ├── locks/              # Lock files
│   └── snapshots/          # Snapshot metadata
└── repo2/
    └── ...

Permissions

Files and directories are created with secure permissions:

  • Directories: 0700 (rwx——)

  • Files: 0600 (rw——-)

This ensures only the owner can access the backup data.

Pros and Cons

Advantages:

✅ Simple and fast ✅ No external dependencies ✅ Easy to backup (standard filesystem) ✅ Works offline ✅ Full control over data

Disadvantages:

❌ Limited to single machine (without NFS/CIFS) ❌ No built-in redundancy ❌ Requires sufficient local disk space

Best For

  • Single-server backups

  • Local network backups

  • Development and testing

  • On-premise deployments

Drime Cloud Backend

The Drime backend stores repository data in Drime Cloud storage.

Prerequisites

Install with Drime support:

pip install pyrestserver[drime]

Configuration

Configure Drime backend:

pyrestserver config add mydrime \
    --type drime \
    --api-key "your-api-key" \
    --workspace-id 0

Or use environment variables:

export DRIME_API_KEY="your-api-key"

pyrestserver serve --backend drime --workspace-id 0

Configuration Options

  • api_key - Drime API authentication key (required)

  • workspace_id - Workspace ID (default: 0 for personal workspace)

Read the configuration from backends.toml:

pyrestserver serve --backend-config mydrime

Storage Structure

The Drime backend creates the same structure as local backend, but in Drime Cloud:

Workspace 0/
├── repo1/
│   ├── config
│   ├── data/
│   │   ├── 00/
│   │   └── ...
│   ├── index/
│   ├── keys/
│   ├── locks/
│   └── snapshots/
└── repo2/
    └── ...

Features

  • Folder caching - Reduces API calls by caching folder IDs

  • Workspace support - Use different workspaces for organization

  • Automatic folder creation - Creates repository structure automatically

  • Hash-based deduplication - Drime’s content-addressable storage

Pros and Cons

Advantages:

✅ Cloud storage - accessible from anywhere ✅ Built-in redundancy ✅ No local disk space needed ✅ Automatic backups and versioning (Drime features) ✅ Scalable storage

Disadvantages:

❌ Requires internet connection ❌ API rate limits may apply ❌ Depends on Drime service availability ❌ Additional cost for storage

Best For

  • Remote backups

  • Multi-location backups

  • Cloud-first deployments

  • Organizations using Drime

Performance

The Drime backend includes optimizations:

  • Folder ID caching - Reduces API calls for repeated operations

  • Batch operations - Where supported by Drime API

  • Connection pooling - Reuses HTTP connections

Typical performance (depends on network and API):

  • Upload: 5-20 MB/s

  • Download: 10-30 MB/s

  • Small file operations: 50-200 per second

Backend Comparison

Backend Selection

Choose based on your requirements:

Use Local backend if:

  • You have a dedicated backup server

  • You want maximum performance

  • You’re backing up to NAS/SAN

  • You prefer offline/air-gapped backups

  • Cost is a primary concern

Use Drime backend if:

  • You need cloud storage

  • You want off-site backups

  • You’re already using Drime

  • You need multi-location access

  • You want managed storage

Hybrid Approach:

You can use both backends:

# Primary backup to local
restic -r rest:http://localhost:8000/main backup /data

# Secondary backup to cloud
restic -r rest:http://localhost:8001/cloud backup /data

Storage Provider Interface

All backends implement the StorageProvider abstract base class.

Core Methods

class StorageProvider(ABC):
    def repository_exists(self, repo_path: str) -> bool:
        """Check if a repository exists."""

    def config_exists(self, repo_path: str) -> tuple[bool, int]:
        """Check if config exists, return (exists, size)."""

    def create_repository(self, repo_path: str) -> bool:
        """Create repository structure."""

    def get_config(self, repo_path: str) -> bytes | None:
        """Get repository config content."""

    def save_config(self, repo_path: str, data: bytes) -> bool:
        """Save repository config."""

    def list_blobs(self, repo_path: str, blob_type: str) -> list[dict] | None:
        """List blobs of a type."""

    def blob_exists(self, repo_path: str, blob_type: str, name: str) -> tuple[bool, int]:
        """Check if blob exists, return (exists, size)."""

    def get_blob(self, repo_path: str, blob_type: str, name: str) -> bytes | None:
        """Get blob content."""

    def save_blob(self, repo_path: str, blob_type: str, name: str, data: bytes) -> bool:
        """Save blob content."""

    def delete_blob(self, repo_path: str, blob_type: str, name: str) -> bool:
        """Delete a blob."""

    def is_readonly(self) -> bool:
        """Check if provider is read-only."""

Creating Custom Backends

See custom_backends for details on implementing your own storage backend.

Configuration Management

Backend configurations are stored using vaultconfig with custom cipher keys.

Configuration File

Location: ~/.config/pyrestserver/backends.toml

Format:

[backend-name]
type = "local"  # or "drime"
# Backend-specific options

[another-backend]
type = "drime"
api_key = "obscured-value"
workspace_id = 0

Security

  • Sensitive values (API keys, passwords) are automatically obscured

  • Custom cipher key unique to pyrestserver

  • File permissions protect configuration

  • See Security Best Practices for more details

Managing Multiple Backends

You can configure multiple backends and switch between them:

# Configure backends
pyrestserver config add local-main --type local --path /srv/restic
pyrestserver config add local-archive --type local --path /archive/restic
pyrestserver config add cloud-backup --type drime --api-key "key"

# Start with different backends
pyrestserver serve --backend-config local-main
pyrestserver serve --backend-config cloud-backup --listen :8001

This allows you to:

  • Run multiple instances on different ports

  • Separate production/staging/development

  • Implement backup strategies with multiple destinations

Next Steps

  • Learn to implement custom_backends

  • Review Security Best Practices for production deployments

  • Check benchmarks for performance testing