{"id":13875972,"url":"https://github.com/Patryk27/lxd-snapper","last_synced_at":"2025-07-16T10:32:14.157Z","repository":{"id":46081714,"uuid":"198270953","full_name":"Patryk27/lxd-snapper","owner":"Patryk27","description":"LXD snapshots, automated","archived":false,"fork":false,"pushed_at":"2024-08-06T08:30:57.000Z","size":2809,"stargazers_count":49,"open_issues_count":1,"forks_count":6,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-11-18T14:20:45.285Z","etag":null,"topics":["backup","lxc","lxd","nix-flake","rust","snapshot","zfs"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Patryk27.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2019-07-22T17:23:31.000Z","updated_at":"2024-08-30T10:25:55.000Z","dependencies_parsed_at":"2024-01-02T10:24:50.628Z","dependency_job_id":"a1e52f7d-8c02-4bf6-be91-d9be3ed3a112","html_url":"https://github.com/Patryk27/lxd-snapper","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Patryk27%2Flxd-snapper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Patryk27%2Flxd-snapper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Patryk27%2Flxd-snapper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Patryk27%2Flxd-snapper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Patryk27","download_url":"https://codeload.github.com/Patryk27/lxd-snapper/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":226122303,"owners_count":17576920,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["backup","lxc","lxd","nix-flake","rust","snapshot","zfs"],"created_at":"2024-08-06T06:00:53.093Z","updated_at":"2024-11-24T03:31:35.803Z","avatar_url":"https://github.com/Patryk27.png","language":"Rust","funding_links":[],"categories":["Rust","rust"],"sub_categories":[],"readme":"# lxd-snapper\n\n**LXD snapshots, automated.**\n\nlxd-snapper automates creating \u0026 removing LXD snapshots - just prepare a\nsnapshotting policy, setup a cronjob, and enjoy your containers.\n\ntl;dr it's a fancy wrapper for `lxc snapshot` \u0026 `lxc delete`; like LXD's\nbuilt-in `snapshots.schedule`, but more powerful.\n\n# Requirements\n\n- LXD 4 / 5 / 6\n- Linux (x86_64)\n\nPlus, if you plan on building lxd-snapper locally:\n\n- Cargo \u0026 Rust 1.78.0\n- Nix (for running integration tests)\n\n# Getting started\n\n## Downloading\n\nYou can either download pre-built binaries:\n\n``` console\n# x86_64\n$ wget https://github.com/Patryk27/lxd-snapper/releases/download/v1.4.0/lxd-snapper-linux64 -O lxd-snapper\n$ chmod u+x lxd-snapper\n```\n\n... or build lxd-snapper on your own:\n\n``` console\n$ git clone https://github.com/Patryk27/lxd-snapper\n$ cd lxd-snapper\n\n# Using Cargo\n$ cargo build --release\n$ ./target/release/lxd-snapper\n\n# (or) Using Nix\n$ nix build\n$ ./result/bin/lxd-snapper\n```\n\n## Configuring\n\nSetting-up lxd-snapper is easy: you just need to prepare a configuration file\nthat will describe which LXD instances (so containers and/or virtual machines)\nyou want to get snapshotted and for how long those snapshots should be kept\naround.\n\nWe can start with the most basic configuration:\n\n``` yaml\npolicies:\n  my-first-policy:\n    keep-last: 2\n```\n\n... which defines a single policy called `my-first-policy` that will snapshot\nall of your instances, keeping around the latest two snapshots per each\ninstance.\n\nTo check how it works, let's go ahead and create some containers:\n\n``` console\n$ lxc launch ubuntu: hello\n$ lxc launch ubuntu: world\n# (the container's OS doesn't matter - Ubuntu is just an example)\n\n$ lxc ls\n+-------+---------+------+------+-----------+-----------+\n| NAME  |  STATE  | IPV4 | IPV6 |   TYPE    | SNAPSHOTS |\n+-------+---------+------+------+-----------+-----------+\n| hello | RUNNING | ...  | ...  | CONTAINER | 0         |\n+-------+---------+------+------+-----------+-----------+\n| world | RUNNING | ...  | ...  | CONTAINER | 0         |\n+-------+---------+------+------+-----------+-----------+\n```\n\nNow, to snapshot those containers, first we have to store that configuration\nfrom before into a file - say, `config.yaml` - and then run `lxd-snapper\nbackup`:\n\n``` console\n$ lxd-snapper --dry-run -c config.yaml backup\n(--dry-run is active, no changes will be applied)\n\nhello\n  - creating snapshot: auto-20221105-130019 [ OK ]\n\nworld\n  - creating snapshot: auto-20221105-130019 [ OK ]\n\nSummary\n-------\n  processed instances: 2\n  created snapshots: 2\n```\n\nAs you can see, there's a detailed output of everything that's happened - or\nrather of everything that _would_ happen: we used a switch called `--dry-run`\nwhich tells lxd-snapper that you only want to **preview** the changes without\nactually creating or removing any snapshots.\n\nWe can confirm that nothing's changed by re-running `lxc ls` and seeing that\nwe've still got zero snapshots:\n\n``` console\n$ lxc ls\n+-------+---------+------+------+-----------+-----------+\n| NAME  |  STATE  | IPV4 | IPV6 |   TYPE    | SNAPSHOTS |\n+-------+---------+------+------+-----------+-----------+\n| hello | RUNNING | ...  | ...  | CONTAINER | 0         |\n+-------+---------+------+------+-----------+-----------+\n| world | RUNNING | ...  | ...  | CONTAINER | 0         |\n+-------+---------+------+------+-----------+-----------+\n```\n\n`--dry-run` is useful after you've made some changes to the configuration and\nwant to confirm that everything is working as intended - since that's the case\nwith us, we can now re-run `lxc-snapper backup` without `--dry-run`:\n\n``` console\n$ lxd-snapper -c config.yaml backup\n\n/* ... */\n\nSummary\n-------\n  processed instances: 2\n  created snapshots: 2\n```\n\n... and voilà:\n\n``` console\n$ lxc ls\n+-------+---------+------+------+-----------+-----------+\n| NAME  |  STATE  | IPV4 | IPV6 |   TYPE    | SNAPSHOTS |\n+-------+---------+------+------+-----------+-----------+\n| hello | RUNNING | ...  | ...  | CONTAINER | 1         |\n+-------+---------+------+------+-----------+-----------+\n| world | RUNNING | ...  | ...  | CONTAINER | 1         |\n+-------+---------+------+------+-----------+-----------+\n```\n\nOur policy says `keep-last: 2`, so let's go ahead and run `lxd-snapper backup`\ntwice more, to trigger this limit:\n\n``` console\n$ lxd-snapper -c config.yaml backup\n$ lxd-snapper -c config.yaml backup\n\n$ lxc ls\n+-------+---------+------+------+-----------+-----------+\n| NAME  |  STATE  | IPV4 | IPV6 |   TYPE    | SNAPSHOTS |\n+-------+---------+------+------+-----------+-----------+\n| hello | RUNNING | ...  | ...  | CONTAINER | 3         |\n+-------+---------+------+------+-----------+-----------+\n| world | RUNNING | ...  | ...  | CONTAINER | 3         |\n+-------+---------+------+------+-----------+-----------+\n```\n\nNow we've got three snapshots per each container - why not two? Because as a\nsafety measure, the `backup` command always only _creates_ snapshots - never\ndeletes them.\n\nTo remove stale snapshots, we have to run `prune`:\n\n``` console\n$ lxd-snapper --dry-run -c config.yaml prune\n(--dry-run is active, no changes will be applied)\n\nhello\n  - keeping snapshot: auto-20221105-130214\n  - keeping snapshot: auto-20221105-130213\n  - deleting snapshot: auto-20221105-130157 [ OK ]\n\nworld\n  - keeping snapshot: auto-20221105-130214\n  - keeping snapshot: auto-20221105-130213\n  - deleting snapshot: auto-20221105-130157 [ OK ]\n\nSummary\n-------\n  processed instances: 2\n  deleted snapshots: 2\n  kept snapshots: 4\n```\n\nAs before, we've started with `--dry-run` as to see if everything looks\nalright - and since it seems so, it's time to kick those stale snapshots out of\nour filesystem for good:\n\n``` console\n$ lxd-snapper -c config.yaml prune\n\n/* ... */\n\nSummary\n-------\n  processed instances: 2\n  deleted snapshots: 2\n  kept snapshots: 4\n\n$ lxc ls\n+-------+---------+------+------+-----------+-----------+\n| NAME  |  STATE  | IPV4 | IPV6 |   TYPE    | SNAPSHOTS |\n+-------+---------+------+------+-----------+-----------+\n| hello | RUNNING | ...  | ...  | CONTAINER | 2         |\n+-------+---------+------+------+-----------+-----------+\n| world | RUNNING | ...  | ...  | CONTAINER | 2         |\n+-------+---------+------+------+-----------+-----------+\n```\n\nRe-running `prune` will now do nothing, since all of the containers have\ncorrect number of snapshots:\n\n``` console\n$ lxd-snapper -c config.yaml prune\nhello\n  - keeping snapshot: auto-20221105-130214\n  - keeping snapshot: auto-20221105-130213\n\nworld\n  - keeping snapshot: auto-20221105-130214\n  - keeping snapshot: auto-20221105-130213\n\nSummary\n-------\n  processed instances: 2\n  deleted snapshots: 0\n  kept snapshots: 4\n```\n\n_(there's also a command called `backup-and-prune` that runs backup and prune\none after another, which is what you'll usually want to do.)_\n\nAnd that's basically it - that's how lxd-snapper works; now let's see what makes\nit unique!\n\n## Filtering instances\n\nBy default, lxd-snapper snapshots all of the instances it can find on the local\nmachine - you can affect that with various `included-` and `excluded-` options:\n\n``` yaml\npolicies:\n  # Matches all instances inside the `important-client` project and keeps the\n  # last 20 snapshots for each of them:\n  a:\n    included-projects: ['important-client']\n    keep-last: 20\n    \n  # Matches all instances _outside_ the `important-client` project and keeps the\n  # last 5 snapshots for each of them:\n  b:\n    excluded-projects: ['important-client']\n    keep-last: 5\n    \n  # Matches all instances named `important-container` (across all projects) and\n  # keeps the last 20 snapshots for each of them:\n  c:\n    included-instances: ['important-container']\n    keep-last: 20\n    \n  # Matches all instances _not_ named `important-container` (across all\n  # projects) and keeps the last 5 snapshots for each of them:\n  d:\n    excluded-instances: ['important-container']\n    keep-last: 5\n    \n  # Matches all instances that are running at the time of performing `backup` /\n  # `prune`.\n  #\n  # Possible values: Aborting, Running, Ready, Starting, Stopped, and Stopping.\n  e:\n    included-statuses: ['Running']\n    \n  # Matches all instances that are _not_ running at the time of performing\n  # `backup` / `prune`.\n  f:\n    excluded-statuses: ['Running']\n    \n  # Matches all instances named `php` or `nginx` that belong to project\n  # `client-a` or `client-b`.\n  #\n  # For an instance to match this policy, it has to match all `included-*`\n  # rules, so e.g.:\n  #\n  # - an instance named `php` for `client-c` will be skipped, since `client-c`\n  #   doesn't match `included-projects`,\n  #\n  # - an instance named `nextcloud` for `client-a` will be skipped, since\n  #   `nextcloud` doesn't match `included-instances`.\n  #\n  # In SQL, this would be:\n  #\n  # SELECT *\n  #   FROM instances\n  #  WHERE (project = \"client-a\" OR project = \"client-b\")\n  #    AND (name = \"php\" OR name = \"nginx\")\n  #    AND (status = \"Running\")\n  g:\n    included-projects: ['client-a', 'client-b']\n    included-instances: ['php', 'nginx']\n    included-statuses: ['Running']\n \n  # Similarly as above (notice the reversed operator for `excluded-*`):\n  #\n  # SELECT *\n  #   FROM instances\n  #  WHERE (project = \"client-a\" OR project = \"client-b\")\n  #    AND (name != \"php\" AND name != \"nginx\")\n  h:\n    included-projects: ['client-a', 'client-b']\n    excluded-instances: ['php', 'nginx']\n```\n\n## Retention strategies\n\nlxd-snapper supports [Borg-style](https://borgbackup.readthedocs.io/en/stable/usage/prune.html)\nretention strategies; each policy must specify at least one `keep-` option that\nsays for how long its snapshots should be kept around.\n\nThe most straightforward setting is `keep-last` - e.g.:\n\n``` yaml\npolicies:\n  my-policy:\n    keep-last: 5\n```\n\n... would keep the five _newest_ snapshots for each container.\n\n(i.e. if you ran `backup-and-prune` once a day, that would effectively keep the\nfive days worth of snapshots around)\n\nBeing versatile, lxd-snapper also supports `keep-hourly`, `keep-daily` etc.,\nallowing you to create more fancy policies such as:\n\n``` yaml\npolicies:\n  my-policy:\n    keep-hourly: 6\n    keep-daily: 5\n    keep-weekly: 4\n    keep-monthly: 3\n    keep-yearly: 2\n```\n\nThis would keep snapshots from 6 latest hours + 5 latest days + 4 latest weeks +\n3 latest months + 2 latest years = 20 snapshots per instance.\n\nOr, rephrasing:\n\n- we'd have a snapshot per each past hour, up to 6 of them (e.g. 15:00, 14:00,\n  13:00, 12:00, 11:00 \u0026 10:00),\n- we'd have a snapshot per each past day, up to 5 of them (e.g. today,\n  yesterday, the day before yesterday, 3 days ago \u0026 4 days ago),\n- we'd have a snapshot per each past week, up to 4 of them (e.g. this week, the\n  past week, two weeks ago \u0026 three weeks ago),\n- et cetera, et cetera.\n\nThis system takes a while to get used to, but it's also extremely versatile;\nyou can find more examples inside the `docs/example-configs` directory and\ninside [Borg's documentation](https://borgbackup.readthedocs.io/en/stable/usage/prune.html#examples).\n\nOf course, you don't have to get fancy -- `keep-last` should get the job done\nmost of the time.\n\n## Cascading\n\nSay, you're using [LXD projects](https://ubuntu.com/tutorials/introduction-to-lxd-projects#1-overview)\nand you've got a few containers:\n\n``` console\n$ lxc ls --project client-a\n+-------+---------+------+------+-----------+-----------+\n| NAME  |  STATE  | IPV4 | IPV6 |   TYPE    | SNAPSHOTS |\n+-------+---------+------+------+-----------+-----------+\n| mysql | RUNNING | ...  | ...  | CONTAINER | 0         |\n+-------+---------+------+------+-----------+-----------+\n| php   | RUNNING | ...  | ...  | CONTAINER | 0         |\n+-------+---------+------+------+-----------+-----------+\n\n$ lxc ls --project client-b\n+-------+---------+------+------+-----------+-----------+\n| NAME  |  STATE  | IPV4 | IPV6 |   TYPE    | SNAPSHOTS |\n+-------+---------+------+------+-----------+-----------+\n| mysql | RUNNING | ...  | ...  | CONTAINER | 0         |\n+-------+---------+------+------+-----------+-----------+\n| php   | RUNNING | ...  | ...  | CONTAINER | 0         |\n+-------+---------+------+------+-----------+-----------+\n\n$ lxc ls --project client-c\n+-------+---------+------+------+-----------+-----------+\n| NAME  |  STATE  | IPV4 | IPV6 |   TYPE    | SNAPSHOTS |\n+-------+---------+------+------+-----------+-----------+\n| mysql | RUNNING | ...  | ...  | CONTAINER | 0         |\n+-------+---------+------+------+-----------+-----------+\n| php   | RUNNING | ...  | ...  | CONTAINER | 0         |\n+-------+---------+------+------+-----------+-----------+\n```\n\nAnd, for the sake of argument, let's say that you want to create the following\nconfiguration:\n\n- all `mysql`-s should have 5 latest snapshots,\n- all `php`-s should have 2 latest snapshots,\n- except for `client-c`, which is important and should get 10 snapshots.\n\nThat's what cascading is for - when multiple policies match a single container:\n\n``` yaml\npolicies:\n  # Matches: client-a/mysql, client-b/mysql, client-c/mysql\n  all-mysqls:\n    included-instances: ['mysql']\n    keep-last: 5\n    \n  # Matches: client-a/php, client-b/php, client-c/php\n  all-phps:\n    included-instances: ['php']\n    keep-last: 2\n    \n  # Matches: client-c/mysql, client-c/php\n  important-clients:\n    included-projects: ['client-c']\n    keep-last: 10\n```\n\n... lxd-snapper will combine them top-bottom into a single policy, separately\nfor each container.\n\nWhat this means practically is that when a few policies match a single\ninstance, policies that are below will have _higher priority_ than the ones\nabove them: `important-clients` is below `all-mysqls` and `all-phps`, so its\n`keep-last` is more important for `client-c/mysql` and `client-c/php`.\n\nThis merging happens on a per-retention-strategy basis, so if we had:\n\n``` yaml\npolicies:\n  # Matches: client-a/mysql, client-b/mysql, client-c/mysql\n  all-mysqls:\n    included-instances: ['mysql']\n    keep-daily: 2\n    \n  # Matches: client-a/php, client-b/php, client-c/php\n  all-phps:\n    included-instances: ['php']\n    keep-hourly: 8\n    \n  # Matches: client-c/mysql, client-c/php\n  important-clients:\n    included-projects: ['client-c']\n    keep-last: 20\n```\n\n... then our effective configuration would be:\n\n``` \nclient-a/mysql + client-b/mysql\n  keep-daily = 2\n  \nclient-a/php + client-b/php\n  keep-hourly = 8\n\nclient-c/mysql\n  keep-daily = 2\n  keep-last = 20\n  (= 22 snapshots)\n\nclient-c/php\n  keep-hourly = 8\n  keep-last = 20\n  (= 28 snapshots)\n```\n\nOther possible use cases for this feature include creating a global \"catch all\"\npolicy, and then creating exceptions of it:\n\n``` yaml\npolicies:\n  all:\n    keep-last: 10\n    \n  storages:\n    include-containers: ['nextcloud', 'minio']\n    keep-last: 20\n```\n\nThis would keep 10 snapshots for all of the containers, with the exception of\n`nextcloud` and `minio` that would have 20 snapshots.\n\n## Hooks\n\nHooks are small shell commands executed when lxd-snapper performs a certain\naction; you can configure them by creating a `hooks:` section inside the\nconfiguration:\n\n``` yaml\nhooks:\n  on-backup-started: 'echo \"on-backup-started\" \u003e\u003e /tmp/log.txt'\n  on-snapshot-created: 'echo \"on-snapshot-created: {{ remoteName }}, {{ projectName }}, {{ instanceName }}, {{snapshotName}}\" \u003e\u003e /tmp/log.txt'\n  on-instance-backed-up: 'echo \"on-instance-backed-up: {{ remoteName }}, {{ projectName }}, {{ instanceName }}\" \u003e\u003e /tmp/log.txt'\n  on-backup-completed: 'echo \"on-backup-completed\" \u003e\u003e /tmp/log.txt'\n\n  on-prune-started: 'echo \"on-prune-started\" \u003e\u003e /tmp/log.txt'\n  on-snapshot-deleted: 'echo \"on-snapshot-deleted: {{ remoteName }}, {{ projectName }}, {{ instanceName }}, {{ snapshotName }}\" \u003e\u003e /tmp/log.txt'\n  on-instance-pruned: 'echo \"on-instance-pruned: {{ remoteName }}, {{ projectName }}, {{ instanceName }}\" \u003e\u003e /tmp/log.txt'\n  on-prune-completed: 'echo \"on-prune-completed\" \u003e\u003e /tmp/log.txt'\n\npolicies:\n  # ...\n```\n\nThey come handy e.g. for synchronizing snapshots to external storage:\n\n``` yaml\nhooks:\n  on-snapshot-created: 'zfs send ... | ssh zfs recv ...'\n  on-snapshot-deleted: 'zfs send ... | ssh zfs recv ...'\n\npolicies:\n  # ...\n```\n\nMost of the hooks support _variable interpolation_ - they are strings that are\nreplaced by lxd-snapper with some concrete value before the hook is run:\n\n- `on-snapshot-created` has `{{ remoteName }}`, `{{ projectName }}`, `{{ instanceName }}` and `{{ snapshotName }}`,\n- `on-instance-backed-up` has `{{ remoteName }}`, `{{ projectName }}` and `{{ instanceName }}`,\n- `on-snapshot-deleted` has `{{ remoteName }}`, `{{ projectName }}`, `{{ instanceName }}` and `{{ snapshotName }}`,\n- `on-instance-pruned` has `{{ remoteName }}`, `{{ projectName }}` and `{{ instanceName }}`.\n\n\\... where:\n\n- `{{ remoteName }}` corresponds to `NAME` as visible in `lxc remote ls`\n  (`local` by default),\n- `{{ projectName }}` corresponds to `NAME` as visible in `lxc project ls`\n  (`default` by default),\n- `{{ instanceName }}` corresponds to `NAME` as visible in `lxc ls`,\n- `{{ snapshotName }}` corresponds to `NAME` as visible in `lxc info instance-name`.\n\nCaveats \u0026 Tips:\n\n- hooks are skipped during `--dry-run`,\n\n- you can provide at most one script per hook (e.g. you can't have\n  `on-backup-started` defined twice),\n  \n- you don't have to provide scripts for hooks you're not interested in (e.g.\n  specifying just `on-backup-started` is alright),\n\n- hooks are run only from inside lxd-snapper (e.g. `on-snapshot-created` will\n  not be run for a manual `lxc snapshot` performed from the command line), \n\n- hooks are launched as soon as the event happens and block lxd-snapper until\n  the hook completes - e.g.\n\n  ``` yaml\n  hooks:\n    on-snapshot-created: 'delay 10'\n  ```\n\n  ... will delay creating _each_ snapshot by 10 seconds; if that's problematic\n  for your use case, you might want to buffer the changes like so:\n\n  ``` yaml\n  hooks:\n    on-backup-started: 'rm /tmp/created-snapshots.txt'\n    on-snapshot-created: 'echo \"{{ instanceName }},{{ snapshotName }}\" \u003e\u003e /tmp/created-snapshots.txt'\n    on-backup-completed: './sync-snapshots.sh /tmp/created-snapshots.txt'\n  ```\n\n- when a hook returns a non-zero exit code, it will be treated as an error,\n\n- hook's stdout and stderr are not displayed, unless the hook returns a non-zero\n  exit code (stdout \u0026 stderr will be then visible in the error message),\n  \n- variables can be written `{{likeThat}}` or `{{ likeThat }}`, whichever way you\n  prefer.\n\n## Remotes\n\nBy default, lxd-snapper sees containers \u0026 virtual machines only from the local\nLXD instance (i.e. as if you run `lxc ls`).\n\nIf you're using LXD remotes, and you'd like for lxd-snapper to snapshot them\ntoo, you have to provide their names in the configuration file:\n\n``` yaml\nremotes:\n  - server-a\n  - server-b\n  - server-c\n```\n\nIf you'd like to snapshot both the local LXD _and_ the remote ones, use a remote\ncalled `local`:\n\n``` yaml\nremotes:\n  - local\n  - server-a\n  - server-b\n  - server-c\n```\n\n(those labels correspond to `NAME` as visible in `lxc remote ls`)\n\nBy default, each policy will match all of the specified remotes - if you want to\nnarrow that down, you can use `included-remotes` and `excluded-remotes`:\n\n``` yaml\nremotes:\n  - unimportant-server-A\n  - unimportant-server-B\n  - important-server-A\n\npolicies:\n  all-servers:\n    keep-last: 10\n  \n  important-servers:\n    included-remotes: ['important-server-A']\n    keep-last: 25 \n```\n\nIf you're going for a centralized backup solution, you can pair this feature \nwith _hooks_ to pull the newly-created snapshots into your coordinator-machine:\n\n``` yaml\nhooks:\n  on-instance-backed-up: 'lxc copy --refresh {{ remoteName }}:{{ instanceName }} {{ instanceName }}'\n  on-instance-pruned: 'lxc copy --refresh {{ remoteName }}:{{ instanceName }} {{ instanceName }}'\n\nremotes:\n  - server-A\n  - server-B\n  - server-C\n\npolicies:\n  all-servers:\n    keep-last: 10\n```\n\n## Scheduling\n\nFinally, lxd-snapper is a fire-and-forget application - it doesn't daemonize\nitself; to keep instances backed-up \u0026 pruned on time, you will want to create a\nsystemctl timer or a cronjob for it:\n\n```\n5 * * * * /usr/bin/lxd-snapper -c /etc/lxd-snapper.yaml backup-and-prune\n```\n\n# Configuration syntax reference\n\n```yaml\n# (optional, defaults to 'auto-')\n#\n# Prefix used to distinguish between snapshots created by lxd-snapper and \n# everything else (e.g. a manual `lxc snapshot`).\n#\n# `lxd-snapper backup` will create snapshots with this prefix and\n# `lxd-snapper prune` will only ever remove snapshots that match this prefix.\nsnapshot-name-prefix: '...'\n\n# (optional, defaults to '%Y%m%d-%H%M%S')\n#\n# Formatting string used to build the rest of the snapshot name.\n# \n# Format:\n# https://docs.rs/chrono/0.4.22/chrono/format/strftime/index.html\nsnapshot-name-format: '...'\n\n# (optional, defaults to '10m')\n#\n# Timeout for each call to lxc; prevents lxd-snapper from running forever if lxc\n# happens to hang.\n#\n# If you've got a (very) slow storage, you might want to increase this limit, \n# but the default should be enough for a typical setup.\n#\n# Format:\n# https://docs.rs/humantime/latest/humantime/\n# (e.g. '30s', '5m', '1h' etc.)\nlxc-timeout: '...'\n\n# (optional)\nhooks:\n  on-backup-started: '...'\n  on-instance-backed-up: '...'\n  on-snapshot-created: '...'\n  on-backup-completed: '...'\n  \n  on-prune-started: '...'\n  on-snapshot-deleted: '...'\n  on-instance-pruned: '...'\n  on-prune-completed: '...'\n\n# (optional, defaults to `local`)\nremotes:\n  - local\n  - server-A\n  - server-B\n\n# (at least one required)\npolicies:\n  policy-name:\n    included-remotes: ['...', '...']\n    excluded-remotes: ['...', '...']\n    included-projects: ['...', '...']\n    excluded-projects: ['...', '...']\n    included-instances: ['...', '...']\n    excluded-instances: ['...', '...']\n    included-statuses: ['...', '...']\n    excluded-statuses: ['...', '...']\n\n    keep-hourly: 1\n    keep-daily: 1\n    keep-weekly: 1\n    keep-monthly: 1\n    keep-yearly: 1\n    keep-last: 1\n    keep-limit: 1\n```\n\n# Contributing\n\nMerge requests are very much welcome! :-)\n\nlxd-snapper is a pretty standard Rust project, so cargo \u0026 rustc should be enough\nto get you going.\n\nThere are also end-to-end tests written using [NixOS Testing Framework](https://nix.dev/tutorials/integration-testing-using-virtual-machines)\nthat you can run with `nix flake check -j4`.\n\n# Disclaimer\n\nSnapshots are _not_ a replacement for backups - to keep your data safe, use\nsnapshots and backups together, wisely.\n\n# License\n\nCopyright (c) 2019 Patryk Wychowaniec \u003cpwychowaniec@pm.me\u003e.    \nLicensed under the MIT license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FPatryk27%2Flxd-snapper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FPatryk27%2Flxd-snapper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FPatryk27%2Flxd-snapper/lists"}