diff --git a/modules/nixos-wiki/backup.nix b/modules/nixos-wiki/backup.nix index 931a59d..b09f7e6 100644 --- a/modules/nixos-wiki/backup.nix +++ b/modules/nixos-wiki/backup.nix @@ -13,8 +13,27 @@ let --add-flags ${config.services.mediawiki.finalPackage}/share/mediawiki/maintenance/run.php ''; - wiki-restore = pkgs.writeShellApplication { - name = "wiki-restore"; + wiki-backup = pkgs.writeShellApplication + { + name = "wiki-backup"; + runtimeInputs = [ + pkgs.postgresql + pkgs.util-linux + ]; + text = '' + tmpdir=$(mktemp -d) + cleanup() { rm -rf "$tmpdir"; } + + chown postgres:users "$tmpdir" + mkdir -p /var/lib/mediawiki/backup/ + runuser -u postgres -- pg_dump --format=custom --file "$tmpdir"/db mediawiki + cp "$tmpdir"/db /var/lib/mediawiki/backup/db + trap cleanup EXIT + ''; + }; + + old-wiki-restore = pkgs.writeShellApplication { + name = "old-wiki-restore"; runtimeInputs = [ pkgs.postgresql pkgs.coreutils @@ -51,7 +70,7 @@ in { environment.systemPackages = [ mediawiki-maintenance ]; - systemd.services.wiki-backup = { + systemd.services.old-wiki-backup = { startAt = "hourly"; serviceConfig = { @@ -64,17 +83,95 @@ in }; }; - systemd.services.wiki-restore = { + systemd.services.old-wiki-restore = { startAt = "daily"; path = [ pkgs.postgresql mediawiki-maintenance ]; serviceConfig = { - ExecStart = "${wiki-restore}/bin/wiki-restore"; + ExecStart = "${old-wiki-restore}/bin/old-wiki-restore"; Type = "oneshot"; }; }; + systemd.services.wiki-backup = { + startAt = "daily"; + path = [ pkgs.postgresql ]; + + unitConfig = { + Conflicts = [ "phpfpm-mediawiki.service" ]; + OnSuccess = [ "phpfpm-mediawiki.service" ]; + OnFailure = [ "phpfpm-mediawiki.service" ]; + }; + serviceConfig = { + ExecStart = "${wiki-backup}/bin/wiki-backup"; + Type = "oneshot"; + }; + }; + + services.nginx.virtualHosts.${config.services.mediawiki.nginx.hostName} = { locations."=/wikidump.xml.gz".alias = wikiDump; }; + + + sops.secrets.storagebox-ssh-key = { + sopsFile = ../../targets/nixos-wiki.nixos.org/secrets/backup_share_ssh_key; + format = "binary"; + path = "/var/keys/storagebox-ssh-key"; + mode = "0600"; + owner = "root"; + group = "root"; + }; + + sops.secrets.backup-secret = { + sopsFile = ../../targets/nixos-wiki.nixos.org/secrets/borg_encryption_passphrase; + format = "binary"; + path = "/var/keys/borg-secret"; + mode = "0600"; + owner = "root"; + group = "root"; + }; + + + programs.ssh.knownHosts."[u391032.your-storagebox.de]:23".publicKey = "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA5EB5p/5Hp3hGW1oHok+PIOH9Pbn7cnUiGmUEBrCVjnAw+HrKyN8bYVV0dIGllswYXwkG/+bgiBlE6IVIBAq+JwVWu1Sss3KarHY3OvFJUXZoZyRRg/Gc/+LRCE7lyKpwWQ70dbelGRyyJFH36eNv6ySXoUYtGkwlU5IVaHPApOxe4LHPZa/qhSRbPo2hwoh0orCtgejRebNtW5nlx00DNFgsvn8Svz2cIYLxsPVzKgUxs8Zxsxgn+Q/UvR7uq4AbAhyBMLxv7DjJ1pc7PJocuTno2Rw9uMZi1gkjbnmiOh6TTXIEWbnroyIhwc8555uto9melEUmWNQ+C+PwAK+MPw=="; + + systemd.services.borgbackup-job-state = { + wants = [ "wiki-backup.service" ]; + after = [ "wiki-backup.service" ]; + }; + + services.borgbackup.jobs.state = { + # Create the repo + doInit = true; + + # Create daily backups, but prune to a reasonable amount + startAt = "daily"; + prune.keep = { + daily = 7; + weekly = 4; + monthly = 3; + }; + + paths = [ "/var/lib/mediawiki-uploads" "/var/lib/mediawiki/backup" ]; + + # Where to backup it to + repo = "u391032-sub1@u391032.your-storagebox.de:wiki.nixos.org/repo"; + environment.BORG_RSH = "ssh -p 23 -i /var/keys/storagebox-ssh-key"; + + # Authenticated & encrypted, key resides in the repository + encryption = { + mode = "repokey-blake2"; + passCommand = "cat /var/keys/borg-secret"; + }; + + # Reduce the backup size + compression = "auto,zstd"; + + # Show summary detailing data usage once completed + extraCreateArgs = "--stats"; + }; + + + + } diff --git a/targets/nixos-wiki.nixos.org/configuration.nix b/targets/nixos-wiki.nixos.org/configuration.nix index aa70fd3..7cb7ea8 100644 --- a/targets/nixos-wiki.nixos.org/configuration.nix +++ b/targets/nixos-wiki.nixos.org/configuration.nix @@ -15,6 +15,11 @@ in sops.secrets.nixos-wiki.owner = config.services.phpfpm.pools.mediawiki.user; sops.secrets.nixos-wiki-github-client-secret.owner = config.services.phpfpm.pools.mediawiki.user; + networking = { + hostName = "wiki"; + domain = "nixos.org"; + }; + services.nixos-wiki = { hostname = "wiki.staging.julienmalka.me"; adminPasswordFile = config.sops.secrets.nixos-wiki.path; diff --git a/targets/nixos-wiki.nixos.org/secrets/backup_share_ssh_key b/targets/nixos-wiki.nixos.org/secrets/backup_share_ssh_key new file mode 100644 index 0000000..3e7e0f9 --- /dev/null +++ b/targets/nixos-wiki.nixos.org/secrets/backup_share_ssh_key @@ -0,0 +1,32 @@ +{ + "data": "ENC[AES256_GCM,data:17TYGA1juFBh4a0KV6fytp3FbHujo3mT6GxTL7GvrrcsrH49iSwn3jHKfIvRDQmuoVAD5ksthlGcr4DbbPKy47ohjJXEoHblFvLKW3TGHLVD5mE5p8Lq30+9CYCG5SLv9I0oW822QHXylr890J9jNdRxGH7tnL1vZ97Cnt4634BZcd3g8QxSPEZIVLAlpyt0xFJgPOVmwZZ0FT3ZS+7aAVdsWGxujlLfjz2GQp4Q9ZxRXO3v78tHVde2vBw5eas0gPs+wzyvONNM4DHQSVRAxewR5PI6O1kieaSFSUoY+q/uODBG+xOsreH9h6nldiHGtig9otoOwI03p4xjeIQISZIQeuvyAMLafaAY+b36ejsuVppZadol/dhry6VYCUg+xPSpR05X/2wHuqT5DJPRZ26zai15BykRTXA2I7hAONZRiCWYTJBZ0FqfbPVyCvx7m/IKETtq7FbQUBwtVs3l1OjhVS3znHnFp79k9b+BY0NWLCNELULMDN4gQyLpEeBoubaq0vUK+mVRBeSm2f7i,iv:o/79IQzWlxI3XyD5jiyEOZ9sXfgn2hKdMiCEdJkqh9g=,tag:wvfhks/O6aktk0N2DPGwfQ==,type:str]", + "sops": { + "kms": null, + "gcp_kms": null, + "azure_kv": null, + "hc_vault": null, + "age": [ + { + "recipient": "age17n64ahe3wesh8l8lj0zylf4nljdmqn28hvqns2g7hgm9mdkhlsvsjuvkxz", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1anplUWVpTDNXMUNYQlhn\nTklOc1FGQTV4T0tVeURTdnZISjV6azYvZFFBClB6Q3JncXRZTE1TclVkazFscng1\ncFVzYUNSKy82N0ZkQWFmb2IvU2p1WWsKLS0tIHd2SU1jRFlQN284RjRpMjVuZHZ0\nc24zUldEWW5jZUIzSjI0VzBTaU9rZ1UK1N1G5EWy6uisnUoBQmUpINIyN+f1/vnX\nTrHn8uHcydiM6wZyAxzdwOV53HWxZ8m4MQTS0CXa2S/z+HGRkTsotg==\n-----END AGE ENCRYPTED FILE-----\n" + }, + { + "recipient": "age1eq0e6uhjj2tja8v338tkdz8ema2aw5anpuyaq2uru7rt4lq7msyqqut6m2", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBjQk1xV1c0VVpqS1NnTERi\nc1pnMkV1ODRrS0dScTBrTUFreG40bGxseUZZCkJ3elVYWkJoaWNSOEE1cFRTUnIr\nejNsK21MTlRJRGxVdmVPeHljcEY3R0kKLS0tIE1HZEl1WlRVejNMWXo2bzFmcnZF\nblpiNU0vT25kV3l1dUFWSzVMVzZlZkUKdlDDCfVRNSDLPFQIGBCLhTSCxs2sZm+C\nBse6v+LRWrgIs0XwJY2Hf4XlZgnnEYw896sSgBz8opeQ4g4mf0Lfuw==\n-----END AGE ENCRYPTED FILE-----\n" + }, + { + "recipient": "age109qksyjgdnf7elnk98dh4vtxt0epju7xjemlqng0j0x75st5zg9qm9h3hy", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB4clM2N3M2SzdPdHRsTGV1\nS1FYV3J1T2Yxa1o3RWlBS3ZReHpQS2dYZFVVCkFrWDNDU2JXaWxDTXN6ckxZLy9H\ndWMvTEZ5WmlKNVFsR2gySzR5ZXlTUmMKLS0tIGtXZUhuUFFtbnVHc0J0d2NiNEE3\nSTRSemtSZHNNYTZsM2R2dFZ1NDBrMlEKINJTmtgKvIPewfGc4cJbMUkyLpr05FqO\ni2D+orxThR9EOiEQkqyDZVnyXV5EKi0X6voArlYonGnON+ixvIVXfA==\n-----END AGE ENCRYPTED FILE-----\n" + }, + { + "recipient": "age1p3dl7q5ahjdhl3g72mqk9pxy3gcptw9dqmg6syq9f9s03ppqp4rsqm93n2", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBIdnlLdE5EWlVLOGg3UllH\nVGU1YnFXSGhhbTA4YzEzRzVjY2lOOXBqU3g4CkRkM2E3WGt0TFBiOEo1TzlKSlZ5\nWXNOVXRqR0c2SUJCSUpLV2VVSUVNNkkKLS0tIGE2SVVsRUZ1WE9MV2xQdDI4Q0pS\neVVOeTFqM0Nna1JiWWIwUFVaMlpiMEUKR+uMYSznyF/96fASHi2PUMy/cN9BSriN\nR0Bur8eEOWTPjOWh6s409SQU0nSDxDxpL0b9ew7uMM9+Fdig7R8IzA==\n-----END AGE ENCRYPTED FILE-----\n" + } + ], + "lastmodified": "2024-02-17T16:29:00Z", + "mac": "ENC[AES256_GCM,data:o9CcQF53wBAmloQpjHMka/ucqW3DgpUEYImd4ZG+40UG8wGo1vADaxghex8fFT3S6a6QE6pEFgxjw9KDJ+Af9xeHeszt68ZIsIDMKuBKW0H7ExwzsdnE2uPHN//wQw28FLfjZL+d9yc6bTkPqe0d5s39TwwahUvlxeUJgNMGJWA=,iv:Wdto00kmAfwrYgDqzp2sFYGpaQ17x0B/vkF3RD7uW04=,tag:A6gL4zM9BMyyULON/m+mdw==,type:str]", + "pgp": null, + "unencrypted_suffix": "_unencrypted", + "version": "3.8.1" + } +} \ No newline at end of file diff --git a/targets/nixos-wiki.nixos.org/secrets/borg_encryption_passphrase b/targets/nixos-wiki.nixos.org/secrets/borg_encryption_passphrase new file mode 100644 index 0000000..0075095 --- /dev/null +++ b/targets/nixos-wiki.nixos.org/secrets/borg_encryption_passphrase @@ -0,0 +1,32 @@ +{ + "data": "ENC[AES256_GCM,data:1DIT/Dh4rQt73CLvh6q+uhGVfw+kdnSeno4C/CSGlof+iaZjVfoU0Wk=,iv:s3t2USkK5OeNZnRD7Pj6qtHxgZFtEvElQrX8aRBQC24=,tag:T3PIhHocYTS/QNvx2jFTcw==,type:str]", + "sops": { + "kms": null, + "gcp_kms": null, + "azure_kv": null, + "hc_vault": null, + "age": [ + { + "recipient": "age17n64ahe3wesh8l8lj0zylf4nljdmqn28hvqns2g7hgm9mdkhlsvsjuvkxz", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB4c3pEOWR0Zi8yU0FGNWQx\nL3A3Y3Y3TXFFdFBNdmJxV3h3WUIxaFZQcHg4CkM0Mkg0SGdTK3U0Z2RDSUNPLzNa\na05uZ3VlbzBxR1FibVVZa0xZTDRrYVUKLS0tIEUrR3RBdjRKRUdIMm5rUUdEajFN\nSHI4anZRa2g4U2E4enJZdDR6RlNoajAKA01UMRoBgwNtha7W05xK+hYJY6oaVvF8\n9v0oi6a+ZONaboHFmiNK89ojCaI/xmtciRXwIpiZnJeAq5OlUyeuqw==\n-----END AGE ENCRYPTED FILE-----\n" + }, + { + "recipient": "age1eq0e6uhjj2tja8v338tkdz8ema2aw5anpuyaq2uru7rt4lq7msyqqut6m2", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBlNktTT3FTSzFRWjhxN0xt\ncklXZmRITDkzaDRtaCtmOWxYWlkrcUlIclNJCjVjeDd0Q3l2ZVRwM2duV3p6Wk5r\nOU9ZNnZ3SVQyTHJDb2FVVW5lQnNiTk0KLS0tIDZvOWROODZGUmw0RUh4YXowTnA0\nTHhyTFo1elZUU1JOVDczd1BGZ2lqZXMKrnwColUqyXHwMwT8hRD0yOzqKu0CINJN\n9ileAN3OTZfjEbfj8Ay9QNEG6ZyytWvsuoC71CsD6W8A7goURgeDZA==\n-----END AGE ENCRYPTED FILE-----\n" + }, + { + "recipient": "age109qksyjgdnf7elnk98dh4vtxt0epju7xjemlqng0j0x75st5zg9qm9h3hy", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBrYVJiUTdGQnBrRG5PeFAy\nc2tQOGEwRG94LzJ3ZG5FczdRT1ZQU1pockNBCklMeGh1N0lkY2VkNVVxaXV6THJW\nVlhMS1M2U29qRHgxc1JBWFlnbWNpMjgKLS0tIExzOGVyeS9Qd3A4VzVWWERZZTJj\nSDNiUXh0SFh5TzhYcXl0cDFWMGJVWUUKgeik/hYj3WgmqEh2+Rw4GSHsX3ZnipOm\nuVpoBGcy5S45i6nzA7NVFH2cWUyxuSx6pzRftEEDI4/p+rJoo9K5gQ==\n-----END AGE ENCRYPTED FILE-----\n" + }, + { + "recipient": "age1p3dl7q5ahjdhl3g72mqk9pxy3gcptw9dqmg6syq9f9s03ppqp4rsqm93n2", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAzSWttMm9oNDREYUduMVRP\nMVdKclhieG5SK01JcUF6STkzcmx3SDJxamhjCmJSdm9YSjduMnNKNlVhQlRDbzVi\nK0I1dE4zbmNHajZvVFRRcGNaOWY2UVUKLS0tIG9WKzZKQm5ob0VUVjRQdWIwd3Iy\neEpJQWxTOFdLTnhHV2dwUTMxam9WdTAKC6SFo+qZRHedKKg/nK5E3qO+nMQgYOiJ\nnw4HqD81zXrLbzoPCPfrfcqnFMFFAlPVoWMvG8UTO2YxOJlLjsRaQw==\n-----END AGE ENCRYPTED FILE-----\n" + } + ], + "lastmodified": "2024-02-17T16:32:53Z", + "mac": "ENC[AES256_GCM,data:zVMRaUL2X+YWQ4uw1QG2g5ihiPfcAriuXScU5dRJVDdqCCoH1xLtYqFd2u4/raUYM6NtyFOTrSGskOwsDTD35Z4dcxsLNcfTUyGuglD9GOHf4Xggv2t9VarDdMBUzEEri4ddyEtUhFU/1wAyPZJit+OrjIpBsLhbP6rwnAFEpfA=,iv:LLRpnA/15GTGAXddLCKyUfKWKzAy784dFVNktSRxoeM=,tag:d6Goh6NlHPRgIkxCgFnpSA==,type:str]", + "pgp": null, + "unencrypted_suffix": "_unencrypted", + "version": "3.8.1" + } +} \ No newline at end of file