---
title: "resticprofile examples: a production config, explained"
description: "A complete resticprofile setup for a Linux server: S3 repository, database dump hooks, systemd schedules, with retention and check on a separate admin host."
source: "https://wardio.net/guides/resticprofile-production/"
---

**Backups**

# resticprofile examples: a production configuration, explained

The official documentation describes every key resticprofile accepts, one reference page at a time. It does not show how they fit together on a server you depend on, or where retention belongs when that server is not allowed to delete its own backups.

By David Kabel · Updated 2026-09-26 · 19 min read

**The short answer**

A production resticprofile setup needs two configuration files. The server's profile holds the repository, an env-file with a storage key that cannot delete data, a password-file, the sources and excludes, a database dump in `run-before` and a systemd schedule. Because that key cannot delete backup data, `forget`, `prune` and `check` run from a second profile on an admin host, using `keep-within` rules and `read-data-subset`. Both samples below are YAML, checked against resticprofile 0.33.1.

## Versions and file format

We checked everything here against resticprofile 0.33.1, the latest release, published on 15 April 2026, and restic 0.19.1, published on 5 July 2026. resticprofile reads TOML, YAML, JSON and HCL, and its documentation recommends TOML or YAML. The samples are YAML, and both produce the expected restic command lines under that version's `show` and `--dry-run`.

Both files declare `version: "1"`. Configuration format 2 exists, but the current documentation still calls it a preview that is "for testing and feedback only", so a production file should not depend on it. In version 1 a retention section does nothing until you switch it on, and some inherited lists merge into the parent's list by position instead of replacing it. Both behaviours come up below.

## Two hosts, two profiles

The server backs up with a storage key that cannot delete data, so whoever compromises the server cannot destroy its history. restic's documentation spells out the consequence: `forget` and `prune` "require full read, write and delete access to the repository", and the recommended setup for append-only repositories is a separate, well-secured client for that maintenance. So the server profile has no retention at all. A second profile, on an admin host the server cannot reach, removes old snapshots, prunes and checks the data. The [Backblaze B2 version cleanup](/guides/restic-backblaze-storage-growth/) belongs there too.

The admin host also holds a copy of the repository password. restic warns that losing the password means the data is irrecoverably lost, and a password that only exists on the server disappears with the server.

## The server profile

```
# /etc/resticprofile/profiles.yaml on the server (web1)
version: "1"

web1:
  repository: "s3:https://objects.example.net/acme-web1-restic"
  password-file: "/etc/resticprofile/web1.key"
  env-file:
    - "/etc/resticprofile/web1.env"
  lock: "/run/resticprofile-web1.lock"
  status-file: "/var/lib/resticprofile/status.json"
  prometheus-save-to-file: "/var/lib/node_exporter/textfile/resticprofile.prom"

  backup:
    source:
      - "/etc"
      - "/home"
      - "/srv"
      - "/var/www"
      - "/var/backups/db"
    exclude:
      - "node_modules"
      - "/home/*/.cache"
    exclude-file: "excludes.txt"
    exclude-caches: true
    tag:
      - "web1"
    extended-status: true

    run-before: "runuser -u postgres -- pg_dump --format=custom shop > /var/backups/db/shop.dump"
    run-after-fail: 'logger -t resticprofile "web1 backup failed: $ERROR_MESSAGE"'
    run-finally: "rm -f /var/backups/db/shop.dump"

    schedule: "*-*-* 01:30"
    schedule-permission: system
    schedule-lock-wait: 2h
    schedule-log: "/var/log/resticprofile-web1.log"
    schedule-after-network-online: true
```

```
# /etc/resticprofile/web1.env   (owner root, mode 600)
# Storage key that can delete only restic's lock files. The key that can delete data stays on the admin host.
AWS_ACCESS_KEY_ID=server-key-id
AWS_SECRET_ACCESS_KEY=server-key-secret
# AWS_DEFAULT_REGION=eu-central-1   only if your provider needs a region
```

```
# on web1, as root, once
install -d -m 700 /etc/resticprofile /var/backups/db
install -d -m 755 /var/lib/resticprofile
install -d -m 755 /var/lib/node_exporter/textfile   # or your textfile collector's directory
resticprofile generate --random-key > /etc/resticprofile/web1.key
# write web1.env as shown above, then
chmod 600 /etc/resticprofile/web1.key /etc/resticprofile/web1.env
# copy web1.key to the admin host before anything else
```

### Repository and secrets

`repository` uses restic's form for S3-compatible storage, `s3:https://host/bucket`. restic reads the storage credentials from `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`, which live in the dotenv file named by `env-file`. The repository password lives in `password-file`. Both files are root-only, so the YAML holds no secret and can go into version control.

The server key needs one narrow delete right. restic removes its lock file at the end of every command, and with a key that cannot delete anything each run leaves its lock behind. The backup still exits 0, but the admin host's `check` and `forget` then fail with "repository is already locked". Allow deletes under `locks/` only, which is also what restic's rest-server permits in append-only mode. On MinIO, this policy left no locks behind and still refused to delete snapshots:

```
{
  "Version": "2012-10-17",
  "Statement": [
    {"Effect": "Allow", "Action": ["s3:GetBucketLocation", "s3:ListBucket"], "Resource": ["arn:aws:s3:::acme-web1-restic"]},
    {"Effect": "Allow", "Action": ["s3:GetObject", "s3:PutObject"], "Resource": ["arn:aws:s3:::acme-web1-restic/*"]},
    {"Effect": "Allow", "Action": ["s3:DeleteObject"], "Resource": ["arn:aws:s3:::acme-web1-restic/locks/*"]}
  ]
}
```

One default works against the secrets split. `schedule-capture-environment` defaults to `RESTIC_*`, so every RESTIC\_ variable present when you run `resticprofile schedule` is copied into the generated systemd unit as an `Environment=` line, and resticprofile 0.33.1 writes unit files with mode 0644. An exported `RESTIC_PASSWORD` in that shell ends up readable by every local account, and `systemctl show` prints it to them even if you tighten the file mode. Run `schedule` from a clean shell, or set `schedule-capture-environment: []` in the section that holds the schedule.

### Source, excludes and tags

An `exclude` pattern without a leading slash matches a complete path component anywhere, so `node_modules` drops every directory of that name. A leading slash anchors the pattern at the root. `exclude-file` takes one pattern per line with `#` comments, and a relative path resolves against the directory holding the configuration file. A path listed directly in `source` is always saved, but excludes still filter what is inside it: list `/srv/app/node_modules` as a source while `node_modules` is excluded and the snapshot holds only the empty directory. `exclude-caches` skips the contents of any directory marked with a CACHEDIR.TAG file and keeps the tag file itself.

`tag` labels every snapshot, and the admin side makes use of it. Running `resticprofile web1.backup --tag keep` before a risky upgrade adds a `keep` tag, and the maintenance policy's `keep-tag` never removes that snapshot.

### The database dump

The dump sits in the `backup` section's `run-before`. At the profile root it would run before every restic command the profile runs, `snapshots` included. pg\_dump makes a consistent export even while the database is in use.

A hook that exits non-zero aborts the run and triggers `run-after-fail`, which receives `ERROR_MESSAGE`, `ERROR_EXIT_CODE` and `ERROR_STDERR`. In my view that is the right default, because a snapshot without its database is a failure you only discover during a restore. Cleanup belongs in `run-finally` rather than `run-after`, because `run-after` only runs when everything succeeded, and a failed night would otherwise leave an unencrypted dump on disk until the next good run.

### Scheduling with systemd

`schedule` takes systemd calendar syntax, so `systemd-analyze calendar "*-*-* 01:30"` shows the next run. With `schedule-permission: system`, resticprofile writes `resticprofile-backup@profile-web1.service` and a matching timer into /etc/systemd/system, and the job runs as root. The default timer sets `Persistent=true`, so a run missed while the machine was off starts once the timer is active again after boot. To change the permission later, unschedule first, edit, then schedule again.

`lock` is resticprofile's own lock file, which stops two runs of the profile overlapping. `schedule-lock-wait` is how long a scheduled run waits for that lock and for restic's repository lock. It matters here because in restic 0.19.1 `check`, `forget` and `prune` all take an exclusive lock, and the admin host runs them against the same repository. `schedule-log` sends output to a file that resticprofile appends to but never rotates, so give it a logrotate rule, or leave the key out and systemd puts the output in the journal instead. `schedule-after-network-online` adds `After=network-online.target`. That only sets the order. The unit gets no `Wants=` line, so it waits for the network only if something else on the host pulls that target in.

The unit calls `resticprofile run-schedule`, which reads the configuration afresh every time. Changes to sources, excludes or hooks apply on the next run. Changing when a job runs, or as whom, needs `resticprofile schedule` again.

### Status and metrics

`status-file` keeps a JSON summary of the last backup, forget and check: success, time, error and duration. resticprofile stores the forget result under the key `retention`, so look for that name in your monitoring. `prometheus-save-to-file` writes metrics in Prometheus text format, for the backup command only; point it at your textfile collector's directory, and keep the .prom ending node\_exporter expects. `extended-status: true` adds file and byte counts at the cost of restic's normal progress output. resticprofile creates neither file's directory, which is why the setup above creates both.

## Retention versus forget

Both end in `restic forget`. The difference is when it runs and what it selects.

| Aspect | `retention` section | `forget` section |
| --- | --- | --- |
| When it runs | Inside `resticprofile backup`, before or after the backup | When you run `resticprofile forget`, or on its own schedule |
| Switched on by | `after-backup: true` or `before-backup: true`. In version 1 neither is the default, so keep rules alone do nothing | Always active when called |
| After a failed backup | Skipped, because `after-backup` only follows a successful backup | Independent of backups |
| Which snapshots | Adds the backup's `source` list as `--path` unless you set `path` | Exactly the flags you write |
| Scheduling | Deprecated. Schedule `forget` instead | Supported |
| Delete rights needed on | The server that runs the backup | Whichever host runs it |

The `path` default is the subtle one. restic only considers snapshots that include every listed path, so after you add a directory to `source`, retention stops matching the snapshots taken before the change and never removes them. The last row is why retention cannot live on an append-only server.

## The admin maintenance profile

```
# /etc/resticprofile/profiles.yaml on the admin host
version: "1"

# Shared rules only: no repository, no schedule, never run directly.
policy:
  forget:
    keep-within: "14d"
    keep-within-weekly: "3m"
    keep-within-monthly: "1y"
    keep-tag:
      - "keep"
    prune: true
  check:
    read-data-subset: "{{ .Now.Day }}/31"

web1:
  inherit: policy
  repository: "s3:https://objects.example.net/acme-web1-restic"
  password-file: "/etc/resticprofile/keys/web1.key"
  env-file:
    - "/etc/resticprofile/web1-admin.env"   # the key that CAN delete
  status-file: "/var/lib/resticprofile/web1.json"
  forget:
    schedule: "Sun 03:00"
    schedule-permission: system
    schedule-lock-wait: 2h
    schedule-log: "/var/log/resticprofile-web1-forget.log"
  check:
    schedule: "*-*-* 05:30"
    schedule-permission: system
    schedule-lock-wait: 2h
    schedule-log: "/var/log/resticprofile-web1-check.log"
```

The policy keeps every snapshot from the last 14 days, the newest of each week for three months and the newest of each month for a year. In restic durations, `m` means months. The plain `keep-within` is deliberate. restic's documentation warns that an attacker with append-only access can add garbage snapshots so that a count-based rule, such as keeping three weekly snapshots, keeps the fakes and forgets the real ones. It recommends `keep-within` for this setup, because that rule keeps every snapshot in the window, real ones included. The bucketed `keep-within-daily`, `-weekly` and `-monthly` forms keep only the newest snapshot in each day, week or month, so a planted snapshot a few minutes newer than each real one displaces it just as with a count. Beyond 14 days the weekly and monthly rules carry that risk, which is why the admin host should look at unexpected snapshots before the window runs out. restic measures the windows from the newest snapshot and ignores snapshots dated in the future. `prune: true` adds `--prune`, so restic prunes only when forget removed something.

`read-data-subset` uses the `.Now.Day` template, so the check on the 23rd downloads and verifies group 23 of 31, about a thirty-first of the pack files. A 31-day month reads every group once; shorter months skip the highest groups until the next long one. A percentage such as `5%` is simpler, but restic notes that random subsets do not guarantee full coverage. Either way, reading data costs download traffic from the storage provider.

The `policy` profile holds only the rules and each server's profile inherits it. Keep list values in one place and check the result with `show`. In version 1 under 0.33.1, `source` and `exclude` merge into the parent's list by index, while `tag` and `keep-tag` replace the parent's list outright. A one-item child `source` therefore replaces only the parent's first entry.

## Commands to run before trusting it

```
# on the admin host, once, before the first backup
resticprofile web1.init

# on the server
resticprofile web1.show               # the profile as resticprofile resolved it
resticprofile --dry-run web1.backup   # print hooks and restic command, run nothing
resticprofile web1.backup             # one real run, end to end
resticprofile schedule --all          # install every schedule in the file
resticprofile status --all            # the installed systemd timers
systemctl list-timers 'resticprofile-*'

# on the admin host
resticprofile web1.forget --dry-run   # restic lists what the policy would remove
resticprofile web1.check              # today's slice of the data, by hand
resticprofile schedule --all
```

1.  **Compare show with the dry-run**: `show` prints the resolved profile with inheritance applied. `--dry-run` before `web1.backup` prints every hook and the restic command line and runs nothing. Compare the two. `restic-arguments-filter` is on by default and drops flags restic does not recognise, so a mistyped `keep-within-daly` appears in one and vanishes from the other.
2.  **Let restic judge the policy**: Flags after the command go to restic, so `web1.forget --dry-run` on the admin host makes restic list what it would keep and remove, and remove nothing.
3.  **Schedule everything as the same user**: Run `schedule --all` as root. The documentation warns against mixing user and system schedules in one run.
4.  **Know which status you are reading**: `resticprofile status` reports the installed timers and journal lines at warning level or above from the last month. With `schedule-log` set, a failed night shows there only as systemd's "Failed with result 'exit-code'" line, without the reason. The status file and the log hold the result.
5.  **Restore something**: A clean check proves the repository is intact. It does not prove that the repository holds what you need. [Restore to a scratch machine and time it](/guides/backups-that-restore/).

## On Windows

The same keys work. resticprofile schedules through Task Scheduler on Windows 10 or later. A `system` schedule needs elevation to install, which resticprofile requests itself, and `user` asks for the account password. `schedule-start-when-available`, added in 0.33.0, runs a backup that was missed while the machine was off, and `use-fs-snapshot: true` in the backup section lets restic read locked files through VSS. If restic.exe is not detected, set its full path as `restic-binary` under `global`. The two-profile split carries over unchanged. If you are still choosing a tool, read [restic versus Borg](/guides/restic-vs-borg/) first.

## Downsides of the append-only split, and how Veeam compares

The split protects history by withholding one permission from the server. That is access control. It does not make the backups immutable, and its costs are worth weighing against a product built around immutability, such as Veeam Backup & Replication 13.

-   **The admin key can still destroy everything.** The risk moves to the admin host and the storage account login. Whoever compromises either can delete the whole repository, and nothing in this design stops them.
-   **A second machine to run and watch.** Retention, prune and check only happen on the admin host. If it stops, nothing expires, the bucket keeps growing, and nobody notices unless that host's runs are monitored as closely as the backups.
-   **Deletion is not the only attack.** Object storage has no separate overwrite permission, so the server's key can write over an existing object, and on Backblaze B2 it can hide files. Versioning keeps the originals, but getting them back is manual, version by version, and only possible until the cleanup job removes non-current versions. That cleanup cutoff is your detection window.
-   **Retention can be gamed.** The server can add snapshots, and planted ones defeat count-based rules, as the gotcha below shows. restic's documentation recommends `keep-within` for append-only repositories for this reason.
-   **The server can still read every backup.** It holds the repository password, so an intruder can decrypt all past and future snapshots. The split protects availability and does nothing for confidentiality.
-   **No console.** Scheduling, alerting, reporting and restore tests are yours to build and keep working.

Veeam answers the first and third points differently. Its hardened repository is a Linux server on which backup files "cannot be moved, modified or deleted, but can be copied" for an immutability period of 7 to 9,999 days. Veeam uses the credentials that deploy it once and does not store them, so a compromised backup server cannot reach it. On object storage, Veeam sets S3 Object Lock in compliance mode on every object it uploads and manages the lock per backup chain. restic cannot do that. It runs on a locked bucket but never sets or extends a lock itself, as the [Object Lock guide](/guides/restic-b2-object-lock/) shows.

Veeam's version has its own costs:

-   **More infrastructure.** A backup server, plus a dedicated Linux machine with local or block storage for the hardened repository. NFS and SMB are not allowed, one repository cannot be shared between backup servers, and Veeam Agent for Linux must not be installed on it.
-   **Root on the repository host is the weak point.** The immutability is the file system's immutable attribute. On our ext4 test system, `chattr -i` as root cleared it and the file could then be deleted. Veeam's own appliance image does not allow SSH on a hardened repository and, unless Security Officer accounts are enabled, does not let you turn multi-factor authentication off. A hand-built one needs the same discipline.
-   **More storage.** A hardened repository accepts only forward incremental backups with periodic full backups, and an immutable file is merged or deleted only after its period ends. On object storage, Veeam adds a 10-day block generation period to the lock expiry, and its documentation warns that an immutability period longer than the job's retention "will result in extra charges".
-   **The bucket belongs to Veeam.** It needs Object Lock and versioning from creation, no default retention, and no lifecycle rules, which Veeam says are not supported and may break backup and restore.
-   **A licence past ten workloads.** Community Edition is free for up to 10 workloads; beyond that you need a paid licence, counted in instances per protected workload. Veeam's licensing page also notes that the Linux-based Veeam Software Appliance supports only data recovery in Community Edition.

In our view the restic split suits one to a handful of Linux servers on object storage. It is small, cheap and scriptable, and its weak points are known and testable. If you need backups that nobody, including you, can delete for a fixed period, or you already run VMware or Hyper-V, Veeam's hardened or object-lock repository gives you that and this design does not. Between the two sits restic on a bucket with Object Lock, with the limits described in that guide.

## Gotchas

-   **A key that cannot delete leaves locks behind.** With no delete right at all, every server command printed "Remove(<lock/...>) failed: Access Denied" and still exited 0. The admin host's `check` then failed with "repository is already locked" (exit 11). `schedule-lock-wait` only waits: once the lock was older than `restic-stale-lock-age` (1h by default), resticprofile gave up and suggested `force-inactive-lock`. Either allow deletes under `locks/` as shown above, or set `force-inactive-lock: true` on the admin profile, which ran `restic unlock` and let the check pass.
-   **A forget on the server blocks every later backup.** Running `web1.forget` with the server key was refused ("Access Denied", exit 3) but left an exclusive lock the server could not remove, and the next backup failed with exit 11 until the admin host ran `unlock`. Keep forget, prune and unlock on the admin host.
-   **Per-day keep-within rules can be gamed.** In a test repository with 84 nightly snapshots, one planted snapshot 30 minutes after each real one left a single real snapshot under `keep-within-daily: 14d` with the weekly and monthly rules above. With `keep-within: 14d` instead, all 14 real snapshots from the last two weeks survived next to the fakes.
-   **Changing the source list strands old snapshots.** restic forget groups snapshots by host and path list, and measures each window from that group's newest snapshot. In a repository whose source list changed in June 2025, this policy run on 23 September 2026 still kept 20 snapshots of the old list and would keep them indefinitely. For a repository that holds one server, add `group-by: "host"` to the `forget` section, which pooled both lists in the test.
-   **A missing directory only warns.** Before the textfile directory existed, each backup logged "saving prometheus file ... no such file or directory" and exited 0, so the metrics never appeared. A `status-file` in a missing directory behaves the same. Check that both files exist after the first run.
-   **Captured variables are visible to every user.** With `RESTIC_PASSWORD` exported, `schedule` wrote it into the unit (mode 0644), and `systemctl show -p Environment` printed it for the nobody account. Rerunning `schedule` from a clean shell rewrote the unit without it, and `schedule-capture-environment: []` stopped the capture altogether.

**How this was tested.** On 23 September 2026 we built resticprofile from the v0.33.1 tag with Go 1.26.8 and ran it with restic 0.19.1 against MinIO RELEASE.2025-09-07T16-13-09Z in Docker on an Ubuntu 24.04 host, as an S3-compatible stand-in, with one key lacking `s3:DeleteObject` and one with full rights. The server and admin host were two Debian 13 containers running systemd 257 as PID 1, with PostgreSQL 17.11 for the dump hook. We ran both samples as printed apart from endpoint and credentials, started the units by hand, and checked Persistent= by stopping and restarting a container rather than with a real reboot. Not tested: a commercial S3 provider, Windows and Task Scheduler, node\_exporter reading the .prom file, and the check rotation over a whole month. The Windows details come from the documentation, and we rendered the check template for day 23 only. The downsides section rests on these tests and the linked guides. The Veeam comparison comes from Veeam's version 13 documentation and was not tested, except that on 26 September 2026 we cleared the immutable attribute as root with `chattr -i`, using e2fsprogs 1.47.0 on ext4, and then deleted the file.

## Sources

1.  [resticprofile releases (v0.33.1, 15 April 2026)](https://github.com/creativeprojects/resticprofile/releases), creativeprojects on GitHub
2.  [Getting started: file formats](https://creativeprojects.github.io/resticprofile/configuration/getting_started/), resticprofile documentation
3.  [Configuration v2 proposal](https://creativeprojects.github.io/resticprofile/configuration/v2/), resticprofile documentation
4.  [Profile reference](https://creativeprojects.github.io/resticprofile/reference/profile/) and [retention section reference](https://creativeprojects.github.io/resticprofile/reference/profile/retention/), resticprofile documentation
5.  [Schedule configuration reference (capture-environment)](https://creativeprojects.github.io/resticprofile/reference/nested/scheduleconfig/) and [global section reference (restic-arguments-filter, restic-binary)](https://creativeprojects.github.io/resticprofile/reference/global/), resticprofile documentation
6.  [Schedules: retention scheduling deprecated](https://creativeprojects.github.io/resticprofile/schedules/), resticprofile documentation
7.  [Schedule configuration](https://creativeprojects.github.io/resticprofile/schedules/configuration/), [systemd](https://creativeprojects.github.io/resticprofile/schedules/systemd/) and [schedule commands](https://creativeprojects.github.io/resticprofile/schedules/commands/), resticprofile documentation
8.  [Command hooks](https://creativeprojects.github.io/resticprofile/configuration/run_hooks/), [variables](https://creativeprojects.github.io/resticprofile/configuration/variables/) and [inheritance](https://creativeprojects.github.io/resticprofile/configuration/inheritance/), resticprofile documentation
9.  [Status file](https://creativeprojects.github.io/resticprofile/monitoring/status/) and [Prometheus](https://creativeprojects.github.io/resticprofile/monitoring/prometheus/), resticprofile documentation
10.  [Windows Task Scheduler](https://creativeprojects.github.io/resticprofile/schedules/task_scheduler/), resticprofile documentation
11.  [systemd/generate.go at v0.33.1 (unit file mode)](https://github.com/creativeprojects/resticprofile/blob/v0.33.1/systemd/generate.go), resticprofile source
12.  [restic releases (0.19.1, 5 July 2026)](https://github.com/restic/restic/releases), restic on GitHub
13.  [Removing backup snapshots, including security considerations in append-only mode](https://restic.readthedocs.io/en/stable/060_forget.html), restic documentation
14.  [Working with repositories: checking integrity](https://restic.readthedocs.io/en/stable/045_working_with_repos.html), restic documentation
15.  [Backing up: excluding files and VSS](https://restic.readthedocs.io/en/stable/040_backup.html), restic documentation
16.  [Preparing a new repository: S3-compatible storage](https://restic.readthedocs.io/en/stable/030_preparing_a_new_repo.html), restic documentation
17.  [cmd\_check.go at v0.19.1 (exclusive lock)](https://github.com/restic/restic/blob/v0.19.1/cmd/restic/cmd_check.go), restic source
18.  [repo/repo.go at v0.14.0 (append-only mode still allows deleting locks)](https://github.com/restic/rest-server/blob/v0.14.0/repo/repo.go), rest-server source
19.  [pg\_dump](https://www.postgresql.org/docs/current/app-pgdump.html), PostgreSQL 18 documentation
20.  [systemd.timer(5): Persistent=](https://man7.org/linux/man-pages/man5/systemd.timer.5.html) and [systemd.exec(5): StandardOutput=](https://man7.org/linux/man-pages/man5/systemd.exec.5.html), man7.org
21.  [WriteToTextfile](https://pkg.go.dev/github.com/prometheus/client_golang/prometheus#WriteToTextfile), Prometheus Go client documentation
22.  [Hardened Repository](https://helpcenter.veeam.com/docs/vbr/userguide/hardened_repository.html), [Requirements and Limitations](https://helpcenter.veeam.com/docs/vbr/userguide/hardened_repository_limitations.html) and [How Immutability Works](https://helpcenter.veeam.com/docs/vbr/userguide/hardened_repository_immutability.html), Veeam Backup & Replication 13 User Guide
23.  [How Immutability Works (object storage, block generation)](https://helpcenter.veeam.com/docs/vbr/userguide/hiw_immutability_os.html) and [Considerations and Limitations](https://helpcenter.veeam.com/docs/vbr/userguide/os_immutability_limitations.html), Veeam Backup & Replication 13 User Guide
24.  [Licensing](https://helpcenter.veeam.com/docs/vbr/userguide/licensing.html), Veeam Backup & Replication 13 User Guide, and [Downloads (Community Edition, up to 10 workloads)](https://www.veeam.com/products/downloads.html), Veeam
25.  [chattr(1): the immutable attribute](https://man7.org/linux/man-pages/man1/chattr.1.html), man7.org

## Questions

### What is the difference between retention and forget in resticprofile?

Both run restic forget. The retention section runs it inside the backup command, before or after the backup, and only when before-backup or after-backup is set; in config version 1 neither is on by default. It also passes the backup source list as --path unless you override it. The forget section configures the standalone forget command and can carry its own schedule. Scheduling retention directly is deprecated in favour of forget.

### How do I schedule resticprofile check?

Add schedule, schedule-permission and schedule-lock-wait to the check section of the profile, then run resticprofile schedule. Put read-data-subset in the same section so each run downloads and verifies part of the pack files rather than only the repository structure. In restic 0.19.1 check takes an exclusive lock, so run it away from the backup window and give the backup a schedule-lock-wait long enough to outlast it.

### How does resticprofile schedule backups on Linux?

With systemd available, resticprofile schedule writes a service and a timer named resticprofile-backup@profile-NAME and enables them. The schedule key uses systemd calendar syntax, so systemd-analyze calendar can test it. With schedule-permission: system the units go into /etc/systemd/system and run as root. The service calls resticprofile run-schedule, which re-reads the configuration, so only a change to when or as whom a job runs needs resticprofile schedule again.

### Does resticprofile work on Windows?

Yes. It schedules through Windows Task Scheduler on Windows 10 or later and uses the same configuration keys. Installing a schedule with schedule-permission: system needs an elevated prompt, and user asks for the account password. Since version 0.33.0, schedule-start-when-available runs a backup that was missed while the machine was off. Add use-fs-snapshot: true to the backup section so restic reads locked files through VSS.

### How do exclude patterns work in resticprofile?

resticprofile hands exclude and exclude-file to restic, so restic pattern rules apply. A pattern without a leading slash matches a complete path component anywhere, so node\_modules drops every directory of that name, while a leading slash anchors the pattern at the root. A relative exclude-file path resolves against the directory holding the configuration file. A path listed directly in source is always saved, but excludes still filter what is inside it, so a source directory whose own name matches an exclude is saved empty.

### Is an append-only restic key as safe as Veeam immutable backups?

No. An append-only key is access control. The backed-up server cannot delete its history, but whoever holds the admin key or the storage account can, and the server key can still overwrite objects, so recovery depends on bucket versioning. Veeam hardened repositories and Veeam object-lock repositories make backup files undeletable for a set period, even to a compromised backup server. The restic split is cheaper and simpler, but it does not make backups immutable.

**Want resticprofile run for you?**

Every Wardio-managed server backs up with resticprofile to storage in a different failure domain, with scheduled integrity checks. [See pricing](/pricing/).

[Free server review](/contact/)
