diff --git a/machines/deedee/configuration.nix b/machines/deedee/configuration.nix index 10021c6..57dead7 100644 --- a/machines/deedee/configuration.nix +++ b/machines/deedee/configuration.nix @@ -214,6 +214,13 @@ rec { enable = true; }; coredns.enable = true; + davis = { + enable = true; + carddavEnable = true; + caldavEnable = false; + webdavEnable = false; + useAuthelia = true; + }; echo-server.enable = false; firefoxsync.enable = true; firefly-iii.enable = true; diff --git a/machines/deedee/secrets.sops.yaml b/machines/deedee/secrets.sops.yaml index b364bb2..aa4f34c 100644 --- a/machines/deedee/secrets.sops.yaml +++ b/machines/deedee/secrets.sops.yaml @@ -39,6 +39,8 @@ system: bazarr: env: BAZARR__API_KEY: ENC[AES256_GCM,data:VX8vZcRO9Lrp+aLMz0bxYsXdlvbxwlwWwj8nY89UZgU=,iv:sVokTihff9vZv3LmDx8vDrZNClud3TUYwH2jZmuuKQg=,tag:K7TbxLgUOGd2s8XvG91VaQ==,type:str] + davis: + envfile: ENC[AES256_GCM,data:YRpZ8AqVFywpq4PhQEfuOuXiB8XujinaOMkJnoqiELilOmeiQ+DsE0M1fpDnGBDB+gg=,iv:qGlElLcLlfoX37ro1MEMrc6HXMPXjHcW3jpOnwY3frQ=,tag:gl9wSSyNKeaTKwZA8By70A==,type:str] ddclient: cloudflare_token: ENC[AES256_GCM,data:edAKKffA/uyxHfVCE5pnk8KFcuzAbWZaqvHMgfykZPmrlezxJFFZBw==,iv:RgwmTIu3szeB58O4fzEmIR3BGY2CbaAGFTdVewTDJtU=,tag:SA1aqxUv5B1Jv7rmblqrEw==,type:str] firefly-iii: @@ -203,8 +205,8 @@ sops: c3FoaFNzbjJubzlBckdDb2lNOUZtOGMKRbHxa1B3QAdredBMTd7W7g3kRz6l8uyV bBclsA8Gm7p+6ndV39sN+Daqm5MyggY1Prwv/Ukdd5Q+1C+XsEW6OQ== -----END AGE ENCRYPTED FILE----- - lastmodified: "2024-12-02T17:27:46Z" - mac: ENC[AES256_GCM,data:S1fZmHQUCNuR2tlsIFzKAhOBaIXD85izYEC1QbSiGkxGJkFivEBcJEPjltPfssUwSvcvRTGxcqr30CZWnTDnfF1qxd+BWVppDM842WFyIogug5QrX5zXoZX3dRf2jGebNNPsWbFrZJ0QfB1xTvFGzHETcQvuPlk5M5mNg5TcxEg=,iv:rAdseyddpdnxK9xHMm14CFGA8pmxpjGSETMc/CVG20I=,tag:fph89x+ZmkauvKO1dzPdYg==,type:str] + lastmodified: "2024-12-19T19:10:29Z" + mac: ENC[AES256_GCM,data:4fQZGlP1tUHTfgJ5P3cSykr9JYNNgFkiZRZXI87AxSKswuewdrJXhHE7BowE/4MLi5QPFfj22z6By+csQVIKqmrRhxCO84vs7Nu4aZ/pcwIX843BEZPTL3BZdY77KXmM/N2Ar8xpZc+JvMp3ZcViYfBw0Bvf7+2vz157XMidsEA=,iv:28v3Kk0PboZSMcfzMrEDB6j1guOOwqPrmxtHdHzNFBE=,tag:bXA8tCHBKUyfyGcPxbVZ1Q==,type:str] pgp: [] unencrypted_suffix: _unencrypted - version: 3.9.1 + version: 3.9.2 diff --git a/modules/system/containers/caddy/default.nix b/modules/system/containers/caddy/default.nix new file mode 100644 index 0000000..ec9d762 --- /dev/null +++ b/modules/system/containers/caddy/default.nix @@ -0,0 +1,90 @@ +{ + config, + lib, + pkgs, + svc, + ... +}: +let + cfg = config.mySystemApps.caddy; +in +{ + options.mySystemApps.caddy = { + enable = lib.mkEnableOption "caddy container"; + dependsOn = lib.mkOption { + type = lib.types.listOf lib.types.str; + description = "List of containers caddy will depend on."; + default = [ ]; + }; + vhosts = lib.mkOption { + type = lib.types.attrsOf lib.types.lines; + description = "Caddy configurations per vhost"; + default = { }; + example = { + "test.example.com" = '' + log + root * /var/www/test + ''; + }; + }; + mounts = lib.mkOption { + type = lib.types.listOf lib.types.str; + description = "List of extra mounts in caddy container, in docker format."; + default = [ ]; + example = [ + "/my/host/path:/var/www/test" + ]; + }; + }; + + config = + let + caddyfile = pkgs.writeText "Caddyfile" ( + '' + { + log { + level info + output stderr + format console + } + http_port 8080 + https_port 8443 + servers { + trusted_proxies static 172.16.0.0/12 + trusted_proxies_strict + } + } + '' + + (builtins.concatStringsSep "\n" ( + builtins.map (vhost: '' + ${vhost}:8080 { + ${builtins.getAttr vhost cfg.vhosts} + } + '') (builtins.attrNames cfg.vhosts) + )) + ); + in + lib.mkIf cfg.enable { + virtualisation.oci-containers.containers.caddy = svc.mkContainer { + cfg = { + inherit (cfg) dependsOn; + + image = "public.ecr.aws/docker/library/caddy:2.8.4@sha256:d17c155b627f4ae14cef9cb4143b63c529a8497966b62febcde79f4ecc3857f7"; + volumes = [ "${caddyfile}:/config/Caddyfile" ] ++ cfg.mounts; + cmd = [ + "caddy" + "run" + "--config" + "/config/Caddyfile" + ]; + extraOptions = [ + "--cap-add=CAP_NET_BIND_SERVICE" + "--mount" + "type=tmpfs,destination=/config/caddy,tmpfs-mode=1777" + "--mount" + "type=tmpfs,destination=/data/caddy,tmpfs-mode=1777" + ]; + }; + }; + }; +} diff --git a/modules/system/containers/davis/default.nix b/modules/system/containers/davis/default.nix new file mode 100644 index 0000000..a8f58a7 --- /dev/null +++ b/modules/system/containers/davis/default.nix @@ -0,0 +1,148 @@ +{ + config, + lib, + pkgs, + svc, + ... +}: +let + cfg = config.mySystemApps.davis; +in +{ + options.mySystemApps.davis = { + enable = lib.mkEnableOption "davis container"; + caldavEnable = lib.mkEnableOption "CalDAV" // { + default = true; + }; + carddavEnable = lib.mkEnableOption "CardDAV" // { + default = true; + }; + webdavEnable = lib.mkEnableOption "WebDAV"; + useAuthelia = lib.mkEnableOption "authelia"; + backup = lib.mkEnableOption "data backup" // { + default = true; + }; + dataDir = lib.mkOption { + type = lib.types.str; + description = "Path to directory containing data."; + default = "/var/lib/davis"; + }; + envFileSopsSecret = lib.mkOption { + type = lib.types.str; + description = "Sops secret name containing redlib envs."; + default = "system/apps/davis/envfile"; + }; + }; + + config = + let + image = "ghcr.io/tchapi/davis:5.0.2@sha256:02f9abdbd4f921b9a3ae27ff2df63ab171bbc27d01fb3ab7eb592ead367f8e06"; + in + lib.mkIf cfg.enable { + warnings = [ (lib.mkIf (!cfg.backup) "WARNING: Backups for davis are disabled!") ]; + + sops.secrets."${cfg.envFileSopsSecret}" = { }; + + mySystemApps.caddy = { + enable = true; + dependsOn = [ "davis" ]; + vhosts."davis.${config.mySystem.rootDomain}" = '' + log + header -Server + header -X-Powered-By + redir /.well-known/carddav /dav/ 301 + redir /.well-known/caldav /dav/ 301 + root * /var/www/davis/public + encode zstd gzip + php_fastcgi davis:9000 { + trusted_proxies 172.16.0.0/12 + } + file_server { + hide .git .gitignore + } + ''; + mounts = [ "/var/cache/davis/web/public:/var/www/davis/public" ]; + }; + + virtualisation.oci-containers.containers.davis = svc.mkContainer { + cfg = { + inherit image; + + user = "82:82"; + dependsOn = [ "lldap" ]; + environment = { + ADMIN_AUTH_BYPASS = if cfg.useAuthelia then "true" else "false"; + APP_ENV = "prod"; + APP_TIMEZONE = "${config.mySystem.time.timeZone}"; + AUTH_METHOD = "LDAP"; + CALDAV_ENABLED = if cfg.caldavEnable then "true" else "false"; + CARDDAV_ENABLED = if cfg.carddavEnable then "true" else "false"; + DATABASE_DRIVER = "sqlite"; + DATABASE_URL = "sqlite:////config/davis-database.db"; + INVITE_FROM_ADDRESS = "${config.mySystem.notificationSender}"; + LDAP_AUTH_URL = "ldap://lldap:3890"; + LDAP_AUTH_USER_AUTOCREATE = "true"; + LDAP_DN_PATTERN = "uid=%U,ou=people,${config.mySystemApps.lldap.baseDN}"; + LDAP_MAIL_ATTRIBUTE = "mail"; + MAILER_DSN = "smtp://maddy:25"; + TRUSTED_HOSTS = "davis.${config.mySystem.rootDomain}"; + TRUSTED_PROXIES = "172.16.0.0/16"; + WEBDAV_ENABLED = if cfg.webdavEnable then "true" else "false"; + WEBDAV_HOMES_DIR = ""; + WEBDAV_PUBLIC_DIR = "/data"; + WEBDAV_TMP_DIR = "/tmp/webdav"; + }; + environmentFiles = [ config.sops.secrets."${cfg.envFileSopsSecret}".path ]; + volumes = [ + "${cfg.dataDir}/config:/config" + "${cfg.dataDir}/data:/data" + "/var/cache/davis/web/public:/var/www/davis/public" + ]; + }; + }; + + services = { + nginx.virtualHosts.davis = svc.mkNginxVHost { + inherit (cfg) useAuthelia; + + host = "davis"; + proxyPass = "http://caddy.docker:8080"; + autheliaIgnorePaths = [ + "/dav" + "/.well-known" + ]; + }; + restic.backups = lib.mkIf cfg.backup ( + svc.mkRestic { + name = "davis"; + paths = [ cfg.dataDir ]; + } + ); + }; + + systemd.services.docker-davis = { + preStart = + let + dockerBin = lib.getExe pkgs."${config.virtualisation.oci-containers.backend}"; + in + lib.mkAfter '' + rm -rf /var/cache/davis/web || true + mkdir -p "${cfg.dataDir}/config" "${cfg.dataDir}/data" /var/cache/davis/web + chown 82:82 "${cfg.dataDir}/config" "${cfg.dataDir}/data" /var/cache/davis/web + ${dockerBin} run --rm -v /var/cache/davis/web:/web ${image} /bin/sh -c "cp -a /var/www/davis/public /web" + ${lib.getExe pkgs.gnused} -i 's@HEADER_X_FORWARDED_ALL@HEADER_X_FORWARDED_FOR@g' /var/cache/davis/web/public/index.php + ''; + }; + + environment.persistence."${config.mySystem.impermanence.persistPath}" = + lib.mkIf config.mySystem.impermanence.enable + { directories = [ cfg.dataDir ]; }; + + mySystemApps.homepage = { + services.Apps.Davis = svc.mkHomepage "davis" // { + icon = "davis.png"; + description = "CardDAV, CalDAV and WebDAV"; + }; + }; + }; +} diff --git a/modules/system/containers/default.nix b/modules/system/containers/default.nix index 8b46c00..cae637e 100644 --- a/modules/system/containers/default.nix +++ b/modules/system/containers/default.nix @@ -3,8 +3,10 @@ _: { ./audiobookshelf ./authelia ./bazarr + ./caddy ./coredns ./echo-server + ./davis ./firefly-iii ./firefoxsync ./flaresolverr diff --git a/modules/system/containers/immich/album-creator.nix b/modules/system/containers/immich/album-creator.nix index a5cc0d8..b53df28 100644 --- a/modules/system/containers/immich/album-creator.nix +++ b/modules/system/containers/immich/album-creator.nix @@ -31,7 +31,7 @@ in -e ROOT_PATH=/external \ -e SYNC_MODE=1 \ -e UNATTENDED=1 \ - -e TZ=Europe/Warsaw \ + -e TZ=${config.mySystem.time.timeZone} \ --mount type=tmpfs,destination=/tmp,tmpfs-mode=1777 \ -v ${cfg.photosPath}:/external:ro \ --read-only \ diff --git a/modules/system/containers/recyclarr/default.nix b/modules/system/containers/recyclarr/default.nix index 502596c..dec6185 100644 --- a/modules/system/containers/recyclarr/default.nix +++ b/modules/system/containers/recyclarr/default.nix @@ -45,7 +45,7 @@ in --log-driver=journald \ -e RADARR_API_KEY=$(cat ${config.sops.secrets."${cfg.radarrApiKeySopsSecret}".path}) \ -e SONARR_API_KEY=$(cat ${config.sops.secrets."${cfg.sonarrApiKeySopsSecret}".path}) \ - -e TZ=Europe/Warsaw \ + -e TZ=${config.mySystem.time.timeZone} \ -v ${./recyclarr.yml}:/config/recyclarr.yml:ro \ --read-only \ '--cap-drop=all' \