{ modulesPath, tree, config, pkgs, lib, ... }: let secrets-db = (import ./secrets-db.nix { }); ports = (import ./ports.nix { }); in { imports = with tree; [ users.root profiles.base profiles.sshd profiles.nix-gc profiles.nginx ./hardware.nix ./networking.nix ./secrets.nix ]; systemd.tmpfiles.rules = [ "d /storage - root root" "d /caches - storage storage" "d /caches/main_webdav_serve - storage storage" ]; users.groups.storage = { }; users.users.storage = { isNormalUser = true; extraGroups = [ "storage" ]; }; systemd.services.populate-rclone-config = { wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; path = with pkgs; [ bash rclone vault getent jq ]; script = let vault_username = "storage"; vault_password_file = "${secrets-db.vault_password.path}"; config_dir = "/home/storage/.config/rclone"; config_file = "/home/storage/.config/rclone/rclone.conf"; in '' mkdir -p ${config_dir} VAULT_ADDR="https://vault.owo.monster" bash ${ ./populate-rclone-config.sh } ${vault_username} ${vault_password_file} ${ ./rclone_config.template } ${config_file} chown storage:storage ${config_file} chmod 660 ${config_file} ''; }; systemd.services.storage-mount = { wantedBy = [ "multi-user.target" ]; after = [ "network.target" "populate-rclone-config.service" ]; partOf = [ "populate-rclone-config.service" ]; path = with pkgs; [ bash rclone mount umount ]; script = '' set -e umount /storage -fl || true sleep 2 rclone --config /home/storage/.config/rclone/rclone.conf mount StorageBox: /storage --allow-non-empty ''; }; services.rclone-serve = let serviceConfig = { after = [ "populate-rclone-config.service" ]; partOf = [ "populate-rclone-config.service" ]; }; in { enable = true; remotes = [ { user = "storage"; remote = "StorageBox:"; type = "webdav"; extraArgs = [ "--addr=:${toString ports.rclone_serve_webdav_main}" "--htpasswd=${secrets-db.webdav_main_htpasswd.path}" "--baseurl=/main/" "--cache-dir=/caches/main_webdav_serve" "--vfs-cache-mode=full" ]; inherit serviceConfig; } { user = "storage"; remote = "StorageBox:Music"; type = "webdav"; extraArgs = [ "--addr=:${toString ports.rclone_serve_webdav_music_ro}" "--read-only" "--baseurl=/music_ro/" ]; inherit serviceConfig; } { user = "storage"; remote = "StorageBox:Music"; type = "http"; extraArgs = [ "--addr=:${toString ports.rclone_serve_http_music}" "--baseurl=/music/" "--read-only" ]; inherit serviceConfig; } { user = "storage"; remote = "StorageBox:Backups/Restic/HetznerVM"; type = "restic"; extraArgs = [ "--addr=:${toString ports.rclone_serve_restic_hvm}" "--htpasswd=${secrets-db.restic_hetznervm_htpasswd.path}" "--baseurl=/HetznerVM/" ]; inherit serviceConfig; } { user = "storage"; remote = "StorageBox:Backups/Restic/Music"; type = "restic"; extraArgs = [ "--addr=:${toString ports.rclone_serve_restic_music}" "--htpasswd=${secrets-db.restic_music_htpasswd.path}" "--baseurl=/Music/" ]; inherit serviceConfig; } { user = "storage"; remote = "StorageBox:Backups/Restic/Vault"; type = "restic"; extraArgs = [ "--addr=:${toString ports.rclone_serve_restic_vault}" "--htpasswd=${secrets-db.restic_vault_htpasswd.path}" "--baseurl=/Vault/" ]; inherit serviceConfig; } ]; }; networking.firewall.allowedTCPPorts = [ 80 443 ]; services.nginx.virtualHosts."storage-webdav.owo.monster" = { forceSSL = true; enableACME = true; locations = { "/main/".proxyPass = "http://localhost:${toString ports.rclone_serve_webdav_main}"; "/music_ro/".proxyPass = "http://localhost:${toString ports.rclone_serve_webdav_music_ro}"; }; }; services.nginx.virtualHosts."storage-http.owo.monster" = { forceSSL = true; enableACME = true; locations = { "/music/".proxyPass = "http://localhost:${toString ports.rclone_serve_http_music}"; }; }; services.nginx.virtualHosts."storage-restic.owo.monster" = { forceSSL = true; enableACME = true; locations = { "/HetznerVM/".proxyPass = "http://localhost:${toString ports.rclone_serve_restic_hvm}"; "/Music/".proxyPass = "http://localhost:${toString ports.rclone_serve_restic_music}"; "/Vault/".proxyPass = "http://localhost:${toString ports.rclone_serve_restic_vault}"; }; }; services.rclone-sync = let sync_defaults = { serviceConfig = { after = [ "populate-rclone-config.service" ]; }; timerConfig = { OnStartupSec = "60"; OnCalendar = "4h"; }; }; in { enable = true; user = "storage"; sync_jobs = map (x: lib.mkMerge [ x sync_defaults ]) [ # My B2 { source = "StorageBox:Backups"; dest = "B2-Chaos-Backups:"; } { source = "StorageBox:Photos"; dest = "B2-Chaos-Photos:"; } { source = "StorageBox:Music"; dest = "B2-Chaos-Music:"; } # Cassie's B2 { source = "StorageBox:Backups"; dest = "B2-Cassie-Cryptidz-Backup:Backups"; } { source = "StorageBox:Photos"; dest = "B2-Cassie-Cryptidz-Backup:Photos"; } { source = "StorageBox:Music"; dest = "B2-Cassie-Cryptidz-Backup:Music"; } ]; }; environment.systemPackages = with pkgs; [ rclone cifs-utils apacheHttpd restic ]; home-manager.users.root = { imports = with tree; [ home.base home.dev.small ]; home.stateVersion = "22.05"; }; networking.hostName = "storage"; time.timeZone = "Europe/London"; system.stateVersion = "21.11"; }