From 8dba2ef88b8126873c43e5ea0aec5405d9358e7e Mon Sep 17 00:00:00 2001 From: Noah Masur <7386960+nmasur@users.noreply.github.com> Date: Sat, 8 Oct 2022 15:52:05 +0000 Subject: [PATCH] litestream backups for nextcloud --- hosts/oracle/default.nix | 7 +++ modules/services/nextcloud.nix | 97 +++++++++++++++++++++++++++++----- private/backup.age | 6 +++ 3 files changed, 98 insertions(+), 12 deletions(-) create mode 100644 private/backup.age diff --git a/hosts/oracle/default.nix b/hosts/oracle/default.nix index 8da7180..096185a 100644 --- a/hosts/oracle/default.nix +++ b/hosts/oracle/default.nix @@ -26,6 +26,13 @@ nixpkgs.lib.nixosSystem { publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB+AbmjGEwITk5CK9y7+Rg27Fokgj9QEjgc9wST6MA3s"; + # Backup config + backupS3 = { + endpoint = "s3.us-west-002.backblazeb2.com"; + bucket = "noahmasur-backup"; + accessKeyId = "0026b0e73b2e2c80000000004"; + }; + # Grant access to Jellyfin directories from nextcloud users.users.nextcloud.extraGroups = [ "jellyfin" ]; } diff --git a/modules/services/nextcloud.nix b/modules/services/nextcloud.nix index 296b352..c9ffa1e 100644 --- a/modules/services/nextcloud.nix +++ b/modules/services/nextcloud.nix @@ -1,6 +1,8 @@ { config, pkgs, lib, ... }: -let adminpassFile = "/var/lib/nextcloud/creds"; +let + adminpassFile = "/var/lib/nextcloud/creds"; + backupS3File = "/var/lib/nextcloud/backup-creds"; in { @@ -13,6 +15,22 @@ in { description = "Hostname for Nextcloud"; }; + # Options for backup + backupS3 = { + endpoint = lib.mkOption { + type = lib.types.str; + description = "S3 endpoint for backups"; + }; + bucket = lib.mkOption { + type = lib.types.str; + description = "S3 bucket for backups"; + }; + accessKeyId = lib.mkOption { + type = lib.types.str; + description = "S3 access key ID for backups"; + }; + }; + }; config = { @@ -72,18 +90,73 @@ in { }]; }]; - # Create credentials files - system.activationScripts.nextcloud = { - deps = [ "age" ]; - text = '' - if [ ! -f "${adminpassFile}" ]; then - $DRY_RUN_CMD mkdir --parents $VERBOSE_ARG $(dirname ${adminpassFile}) - $DRY_RUN_CMD ${pkgs.age}/bin/age --decrypt \ + # Create credentials file for nextcloud + systemd.services.nextcloud-creds = { + requiredBy = [ "nextcloud-setup.service" ]; + before = [ "nextcloud-setup.service" ]; + serviceConfig = { + Type = "oneshot"; + User = "root"; + }; + script = '' + mkdir --parents $(dirname ${adminpassFile}) + ${pkgs.age}/bin/age --decrypt \ + --identity ${config.identityFile} \ + --output ${adminpassFile} \ + ${builtins.toString ../../private/nextcloud.age} + chown nextcloud:nextcloud ${adminpassFile} + chmod 0700 ${adminpassFile} + ''; + }; + + ## Backup config + + # Open to groups, allowing for backups + systemd.services.phpfpm-nextcloud.serviceConfig.StateDirectoryMode = + lib.mkForce "0770"; + + # Allow litestream and nextcloud to share a sqlite database + users.users.litestream.extraGroups = [ "nextcloud" ]; + users.users.nextcloud.extraGroups = [ "litestream" ]; + + # Backup sqlite database with litestream + services.litestream = { + enable = true; + settings = { + dbs = [{ + path = "/var/lib/nextcloud/data/nextcloud.db"; + replicas = [{ + url = + "s3://${config.backupS3.bucket}.${config.backupS3.endpoint}/nextcloud"; + }]; + }]; + }; + environmentFile = backupS3File; + }; + + # Don't start litestream unless nextcloud is up + systemd.services.litestream = { + after = [ "phpfpm-nextcloud.service" ]; + requires = [ "phpfpm-nextcloud.service" ]; + environment.LITESTREAM_ACCESS_KEY_ID = config.backupS3.accessKeyId; + }; + + # Create credentials file for litestream + systemd.services.litestream-s3 = { + requiredBy = [ "litestream.service" ]; + before = [ "litestream.service" ]; + serviceConfig = { + Type = "oneshot"; + User = "root"; + }; + script = '' + echo \ + LITESTREAM_SECRET_ACCESS_KEY=$(${pkgs.age}/bin/age --decrypt \ --identity ${config.identityFile} \ - --output ${adminpassFile} \ - ${builtins.toString ../../private/nextcloud.age} - $DRY_RUN_CMD chown nextcloud:nextcloud ${adminpassFile} - fi + ${builtins.toString ../../private/backup.age} \ + ) > ${backupS3File} + chown litestream:litestream ${backupS3File} + chmod 0700 ${backupS3File} ''; }; diff --git a/private/backup.age b/private/backup.age new file mode 100644 index 0000000..bc1483a --- /dev/null +++ b/private/backup.age @@ -0,0 +1,6 @@ +age-encryption.org/v1 +-> ssh-ed25519 MgHaOw 2y5C1sRq3NZqmfGBiPgMS7qcU5v+70wri5xkXbceaHM +zyd7b+OuVi3rxxUEm+QW/80M80SSKaebOwOioRjnYak +--- yZQxxjYYNouD5wnEj+qNjUSrRU01hXvWUuax4C252i8 +/2*MD^ӜOQ +5