WIUNIX ACADEMY
Restic offsite backup: prove a specific snapshot restores before trusting it
Use protected credentials, a verified SFTP repository, explicit snapshot identity and an isolated restore with byte checks; separate repository checks from application recovery.
Make this guide yoursYOUR SYSTEM. YOUR STEPS.
Where are you working?
Choose your OS and version. The prerequisites, commands and troubleshooting follow your environment.
USE YOUR OWN VALUES
Configure this tutorial
Set the example values for your environment; related explanations and copy panels update together. Never enter passwords, private keys or tokens. Values stay in this tab and are not sent to the server or share links. Check actual DNS, certificates and network policy before running commands.
Different IP addresses, domains or ports? Open the settings below, change the values and select “Apply to tutorial”, then copy the updated commands.
Set values for my environment7 editable values
THE OUTCOME
What will you have at the end?
Create a controlled encrypted offsite backup of a consistent export and verify restoration of the exact snapshot without overwriting the source.
Supported operating systems and versions
Documented restic0.19.1 stable workflow on Linux; no credentials, repository, backup or production dataset was accessed during authoring.
Before you begin
- Existing supported restic, OpenSSH, OpenSSL, Python3 and GNU find/coreutils on an authorized Linux operator host
- Dedicated SFTP backup account on an independent host, trusted host key and reviewed capacity
- Existing stable application-consistent export, independently retained recovery key and a new isolated restore target
LET’S BUILD
Prepare the selected operator host
These are operator-host packages only. Review the transaction before approving; do not install tools inside application containers. The cluster, server and application binaries must already exist with owner-approved versions. Use Bash for the following panels. Package installation changes this selected host but starts no new application server.
This path targets an already verified upstream restic0.19.1 client (or a separately reviewed compatible build). Debian12 ships0.14 and Debian13 ships0.18: do not assume their distro restic satisfies this path. The package panel intentionally does not install/upgrade restic or enable EPEL. Obtain approval and verify the upstream release/signature through the documented installation process before using another binary.
Selected operator host; approved package transaction
sudo apt-get update
sudo apt-get install --no-install-recommends ca-certificates curl bash coreutils openssh-client openssl python3 findutils
cat /etc/os-release
command -v bash curl timeout
restic version
ssh -V
python3 --version
openssl version
command -v sha256sum find sort xargsThe OS/version matches the selection, required tools resolve, and existing application/client versions satisfy the stated compatibility boundary. Stop if a binary is missing or incompatible.
Preserve host security and existing paths
Ubuntu/Debian may use AppArmor and host firewall rules. This workflow opens no inbound host port and changes no security profile. For denied file/network access, inspect the owning service logs and policy with its administrator. Keep existing executable/config paths; public path fields are reviewed example locations, not discovered installation paths.
Define recovery before the first backup
A completed upload is not an application recovery. Define the source, consistency point, maximum acceptable data age and restore-time target. This recipe backs up an existing quiesced file export; it does not make live database files transaction-consistent. Use the database’s native backup/export procedure first and include its recovery metadata.
Offsite means a separate failure domain with independent access, not another directory on the same disk. Encryption protects repository content at rest, but a writer with delete access can still destroy backups. Append-only/immutable retention and independent credentials require backend-specific design; SFTP alone does not provide them.
LET’S BUILD
Verify version, destination and host identity
Use an existing supported restic client and dedicated backup SSH identity. Verify the server host key through a trusted independent channel before this step; never disable host checking. The target repository must be a new approved path whose parent is writable by the backup account. Inspect existing SSH restrictions with the owner, not by broadening permissions.
Operator terminal; authorized lab context
restic version
ssh -o BatchMode=yes -o StrictHostKeyChecking=yes 'backup@backup.example.com' 'pwd'
ssh -o BatchMode=yes -o StrictHostKeyChecking=yes 'backup@backup.example.com' 'test ! -e /srv/restic/academy-repo'The verified host/account works and the exact new repository path does not exist; any access/error result stops initialization.
LET’S BUILD
Create a protected repository password without argv exposure
Create a new private local directory with restrictive permissions and generate a password directly into a file. It is never a public form value or command argument. Arrange an independently protected recovery copy of this password and SSH access through the existing secret-management process before relying on the backup. Losing all repository passwords/keys makes recovery impossible.
Operator terminal; authorized lab context
umask 077
mkdir '/home/operator/academy-restic-private' || exit 1
openssl rand -base64 48 > '/home/operator/academy-restic-private/repository-password' || exit 1
chmod 600 '/home/operator/academy-restic-private/repository-password'
stat -c '%a %n' '/home/operator/academy-restic-private' '/home/operator/academy-restic-private/repository-password'The new directory is700 and password file600; no password value is displayed.
LET’S BUILD
Guard source and restore paths and estimate capacity
The source must be a stable readable export, and restore_dir must not exist. The guard rejects overlapping paths in either direction, a symlinked existing restore path and a filesystem root source. Check local restore capacity and remote repository capacity with the storage owner; deduplication ratios cannot be assumed. Public path fields do not prove filesystem ownership.
Operator terminal; authorized lab context
python3 - <<'PY'
from pathlib import Path
import os
s=Path('/srv/backup-export').resolve(strict=True)
p=Path('/home/operator/academy-restic-private').resolve(strict=True)
assert p.is_dir(), 'Invalid private directory'
r=Path('/srv/academy-restic-restore')
assert s.is_dir() and s != Path(s.anchor), 'Invalid source'
assert not r.exists() and not r.is_symlink(), 'Restore target already exists'
r=r.resolve()
assert s != r and s not in r.parents and r not in s.parents, 'Overlapping source/restore'
assert p != s and s not in p.parents and p not in s.parents, 'Private directory overlaps source'
assert p != r and p not in r.parents and r not in p.parents, 'Private directory overlaps restore'
parent=r.parent.resolve(strict=True)
assert parent.is_dir() and os.access(parent,os.W_OK|os.X_OK), 'Restore parent is not writable'
print('Source/private/restore paths are non-overlapping; restore parent exists and is writable')
PY
du -xsh -- '/srv/backup-export'
df -h -- '/srv/backup-export' '/home/operator/academy-restic-private' "$(dirname -- '/srv/academy-restic-restore')"The paths are distinct and owned, the source is stable and capacity has been reviewed before upload.