Docker & DevOps

Restore a single file or folder from a restic snapshot

Find the right restic snapshot, restore just one file or directory to a temporary path, and put it back in place without running a full restore.

BeginnerLinux server5 min read

You deleted a config file, overwrote a template, or need one database dump from last week. You do not need to restore the whole snapshot — restic can pull a single file or folder out of any snapshot in seconds. This guide walks through finding the right snapshot, checking what is inside it, and restoring only the path you need.

Before you start

You need:

  • SSH access to the Linux VPS that holds the restic repository. If you are connecting for the first time, see Connect to your Linux VPS with SSH.
  • The restic binary installed (restic version should print a version).
  • The repository location and the password. If you have not set up a repository yet, start with Encrypted off-site backups with restic.
  • Enough free space in /tmp or wherever you restore to. A single file needs almost nothing; a full directory needs roughly its uncompressed size.

Export the connection details once so every command below works without repeating flags:

Bash
export RESTIC_REPOSITORY="sftp:backup@203.0.113.10:/srv/restic-repo"
export RESTIC_PASSWORD_FILE="/root/.restic-pass"
restic snapshots --latest 3

If that prints snapshots, you are ready. If it fails, fix the repository path or password before continuing.

Tip: Run restic snapshots with no arguments first to see hosts, tags and paths. The ID column is the short snapshot ID you will pass to later commands.

Find the snapshot that contains the file

Start by narrowing the list. Filter by host, path or tag instead of scrolling through hundreds of entries:

Bash
restic snapshots --host web01 --path /var/www/html
restic snapshots --tag daily --latest 5

If you do not know which snapshot holds the file, let restic search the index for you:

Bash
restic find "wp-config.php"
restic find --snapshot latest "*.conf"

restic find prints every snapshot that contains a matching path, plus the full path inside the snapshot. That output is usually all you need to pick an ID.

Inspect the snapshot before restoring

List the contents of a snapshot without touching the live filesystem:

Bash
restic ls latest
restic ls latest /var/www/html
restic ls -l latest /etc/nginx

The first command dumps the whole tree, which is noisy on a busy server. Pass a directory to limit it. -l adds size and mode, which is handy when you are looking for the most recent version of a file.

Compare two snapshots when you are unsure which one is good:

Bash
restic ls latest /var/www/html/index.php
restic ls 3f9c1a2b /var/www/html/index.php

Paths inside a snapshot are absolute and match what was backed up. If your backup used --path /var/www, then the file appears as /var/www/html/index.php, not html/index.php.

Restore one file or folder

Restore to a scratch directory first. Never write straight over a live file until you have looked at the restored copy.

Bash
mkdir -p /tmp/restic-restore
restic restore latest \
  --target /tmp/restic-restore \
  --include /var/www/html/wp-config.php

The result lands at /tmp/restic-restore/var/www/html/wp-config.php — restic recreates the full path under the target. Add --verify to re-read the restored data and confirm it matches the repository.

For a whole directory, repeat --include for each path or pass the parent:

Bash
restic restore latest \
  --target /tmp/restic-restore \
  --include /etc/nginx \
  --exclude /etc/nginx/cache

To restore from a specific snapshot instead of latest, replace latest with the short ID from restic snapshots:

Bash
restic restore 3f9c1a2b --target /tmp/restic-restore --include /etc/nginx/nginx.conf

Warning: Do not add --delete to a restore aimed at a live directory. It removes files in the target that are not in the snapshot, which can wipe data you still need.

Once the file looks right, copy it into place and fix ownership:

Bash
sudo cp /tmp/restic-restore/var/www/html/wp-config.php /var/www/html/wp-config.php
sudo chown www-data:www-data /var/www/html/wp-config.php
sudo chmod 640 /var/www/html/wp-config.php

Restoring as root preserves the ownership and permissions recorded at backup time. Restoring as a normal user skips ownership, so check with ls -l afterwards.

Pull one file to stdout with restic dump

When you only need to read a file, or pipe it somewhere, skip the restore step entirely:

Bash
restic dump latest /var/www/html/wp-config.php
restic dump latest /etc/nginx/nginx.conf > /tmp/nginx.conf

restic dump writes the file contents to standard output. Point it at a directory and it streams a tar archive:

Bash
restic dump latest /var/www/html | tar -x -C /tmp/restic-restore

This is the fastest option for a single small file, and it never writes to the live path.

Check it works

Confirm the restored copy is the version you expected:

Bash
diff -u /var/www/html/wp-config.php /tmp/restic-restore/var/www/html/wp-config.php

Then reload whatever reads the file and check the service:

Bash
sudo nginx -t
sudo systemctl reload nginx
sudo systemctl status nginx --no-pager

For an application file, open the site or run the app's own health check. If the service starts and the diff shows only the change you wanted, the restore is done. Clean up the scratch directory when you are finished:

Bash
rm -rf /tmp/restic-restore

Troubleshooting

  • Fatal: unable to open repository or wrong password — the repository URL or password file is wrong. Re-check RESTIC_REPOSITORY and RESTIC_PASSWORD_FILE, and confirm the remote host is reachable with ssh backup@203.0.113.10.
  • path not found in snapshot — the --include path does not match the snapshot exactly. Run restic ls <snapshot> / and copy the path character for character; a trailing slash or a relative path will fail.
  • Restored file has the wrong owner — you ran the restore as a non-root user. Re-run with sudo, or set ownership manually with chown as shown above.
  • target directory is not empty — restic refuses to overwrite a populated target in some versions. Use a fresh directory such as /tmp/restic-restore-$(date +%s).
  • Restore is very slow — a large --include still has to read many pack files. Restore only the exact subdirectory you need, or use restic dump for a single file.

Next steps

Was this guide helpful?

Still stuck?

Ask MdmHost AI for a quick answer, or open a ticket and our team will take a look. We are here 24/7.