feat(youko): serve restic backups over an append-only REST server

Run restic-rest-server behind caddy (append-only, private repos, htpasswd
from agenix) and register youko's host key centrally.
This commit is contained in:
Ryan Yin authored and ryan4yin | 二花 committed 2026-09-21 20:38:08 +08:00
1 parent 12ac5f45aa
commit 1e2cef2550
3 files changed
+38

No files matched your search

+31
View File
@@ -36,10 +36,41 @@ in
repository = "/data/backups/restic/youko";
snapshotSource = "/btr_pool/@persistent";
requiresMountsFor = "/data/backups";
exclude = [
# regenerable, huge, or unsuitable for file-level backup
#
# the whole podman storage tree: the image layers are re-pullable, and its
# storage DB is not consistent when copied from a running podman.
# (uptime-kuma uses a named volume under here; its data is not wanted.)
"var/lib/containers"
"var/lib/microvms"
"var/lib/libvirt"
"nfs"
"var/cache"
"var/tmp"
"var/log"
"*.qcow2"
];
};
modules.btrbk.enable = true;
# The restic REST server the desktops push their backups to. Append-only, so
# a compromised client still cannot delete history; private repos, so each
# client only reaches the repository named after its user. Credentials come
# from agenix; caddy terminates TLS in front of it.
services.restic.server = {
enable = true;
listenAddress = "127.0.0.1:8000";
dataDir = "/data/backups/rest-server";
appendOnly = true;
privateRepos = true;
"htpasswd-file" = config.age.secrets."restic-rest-htpasswd".path;
};
# repositories live on the HDD, which has to be mounted first
systemd.services.restic-rest-server.unitConfig.RequiresMountsFor = "/data/backups";
boot.kernelParams = [
# Use transparent huge pages on demand (madvise) instead of a fixed 1G hugetlb
# pool (cannot be overcommitted/shared; it stranded memory and blocked
@@ -63,6 +63,11 @@ in
encode zstd gzip
reverse_proxy http://localhost:3303
'';
# the restic REST server the backup clients push to
virtualHosts."backup.writefor.fun".extraConfig = ''
${hostCommonConfig}
reverse_proxy http://localhost:8000
'';
virtualHosts."transmission.writefor.fun".extraConfig = ''
${hostCommonConfig}
encode zstd gzip
+2
View File
@@ -187,6 +187,8 @@ rec {
# Define the root user's host key for remote builders, so that nix can verify all the remote builders
aquamarine.publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEOXFhFu9Duzp6ZBE288gDZ6VLrNaeWL4kDrFUh9Neic root@aquamarine";
# the restic backup server
youko.publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEs8b3CmxM+utXZVKvJBssXBupBXvvzjHP40HcY7PSyZ root@youko";
# ruby.publicKey = "";
# kana.publicKey = "";