From 47b2436ab03c0af751e73d684d065c80b49208b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leon=20Schwarz=C3=A4ugl?= Date: Sat, 8 Nov 2025 03:38:04 +0100 Subject: [PATCH] feat[server]: add garage --- hosts/nixos/winters/default.nix | 9 +++ modules/nixos/server/garage.nix | 101 ++++++++++++++++++++++++++++++++ secrets/winters/secrets2.yaml | 9 ++- 3 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 modules/nixos/server/garage.nix diff --git a/hosts/nixos/winters/default.nix b/hosts/nixos/winters/default.nix index 98d3bc5..cbe391e 100644 --- a/hosts/nixos/winters/default.nix +++ b/hosts/nixos/winters/default.nix @@ -29,6 +29,14 @@ isBtrfs = false; isLinux = true; isNixos = true; + server.garage = { + data_dir = [ + { + capacity = "200G"; + path = "/Vault/data/garage/main"; + } + ]; + }; }; } // lib.optionalAttrs (!minimal) { @@ -67,6 +75,7 @@ # snipeit = lib.mkDefault false; homebox = lib.mkDefault true; opkssh = lib.mkDefault true; + garage = lib.mkDefault false; }; } diff --git a/modules/nixos/server/garage.nix b/modules/nixos/server/garage.nix new file mode 100644 index 0000000..5ac3673 --- /dev/null +++ b/modules/nixos/server/garage.nix @@ -0,0 +1,101 @@ +{ self, lib, pkgs, config, configName, globals, ... }: +let + sopsFile = self + /secrets/${configName}/secrets2.yaml; + + serviceName = "garage"; + servicePort = 3900; + serviceDomain = config.repo.secrets.common.services.domains."${serviceName}-${configName}"; + serviceAddress = globals.hosts.${configName}.ipv4; + + cfg = config.services.${serviceName}; + metadata_dir = "/var/lib/garage/meta"; +in +{ + options = { + swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; + swarselsystems.server.${serviceName} = { + data_dir = lib.mkOption { + type = lib.types.either lib.types.path (lib.types.listOf lib.types.attrs); + default = "/var/lib/garage/data"; + }; + }; + }; + config = lib.mkIf config.swarselmodules.server.${serviceName} { + + sops = { + secrets.garage-admin-token = { inherit sopsFile; }; + secrets.garage-rpc-secret = { inherit sopsFile; }; + }; + + environment = { + persistence."/persist".directories = lib.mkIf config.swarselsystems.isImpermanence [ + { directory = metadata_dir; } + ]; + systemPackages = [ + cfg.package + ]; + }; + + systemd.services.${serviceName}.serviceConfig = { + DynamicUser = false; + ProtectHome = lib.mkForce false; + }; + + services.${serviceName} = { + enable = true; + package = pkgs.garage_2; + settings = { + inherit (config.swarselsystems.${serviceName}) data_dir; + inherit metadata_dir; + db_engine = "lmdb"; + block_size = "1MiB"; + use_local_tz = false; + + replication_factor = 2; # Number of copies of data + + rpc_bind_addr = "[::]:3901"; + rpc_public_addr = "${config.repo.secrets.local.ipv4}:4317"; + rpc_secret_file = config.sops.secrets.garage-rpc-secret.path; + + s3_api = { + s3_region = "swarsel"; + api_bind_addr = "0.0.0.0:${builtins.toString servicePort}"; + root_domain = ".s3.garage.localhost"; + }; + + admin = { + api_bind_addr = "0.0.0.0:3903"; + admin_token_file = config.sops.secrets.garage-admin-token.path; + }; + + k2v_api = { + api_bind_addr = "[::]:3904"; + }; + }; + }; + + nodes.moonside.services.nginx = { + upstreams = { + ${serviceName} = { + servers = { + "${serviceAddress}:${builtins.toString servicePort}" = { }; + }; + }; + }; + virtualHosts = { + "${serviceDomain}" = { + enableACME = true; + forceSSL = true; + acmeRoot = null; + oauth2.enable = false; + locations = { + "/" = { + proxyPass = "http://${serviceName}"; + }; + }; + }; + }; + }; + + }; +} diff --git a/secrets/winters/secrets2.yaml b/secrets/winters/secrets2.yaml index 18deb9d..00ea63e 100644 --- a/secrets/winters/secrets2.yaml +++ b/secrets/winters/secrets2.yaml @@ -4,6 +4,9 @@ radicale-user: ENC[AES256_GCM,data:2G+WXxw6jrnPXsI=,iv:bUEhBDrdTt+O/4TXMkhmqnzfk prometheus-admin-hash: ENC[AES256_GCM,data:dUmTW6W419TzF8dLGcgRLlbLBg9puzgznNCrrAuNOIuhXCBrqaJdtyIVFCsnrDSEh1ZdMfGki4UERZcf,iv:XIlb65V6yhrKSU7AbRs6k1ISljZjWnAm1dPTCONwDJI=,tag:UkdDTywivitSxYR902uM5A==,type:str] snipe-it-appkey: ENC[AES256_GCM,data:VWEGKbCD5P3uxeyMVtK9a7BcVjXlXSEsJxfLEwkHz8l5o0Xq9lTbTpsfOoc=,iv:3nq+xuuujjevWdmk3SdBai/EWXwL4F3Kv4M3yc/faIM=,tag:/cNC/EKR1NWQhJrh46meCw==,type:str] snipe-it-db-password: ENC[AES256_GCM,data:O+LgX+XyJEaF+1oYcjyMpUab7AD7tWK3LBd+7VJOKq/Mz+k=,iv:yJgwlG/ln5BdwW2c62UJLIkrCWakKvj64LMQsjTIwJI=,tag:yw0rC1GJo+KMn1wXRdJomA==,type:str] +#ENC[AES256_GCM,data:jGvWDKbVKA==,iv:N4cMopsUPOfymKpMD7oB04VtS0cUX9yNNqwyWEdyMi4=,tag:L4PMmMcM1NCc8LPG6GJLMQ==,type:comment] +garage-admin-token: ENC[AES256_GCM,data:2N2kqXt7kraqMQEkDuNQN3SRiL2WKRA959Uc7HAdSlZcC2Ft06YUb+Elktw=,iv:dhAZoQBhvK07+wBpMEsI73YN2oX9dMthV3SaDWZgea4=,tag:0Pu0BDEYU9WYQQ1hJr8qFQ==,type:str] +garage-rpc-secret: ENC[AES256_GCM,data:s8qGCm8WM/pvX7wZJyenohMAHnNWrumUxyJvst194h2XPfpLBbKVZwZ5t4zkwqh0yJNgLqE+2ekwCxa/xKqemQ==,iv:zUo/x2LWS7b2E2kZHDfa6lAwxAcuNir5a+mg+ASDarE=,tag:XgBh3ajVDy0vWccX8yZXSg==,type:str] sops: age: - recipient: age1h72072slm2pthn9m2qwjsyy2dsazc6hz97kpzh4gksvv0r2jqecqul8w63 @@ -15,8 +18,8 @@ sops: ZWxwbGs1bTNzdXVNSzhpNWVESGJlUzQKzZr3cYBF6s5ihgW/6CreOKWvQpqITrFX pW6gwbRbxaxDPRRdfn8qswcezxq5AwOk9drbOH+qgcwL2owRGxEhcQ== -----END AGE ENCRYPTED FILE----- - lastmodified: "2025-08-24T13:27:33Z" - mac: ENC[AES256_GCM,data:1Eqt/uwVuGlihw04FMxrRDDSHMkEqeueEz3yFFpFcKCnOa2VAE2dlTr3a72NPHgLHGnKZvEwJBDq7kwxvB9vtE4360AdfCMd7tpoLCzO9W475nSsYk2En1uQIuZDwuPEg0DHF8+qeBfPerky2mLE7vM/zLdlJQGVRI/0+scLPVo=,iv:8A72UAeUdIZOZtwj5NK+SulnCqAUhe0CsLXLUubmGs4=,tag:sg5vntLuvL9Jx2J33soE9Q==,type:str] + lastmodified: "2025-11-05T14:55:44Z" + mac: ENC[AES256_GCM,data:nyz3jp/qV8bwgx0q6c7RmXtzdmwVrt8C6FU36qtzUm8tPlAd1K7MmgxRKFi85NqOu3XPII2OkwhNPRBOJuQOoXGfo27odfZl4riQ+any4GNarDZ5deZ54+kjgqyvP70dsm/tiZgZ8Fjwat4iLV+mqJYMS4OBl5krr5ocU+LY1pU=,iv:l56tIBgMog4HSxP9Fb4pWSD/z5FaPlHRkUYqlkhydzc=,tag:IT++kT0EncDzEEX4DdjW3g==,type:str] pgp: - created_at: "2025-06-28T23:22:37Z" enc: |- @@ -50,4 +53,4 @@ sops: -----END PGP MESSAGE----- fp: 4BE7925262289B476DBBC17B76FD3810215AE097 unencrypted_suffix: _unencrypted - version: 3.10.2 + version: 3.11.0