Qvantor logo QvantorInfrastructure, explained plainly
Guides

Restic Backups for a Self Hosted Server Step by Step

Your self hosted server has been running for months, and the only copy of its mail, configs and databases sits on the same disk that will one day fail.

Small home server with blinking drive lights on a shelf beside a laptop showing a terminal with backup snapshot logs

Your self hosted server has been running for months, and the only copy of its mail, configs and databases sits on the same disk that will one day fail. Restic backups fix that in about an hour of setup, with encrypted, deduplicated snapshots you can restore from any machine.

This guide walks through a setup I run on a small Debian box: restic installed from the distro package, a repository on an off-site storage bucket, a nightly systemd timer, a retention policy and, most importantly, a restore test. Every command below works on Debian 12 and Ubuntu 24.04 without changes.

Why restic backups suit a small server

Restic is a single binary with no daemon and no server component. It splits files into chunks, stores each unique chunk once, and encrypts everything with a key derived from your repository password. That means three things matter in practice:

  • Deduplication is real. A server with 40 GB of data and 30 daily snapshots typically uses 45 to 55 GB of repository space, not 1.2 TB.
  • The storage provider sees nothing useful. File names, contents and directory structure are all encrypted before upload.
  • Restores do not need the original machine. Any computer with restic, the repository location and the password can pull files back.

The tradeoff is that the password is the whole game. Lose it and the data is gone. Write it into your password manager and on paper before you run a single backup.

Step 1: Install restic and create the repository

Install from the package manager, then let restic update itself to the current release, since distro versions often lag by a year or more:

  • Install: sudo apt install restic
  • Update the binary: sudo restic self-update
  • Check: restic version should report 0.17 or newer

Pick a repository backend. For off-site storage, any S3 compatible bucket works, and a second server you control over SFTP works too. Costs for 50 GB on budget object storage usually land between 0.30 and 1.20 dollars a month, which is cheaper than the coffee you will drink while setting this up.

Create a file at /etc/restic/env with mode 600, owned by root, holding the environment variables restic reads:

  • RESTIC_REPOSITORY set to your bucket path, for example s3:your-provider-endpoint/bucket-name/server1
  • RESTIC_PASSWORD_FILE pointing to /etc/restic/password
  • AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY for the bucket credentials

Generate the password with openssl rand -base64 32, save it into /etc/restic/password with mode 600, then load the environment and run restic init. You should see a line confirming the repository was created. If you keep project secrets in shell files elsewhere, the same discipline from setting up direnv for per project environment variables applies here: one file, tight permissions, never committed to git.

Step 2: Decide what to back up and what to skip

Backing up the whole root filesystem is tempting and mostly wasteful. A fresh OS install takes ten minutes. What takes days to rebuild is your data and configuration. On a typical mail and web box, the list looks like this:

PathWhy it mattersTypical size
/etcEvery service config, certificates, cron jobs5 to 20 MB
/var/vmail or /var/mailMailboxes2 to 30 GB
/srv or /var/wwwSite files and uploads1 to 10 GB
/homeUser data and dotfilesVaries
Database dump folderConsistent copies of live databases100 MB to 5 GB

Put exclusions into /etc/restic/excludes: cache folders, node_modules.cache, temporary upload directories and container image layers. Pass that file to restic with the exclude-file option.

Never back up a running database by copying its data directory. Dump it first. For PostgreSQL, pg_dumpall into a dated file in /var/backups/db. For MariaDB, mariadb-dump with the all-databases and single-transaction options. Run the dump in the same script, just before restic, so the snapshot always holds a fresh, consistent copy.

Step 3: Schedule nightly snapshots with systemd

Create a small script at /usr/local/sbin/restic-backup.sh that does four things in order: dump databases, run restic backup on your path list, run restic forget with a retention policy, and run restic check with a small read sample. Mark it executable.

A retention policy that works for most small servers, passed as options to restic forget:

  1. keep-daily 7 keeps one snapshot for each of the last 7 days.
  2. keep-weekly 5 keeps one per week for about a month.
  3. keep-monthly 12 keeps one per month for a year.
  4. prune removes chunks no snapshot references anymore.

Then create a service unit that runs the script with EnvironmentFile=/etc/restic/env, and a timer unit with OnCalendar=*-*-* 03:15:00 and RandomizedDelaySec=900 so the job does not collide with other 3 a.m. jobs. Enable and start the timer with systemctl enable, then start restic-backup.timer, and confirm it with systemctl list-timers.

The first run uploads everything and may take an hour or more on a home connection. After that, nightly runs on a server with modest churn finish in two to five minutes.

The advice I disagree with: prune every night

Many guides tell you to run forget with prune after every backup. On a small repository it works, but on object storage it is often the wrong call. Pruning rewrites pack files, which means downloads, uploads and API calls, and some providers charge for early deletion or egress. On a 50 GB repository, a nightly prune can generate more billable traffic than the backup itself.

A better pattern: run forget without the prune option every night, which only removes snapshot references and costs almost nothing, then prune once a week on Sunday. You lose nothing in safety, because the data from forgotten snapshots is simply not reclaimed for a few days. Restic 0.17 also supports a max-unused setting of 10% so prune only repacks when enough dead space has built up.

Step 4: Test a restore before you trust anything

A backup you have never restored is a hope, not a backup. Once a month, put 20 minutes on the calendar and do this:

  1. Run restic snapshots and confirm last night's snapshot exists with the expected paths.
  2. Restore a single known file: restic restore latest with /tmp/restore-test as the target and /etc/postfix/main.cf as the only included path, then diff it against the live file.
  3. Restore last night's database dump into a scratch database and run a quick count on one table.
  4. Once a quarter, do the full test from a different machine, using only the password from your password manager.

Add failure alerts too. A timer that silently fails for three weeks is common. The simplest fix is a push monitor: the script pings a URL only when it finishes successfully, and you get an alert when the ping stops. If you already followed the guide on uptime monitoring with Uptime Kuma, its push monitor type does exactly this.

For more step by step setups like this one, browse the guides collection.

Frequently asked questions

How much storage do restic backups need?

Plan for roughly 1.2 to 1.4 times your source data size with a daily, weekly and monthly retention policy. Deduplication keeps unchanged files from being stored twice, so growth comes mostly from files that change often, such as mailboxes and database dumps. Compressed repositories, the default since restic 0.14, shrink text heavy data further.

Can I back up to two locations with restic?

Yes. The simplest approach is a second repository and a second environment file, with the script running backup against each one. Restic also has a copy command that duplicates snapshots between repositories, which saves reading the source disk twice.

What happens if I lose the restic password?

The repository becomes unreadable, permanently. There is no recovery service and no back door, because the encryption key is derived from that password. Store it in your password manager and keep a printed copy somewhere physically separate from the server.

IV
Ilkka Varis

Ilkka has run mail servers for small companies since the days of hand edited DNS zones.

More posts by Ilkka

More in Guides

01doorganico 084goad 3hot8 4465456 after5internprogram ahandfulofblessings ahmadpc ahomcybersecurity allodialresources annodex antiquesandperiodcollectibles aotc asianworldkashmir beedlectrics bloggertemplatefree bluefeatheragency bodyweightsolution campaign08blog carfixadvisor catstreetcollective cbstvsports cnfanspurchasing committeeof500yearsofdignityandresistance covertopsdjs cs-kaiyuangame cuestacomunicaciontotal cxoutlet dancebetgame deskgearhub destinyvillastay detectmagazine di33 diamondsteelbuildings donmo dyanadropship emarsysfinance emimattl escapechan eskitarih evautoplay everythingweddings-orlando farmzone feedviewerapp foxstudiosscratch gamevui123 gleasongrade greetingsday hacklabasu haskell iw-kaiyun jagoanproperti jilidskripsi joltbusinessfinance juegodepokergratis juegospucca kaeru-festival latestmehndidesigns lestanzediottaviano litemagazines localcommunityhero lustrsazan mariashebets menswheels newwebstechs1 nikkit ootheday oxigenvpn plurfitness prefetial probudgetcarpetcleaning psychicmrsmartin pyaten rejoignezlogis rexzbot riselayouts ruchin rwxqsgd5 sakaltime shibiaowang shop-bot skrtips strcoding tetapatrium topselller uneplanteartificielle vipertechcr webtech1223411 wo-kygaming yamaha-mekar yeknava yoybuysheets zenunwa yamaha-mekar jilidskripsi ankertoto ankertoto ankertoto ankertoto