Skip to main contentSkip to navigation
[email protected]
Client AreaSupport
Hosting Mammoth
HostingMammothYour Data, Our Responsibility
Home
Solutions
Hosting Services
Store
Pricing
About
Blog
API
Contact

Stay Ahead of the Curve

Get the latest insights on cybersecurity, AI innovations, and enterprise data solutions delivered to your inbox.

Hosting Mammoth
HostingMammothEnterprise Solutions

Enterprise-grade data solutions. Hosting, recovery, cybersecurity, and AI-powered services for businesses worldwide.

[email protected]
Sun - Fri, 9:00am - 5:00pm

Services

  • Cloud Hosting
  • Data Recovery
  • Cybersecurity
  • Legal Support
  • MSP Services
  • Web Development
  • AI Services
  • Free Server Migration

Hosting

  • VPS Hosting (NVMe SSD)
  • VDS Hosting (NVMe)
  • Storage VPS (High SSD)
  • GPU Servers
  • Managed Services
  • Cloud Firewall
  • Load Balancer
  • One-Click Apps
  • n8n Hosting
  • Object Storage
  • FAQ

Company

  • Store
  • Pricing
  • About Us
  • Locations
  • Blog
  • Testimonials
  • Contact
  • Affiliate Program
  • White-Label
  • Terms of Service
  • Privacy Policy
  • Browser Cookies
  • SLA

Support

  • Client Area
  • Submit Ticket
  • Knowledge Base
  • Server Status
  • API Documentation

© 2026 Hosting Mammoth. All rights reserved.

Knowledge Base
Getting StartedAccount ManagementVPS HostingGPU ServersStorage VPSCloud FirewallLoad BalancerServer ManagementBilling & PaymentsSupport & TicketsAffiliate ProgramReseller ProgramMarketplace & Appsn8n HostingManaged ServicesServer MigrationAPI & DevelopersSecurityTroubleshootingGlossaryInstall Guides
  1. Home
  2. /
  3. Support
  4. /
  5. Install Guides
  6. /
  7. How To Install Restic Ubuntu
GUIDEInstall Guides

How to Set Up Restic Encrypted Backups on Ubuntu 24.04 VPS

23 min read

How to Set Up Restic Encrypted Backups on Ubuntu 24.04 VPS

A VPS without backups is a VPS waiting to lose data. Disks fail, rm -rf happens, ransomware encrypts what you did not encrypt first, and "I will set up backups tomorrow" is a phrase every sysadmin regrets at least once. This guide walks you through installing Restic on Ubuntu 24.04, initialising an encrypted repository on S3-compatible object storage, running your first backup, automating nightly runs with a systemd timer, and rehearsing the restore before you actually need it.

Need a VPS to back up from or to? The CloudCore Starter plan gives you 100 GB of NVMe for your workload plus room to spin up a second box as your MinIO backup target. Deploy in 60 seconds.

Table of Contents

  • Why Restic?
  • Prerequisites
  • Step 1: Update System Packages
  • Step 2: Install Restic
  • Step 3: Choose and Configure a Repository Backend
  • Step 4: Initialise the Encrypted Repository
  • Step 5: Run Your First Backup
  • Step 6: List and Inspect Snapshots
  • Step 7: Restore from a Snapshot
  • Step 8: Apply a Retention Policy with forget and prune
  • Step 9: Automate with a systemd Service and Timer
  • Step 10: Verify Integrity with restic check
  • Offsite Strategy
  • Alerting and Monitoring
  • Restic vs. Borg vs. Duplicity vs. Kopia
  • Troubleshooting
  • FAQ
  • Next Steps
  • Why Restic?

    Restic is an open-source backup tool written in Go that has quietly become the default choice for Linux admins who want encryption, deduplication, and cross-cloud portability without wrestling with a dozen config files. It ships as a single static binary with no runtime dependencies, which means installing it on a fresh Ubuntu 24.04 server is essentially a file copy.

    The feature list is short, opinionated, and directly aligned with what modern infrastructure needs:

    • Encrypted by default -- Every byte written to the repository is encrypted client-side with AES-256 in counter mode, authenticated with Poly1305-AES. You cannot accidentally create an unencrypted repo. Whoever holds your storage (AWS, Backblaze, a compromised VPS) cannot read your data.
    • Content-defined deduplication -- Restic splits files into variable-sized chunks using a rolling hash (CDC), and identical chunks are stored only once. Back up 50 identical WordPress sites and you pay the storage cost of roughly one.
    • Incremental forever -- After the first snapshot, every subsequent backup only uploads new or changed chunks. A nightly backup of a 200 GB server typically transfers a few hundred megabytes.
    • Works with everything -- Native backends for Amazon S3, Backblaze B2, Google Cloud Storage, Azure Blob, MinIO, Wasabi, any S3-compatible service, SFTP, local disks, REST server, and anything rclone can reach.
    • BSD 2-Clause licensed -- Use it commercially, embed it in products, ship it with appliances. No license fees, no "open core" upsell.
    • Atomic snapshots -- Each backup is a full, self-contained snapshot from the user's perspective, even though the storage layer is incremental. Restoring a snapshot never requires reassembling a chain of fulls + incrementals like tar-based tools.
    For a typical Ubuntu VPS running web apps, databases, and user data, Restic hits the sweet spot: strong enough for compliance conversations, simple enough that a junior admin can operate it after a single afternoon.

    Prerequisites

    Before you begin, make sure you have:

    • A VPS running Ubuntu 24.04 LTS with root or sudo access
    • SSH access to your server
    • A storage target -- one of: an S3 bucket (AWS, Wasabi, Backblaze B2, MinIO on a second VPS), an SFTP-accessible server, or a mounted external disk
    • At least 1 GB of free RAM for Restic to run comfortably on large repos
    • Disk headroom equal to 1-2% of your protected data for Restic's local cache
    Recommended Plan: CloudCore Starter
    >
    For most single-server backup setups, CloudCore Starter is enough:
    >
    - 4 vCPU cores
    - 8 GB RAM
    - 100 GB NVMe SSD
    - Unmetered bandwidth
    >
    Many users deploy two CloudCore Starter instances in different regions: one as the production server, the second as a MinIO target. That way your backups live on hardware you control, encrypted with a key only you hold.

    Connect to your server via SSH:

    bash
    ssh root@your-server-ip

    Step 1: Update System Packages

    Start by bringing the package index current. Ubuntu 24.04 LTS ships a reasonably recent Restic in the official universe repository, and keeping the system patched avoids surprises during install.

    bash
    sudo apt update && sudo apt upgrade -y

    If the kernel or glibc was updated, reboot before continuing:

    bash
    sudo reboot

    Reconnect once the server is back.

    Step 2: Install Restic

    Ubuntu 24.04 includes Restic in the universe component, so apt is the fastest way to get a working binary:

    bash
    sudo apt install -y restic

    Verify the install:

    bash
    restic version

    Expected output:

    text
    restic 0.16.4 compiled with go1.22.0 on linux/amd64

    The Ubuntu-packaged version lags a few minor releases behind upstream. That is fine for most users, but if you want the latest features (for example, compression, which became the default in 0.16) or a specific fix, grab the binary directly from the release page:

    bash
    RESTIC_VERSION=0.17.1
    curl -L https://github.com/restic/restic/releases/download/v${RESTIC_VERSION}/restic_${RESTIC_VERSION}_linux_amd64.bz2 \
      | bunzip2 > /usr/local/bin/restic
    sudo chmod +x /usr/local/bin/restic
    restic version

    From here on, either restic path works identically.

    Enable shell completion so tab-completing subcommands and flags Just Works:

    bash
    restic generate --bash-completion /etc/bash_completion.d/restic

    Step 3: Choose and Configure a Repository Backend

    A Restic repository is just a directory structure (config, keys/, snapshots/, data/, index/, locks/) that Restic can reach through one of its backends. The choice of backend determines how you address the repo.

    The three backends that cover 95% of real deployments:

    Option A: S3-Compatible (MinIO, Backblaze B2, Wasabi, AWS S3)

    This is the standard choice for offsite backups. Any service that speaks the S3 API works, and the URL syntax is uniform:

    bash
    export RESTIC_REPOSITORY="s3:https://s3.eu-central-003.backblazeb2.com/my-restic-bucket"
    export AWS_ACCESS_KEY_ID="your-key-id"
    export AWS_SECRET_ACCESS_KEY="your-application-key"

    The endpoint changes per provider:

    • Backblaze B2 (S3 API): s3:https://s3.<region>.backblazeb2.com/<bucket>
    • Wasabi: s3:https://s3.<region>.wasabisys.com/<bucket>
    • AWS S3: s3:s3.amazonaws.com/<bucket> (region inferred from creds)
    • MinIO on your own VPS: s3:https://minio.yourdomain.com/<bucket>

    Option B: SFTP to Another Server

    Simplest and zero-cost if you already have a second box:

    bash
    export RESTIC_REPOSITORY="sftp:[email protected]:/srv/restic/myserver"

    Restic will use your SSH keys -- set up ~/.ssh/config so backup-host.example.com resolves to the right user, port, and identity file.

    Option C: Local Disk or Mounted Volume

    Useful as a staging target before pushing offsite, or when you have attached block storage:

    bash
    export RESTIC_REPOSITORY="/mnt/backup/restic"

    Store the Password Securely

    Whichever backend you pick, Restic needs a repository password at init and every subsequent operation. If you lose this password, your data is unrecoverable. There is no recovery mechanism. This is the cost of strong encryption.

    Create a password file readable only by root:

    bash
    sudo mkdir -p /etc/restic
    openssl rand -base64 48 | sudo tee /etc/restic/password > /dev/null
    sudo chmod 600 /etc/restic/password

    Tell Restic where to find it:

    bash
    export RESTIC_PASSWORD_FILE=/etc/restic/password

    Back this password up separately -- in a password manager, a sealed envelope in a safe, a second admin's keychain. Losing /etc/restic/password without a copy means losing the backup.

    Persist Environment Variables

    Drop all the variables into an env file so cron, systemd, and interactive sessions share one source of truth:

    bash
    sudo tee /etc/restic/restic.env > /dev/null <<'EOF'
    RESTIC_REPOSITORY=s3:https://s3.eu-central-003.backblazeb2.com/my-restic-bucket
    RESTIC_PASSWORD_FILE=/etc/restic/password
    AWS_ACCESS_KEY_ID=your-key-id
    AWS_SECRET_ACCESS_KEY=your-application-key
    EOF
    sudo chmod 600 /etc/restic/restic.env

    For interactive use:

    bash
    set -a; source /etc/restic/restic.env; set +a

    Step 4: Initialise the Encrypted Repository

    With environment variables loaded, initialise the repo. This is a one-time operation that writes the encryption keys and empty index structures to the backend.

    bash
    restic init

    Expected output:

    text
    created restic repository 8e1a7b2cc3 at s3:https://s3.eu-central-003.backblazeb2.com/my-restic-bucket

    Please note that knowledge of your password is required to access the repository. Losing your password means that your data is irrecoverably lost.

    If you see Fatal: create repository ... failed: repository master key and config already initialized, the repository already exists -- either you are re-running against a populated target, or somebody got here first. Do not re-init; that would destroy existing data.

    Step 5: Run Your First Backup

    The backup subcommand takes one or more paths and an optional tag. Tags are free-form strings you use later to filter snapshots.

    Back up /var/www (typical webserver document root):

    bash
    restic backup /var/www --tag webroot --tag daily

    Expected output:

    text
    repository 8e1a7b2c opened (version 2, compression level auto)
    created new cache in /root/.cache/restic
    no parent snapshot found, will read all files

    Files: 2743 new, 0 changed, 0 unmodified Dirs: 318 new, 0 changed, 0 unmodified Added to the repository: 612.447 MiB (158.221 MiB stored)

    processed 2743 files, 1.204 GiB in 0:47 snapshot 4f2e8a1c saved

    A few things to notice:

    • "Added to the repository" shows raw bytes and compressed/stored bytes. Restic 0.14+ enables zstd compression by default; expect 50-70% savings on text-heavy workloads.
    • "snapshot 4f2e8a1c" is the first 8 hex chars of the snapshot ID. You will reference this in ls, restore, and forget commands.
    • The first run reads every file. Subsequent runs walk the filesystem, compare modification times and sizes against the parent snapshot, and only re-read files that look changed.

    Backing Up Multiple Paths

    Pass as many paths as you like:

    bash
    restic backup /etc /home /var/www /srv --tag nightly

    Excluding Files

    Large, regenerable, or sensitive paths should be skipped. Create an exclude file:

    bash
    sudo tee /etc/restic/excludes.txt > /dev/null <<'EOF'
    

    Caches and build artefacts

    **/node_modules **/.cache **/__pycache__ *.log.gz

    Volatile databases (back these up via dump, not raw files)

    /var/lib/mysql /var/lib/postgresql

    Mounted shares

    /mnt /media

    Swap and tmp

    /swap.img /tmp EOF

    Pass it to backup:

    bash
    restic backup / \
      --exclude-file=/etc/restic/excludes.txt \
      --one-file-system \
      --tag system

    --one-file-system prevents descent into bind mounts and virtual filesystems like /proc, /sys, /dev.

    Database Backups

    Do not back up live /var/lib/mysql or /var/lib/postgresql as raw files -- you will capture mid-write pages and the restore will be corrupt. Dump first, then let Restic pick up the dump file:

    bash
    # Postgres
    sudo -u postgres pg_dumpall | gzip > /var/backups/pg_all_$(date +%F).sql.gz

    MySQL / MariaDB

    mysqldump --all-databases --single-transaction --quick | gzip > /var/backups/mysql_all_$(date +%F).sql.gz

    Then back up /var/backups along with the rest

    restic backup /var/backups /etc /var/www --tag nightly

    Step 6: List and Inspect Snapshots

    After a few backups, list what you have:

    bash
    restic snapshots

    Expected output:

    text
    ID        Time                 Host          Tags               Paths
    -----------------------------------------------------------------------------
    4f2e8a1c  2026-04-15 03:00:12  web-01        webroot,daily      /var/www
    91c3d7b2  2026-04-16 03:00:08  web-01        webroot,daily      /var/www
    a7e4f0d9  2026-04-16 03:00:08  web-01        system             /etc /home /var/www
    -----------------------------------------------------------------------------
    3 snapshots

    Filter by tag, host, or path:

    bash
    restic snapshots --tag daily
    restic snapshots --host web-01 --path /var/www

    List the contents of a snapshot:

    bash
    restic ls 91c3d7b2 | head -20

    Diff two snapshots to see exactly what changed:

    bash
    restic diff 4f2e8a1c 91c3d7b2

    Expected output:

    text
    comparing snapshot 4f2e8a1c to 91c3d7b2:

    M /var/www/html/index.php + /var/www/html/new-page.html

    • /var/www/html/old-banner.jpg
    Files: 1 new, 1 removed, 1 changed Dirs: 0 new, 0 removed Others: 0 new, 0 removed Data Blobs: 3 new, 4 removed Tree Blobs: 2 new, 2 removed Added: 1.823 MiB Removed: 984.214 KiB

    Step 7: Restore from a Snapshot

    Restic offers two restore workflows. Pick based on what you need back.

    Full Restore

    Restore the latest snapshot's contents to a staging directory:

    bash
    mkdir -p /tmp/restore
    restic restore latest --target /tmp/restore

    latest resolves to the newest snapshot for the current host and paths. Use an explicit ID for precision:

    bash
    restic restore 91c3d7b2 --target /tmp/restore

    Restore only specific paths from a snapshot:

    bash
    restic restore 91c3d7b2 --target /tmp/restore --include /var/www/html

    Once the restore is verified, move files into place with rsync -a. Never restore directly over a running service's live directory -- always stage to /tmp/restore or /var/tmp/restore first.

    Mount and Browse (FUSE)

    For recovering a single file without pulling down the whole snapshot, mount the repo as a FUSE filesystem:

    bash
    sudo apt install -y fuse
    mkdir -p /mnt/restic
    restic mount /mnt/restic

    In another terminal:

    bash
    ls /mnt/restic/snapshots/
    cp /mnt/restic/snapshots/2026-04-16T03:00:08/var/www/html/index.php /root/recovered-index.php

    Press Ctrl+C in the original terminal to unmount.

    This is the single most useful feature Restic offers for day-to-day ops. A user asks "hey, can you pull me last Tuesday's version of that one config file?" and you answer in 30 seconds without downloading the whole snapshot.

    Step 8: Apply a Retention Policy with forget and prune

    Without a retention policy, snapshots accumulate forever. restic forget removes snapshot pointers according to rules you define; restic prune then reclaims the underlying storage.

    A sensible default for production servers:

    bash
    restic forget \
      --keep-daily 7 \
      --keep-weekly 4 \
      --keep-monthly 12 \
      --keep-yearly 3 \
      --prune

    This keeps:

    • The 7 most recent daily snapshots
    • One per week for the last 4 weeks (distinct from the dailies)
    • One per month for the last 12 months
    • One per year for the last 3 years
    The --prune flag runs repository garbage collection in the same command. On large repos this can take 10-30 minutes; for nightly automation, run forget without --prune and schedule prune weekly instead:

    bash
    # Nightly
    restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 12 --keep-yearly 3

    Weekly (Sunday)

    restic prune

    To apply retention only to a tag:

    bash
    restic forget --tag daily --keep-daily 14 --prune

    Step 9: Automate with a systemd Service and Timer

    Cron works, but a systemd service + timer gives you structured logs, dependency ordering, and proper failure handling. This is the right tool on Ubuntu 24.04.

    Create the backup script:

    bash
    sudo tee /usr/local/sbin/restic-backup.sh > /dev/null <<'EOF'
    #!/usr/bin/env bash
    set -euo pipefail

    set -a source /etc/restic/restic.env set +a

    HOSTNAME="$(hostname -s)" DUMP_DIR=/var/backups/db mkdir -p "$DUMP_DIR"

    Dump databases first (uncomment what applies)

    sudo -u postgres pg_dumpall | gzip > "$DUMP_DIR/pg_all.sql.gz"

    mysqldump --all-databases --single-transaction --quick | gzip > "$DUMP_DIR/mysql_all.sql.gz"

    Main backup

    restic backup \ /etc /home /root /srv /var/www "$DUMP_DIR" \ --exclude-file=/etc/restic/excludes.txt \ --one-file-system \ --tag nightly \ --tag "$HOSTNAME"

    Retention (forget only; prune runs weekly from a separate timer)

    restic forget \ --tag nightly \ --keep-daily 7 \ --keep-weekly 4 \ --keep-monthly 12 \ --keep-yearly 3 EOF sudo chmod 700 /usr/local/sbin/restic-backup.sh

    Create the systemd service unit:

    bash
    sudo tee /etc/systemd/system/restic-backup.service > /dev/null <<'EOF'
    [Unit]
    Description=Restic nightly backup
    Wants=network-online.target
    After=network-online.target

    [Service] Type=oneshot Nice=19 IOSchedulingClass=idle ExecStart=/usr/local/sbin/restic-backup.sh

    Lock the repo automatically if a previous run left a stale lock (rare)

    ExecStartPre=/usr/bin/restic unlock || true EOF

    Create the timer unit:

    bash
    sudo tee /etc/systemd/system/restic-backup.timer > /dev/null <<'EOF'
    [Unit]
    Description=Run Restic backup nightly

    [Timer] OnCalendar=--* 03:00:00 RandomizedDelaySec=30m Persistent=true

    [Install] WantedBy=timers.target EOF

    Persistent=true ensures that if the VPS was off at 03:00, the backup runs on next boot. RandomizedDelaySec=30m staggers runs so you are not hammering your S3 endpoint from a fleet of servers at the same second.

    Enable and start:

    bash
    sudo systemctl daemon-reload
    sudo systemctl enable --now restic-backup.timer

    Check scheduling:

    bash
    systemctl list-timers restic-backup.timer

    Run the backup immediately to validate end-to-end:

    bash
    sudo systemctl start restic-backup.service
    sudo journalctl -u restic-backup.service -f

    For prune, create a parallel restic-prune.service + restic-prune.timer running OnCalendar=Sun 04:00:00 weekly.

    If you want a systemd primer beyond this, see our guide on writing robust systemd services.

    Step 10: Verify Integrity with restic check

    A backup you have not tested is a wish. restic check walks the repository and verifies that every pack file is well-formed and that indexes match reality:

    bash
    restic check

    Expected output:

    text
    using temporary cache in /tmp/restic-check-cache-2637485913
    created new cache in /tmp/restic-check-cache-2637485913
    create exclusive lock for repository
    load indexes
    check all packs
    check snapshots, trees and blobs
    no errors were found

    For deeper verification, sample-read actual data blobs:

    bash
    restic check --read-data-subset=5%

    This downloads and cryptographically verifies 5% of data packs. Run it monthly. For the paranoid, --read-data reads 100% (expensive -- the whole repo gets re-downloaded).

    Cold-Restore Rehearsal

    Checking the repo proves the repo is intact. It does not prove you can actually recover. Once a quarter, rehearse a true cold restore:

  • Spin up a fresh Ubuntu VPS with no existing knowledge of your infrastructure.
  • Install Restic.
  • Paste in the repository URL, credentials, and password (read from your password manager, not from /etc/restic/password on the source server).
  • Run restic restore latest --target /recovered.
  • Diff critical files against the live server.
  • Destroy the test VPS.
  • If this fails, you find out on a Tuesday afternoon rather than during a disaster at 3 a.m.

    Offsite Strategy

    The oft-quoted 3-2-1 rule (three copies, two media, one offsite) applies. A few patterns that work well with Restic:

    Pattern A: Primary Server -> Backblaze B2

    Cheapest and simplest. B2 storage is ~$0.006/GB/month, egress to Cloudflare is free via their Bandwidth Alliance partnership. For a 100 GB backup retained with the policy above (deduped to ~40 GB typical), you pay under 30 cents per month.

    Pattern B: Primary Server -> Self-Hosted MinIO on a Second VPS

    If your compliance posture rules out third-party object storage, run MinIO on a second VPS in a different region. Restic treats MinIO exactly like AWS S3. A CloudCore Starter in a different region gives you fully-controlled, encrypted-at-rest-and-in-transit backups for a flat monthly price with no egress charges.

    See our guide on deploying MinIO on Ubuntu 24.04 for the receiving side.

    Pattern C: Primary Server -> Local Mount -> rclone -> Cloud

    If your VPS has attached block storage, back up to local first (fast), then replicate the repo directory to cloud overnight using rclone sync. This optimises for restore speed (local is fast) while keeping the offsite copy.

    Whichever pattern you pick, ensure the offsite credentials are append-only or write-only where the backend supports it (B2 application keys, AWS IAM). Ransomware that reaches the source server should not be able to delete backups.

    Alerting and Monitoring

    A silent backup that silently stopped working six weeks ago is worse than no backup -- you are planning around data you no longer have. Wire up failure alerts.

    Healthchecks.io (Free Tier)

    Sign up at healthchecks.io, create a check with grace period 90 minutes, copy the ping URL, and append to your backup script:

    bash
    # At the very end of restic-backup.sh
    curl -fsS --retry 3 https://hc-ping.com/your-check-uuid > /dev/null

    To distinguish failures from silent non-runs, use the start/failure endpoints:

    bash
    curl -fsS https://hc-ping.com/your-check-uuid/start > /dev/null
    restic backup ... || { curl -fsS https://hc-ping.com/your-check-uuid/fail > /dev/null; exit 1; }
    curl -fsS https://hc-ping.com/your-check-uuid > /dev/null

    Healthchecks emails (or Slacks, or PagerDuty-pages) you the moment a run misses its window.

    systemd OnFailure

    As a belt-and-braces backup, add email-on-failure to the service unit:

    text
    [Unit]
    OnFailure=status-email@%n.service

    Combined with a sendmail-ready MTA (Postfix + a transactional provider), any non-zero exit from the service lands in your inbox within seconds.

    Restic vs. Borg vs. Duplicity vs. Kopia

    All four are legitimate choices. Short version of how they compare:

    FeatureResticBorgDuplicityKopia
    LanguageGo (single binary)Python + CPythonGo (single binary)
    EncryptionAES-256 + Poly1305, always onAES-CTR + HMAC, always onGPG (optional)AES-256-GCM, always on
    DeduplicationCDC (variable chunks)CDC (variable chunks)None (tar chains)CDC (variable chunks)
    Cloud-native backendsYes (S3, B2, GCS, Azure, rclone)No (SSH only, needs rclone)Yes (many)Yes (S3, B2, GCS, Azure, SFTP)
    Compressionzstd (default in 0.14+)lz4/zstd/zlibgzip/bzip2zstd
    Multi-client to one repoYes (concurrent)Serialised (one at a time)SerialisedYes (concurrent)
    GUIThird-partyThird-partyNoBuilt-in (Kopia UI)
    MatureYesYesYes (older)Newer (2019+)
    Pick Restic when you want modern cloud backends, strong defaults, active development, and a single static binary.

    Pick Borg when your targets are always SSH-accessible and you value Borg's slightly better compression ratio on some workloads. Borg's pull model (backup server pulls from clients) has a security edge in some threat models.

    Pick Duplicity if you are already running it and it works. New deployments should skip it -- no deduplication means it balloons on large or churny datasets.

    Pick Kopia if you want a GUI, policy-per-directory configuration, and are comfortable with a slightly newer project. It is the most feature-rich of the four in pure capability terms.

    For a typical Ubuntu VPS shop, Restic is the path of least regret.

    Troubleshooting

    ProblemCauseSolution
    Fatal: unable to open config file: ... Is there a repository at the following location?Repository not initialised at that URL, or credentials wrongRun restic init. If already initialised elsewhere, double-check RESTIC_REPOSITORY and bucket name.
    Fatal: wrong password or no key foundWrong password, or wrong repo pointed atVerify RESTIC_PASSWORD_FILE path. If the password is truly lost, the data is unrecoverable -- there is no backdoor.
    unable to create lock in backend: repository is already lockedPrevious run crashed, or a concurrent operation is runningCheck for running restic processes: pgrep -a restic. If none, clear stale lock: restic unlock.
    prune runs for hoursLarge repo, many small snapshots, many deleted blobsExpected on first-ever prune after a long retention buildup. Subsequent prunes are fast. Use --max-repack-size 10G to chunk the work.
    Fatal: StorageError: ... 403 Forbidden on S3IAM / bucket policy does not grant required actionsEnsure the key has s3:ListBucket, s3:GetObject, s3:PutObject, s3:DeleteObject on the bucket and its objects.
    Slow first backup over the internetNormal -- first run uploads everythingConsider seeding: run initial backup to a local repo, then rclone sync the repo to S3. Subsequent runs are incremental and fast.
    backup skips changed filesFilesystem modification times are not updating (some network filesystems)Pass --ignore-ctime --ignore-inode cautiously, or --force to re-scan all files.
    Memory usage ballooning on large reposIndex loaded into RAMNormal. Expect ~1 GB RAM per ~5 TB logical data. If constrained, add swap or run backups from a larger box.
    Backup succeeded but restore produces empty filesSource files were being written during backup (e.g., live DB)Always dump databases to files first, then back up the dumps. Never back up running DB data directories raw.

    Viewing Logs

    bash
    sudo journalctl -u restic-backup.service -n 100 --no-pager
    sudo journalctl -u restic-backup.service --since "1 week ago"

    For interactive debugging, crank verbosity:

    bash
    restic -v backup /var/www
    restic --verbose=3 check   # Very chatty

    FAQ

    What happens if I forget the repository password?

    Your data is gone. Restic's encryption has no master key, no recovery phrase, no support hotline. This is a feature -- it is what makes the backup genuinely useless to whoever steals the storage -- but it means you must treat the password as irreplaceable. Store it in at least two independent locations: a team password manager (1Password, Bitwarden, Vaultwarden) and a printed copy in a sealed envelope in a physical safe. Test recovery from each location once a year.

    Can multiple servers back up to the same repository?

    Yes. Restic is designed for concurrent writers to a single repository. Each server identifies itself via hostname, and snapshots are tagged accordingly. Deduplication works across servers -- if ten VPSes all have the same Ubuntu base files, those chunks are stored once. You can target the same bucket from your fleet and restic snapshots --host web-03 to filter. The only constraint is that prune takes an exclusive lock, so schedule it when no backups are running.

    How much will Backblaze B2 actually cost me for VPS backups?

    For a single Ubuntu VPS with 50 GB of protected data backed up nightly and the 7/4/12/3 retention policy above, real-world storage after dedup + zstd compression typically lands at 20-30 GB. At Backblaze's $0.006/GB/month, that is 12-18 cents per month in storage. Egress (what you pay when restoring) is $0.01/GB but the first 3x of stored data each month is free. For 99% of VPS users, the monthly bill stays under $1.

    Is it safe to back up a running database with Restic?

    Not if you point Restic at the live data directory. MySQL's /var/lib/mysql and Postgres's /var/lib/postgresql contain files that are being written mid-transaction; a file-level snapshot captures an inconsistent state that will fail to replay on restore. The correct pattern is to dump first: pg_dumpall or mysqldump --single-transaction, write the dump to /var/backups, then let Restic back up the dump files. For high-volume databases where downtime from dumping is unacceptable, consider filesystem-level snapshots (LVM, ZFS) as an intermediate step, or use the database's native streaming backup tool (WAL archiving for Postgres, xtrabackup for MySQL).

    Can I use Restic with Windows or macOS?

    Yes. Restic is cross-platform and works on Windows, macOS, Linux, and the BSDs. This guide focuses on Ubuntu 24.04 because that is the dominant VPS Linux, but the same repository can be read from any OS with the password and credentials. A common setup: Linux servers back up nightly via systemd timers, developers on macOS run ad-hoc backups of their home directories to the same B2 bucket, and a Windows workstation in the office backs up via Task Scheduler. All three see each other's snapshots and dedupe against each other.

    Next Steps

    With Restic running, some natural follow-ups:

    • Deploy MinIO as your own backup target -- Turn a second VPS into a fully-controlled S3-compatible store. See our guide on installing MinIO on Ubuntu 24.04. No egress fees, no third-party credentials.
    • Harden SSH before trusting SFTP backends -- If you are using sftp: as your backend, the SSH configuration on the receiving server is the security boundary. Work through hardening SSH on Ubuntu -- key-only auth, Fail2ban, restricted chroot for the backup user.
    • Document the restore runbook -- Write down, in one page, the exact steps to restore this server onto a fresh VPS. Keep it outside the server (a Git repo, Notion, a printout). Future-you at 3 a.m. will not remember today's environment variables.
    • Scale to fleet-wide management with resticprofile -- resticprofile wraps Restic with YAML-based profiles, making it easy to manage dozens of servers with a shared config pattern.
    • Read the community -- forum.restic.net is active, well-moderated, and the Restic maintainers participate directly. Most operational questions already have high-quality answers there.

    Pair Restic with a Reliable VPS
    >
    Restic is only as good as the box it runs on. Our CloudCore Starter plan gives you NVMe-backed Ubuntu 24.04 with unmetered bandwidth -- enough for nightly offsite backups without worrying about transfer caps. Deploy two and you have a production server plus a private MinIO target, encrypted end-to-end with a key only you hold.
    >
    Launch Your VPS Now

    Was this article helpful?

    ← Back to Install GuidesBrowse all categories →

    Still have questions?

    Contact Support →Submit a Ticket