{"version":"https://jsonfeed.org/version/1.1","title":"Vic Demuzere - Restic","home_page_url":"https://vic.demuzere.be/articles/tags/restic/","feed_url":"https://vic.demuzere.be/articles/tags/restic/feed.json","description":"Blog posts tagged Restic by Vic Demuzere","language":"en","items":[{"id":"https://vic.demuzere.be/articles/how-i-almost-lost-my-backups/","content_html":"<p>My backup strategy follows the <a href=\"https://www.backblaze.com/blog/the-3-2-1-backup-strategy/\" title=\"Backblaze on the 3-2-1 backup rule\">3-2-1 backup rule</a>:</p>\n<ul>\n<li><strong>Three</strong> copies of your data</li>\n<li>On <strong>two</strong> different media</li>\n<li><strong>One</strong> copy off-site</li>\n</ul>\n<p>Some people argue that your production data (the copy stored on your laptop, for example) counts as one of those copies.\nI disagree.\nWhile it may be a copy of your <em>current</em> data, it's not a copy of your historical data.\nIf I need to recover a file that I modified or deleted 2 years ago, my laptop won't have it.</p>\n<h2 id=\"device-backups\">Device backups<a href=\"#device-backups\" aria-label=\"Link to heading 'Device backups'\" data-heading-content=\"Device backups\" class=\"anchor\"></a></h2>\n<p>I use <strong><a href=\"https://restic.net/\" title=\"Restic\">Restic</a></strong> to write encrypted backups to a 2.5&quot; SSD inside an external USB enclosure.\nThis disk also contains a few scripts to automate the process.\nFriday is backup day: connect the disk, run the script, done.</p>\n<p>Using <code>rsync</code>, I make copies of this master disk:</p>\n<ul>\n<li>\n<p>To another USB 2.5&quot; hard drive located at the office.\nThis is a physical copy I can easily access if my house burns down.\nRestic's encryption is vital here, as coworkers have access to the area where this disk is kept.</p>\n</li>\n<li>\n<p>To a dedicated server at <a href=\"https://www.hetzner.com/sb/\" title=\"Refurbished dedicated servers at Hetzner\">Hetzner</a>.\nA few friends have SSH access<sup class=\"footnote-ref\"><a href=\"#fn-1\" id=\"fnref-1\" data-footnote-ref>1</a></sup> to the account that stores this copy.\nThis provides another &quot;worst-case scenario&quot; path to my data.</p>\n</li>\n</ul>\n<p>Every few months I run a validation script on my Hetzner server.\nThis executes <a href=\"https://restic.readthedocs.io/en/latest/045_working_with_repos.html#checking-integrity-and-consistency\" title=\"Restic: checking integrity and consistency\">Restic with the <code>check --read-data</code></a> subcommand on the copy stored there.\nA few days later, I know whether the data is still correct.\nWhile not exactly the same as a full restore test, it gives me some piece of mind.</p>\n<h3 id=\"additional-backup-for-documents\">Additional backup for documents<a href=\"#additional-backup-for-documents\" aria-label=\"Link to heading 'Additional backup for documents'\" data-heading-content=\"Additional backup for documents\" class=\"anchor\"></a></h3>\n<p>Important folders on my desktop and laptop are synced using <a href=\"https://syncthing.net/\" title=\"Syncthing\">Syncthing</a>.\nIn addition to my personal devices, these also replicate to one of my servers.\nFrom there, an hourly <a href=\"https://restic.net/\" title=\"Restic\">Restic</a> snapshot is made to <a href=\"https://www.backblaze.com/cloud-storage\" title=\"Backblaze B2 cloud storage\">Backblaze B2</a>.\nIn case my 3-2-1 drives fail, I have one last chance to recovery my important documents here.</p>\n<h2 id=\"post-mortem\">Post mortem<a href=\"#post-mortem\" aria-label=\"Link to heading 'Post mortem'\" data-heading-content=\"Post mortem\" class=\"anchor\"></a></h2>\n<p>I was assured my backup scheme was solid, until it wasn't.</p>\n<p>Suddenly, the data validation on the Hetzner server failed.<sup class=\"footnote-ref\"><a href=\"#fn-2\" id=\"fnref-2\" data-footnote-ref>2</a></sup>\nRestic saves backups as <a href=\"https://en.wikipedia.org/wiki/Data_deduplication\" title=\"Data Deduplication on Wikipedia\">deduplicated</a> chunks in what it calls &quot;pack files.&quot;\nSeveral of these files no longer matched their checksums.\nSince pack files are named after their SHA-256 hash, I checked them again manually.\nSadly, <code>sha256sum</code> confirmed the worst: the data in these files was not what it was supposed to be.</p>\n<p>This server has two 4TB disks in RAID 1.\nI assumed there was a hardware issue with the server, but everything looked fine.\nThe other services on the server ran fine, the disks reported no errors, and the RAID was healthy.</p>\n<p>Then I realized: <em>the Hetzner server was not the source of corruption</em>.\nChecking the pack files on my USB disk quickly revealed the truth.\n<strong>These files were also corrupt</strong>, and <code>rsync</code> had dutifully <strong>replicated the corrupted data to my server</strong>.</p>\n<p>It quickly became obvious what was happening.\nDuring additional checks on my USB disk, my laptop started reporting I/O errors.\nThe SSD in this enclosure has been failing silently for a while, returning random data instead of my files.\nI hadn't noticed because I rarely <em>use</em> these backups.\nThe data is usually only read by rsync to push it to the server.</p>\n<p>An hour later, the SSD died completely.</p>\n<p>Two days later, when I was back at the office, I checked the second USB drive.\nI had little hope.\nI usually sync both the Hetzner server and this disk at the same time.\nAs expected, the same errors were present.</p>\n<p><strong>I had managed to corrupt all three copies of my backups simultaneously.</strong></p>\n<h2 id=\"recovery\">Recovery<a href=\"#recovery\" aria-label=\"Link to heading 'Recovery'\" data-heading-content=\"Recovery\" class=\"anchor\"></a></h2>\n<p>There is no magic recovery procedure here.\nIf all copies of a piece of data are gone, they are gone forever.\nRegrettably, I did lose some data that day.</p>\n<p>However, Restic was <a href=\"https://restic.readthedocs.io/en/latest/077_troubleshooting.html\">quite helpful</a> during the recovery process:</p>\n<ul>\n<li>\n<p>A nice side-effect of the data deduplication is that <strong>you can &quot;import&quot; files again</strong>.\nBy creating a temporary snapshot with files gathered from other locations (like old laptop folders or emails), Restic recreates the deduplicated chunks.\nThis makes those files usable again in the older, previously &quot;corrupt&quot; snapshots!</p>\n</li>\n<li>\n<p>Dry-running <code>restic repair snapshots --forget</code> listed exactly which files would be removed due to missing data.\nUse this as a to-do list to gather missing files.</p>\n</li>\n<li>\n<p>Part of the missing data turned out to be logfiles I didn't care about.\nPurging these from snapshots made it a lot easier to identify which important files were actually missing.<sup class=\"footnote-ref\"><a href=\"#fn-3\" id=\"fnref-3\" data-footnote-ref>3</a></sup></p>\n</li>\n</ul>\n<p>In the end, I lost only three possibly important files: pictures.\nSince the data is gone, I don't know exactly what was in them, but I know which albums they belonged to.\nMy backup disk now contains a text file listing those three missing filenames as a permanent reminder.</p>\n<h2 id=\"preventing-this-in-the-future\">Preventing this in the future<a href=\"#preventing-this-in-the-future\" aria-label=\"Link to heading 'Preventing this in the future'\" data-heading-content=\"Preventing this in the future\" class=\"anchor\"></a></h2>\n<p>Clearly, I needed safeguards.\nI made two specific changes to the script I use to sync backups from my local USB SSD to the other destinations:</p>\n<ol>\n<li>\n<p>Before executing <code>rsync</code>, the script now runs <code>restic check</code>.\nWhile a full <code>--read-data</code> takes too long for a weekly routine, a basic check catches structural errors.\nBefore my previous SSD died, the basic check also found errors.\nI'm not sure it would have catched the SSD returning small bits of random data, though.</p>\n</li>\n<li>\n<p>Except for the <code>locks</code> directory, restic never overwrites files.\nIt only creates new ones.\nOld files stay until you run <code>restic forget</code> to clean up your repository.\nI now run <code>rsync</code> with the <code>--ignore-existing</code> flag, as there is no reason to overwrite remote files.</p>\n</li>\n</ol>\n<p>I'm confident that this would prevent data loss if a drive fails silently again.</p>\n<p>Once <a href=\"https://www.techpowerup.com/345260/hdd-prices-increase-by-an-average-of-46-over-the-past-four-months\" title=\"Random article about disk prices increases\">hard drive prices stabilize</a>, I'll likely buy another external drive for a yearly &quot;cold&quot; archive.\nThe hardest files to replace where those that have been removed from my devices years ago.\nHaving an additional offline drive with an old copy would allow me to recover those files.</p>\n<section class=\"footnotes\" data-footnotes>\n<ol>\n<li id=\"fn-1\">\n<p>Not all of them know about it though. <a href=\"#fnref-1\" class=\"footnote-backref\" data-footnote-backref data-footnote-backref-idx=\"1\" aria-label=\"Back to reference 1\">↩</a></p>\n</li>\n<li id=\"fn-2\">\n<p>I would have never discovered about this if it wasn't for this regular data check.\nBackups are not backups if you don't check them. <a href=\"#fnref-2\" class=\"footnote-backref\" data-footnote-backref data-footnote-backref-idx=\"2\" aria-label=\"Back to reference 2\">↩</a></p>\n</li>\n<li id=\"fn-3\">\n<p>Figuring out what data I had lost took a few days and I didn't really take notes.\nDocumenting which commands I used here would have been the most interesting part of the article.\nOh well.. <a href=\"#fnref-3\" class=\"footnote-backref\" data-footnote-backref data-footnote-backref-idx=\"3\" aria-label=\"Back to reference 3\">↩</a></p>\n</li>\n</ol>\n</section>\n<div class=\"footer\"><hr><p>Thanks for subscribing to my feed!</p><p>Feel free to e-mail comments or corrections to <a href=\"mailto:vic@demuzere.be?subject=RE%3A%20How%20I%20almost%20lost%20my%20backups\">vic@demuzere.be</a>.</p></div>","url":"https://vic.demuzere.be/articles/how-i-almost-lost-my-backups/","date_published":"2026-05-07T16:08:09Z","date_modified":"2026-05-07T16:08:09Z","language":"en"},{"id":"https://vic.demuzere.be/articles/backups-restic-systemd/","content_html":"<p>Since moving away from Digital Ocean (and their snapshots) I've been looking for a good way to create backups for my servers.\nI've recently stumbled upon the <a href=\"https://restic.github.io/\" title=\"Restic\">Restic</a> project and have been using it ever since.</p>\n<ul>\n<li>Restic is very <strong>simple to use</strong>. It's a cli-tool with a few easy to understand commands and has good documentation including examples.</li>\n<li>You <strong>don't need a special backup service</strong>. Restic runs on the host being backed up, and is happy to store its backups on a simple file server or cloud service.</li>\n<li>Security is important and the developers have written a <strong>decent <a href=\"https://restic.readthedocs.io/en/latest/100_references.html#threat-model\" title=\"Restic threat model\">threat model</a></strong>: trust only the host where restic runs, which makes sense as it contains the data anyway. The place where you store your backups is always considered insecure.</li>\n</ul>\n<h2 id=\"mounting-storage-space\">Mounting storage space<a href=\"#mounting-storage-space\" aria-label=\"Link to heading 'Mounting storage space'\" data-heading-content=\"Mounting storage space\" class=\"anchor\"></a></h2>\n<p><a href=\"https://www.transip.be/\" title=\"TransIP\">TransIP</a> is giving 1TB of free storage on their <a href=\"https://www.transip.be/stack/\" title=\"TransIP Stack\">Stack storage service</a>, which is more than enough for my backup needs.\nThe downside is that the only useful way to access it is a painfully slow webdav mount.\nIf you're backing up data that changes fast and need a consistent state, I would suggest choosing a different place to store your data.\nFor most of my servers I don't really care about backup speeds, though.</p>\n<p>Mounting the volume using an entry in <code>/etc/fstab</code> would work, but as I want to specify dependencies later I opt to create a <em><a href=\"https://www.freedesktop.org/software/systemd/man/systemd.mount.html\" title=\"systemd Mount Unit\">Mount Unit</a></em> instead.\nThis is basically the systemd version of a single fstab entry.</p>\n<pre><code># /etc/systemd/systemd/mnt-backups.mount\n[Unit]\nDescription=Backup storage\nAfter=network-online.target\nWants=network-online.target\n\n[Mount]\nType=davfs\nWhat=https://something.stackstorage.com/remote.php/webdav/\nWhere=/mnt/backups\nOptions=uid=root,gid=root,file_mode=644,dir_mode=755,nosuid,noexec,rw\nTiemoutSec=15\n\n[Install]\nWantedBy=multi-user.target\n</code></pre>\n<p>If you're using webdav (using davfs2) like me, you'll also have to set your username and password in the secrets file <code>/etc/davfs2/secrets</code>.\nBe sure to restrict the permissions on this file as it contains passwords.</p>\n<pre><code>https://something.stackstorage.com/remote.php/webdav/ username password\n</code></pre>\n<p>We can now tell systemd to mount our volume:</p>\n<pre><code>systemctl start mnt-backups.mount\n</code></pre>\n<p>And also set it to be mounted every time our machine boots:</p>\n<pre><code>systemctl enable mnt-backups.mount\n</code></pre>\n<h2 id=\"initialize-the-repository\">Initialize the repository<a href=\"#initialize-the-repository\" aria-label=\"Link to heading 'Initialize the repository'\" data-heading-content=\"Initialize the repository\" class=\"anchor\"></a></h2>\n<p>Before our first backup we have to initialize a repository.\nThis creates the directory structure and configuration that restic will use to store our backups.\nNote that, as restic does not trust our backup volume, any configuration stored there is also encrypted!</p>\n<pre><code>restic init --repo /mnt/backups/myserver\n</code></pre>\n<p>Do not forget the password you enter during this step.\nEvery single file on the backup volume is encrypted and without the password your backups become useless.</p>\n<h2 id=\"backup-service\">Backup service<a href=\"#backup-service\" aria-label=\"Link to heading 'Backup service'\" data-heading-content=\"Backup service\" class=\"anchor\"></a></h2>\n<p>The <em><a href=\"https://www.freedesktop.org/software/systemd/man/systemd.service.html\" title=\"systemd Service Unit\">Service Unit</a></em> shown below describes a service that creates a single backup and stops.</p>\n<pre><code># /etc/systemd/system/backup.service\n[Unit]\nDescription=Backup\nAfter=mnt-backups.mount\nWants=mnt-backups.mount\n\n[Service]\nType=simple\nEnvironment=RESTIC_PASSWORD=mysupers3cr3tpassw0rd!\nEnvironment=RESTIC_REPOSITORY=/mnt/backups/myserver\nExecStart=/usr/local/bin/restic backup /home /srv/web\n</code></pre>\n<p>In the <code>[Unit]</code> section we specify that the mount we created earlier is a requirement for making backups (<code>Wants</code>).\nThe <code>After</code> setting is used to order the units when both are set to start when booting the system.\nIt's a bit redundant to specify that the <em>Service</em> should be after the <em>Mount</em> as we already specified a dependency, but it's a common thing to do.</p>\n<p>Note that I only backup my <code>/home</code> and <code>/srv/web</code> folders as everything else can either be recreated or is managed by Ansible on my servers.\nIf you prefer to have a copy of your entire filesystem remember to change the path!</p>\n<p>We can now create a new backup manually by running <code>systemctl start backup</code>.\nThis isn't really useful by itself as we could have run <code>restic backup</code> manually just as easy, with the exception that we don't have to type the password anymore.\nOnce we combine this with a systemd timer, things become interesting!</p>\n<p>Remember that we set the backup volume to be mounted on boot? That isn't really required.\nAs we have specified a dependency on the volume, systemd will check if it's mounted before starting the backup service.\nThe free <a href=\"https://www.transip.be/stack/\" title=\"TransIP Stack\">Stack</a> volume I'm using is a bit wonky though, so I prefer to keep it mounted as that's a bit more stable.</p>\n<h2 id=\"creating-backups-automatically\">Creating backups automatically<a href=\"#creating-backups-automatically\" aria-label=\"Link to heading 'Creating backups automatically'\" data-heading-content=\"Creating backups automatically\" class=\"anchor\"></a></h2>\n<p>Now that our backup works, it's time to have it create a backup automatically every night.\nCreating a <em><a href=\"https://www.freedesktop.org/software/systemd/man/systemd.mount.html\" title=\"systemd Timer Unit\">Timer Unit</a></em> with the same name as the service we want to start does exactly that!</p>\n<pre><code># /etc/systemd/system/backup.timer\n[Unit]\nDescription=Backup daily\n\n[Timer]\nOnCalendar=daily\nPersistent=true\n\n[Install]\nWantedBy=timers.target\n</code></pre>\n<p>This simple timer is set to run daily at midnight.\nSetting the <code>Persistent</code> attribute tells systemd that if our host was down at midnight, it has to run the backup as soon as it comes up again.\nAs servers are usually online 24/7 this doesn't really matter but it is a great setting for desktops and laptops.</p>\n<p>Enable the timer using systemctl:</p>\n<pre><code>systemctl enable backup.timer\n</code></pre>\n<p>Now enjoy having a fresh backup of your server every night!\nSimilar to the backup service, you can also create a service to <a href=\"https://restic.readthedocs.io/en/latest/060_forget.html\" title=\"Remove old snapshots\">remove your old snapshots</a>.\nBy default <a href=\"https://restic.github.io/\" title=\"Restic\">Restic</a> just keeps adding data and never removes anything, this may become a problem pretty fast if you're backup up a lot of data.</p>\n<h2 id=\"restoring\">Restoring<a href=\"#restoring\" aria-label=\"Link to heading 'Restoring'\" data-heading-content=\"Restoring\" class=\"anchor\"></a></h2>\n<p>As with any backup system: remember to test restoring your backups regularly.\nRestic gives us two great options in case we fuck up and need our data back:</p>\n<ul>\n<li><a href=\"https://restic.readthedocs.io/en/latest/050_restore.html#restoring-from-a-snapshot\" title=\"Restore a snapshot using restic\">Restore a complete snapshot</a> if you know to which point in time you need to return and if you need a copy of all your files.</li>\n<li><a href=\"https://restic.readthedocs.io/en/latest/050_restore.html#restore-using-mount\" title=\"Mount all your snapshots using restic\">Mount your backup repository</a> as a fuse filesystem, allowing you to browse all your snapshots and the files within as if they're all just there on your server.</li>\n</ul>\n<div class=\"footer\"><hr><p>Thanks for subscribing to my feed!</p><p>Feel free to e-mail comments or corrections to <a href=\"mailto:vic@demuzere.be?subject=RE%3A%20Using%20Restic%20and%20systemd%20to%20backup%20a%20linux%20host\">vic@demuzere.be</a>.</p></div>","url":"https://vic.demuzere.be/articles/backups-restic-systemd/","date_published":"2017-11-24T21:20:00Z","date_modified":"2023-11-28T19:55:32Z","language":"en"}]}