From e6b4cc86190f691c32858607ed324bc6d3223f34 Mon Sep 17 00:00:00 2001 From: Luka Dekanozishvili Date: Mon, 2 Feb 2026 01:32:58 +0100 Subject: [PATCH] feat: 10min incremental snapshots/backups --- flake.lock | 20 +++++++------- flake.nix | 13 +++++---- pkgs/backend.nix | 2 +- pkgs/postgres.nix | 45 +++++++++---------------------- pkgs/restic.nix | 38 ++++++++++++++++++++++++++ pkgs/zfs.nix | 19 +++++++++++++ scripts/pdns-init-config-dns.sh | 4 +-- services/backup-postgres.nix | 47 +++++++++++++++++++++++++++++++++ services/update-containers.nix | 2 +- 9 files changed, 139 insertions(+), 51 deletions(-) create mode 100644 pkgs/restic.nix create mode 100644 pkgs/zfs.nix create mode 100644 services/backup-postgres.nix diff --git a/flake.lock b/flake.lock index eab850f..0ce05dd 100755 --- a/flake.lock +++ b/flake.lock @@ -48,11 +48,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1769526729, - "narHash": "sha256-/ew2cd+lz9xOkTLsYZLqYKfnOoxqlAhpRR7jAqOUljc=", + "lastModified": 1769949729, + "narHash": "sha256-6JCFnE4qtV/nbwqbAT/ePE6tSNmLYGW31w9xp06X2G8=", "ref": "refs/heads/main", - "rev": "59180721d3b95f28c17eff9e3a18e54b0a1fa588", - "revCount": 23, + "rev": "0ec88131ff6faf182c2bd6a886b91dbff64290ac", + "revCount": 24, "type": "git", "url": "ssh://forgejo@git.lukadeka.com:6968/LukaDeka/HexName-Backend.git" }, @@ -101,11 +101,11 @@ }, "nixpkgs-stable": { "locked": { - "lastModified": 1769598131, - "narHash": "sha256-e7VO/kGLgRMbWtpBqdWl0uFg8Y2XWFMdz0uUJvlML8o=", + "lastModified": 1769741972, + "narHash": "sha256-RxSg1EioTWNpoLaykiT1UQKTo/K0PPdLqCyQgNjNqWs=", "owner": "nixos", "repo": "nixpkgs", - "rev": "fa83fd837f3098e3e678e6cf017b2b36102c7211", + "rev": "63590ac958a8af30ebd52c7a0309d8c52a94dd77", "type": "github" }, "original": { @@ -117,11 +117,11 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1769461804, - "narHash": "sha256-msG8SU5WsBUfVVa/9RPLaymvi5bI8edTavbIq3vRlhI=", + "lastModified": 1769789167, + "narHash": "sha256-kKB3bqYJU5nzYeIROI82Ef9VtTbu4uA3YydSk/Bioa8=", "owner": "nixos", "repo": "nixpkgs", - "rev": "bfc1b8a4574108ceef22f02bafcf6611380c100d", + "rev": "62c8382960464ceb98ea593cb8321a2cf8f9e3e5", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 56726eb..44c933d 100755 --- a/flake.nix +++ b/flake.nix @@ -26,24 +26,27 @@ ./pkgs/powerdns.nix ./pkgs/postgres.nix + ./pkgs/restic.nix # Defines `restic-backups-postgres.service` + ######## Networking ######## ./pkgs/ssh.nix ./pkgs/tailscale.nix ./pkgs/virtualisation.nix - ./pkgs/stalwart.nix + ./pkgs/stalwart.nix # Mailserver ######## Sysadmin ######## ./pkgs/neovim.nix ./pkgs/common-packages.nix ./pkgs/aliases.nix + ######## Services ######## + ./services/backup-postgres.nix # Runs `pg_dump` every 10 mins + ./services/update-containers.nix # Runs podman pull weekly + ./services/restart-powerdns.nix + ######## etc. ######## ./pkgs/extra.nix ./pkgs/zfs.nix - - ######## Scripts ######## - ./services/update-containers.nix # Runs podman pull weekly - ./services/restart-powerdns.nix ]; }; }; diff --git a/pkgs/backend.nix b/pkgs/backend.nix index 27d28f6..218f00c 100644 --- a/pkgs/backend.nix +++ b/pkgs/backend.nix @@ -30,7 +30,7 @@ Group = "hexname"; Type = "simple"; Restart = "always"; - ExecStart = "${pkgs.hexname-backend}/bin/dns-backend"; + ExecStart = "${pkgs.hexname-backend}/bin/hexname-backend"; }; }; } diff --git a/pkgs/postgres.nix b/pkgs/postgres.nix index 9db7af1..04157f6 100644 --- a/pkgs/postgres.nix +++ b/pkgs/postgres.nix @@ -14,43 +14,24 @@ listen_addresses = lib.mkForce "127.0.0.1,100.123.91.36"; }; - # Allow root to log in as postgres in the DB (for the PowerDNS container) - # identMap = '' - # postgres root postgres + # authentication = '' + # host all replication_user 100.112.93.9/32 scram-sha-256 # ''; - authentication = '' - host all replication_user 100.112.93.9/32 scram-sha-256 + authentication = lib.mkForce '' + # TYPE DATABASE USER ADDRESS AUTH-METHOD + + # Allow the replication subscriber to connect from Tailscale IP + host all replication_user 100.112.93.9/32 scram-sha-256 + + host hexname-backend hexname-backend 127.0.0.1/32 scram-sha-256 + host powerdns powerdns 127.0.0.1/32 scram-sha-256 + local all all peer + + # local all postgres peer ''; - # authentication = lib.mkForce '' - # # TYPE DATABASE USER ADDRESS AUTH-METHOD [auth-options] - # # host hexname-backend hexname-backend 127.0.0.1/24 scram-sha-256 - # # host postgres postgres 127.0.0.1/24 scram-sha-256 - # host all all 127.0.0.1/24 scram-sha-256 - # # host all powerdns-user 127.0.0.1/24 scram-sha-256 - # # local all root trust - # ''; - - # This password is only the initial one - don't get too excited initialScript = "/etc/env/hexname/init-db-dns.sql"; - # initialScript = pkgs.writeText "set-initial-password-script" '' - # CREATE USER powerdns WITH PASSWORD 'shuaze-gagyof'; - # CREATE USER hexname_backend WITH PASSWORD 'shuaze-gagyof2' CREATEDB; - # CREATE USER replication_user SUPERUSER WITH PASSWORD 'shuaze-gagyof3'; - - # CREATE DATABASE powerdns OWNER "powerdns"; - # CREATE DATABASE hexname_backend OWNER "hexname-backend"; - # CREATE DATABASE hexname_backend OWNER "hexname-backend"; - - # \c powerdns; - # CREATE PUBLICATION powerdns_pub FOR ALL TABLES; - - # CREATE SUBSCRIPTION hexname_ns2 - # CONNECTION 'host=publisher_ip_address port=5432 user=replication_user password=' ' dbname=powerdns' - # PUBLICATION powerdns_pub; - # ''; - # ALTER USER "postgres" WITH PASSWORD 'shuaze-gagyof'; }; } diff --git a/pkgs/restic.nix b/pkgs/restic.nix new file mode 100644 index 0000000..f5985e3 --- /dev/null +++ b/pkgs/restic.nix @@ -0,0 +1,38 @@ +{ config, ... }: + +{ + # users.groups.hexname-postgres-backup = {}; + # users.users = { + # hexname-postgres-backup = { + # group = "hexname-postgres-backup"; + # isSystemUser = true; + # createHome = true; + # home = "/var/lib/hexname/postgres"; + # }; + # }; + + services.restic.backups = { + postgres = { + paths = [ + # This is where I store the output of `pg_dump`, not the DB itself + "/var/lib/hexname/postgres" + ]; + repository = "sftp:hexname-postgres-backup@ns2.hexname.com:/etc/backups/ns1"; + extraOptions = [ + "sftp.command='ssh -p 6968 hexname-postgres-backup@ns2.hexname.com -i /etc/env/restic/id_ed25519 -s sftp'" + ]; + passwordFile = "/etc/env/restic/gateway-password"; + initialize = true; + + timerConfig = null; # Explicitly invoked by backup-postgres.service + pruneOpts = [ + "--keep-last 36" # 6 hours' worth + "--keep-daily 7" + "--keep-weekly 2" + "--keep-monthly 3" + "--keep-yearly 1" + ]; + }; + }; +} + diff --git a/pkgs/zfs.nix b/pkgs/zfs.nix new file mode 100644 index 0000000..1140849 --- /dev/null +++ b/pkgs/zfs.nix @@ -0,0 +1,19 @@ +{ ... }: + +{ + services.zfs = { + autoSnapshot = { + enable = true; + flags = "-k -p -u"; + + monthly = 6; + weekly = 2; + daily = 7; + hourly = 24; + frequent = 8; + }; + + autoScrub.enable = true; + }; +} + diff --git a/scripts/pdns-init-config-dns.sh b/scripts/pdns-init-config-dns.sh index d5e55b0..34113fd 100755 --- a/scripts/pdns-init-config-dns.sh +++ b/scripts/pdns-init-config-dns.sh @@ -71,11 +71,11 @@ add_record "A" 3600 "mta-sts.hexname.com." "188.245.239.209" add_record "CNAME" 3600 "mail.hexname.com." "mx.hexname.com." add_record "MX" 3600 "hexname.com." "10 mx.hexname.com." +add_record "TXT" 3600 "hexname.com." "\"google-site-verification=yOG8oyjZY9hKDxSNiD730PD9HO-zsQz0xEke49U6lrM\"" +add_record "TXT" 3600 "hexname.com." "\"ahrefs-site-verification_eadd521586ff26f292e19c7a99f7feb5c22420c290ce62b452ce381b2f1b9c16\"" add_record "TXT" 3600 "_mta-sts.hexname.com." "\"v=STSv1; id=20260127182600Z;\"" - add_record "TXT" 3600 "202601e._domainkey.hexname.com." "\"v=DKIM1; k=ed25519; h=sha256; p=C30gZd1CbkUpIGInw/wZgZQD0pmUEnwTp+svCLm1oCk=\"" add_record "TXT" 3600 "202601r._domainkey.hexname.com." "\"v=DKIM1; k=rsa; h=sha256; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnyQRHisJtMpgRCAKAE5mfq63n1hvguiNheRrGWcLjEziA9r3M8oaxM71gDNeDEZj19yXlYBWlZZiPsdkMNsumFaElTt3E810JjZxvWslvRgCQ9qMK6lE4ytJZHXJD1a+g82/j4Pfu3C0iz0GfMvngXf03pDl5jWeScwfSFgvKx/0tRdzCAzwkSZfZaSKCh5bcvVwoxzXqHjz3zxwxDJGlUPoERymd18/7NkdRRfJZoqAo/aHdsh5JsYa8APtNIHjSjp2vUBPQnNrtx9+lI0qRnwdyrim8v8CRKin+QUW0sstWGuyqZxgxOGXO2Ek2fqTrpzVu2fu6pzGqJdbTVf5BQIDAQAB\"" - add_record "TXT" 3600 "mx.hexname.com." "\"v=spf1 a ra=spf-reports -all\"" add_record "TXT" 3600 "hexname.com." "\"v=spf1 mx ra=spf-reports -all\"" add_record "TXT" 3600 "_dmarc.hexname.com." "\"v=DMARC1; p=reject; rua=mailto:dmarc-reports@hexname.com; ruf=mailto:dmarc-reports@hexname.com\"" diff --git a/services/backup-postgres.nix b/services/backup-postgres.nix new file mode 100644 index 0000000..9a01bef --- /dev/null +++ b/services/backup-postgres.nix @@ -0,0 +1,47 @@ +{ config, pkgs, ... }: + +let + serviceName = "backup-postgres"; +in +{ + environment.systemPackages = [ + pkgs.restic + ]; + + systemd.timers."${serviceName}" = { + wantedBy = [ "timers.target" ]; + timerConfig = { + OnBootSec = "10m"; + OnUnitActiveSec = "10m"; + Unit = "${serviceName}.service"; + }; + }; + systemd.services."${serviceName}"= { + script = '' + set -euo pipefail + + cd /var/lib/hexname/postgres + ${config.services.postgresql.package}/bin/pg_dumpall \ + --exclude-database=roundcube \ + --exclude-database=template0 \ + --exclude-database=template1 \ + --exclude-database=postgres \ + --clean \ + --file ./postgres.out + ''; + wants = [ "restic-backups-postgres.service" ]; + serviceConfig = { + Type = "oneshot"; + User = "postgres"; + Group = "postgres"; + RemainAfterExit = true; # Don't start the service on every rebuild + }; + }; + + # Overwrite the restic backup service so that it's triggered after `pg_dump` + systemd.services.restic-backups-postgres = { + after = [ "backup-postgres.service" ]; + # requires = [ "backup-postgres.service" ]; + }; +} + diff --git a/services/update-containers.nix b/services/update-containers.nix index cb90696..528aed7 100644 --- a/services/update-containers.nix +++ b/services/update-containers.nix @@ -1,4 +1,4 @@ -{ pkgs, lib, ... }: +{ lib, pkgs, ... }: { systemd.timers.update-containers = {