diff --git a/hosts/glyph/default.nix b/hosts/glyph/default.nix index b4091541..de7358db 100644 --- a/hosts/glyph/default.nix +++ b/hosts/glyph/default.nix @@ -29,6 +29,16 @@ device = "zdata/backup"; fsType = "zfs"; }; + fileSystems."/mnt/documents" = { + device = "zdata/documents"; + fsType = "zfs"; + }; + + users.users.colleen = { + isSystemUser = true; + group = "users"; + description = "Partner's Samba user"; + }; networking.hostName = "glyph"; networking.hostId = "e7bdc076"; # Ensure correct ZFS pool imported diff --git a/hosts/glyph/services/default.nix b/hosts/glyph/services/default.nix index 468d631a..db05bb11 100644 --- a/hosts/glyph/services/default.nix +++ b/hosts/glyph/services/default.nix @@ -20,6 +20,7 @@ ./open-webui.nix ./prometheus.nix ./samba.nix + ./webdav.nix ./torrents.nix ./windmill.nix ]; diff --git a/hosts/glyph/services/samba.nix b/hosts/glyph/services/samba.nix index 7cd7d795..08dd8f3e 100644 --- a/hosts/glyph/services/samba.nix +++ b/hosts/glyph/services/samba.nix @@ -21,6 +21,7 @@ shares = { Archive = mkShare "/mnt/archive" "mu" "users"; Backup = mkShare "/mnt/backup" "mu" "users" // {"fruit:time machine" = "yes";}; + Documents = mkShare "/mnt/documents" "colleen" "users"; Media = mkShare "/mnt/media" config.services.jellyfin.user config.services.jellyfin.group; Notes = mkShare "/var/lib/basic-memory/basic-memory" "basic-memory" "basic-memory"; Torrents = mkShare "/mnt/torrents" config.services.transmission.user config.services.transmission.group; @@ -33,7 +34,7 @@ { global = { "invalid users" = []; - securityType = "user"; + security = "user"; "vfs objects" = "catia fruit streams_xattr"; "fruit:metadata" = "stream"; "fruit:resource" = "file"; @@ -65,11 +66,13 @@ Type = "oneshot"; ExecStart = let defaultUsrGrp = "mu:users"; + colleenUsrGrp = "colleen:users"; jellyfinUsrGrp = with config.services.jellyfin; "${user}:${group}"; transmissionUsrGrp = with config.services.transmission; "${user}:${group}"; in [ "${pkgs.coreutils}/bin/chown -R ${defaultUsrGrp} archive" "${pkgs.coreutils}/bin/chown -R ${defaultUsrGrp} backup" + "${pkgs.coreutils}/bin/chown -R ${colleenUsrGrp} documents" # N.B.: /mnt/media/Music is used by Roon, not Jellyfin "${pkgs.coreutils}/bin/chown -R ${jellyfinUsrGrp} media/Movies media/TV media/Unsorted media/Video" "${pkgs.coreutils}/bin/chown -R ${defaultUsrGrp} media/Music" diff --git a/hosts/glyph/services/webdav.nix b/hosts/glyph/services/webdav.nix new file mode 100644 index 00000000..639f53cf --- /dev/null +++ b/hosts/glyph/services/webdav.nix @@ -0,0 +1,35 @@ +{lib, ...}: { + services.httpd = { + enable = true; + adminAddr = "admin@localhost"; + extraModules = ["dav" "dav_fs" "dav_lock"]; + virtualHosts."docs.zx.dev" = { + listen = [ + { + ip = "*"; + port = 8185; + } + ]; + documentRoot = "/mnt/documents"; + extraConfig = '' + DavLockDB /var/lib/httpd/DavLockDB + + + DAV On + Options Indexes + AllowOverride None + Require all granted + + ''; + }; + }; + + users.users.wwwrun.extraGroups = ["users"]; + + systemd.services.httpd.serviceConfig.ReadWritePaths = ["/mnt/documents"]; + + systemd.tmpfiles.rules = [ + "d /mnt/documents 2775 colleen users -" + "d /var/lib/httpd 0755 wwwrun wwwrun -" + ]; +} diff --git a/hosts/spore/secrets/docs-htpasswd.age b/hosts/spore/secrets/docs-htpasswd.age new file mode 100644 index 00000000..495bdeb1 Binary files /dev/null and b/hosts/spore/secrets/docs-htpasswd.age differ diff --git a/hosts/spore/services/web/default.nix b/hosts/spore/services/web/default.nix index 30a3e777..d40726a3 100644 --- a/hosts/spore/services/web/default.nix +++ b/hosts/spore/services/web/default.nix @@ -12,6 +12,11 @@ ]; age.secrets.cloudflare-dns.file = ../../secrets/cloudflare-dns.age; + age.secrets.docs-htpasswd = { + file = ../../secrets/docs-htpasswd.age; + owner = "nginx"; + mode = "400"; + }; services.nginx = { enable = true; @@ -126,6 +131,28 @@ useACMEHost = "zx.dev"; locations."/".proxyPass = "http://glyph.note-iwato.ts.net:8096"; }; + "docs.zx.dev" = { + forceSSL = true; + useACMEHost = "zx.dev"; + locations."/" = { + proxyPass = "http://glyph.note-iwato.ts.net:8185"; + extraConfig = '' + auth_basic "Documents"; + auth_basic_user_file ${config.age.secrets.docs-htpasswd.path}; + proxy_set_header Authorization ""; + client_max_body_size 0; + proxy_request_buffering off; + + # Rewrite WebDAV Destination header for MOVE/COPY: Finder sends + # https://docs.zx.dev/... but Apache sees itself as http://docs.zx.dev:8185. + set $dav_dest $http_destination; + if ($dav_dest ~ "^https://docs\.zx\.dev(/.*)$") { + set $dav_dest http://docs.zx.dev:8185$1; + } + proxy_set_header Destination $dav_dest; + ''; + }; + }; "music.zx.dev" = { forceSSL = true; useACMEHost = "zx.dev"; diff --git a/lib/secrets/spore.nix b/lib/secrets/spore.nix index 7c414e3b..1a434d9d 100644 --- a/lib/secrets/spore.nix +++ b/lib/secrets/spore.nix @@ -2,6 +2,7 @@ let keys = with (import ../keys.nix); [spore Rhizome]; in { "hosts/spore/secrets/cloudflare-dns.age".publicKeys = keys; + "hosts/spore/secrets/docs-htpasswd.age".publicKeys = keys; "hosts/spore/secrets/homepage-env.age".publicKeys = keys; "hosts/spore/secrets/grafana-client-secret.age".publicKeys = keys; "hosts/spore/secrets/grafana-secret-key.age".publicKeys = keys;