Overview
This guide will walk you through creating a complete backup workflow:
Initialize a new repository
Create a backup snapshot
List snapshots
Restore data
By the end, you’ll have a working backup system!
Prerequisites
Make sure you have rustic_core installed:
[ dependencies ]
rustic_core = "0"
rustic_backend = "0"
simplelog = "0.12" # For logging output
Complete Example
Here’s a complete working example that demonstrates the full backup lifecycle:
use rustic_backend :: BackendOptions ;
use rustic_core :: {
BackupOptions , CheckOptions , ConfigOptions , KeyOptions ,
LocalDestination , LsOptions , PathList , Repository ,
RepositoryOptions , RestoreOptions , SnapshotOptions
};
use simplelog :: { Config , LevelFilter , SimpleLogger };
use std :: error :: Error ;
fn main () -> Result <(), Box < dyn Error >> {
// Enable info-level logging to see what's happening
let _ = SimpleLogger :: init ( LevelFilter :: Info , Config :: default ());
// Step 1: Initialize repository
init_repository () ? ;
// Step 2: Create a backup
create_backup () ? ;
// Step 3: Restore from backup
restore_backup () ? ;
// Step 4: Check repository integrity
check_repository () ? ;
println! ( " \n Backup workflow completed successfully!" );
Ok (())
}
fn init_repository () -> Result <(), Box < dyn Error >> {
println! ( "=== Initializing Repository ===" )
// Configure backend (local filesystem in this example)
let backends = BackendOptions :: default ()
. repository ( "/tmp/my-backup-repo" )
. to_backends () ? ;
// Set repository password
let repo_opts = RepositoryOptions :: default ()
. password ( "my-secure-password" );
// Configure encryption key
let key_opts = KeyOptions :: default ();
// Configure repository settings
let config_opts = ConfigOptions :: default ();
// Initialize the repository
let _repo = Repository :: new ( & repo_opts , & backends ) ?
. init ( & key_opts , & config_opts ) ? ;
println! ( "Repository initialized at /tmp/my-backup-repo \n " );
Ok (())
}
fn create_backup () -> Result <(), Box < dyn Error >> {
println! ( "=== Creating Backup ===" )
// Open the repository
let backends = BackendOptions :: default ()
. repository ( "/tmp/my-backup-repo" )
. to_backends () ? ;
let repo_opts = RepositoryOptions :: default ()
. password ( "my-secure-password" );
// Open and prepare for backup operations
let repo = Repository :: new ( & repo_opts , & backends ) ?
. open () ?
. to_indexed_ids () ? ;
// Define what to back up
let source = PathList :: from_string ( "." ) ?. sanitize () ? ;
// Configure backup options
let backup_opts = BackupOptions :: default ();
// Create snapshot with tags
let snap = SnapshotOptions :: default ()
. add_tags ( "quickstart,example" ) ?
. to_snapshot () ? ;
// Perform the backup
let snap = repo . backup ( & backup_opts , & source , snap ) ? ;
println! ( "Snapshot created successfully!" );
println! ( "Snapshot ID: {}" , snap . id);
println! ( "Paths: {:?} \n " , snap . paths);
Ok (())
}
fn restore_backup () -> Result <(), Box < dyn Error >> {
println! ( "=== Restoring Backup ===" )
// Open repository
let backends = BackendOptions :: default ()
. repository ( "/tmp/my-backup-repo" )
. to_backends () ? ;
let repo_opts = RepositoryOptions :: default ()
. password ( "my-secure-password" );
let repo = Repository :: new ( & repo_opts , & backends ) ?
. open () ?
. to_indexed () ? ;
// Get the latest snapshot
let node = repo . node_from_snapshot_path ( "latest" , | _ | true ) ? ;
// List contents
let streamer_opts = LsOptions :: default ();
let ls = repo . ls ( & node , & streamer_opts ) ? ;
// Configure restore destination
let destination = "./restore/" ;
let create = true ;
let dest = LocalDestination :: new ( destination , create , ! node . is_dir ()) ? ;
// Prepare restore
let opts = RestoreOptions :: default ();
let dry_run = false ;
let restore_infos = repo . prepare_restore ( & opts , ls . clone (), & dest , dry_run ) ? ;
// Execute restore
repo . restore ( restore_infos , & opts , ls , & dest ) ? ;
println! ( "Restore completed to ./restore/ \n " );
Ok (())
}
fn check_repository () -> Result <(), Box < dyn Error >> {
println! ( "=== Checking Repository ===" )
let backends = BackendOptions :: default ()
. repository ( "/tmp/my-backup-repo" )
. to_backends () ? ;
let repo_opts = RepositoryOptions :: default ()
. password ( "my-secure-password" );
let repo = Repository :: new ( & repo_opts , & backends ) ?. open () ? ;
// Check repository integrity
let opts = CheckOptions :: default () . trust_cache ( true );
repo . check ( opts ) ? ;
println! ( "Repository check passed! \n " );
Ok (())
}
Step-by-Step Breakdown
Let’s break down each step in detail:
Initialize the Repository
The first step is creating a new backup repository: use rustic_backend :: BackendOptions ;
use rustic_core :: { ConfigOptions , KeyOptions , Repository , RepositoryOptions };
// Configure where to store backups
let backends = BackendOptions :: default ()
. repository ( "/tmp/repo" )
. to_backends () ? ;
// Set repository password
let repo_opts = RepositoryOptions :: default () . password ( "test" );
// Initialize
let key_opts = KeyOptions :: default ();
let config_opts = ConfigOptions :: default ();
let _repo = Repository :: new ( & repo_opts , & backends ) ?
. init ( & key_opts , & config_opts ) ? ;
The repository password encrypts all data. Keep it safe - there’s no way to recover your backups without it!
What happens : This creates the repository structure with encryption keys and configuration files.
Open the Repository
Before performing operations, open the repository: let repo = Repository :: new ( & repo_opts , & backends ) ?
. open () ?
. to_indexed_ids () ? ;
The to_indexed_ids() method prepares the repository for backup operations by loading the index of existing data blobs. Different repository states enable different operations:
.open() - Basic operations (list snapshots, check)
.to_indexed_ids() - Backup operations
.to_indexed() - Restore operations
.to_indexed_full() - Prune and maintenance
Create a Backup
Now create your first snapshot: use rustic_core :: { BackupOptions , PathList , SnapshotOptions };
// Define what to backup
let source = PathList :: from_string ( "." ) ?. sanitize () ? ;
// Configure backup
let backup_opts = BackupOptions :: default ();
// Create snapshot with metadata
let snap = SnapshotOptions :: default ()
. add_tags ( "tag1,tag2" ) ?
. to_snapshot () ? ;
// Execute backup
let snap = repo . backup ( & backup_opts , & source , snap ) ? ;
println! ( "Created snapshot: {}" , snap . id);
What happens : rustic_core:
Scans the source directory
Chunks files using content-defined chunking
Deduplicates against existing data
Encrypts and compresses new chunks
Writes to the repository
Creates a snapshot pointing to the data
Subsequent backups are incremental - only changed data is stored!
List Snapshots
View all snapshots in the repository: let repo = Repository :: new ( & repo_opts , & backends ) ?. open () ? ;
let snapshots = repo . get_all_snapshots () ? ;
for snap in snapshots {
println! ( "Snapshot {}" , snap . id);
println! ( " Time: {}" , snap . time);
println! ( " Paths: {:?}" , snap . paths);
println! ( " Tags: {:?}" , snap . tags);
}
Restore Data
Restore from a snapshot: use rustic_core :: { LocalDestination , LsOptions , RestoreOptions };
let repo = Repository :: new ( & repo_opts , & backends ) ?
. open () ?
. to_indexed () ? ;
// Get latest snapshot
let node = repo . node_from_snapshot_path ( "latest" , | _ | true ) ? ;
// List contents
let ls = repo . ls ( & node , & LsOptions :: default ()) ? ;
// Setup destination
let dest = LocalDestination :: new ( "./restore/" , true , ! node . is_dir ()) ? ;
// Restore
let opts = RestoreOptions :: default ();
let restore_infos = repo . prepare_restore ( & opts , ls . clone (), & dest , false ) ? ;
repo . restore ( restore_infos , & opts , ls , & dest ) ? ;
Instead of “latest”, you can use:
A specific snapshot ID
“latest” for the most recent snapshot
A tag like “tag:production”
Backend Options
rustic_core supports various storage backends:
Local Filesystem
With Hot/Cold Storage
REST Server
let backends = BackendOptions :: default ()
. repository ( "/path/to/repo" )
. to_backends () ? ;
Password Management
Never hardcode passwords in production code! Use environment variables or secure credential storage.
Better password handling:
use std :: env;
// From environment variable
let password = env :: var ( "RUSTIC_PASSWORD" )
. expect ( "RUSTIC_PASSWORD must be set" );
let repo_opts = RepositoryOptions :: default ()
. password ( & password );
Or use a password file:
let repo_opts = RepositoryOptions :: default ()
. password_file ( "/secure/path/to/password.txt" );
Common Operations
Filtering Snapshots
let all_snapshots = repo . get_all_snapshots () ? ;
// Filter by tag
let production_snaps : Vec < _ > = all_snapshots
. iter ()
. filter ( | s | s . tags . contains ( & "production" . to_string ()))
. collect ();
Checking Repository Health
use rustic_core :: CheckOptions ;
let repo = Repository :: new ( & repo_opts , & backends ) ?. open () ? ;
let opts = CheckOptions :: default ()
. trust_cache ( true ) // Skip cache verification for speed
. read_data ( true ); // Verify data pack integrity
repo . check ( opts ) ? ;
Backup with Progress
use rustic_core :: { BackupOptions , ProgressBars };
let progress = ProgressBars :: new ();
let backup_opts = BackupOptions :: default ();
let snap = repo . backup ( & backup_opts , & source , snap ) ? ;
Error Handling
Use proper error handling in production:
use rustic_core :: { RusticError , RusticResult };
fn backup_with_retry () -> RusticResult <()> {
match repo . backup ( & backup_opts , & source , snap ) {
Ok ( snap ) => {
println! ( "Backup successful: {}" , snap . id);
Ok (())
}
Err ( e ) => {
eprintln! ( "Backup failed: {}" , e );
Err ( e )
}
}
}
Next Steps
Now that you have a working backup system, explore more features:
Repository Management Learn about repository states and configuration
Backup Operations Advanced backup options and strategies
Restore Operations Selective restore and recovery options
Maintenance Prune, check, and optimize your repository