GOING FURTHER
Tested for real: I ran every command in this guide top-to-bottom on a fresh Ubuntu 24.04 virtual machine (4 CPUs, 8 GB RAM) on 13 August 2026. The run continued directly from the end state of the restic guide, and carried straight on into the off-site companion guide. Versions at test time: Ubuntu 24.04.4 LTS, restic 0.16.4, systemd 255.
Found a problem? Tell me via the contact page.
Placeholders: anything written in CAPS-WITH-DASHES, like YOUR-SERVER-IP, is a value you replace with your own. $USER is different — leave it exactly as written; the shell fills in your username for you, as explained below.
What you'll end up with
A backup that runs itself every night: back up, then apply a keep-this-many rule. No cron syntax, no forgetting.
The finished state from my test run:
$ systemctl list-timers restic-backup.timer
NEXT LEFT LAST PASSED UNIT ACTIVATES
Fri 2026-08-14 02:30:00 UTC 9h - - restic-backup.timer restic-backup.service
This guide has a companion: The off-site copy, and proving your backups still restore. It adds the copy on a second machine and the restore drill. Do this one first.
Who this is for
GOING FURTHER. You have done Backups that actually restore: restic from zero and kept its end state: a repository at /mnt/backup-drive/restic-repo, a password file at ~/.config/restic/password, and the ~/my-files folder. This guide starts exactly there.
Time and cost
The commands for this guide and its off-site companion took me about 5 minutes in total on the test machine, measured as one run. Budget 35 minutes for this half — there are two config files to understand, not just paste. Cost: nothing.
Words you'll meet
- Unit — one systemd config file describing one job or service. Lives in
/etc/systemd/system/. (basics) - Service unit — a unit that does something — here, running our backup commands. (basics)
- Timer unit — a unit whose only job is firing a service on a schedule. Systemd's replacement for cron. (basics)
- Journal — systemd's central log.
journalctlreads it; everything our service prints lands there. (basics) - Retention policy — the rule for which old snapshots to keep and which to drop. (basics)
Before you start
- The end state of the restic guide — repository, password file,
~/my-files. - Everywhere below,
$USERfills in your username automatically as files are written — nothing to edit mid-line. Verify with thecatchecks.
The steps
Step 1 — write the backup service
First the what: a service unit that runs two restic commands in order — back up, then apply retention. Type=oneshot means "run to completion and stop"; that is the right shape for a scheduled job. User= makes the backup run as you, so the timer and your terminal commands never fight over file ownership.
The block below writes the whole file in one go. The shell replaces every $USER with your username as it writes:
sudo tee /etc/systemd/system/restic-backup.service > /dev/null <<EOF
[Unit]
Description=restic backup of my-files (with retention and off-site copy)
Wants=network-online.target
After=network-online.target
[Service]
Type=oneshot
User=$USER
ExecStart=/usr/bin/restic -r /mnt/backup-drive/restic-repo --password-file /home/$USER/.config/restic/password backup /home/$USER/my-files
ExecStart=/usr/bin/restic -r /mnt/backup-drive/restic-repo --password-file /home/$USER/.config/restic/password forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
EOF
(The description mentions an off-site copy because the companion guide adds one as a third command in this same file. Nothing off-site happens yet.)
About that second line — the retention policy. --keep-daily 7 --keep-weekly 4 --keep-monthly 6 keeps one snapshot per day for a week. It also keeps one per week for a month, and one per month for half a year. Everything older gets dropped, and --prune reclaims the space. Backups stay useful without eating the disk.
Check it worked. Print the file back:
cat /etc/systemd/system/restic-backup.service
You should see the file above with your actual username everywhere $USER was — for example User=tester. If you can still see a literal $USER, delete the file and repeat this step.
Step 2 — write the timer
Now the when. Two lines matter:
OnCalendar=*-*-* 02:30:00means every day, any year-month-day, at 02:30. Night time, because backups deserve an idle machine.Persistent=trueis the line most guides forget. If the machine is off at 02:30, the job runs at next boot instead of silently skipping. Without it, a laptop that sleeps every night backs up never.
sudo tee /etc/systemd/system/restic-backup.timer > /dev/null <<EOF
[Unit]
Description=Nightly restic backup
[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
[Install]
WantedBy=timers.target
EOF
Check it worked. Print it back:
cat /etc/systemd/system/restic-backup.timer
You should see exactly the block above — no placeholders in this one.
Step 3 — switch the timer on
Tell systemd to re-read its files:
sudo systemctl daemon-reload
Enable the timer now and on every boot:
sudo systemctl enable --now restic-backup.timer
The important line is:
Created symlink /etc/systemd/system/timers.target.wants/restic-backup.timer → /etc/systemd/system/restic-backup.timer.
Check it worked. Ask systemd when it will fire:
systemctl list-timers restic-backup.timer
You should see something like:
NEXT LEFT LAST PASSED UNIT ACTIVATES
Fri 2026-08-14 02:30:00 UTC 9h - - restic-backup.timer restic-backup.service
1 timers listed.
The NEXT column shows a real date — tomorrow, 02:30. LAST and PASSED are - because it has never fired yet. That changes tonight.
Step 4 — fire it once by hand
Never let a scheduled job's first run happen unattended. Start the service directly — this is exactly what the timer will do at 02:30:
sudo systemctl start restic-backup.service
It returns silently when finished. Now read the service's status:
systemctl status restic-backup.service
Your output will vary, but look for:
○ restic-backup.service - restic backup of my-files (with retention and off-site copy)
Loaded: loaded (/etc/systemd/system/restic-backup.service; static)
Active: inactive (dead) since Thu 2026-08-13 16:36:00 UTC; 30ms ago
TriggeredBy: ● restic-backup.timer
Process: 2725 ExecStart=/usr/bin/restic [...snipped...] (code=exited, status=0/SUCCESS)
Process: 2735 ExecStart=/usr/bin/restic [...snipped...] (code=exited, status=0/SUCCESS)
This confused me the first time, so let me save you the moment: inactive (dead) is the success state for a oneshot service. It ran, it finished, it stopped. The lines that matter are the two status=0/SUCCESS — both restic commands exited cleanly.
The full output lives in the journal:
sudo journalctl -u restic-backup.service
A passing run includes:
Aug 13 16:35:59 ubuntu-testbed restic[2725]: using parent snapshot 95cb8fa0
Aug 13 16:35:59 ubuntu-testbed restic[2725]: snapshot ec6479d9 saved
Aug 13 16:36:00 ubuntu-testbed restic[2735]: Applying Policy: keep 7 daily, 4 weekly, 6 monthly snapshots
[...snipped...]
Aug 13 16:36:00 ubuntu-testbed systemd[1]: Finished restic-backup.service - restic backup of my-files (with retention and off-site copy).
Check it worked. You can find snapshot ... saved, Applying Policy, and the final Finished line.
That is the whole automation: back up, apply retention, every night at 02:30. Next, give the backup somewhere else to live — the off-site copy, and proving your backups still restore.
Something went wrong?
- You see
Active: inactive (dead)insystemctl statusand assume failure → it means a oneshot service finished — this is success → look forstatus=0/SUCCESSon eachProcess:line instead. - You see a literal
$USERinside a unit file when youcatit → it means the heredoc was quoted or copied oddly, so the shell never expanded it → delete the file and re-paste the whole block from the first line toEOF.
Undo all of this
Tested for real, in this order. It removes everything this guide added. (If you also did the off-site companion guide, run its undo first; deleting the service file below also removes the off-site line that guide appends.) The restic guide's undo then clears the rest.
Stop the timer and remove it from boot:
sudo systemctl disable --now restic-backup.timer
The important line is:
Removed "/etc/systemd/system/timers.target.wants/restic-backup.timer".
Delete both unit files:
sudo rm /etc/systemd/system/restic-backup.service /etc/systemd/system/restic-backup.timer
Tell systemd to forget them:
sudo systemctl daemon-reload
Check they are really gone. Ask for the timer:
systemctl list-timers restic-backup.timer
You should see something like:
0 timers listed.
And the service:
systemctl status restic-backup.service
The important line is:
Unit restic-backup.service could not be found.
0 timers listed and could not be found are the pass marks. To remove restic and the local repository as well, follow the Undo in the restic guide. I ran the undos back-to-back in that order and ended with a completely clean machine.
Where to go next
- The off-site copy, and proving your backups still restore — the second half of this pair: a copy on another machine, a one-word restore drill, and the read-every-byte check.
- Know when things break: a tiny monitoring setup — so a failed nightly backup pings you instead of rotting silently.
- Official docs: restic — scripting and automation and
man systemd.timer.
Last tested: 13 August 2026 on Ubuntu 24.04.4 LTS. Versions: restic 0.16.4 (Ubuntu archive), systemd 255. Tested as one continuous run with the off-site companion guide.
Tried it? Improved it?
Tell the forum what worked and what didn’t: real experience beats recommendations, and the best answers get folded back into this guide with credit.
Related guides
SSH keys, properly: never type a server password again
Your laptop will hold a small pair of files called an SSH key. Your server will trust it, so logging in never asks for a password — then we turn password logins off completely.
12 min read
First hour with a new Ubuntu server: locking the doors
A fully updated server, a personal account with admin rights, a firewall that blocks everything except SSH, and security updates that install themselves.
10 min read