diff --git a/modules/services/frigate.nix b/modules/services/frigate.nix index 5825914..6c5c52d 100644 --- a/modules/services/frigate.nix +++ b/modules/services/frigate.nix @@ -3,15 +3,16 @@ with lib; let + frigateVersion = "0.16.4"; helper = import ./lib.nix { inherit config pkgs lib; }; cfg = config.numbus.services.frigate; in helper.mkPodmanService { - name = "frigate"; description = "Frigate, your fully-local NVR (Network Video Recorder)"; - defaultPort = "8971"; + name = "frigate"; pod = "home-assistant"; + defaultPort = "8971"; scheme = "https"; dependencies = [ "traefik.service" "${config.numbus.services.dns}.service" "home-assistant.service" ]; @@ -27,7 +28,7 @@ helper.mkPodmanService { composeText = '' services: frigate: - image: ghcr.io/blakeblackshear/frigate:stable + image: ghcr.io/blakeblackshear/frigate:${frigateVersion} container_name: frigate hostname: frigate shm_size: "256mb" @@ -50,8 +51,12 @@ ${lib.optionalString (cfg.devices != []) '' devices: ${lib.concatStringsSep "\n" (map (d: " - \"${d}\"") cfg.devices)} ''} + security_opt: + - no-new-privileges:true + cap_drop: + - NET_RAW + stop_grace_period: 30s restart: unless-stopped - networks: home-assistant: external: true diff --git a/modules/services/gitea.nix b/modules/services/gitea.nix index 673aaf1..ec8c6d1 100644 --- a/modules/services/gitea.nix +++ b/modules/services/gitea.nix @@ -3,29 +3,32 @@ with lib; let + giteaVersion = "1.25.4-rootless"; + databaseVersion = "18-alpine"; helper = import ./lib.nix { inherit config pkgs lib; }; cfg = config.numbus.services.gitea; in helper.mkPodmanService { - name = "gitea"; description = "Gitea, your own self-hosted git platform"; - defaultPort = "3000"; + name = "gitea"; pod = "gitea"; + defaultPort = "3000"; composeText = '' services: gitea-server: - image: docker.gitea.com/gitea:latest-rootless + image: docker.gitea.com/gitea:${giteaVersion} container_name: gitea-server hostname: gitea-server + user: '1000:1000' networks: gitea: ports: - "${cfg.port}:3000/tcp" volumes: - - ${cfg.dataDir}:/var/lib/gitea - - ${cfg.configDir}:/etc/gitea + - ${cfg.configDir}/data:/var/lib/gitea + - ${cfg.configDir}/config:/etc/gitea - /etc/localtime:/etc/localtime:ro environment: - GITEA__database__DB_TYPE=postgres @@ -37,22 +40,32 @@ helper.mkPodmanService { - GITEA__server__ROOT_URL=${cfg.subdomain}.${config.numbus.services.domain} depends_on: - gitea-database + security_opt: + - no-new-privileges:true + cap_drop: + - NET_RAW restart: unless-stopped gitea-database: - image: docker.io/library/postgres:14 + image: docker.io/library/postgres:${databaseVersion} container_name: gitea-database hostname: gitea-database + user: '999:999' networks: gitea: volumes: - - gitea_database:/var/lib/postgresql/data + - ${cfg.configDir}/database:/var/lib/postgresql environment: - POSTGRES_USER=$DB_USERNAME - POSTGRES_PASSWORD=$DB_PASSWORD - POSTGRES_DB=$DB_NAME + security_opt: + - no-new-privileges:true + cap_drop: + - NET_RAW restart: unless-stopped volumes: gitea_database: + name: gitea_database networks: gitea: name: gitea diff --git a/modules/services/home-assistant.nix b/modules/services/home-assistant.nix index 37f65d7..da17850 100644 --- a/modules/services/home-assistant.nix +++ b/modules/services/home-assistant.nix @@ -3,15 +3,17 @@ with lib; let + homeAssistantVersion = "2026.2.3"; + mqttVersion = "2.1-alpine"; helper = import ./lib.nix { inherit config pkgs lib; }; cfg = config.numbus.services.home-assistant; in helper.mkPodmanService { - name = "home-assistant"; description = "Home Assistant, libre house control and much more"; - defaultPort = "8123"; + name = "home-assistant"; pod = "home-assistant"; + defaultPort = "8123"; dataDir = false; extraOptions = { @@ -23,14 +25,11 @@ helper.mkPodmanService { }; }; - extraConfig = { - - }; - +# Compose file good composeText = '' services: home-assistant: - image: ghcr.io/home-assistant/home-assistant:latest + image: ghcr.io/home-assistant/home-assistant:${homeAssistantVersion} container_name: home-assistant hostname: home-assistant networks: @@ -38,26 +37,35 @@ helper.mkPodmanService { ports: - "${cfg.port}:8123/tcp" volumes: - - ${cfg.configDir}:/config + - ${cfg.configDir}/config:/config - /etc/localtime:/etc/localtime:ro - /run/dbus:/run/dbus:ro ${lib.optionalString (cfg.devices != []) '' devices: ${lib.concatStringsSep "\n" (map (d: " - \"${d}\"") cfg.devices)} ''} + security_opt: + - no-new-privileges:true + cap_drop: + - NET_RAW restart: unless-stopped home-assistant-mqtt: - image: docker.io/library/eclipse-mosquitto:latest + image: docker.io/library/eclipse-mosquitto:${mqttVersion} container_name: home-assistant-mqtt hostname: home-assistant-mqtt + user: '1000:1000' networks: home-assistant: volumes: - - /mnt/config/mosquitto:/mosquitto + - ${cfg.configDir}/mqtt:/mosquitto + security_opt: + - no-new-privileges:true + cap_drop: + - NET_RAW restart: unless-stopped networks: home-assistant: name: home-assistant driver: bridge ''; -} \ No newline at end of file +} diff --git a/modules/services/immich.nix b/modules/services/immich.nix index addf681..d254ba6 100644 --- a/modules/services/immich.nix +++ b/modules/services/immich.nix @@ -3,29 +3,33 @@ with lib; let + immichVersion = "v2.5.6"; + redisVersion = "9@sha256:546304417feac0874c3dd576e0952c6bb8f06bb4093ea0c9ca303c73cf458f63"; + databaseVersion = "14-vectorchord0.4.3-pgvectors0.2.0@sha256:bcf63357191b76a916ae5eb93464d65c07511da41e3bf7a8416db519b40b1c23"; helper = import ./lib.nix { inherit config pkgs lib; }; cfg = config.numbus.services.immich; in helper.mkPodmanService { - name = "immich"; description = "Immich, Google Photos but better"; - defaultPort = "2283"; + name = "immich"; pod = "immich"; + defaultPort = "2283"; +# Compose file good composeText = '' services: immich-server: - image: ghcr.io/immich-app/immich-server:latest container_name: immich-server hostname: immich-server + image: ghcr.io/immich-app/immich-server:${immichVersion} user: '1000:1000' networks: immich: ports: - "${cfg.port}:2283/tcp" volumes: - - ${cfg.dataDir}:/data + - $UPLOAD_LOCATION:/data - /etc/localtime:/etc/localtime:ro env_file: - .env @@ -40,14 +44,16 @@ helper.mkPodmanService { - NET_RAW restart: unless-stopped immich-machine-learning: - image: ghcr.io/immich-app/immich-machine-learning:latest container_name: immich-machine-learning hostname: immich-machine-learning + image: ghcr.io/immich-app/immich-machine-learning:${immichVersion} user: '1000:1000' networks: immich: volumes: - - ${cfg.configDir}/machine-learning:/cache + - ${cfg.configDir}/model-cache:/cache + - ${cfg.configDir}/machine-learning-config:/usr/src/.config + - ${cfg.configDir}/machine-learning-cache:/usr/src/.cache/ env_file: - .env healthcheck: @@ -58,34 +64,30 @@ helper.mkPodmanService { - NET_RAW restart: unless-stopped immich-redis: - image: docker.io/valkey/valkey:8-bookworm container_name: immich-redis hostname: immich-redis + image: docker.io/valkey/valkey:${redisVersion} user: '1000:1000' networks: immich: healthcheck: test: redis-cli ping || exit 1 - security_opt: - - no-new-privileges:true - cap_drop: - - NET_RAW restart: unless-stopped immich-database: - image: ghcr.io/immich-app/postgres:14 container_name: immich-database hostname: immich-database - user: '1000:1000' + image: ghcr.io/immich-app/postgres:${databaseVersion} + user: '999:999' networks: immich: - shm_size: 128mb - volumes: - - ${cfg.configDir}/database:/var/lib/postgresql/data environment: POSTGRES_PASSWORD: $DB_PASSWORD POSTGRES_USER: $DB_USERNAME POSTGRES_DB: $DB_DATABASE_NAME POSTGRES_INITDB_ARGS: '--data-checksums' + volumes: + - $DB_DATA_LOCATION:/var/lib/postgresql/data + shm_size: 128mb healthcheck: disable: false security_opt: diff --git a/modules/services/it-tools.nix b/modules/services/it-tools.nix index 815896e..530ce07 100644 --- a/modules/services/it-tools.nix +++ b/modules/services/it-tools.nix @@ -3,22 +3,24 @@ with lib; let + it-toolsVersion = "2024.10.22-7ca5933"; helper = import ./lib.nix { inherit config pkgs lib; }; cfg = config.numbus.services.it-tools; in helper.mkPodmanService { - name = "it-tools"; description = "IT-tools, useful tools when doing IT"; - defaultPort = "8880"; + name = "it-tools"; pod = "false"; + defaultPort = "8880"; configDir = false; dataDir = false; +# Compose file good composeText = '' services: it-tools: - image: docker.io/corentinth/it-tools:latest + image: docker.io/corentinth/it-tools:${it-toolsVersion} container_name: it-tools hostname: it-tools networks: @@ -26,7 +28,6 @@ helper.mkPodmanService { ports: - "${cfg.port}:80/tcp" restart: unless-stopped - networks: it-tools: name: it-tools diff --git a/modules/services/lib.nix b/modules/services/lib.nix index 53c9e85..3333f71 100644 --- a/modules/services/lib.nix +++ b/modules/services/lib.nix @@ -4,129 +4,146 @@ with lib; { mkPodmanService = { - name, description, - defaultPort ? "0", + name, + secondName ? null, + thirdName ? null, defaultSubdomain ? name, - pod ? name, - reverseProxied ? true, - composeFile ? "podman/${name}/compose.yaml", - composeText, + secondDefaultSubdomain ? secondName, + thirdDefaultSubdomain ? thirdName, + defaultPort ? "", + secondDefaultPort ? "", + thirdDefaultPort ? "", scheme ? "http", - middlewares ? [ "secureHeaders" ], - dependencies ? [ "traefik.service" "${config.numbus.services.dns}.service" ], + secondScheme ? "http", + thirdScheme ? "http", + reverseProxied ? true, + secondReverseProxied ? false, + thirdReverseProxied ? false, + configDirEnabled ? true, + secondConfigDirEnabled ? false, + thirdConfigDirEnabled ? false, + dataDirEnabled ? true, + secondDataDirEnabled ? false, + thirdDataDirEnabled ? false, + pod ? "false", + composeText, extraOptions ? {}, extraConfig ? {}, - configDir ? true, - dataDir ? true, - delaySec ? 180 + delaySec ? 180, + middlewares ? [ "secureHeaders" ], + dependencies ? [ "traefik.service" "${config.numbus.services.dns}.service" ], }: let - cfg = config.numbus.services.${name}; - Deps = dependencies; - in - { - options.numbus.services.${name} = recursiveUpdate ({ - enable = mkEnableOption description; - - subdomain = mkOption { - type = types.str; - default = defaultSubdomain; - example = defaultSubdomain; - description = "The subdomain that ${name} will use"; - }; - - port = mkOption { - type = types.str; - default = defaultPort; - example = defaultPort; - description = "The port that ${name} will use."; - }; - - reverseProxied = mkOption { - type = types.bool; - default = reverseProxied; - description = "Whether to create a Traefik reverse proxy configuration for this service."; - }; - } // (optionalAttrs configDir { - configDir = mkOption { - type = types.str; - default = "/mnt/config/${name}"; - example = "/mnt/config/${name}"; - description = "The directory where ${name}'s configuration files will be stored"; - }; - }) // (optionalAttrs dataDir { - dataDir = mkOption { - type = types.str; - default = "/mnt/data/${name}"; - example = "/mnt/data/${name}"; - description = "The directory where ${name}'s data will be stored"; - }; - })) extraOptions; - - config = mkIf cfg.enable (mkMerge [ + mkServiceOpts = svcName: svcDesc: svcPort: svcSubdomain: svcReverseProxied: svcConfigDir: svcDataDir: { - environment.etc."${composeFile}".text = composeText; + numbus.services.${svcName} = { + enable = mkEnableOption svcDesc; - environment.etc."${config.numbus.traefikDynamicConfigDir}/${name}.yaml" = mkIf cfg.reverseProxied { - text = '' + subdomain = mkOption { + type = types.str; + default = svcSubdomain; + example = svcSubdomain; + description = "The subdomain that ${svcName} will use"; + }; + + port = mkOption { + type = types.str; + default = svcPort; + example = svcPort; + description = "The port that ${svcName} will use."; + }; + + reverseProxied = mkOption { + type = types.bool; + default = svcReverseProxied; + description = "Whether to create a Traefik reverse proxy configuration for this service."; + }; + } // (optionalAttrs svcConfigDir { + configDir = mkOption { + type = types.str; + default = "/mnt/config/${svcName}"; + example = "/mnt/config/${svcName}"; + description = "The directory where ${svcName}'s configuration files will be stored"; + }; + }) // (optionalAttrs svcDataDir { + dataDir = mkOption { + type = types.str; + default = "/mnt/data/${svcName}"; + example = "/mnt/data/${svcName}"; + description = "The directory where ${svcName}'s data will be stored"; + }; + }); + }; + + cfg = config.numbus.services.${name}; + cfg2 = if secondName != null then config.numbus.services.${secondName} else {}; + cfg3 = if thirdName != null then config.numbus.services.${thirdName} else {}; + + mkTraefikConfig = svcName: svcCfg: svcScheme: + mkIf (cfg.enable && svcCfg.reverseProxied) { + text = '' http: routers: - ${name}: - rule: "Host(`${cfg.subdomain}.${config.numbus.services.domain}`)" + ${svcName}: + rule: "Host(`${svcCfg.subdomain}.${config.numbus.services.domain}`)" entrypoints: - "websecure" - service: ${name} + service: ${svcName} middlewares: -${concatStringsSep "\n" (map (m: " - ${m}") middlewares)} +${concatStringsSep "\n" (map (m: " - ${m}") middlewares)} tls: certresolver: "cloudflare" options: "secureTLS" services: - ${name}: + ${svcName}: loadBalancer: servers: - - url: "${scheme}://host.containers.internal:${cfg.port}" + - url: "${svcScheme}://host.containers.internal:${svcCfg.port}" ''; - }; + }; + in + { + options = mkMerge [ + (mkServiceOpts name description defaultPort defaultSubdomain reverseProxied configDirEnabled dataDirEnabled) + (optionalAttrs (secondName != null) (mkServiceOpts secondName "Secondary service for ${name}" secondDefaultPort secondDefaultSubdomain secondReverseProxied secondConfigDirEnabled secondDataDirEnabled)) + (optionalAttrs (thirdName != null) (mkServiceOpts thirdName "Tertiary service for ${name}" thirdDefaultPort thirdDefaultSubdomain thirdReverseProxied thirdConfigDirEnabled thirdDataDirEnabled)) + { numbus.services.${name} = extraOptions; } + ]; + + config = mkIf cfg.enable (mkMerge [ + { + environment.etc."podman/${name}/compose.yaml".text = composeText; + + environment.etc = mkMerge [ + { "${config.numbus.traefikDynamicConfigDir}/${name}.yaml" = mkTraefikConfig name cfg scheme; } + (mkIf (secondName != null) { + "${config.numbus.traefikDynamicConfigDir}/${secondName}.yaml" = mkTraefikConfig secondName cfg2 secondScheme; + }) + (mkIf (thirdName != null) { + "${config.numbus.traefikDynamicConfigDir}/${thirdName}.yaml" = mkTraefikConfig thirdName cfg3 thirdScheme; + }) + ]; systemd.services."${name}" = { description = "Podman container : ${name}"; - requires = Deps; - after = Deps; + requires = dependencies; + after = dependencies; wantedBy = [ "multi-user.target" ]; path = [ pkgs.podman pkgs.podman-compose pkgs.coreutils pkgs.sudo ]; serviceConfig = { Type = "exec"; - ExecStartPre = "bash -c 'sleep $((RANDOM % ${delaySec}))'"; - ExecStart = "sudo -u numbus-admin podman-compose --in-pod ${pod} -f /etc/${composeFile} up --remove-orphans"; - ExecStop = "sudo -u numbus-admin podman-compose --in-pod ${pod} -f /etc/${composeFile} down"; + ExecStartPre = [ + "bash -c 'sleep $((RANDOM % ${toString delaySec}))'" + "-sudo -u numbus-admin podman-compose -f /etc/podman/${name}/compose.yaml pull" + ]; + ExecStart = "sudo -u numbus-admin podman-compose --in-pod ${toString pod} -f /etc/podman/${name}/compose.yaml up --remove-orphans"; + ExecStop = "sudo -u numbus-admin podman-compose --in-pod ${toString pod} -f /etc/podman/${name}/compose.yaml down"; Restart = "on-failure"; RestartSec = "1m"; StartLimitBurst = "5"; }; }; - - systemd.services."update-${name}" = { - description = "Update ${name} container"; - path = [ pkgs.podman pkgs.podman-compose pkgs.sudo pkgs.systemd ]; - serviceConfig = { - Type = "oneshot"; - ExecStart = [ - "sudo -u numbus-admin podman-compose --in-pod ${pod} -f /etc/${composeFile} pull" - "${pkgs.systemd}/bin/systemctl restart ${name}.service" - ]; - }; - }; - - systemd.timers."update-${name}" = { - timerConfig = { - OnCalendar = "02:00"; - RandomizedDelaySec = "60m"; - Unit = "update-${name}.service"; - }; - wantedBy = [ "timers.target" ]; - }; } extraConfig ]); diff --git a/modules/services/nextcloud.nix b/modules/services/nextcloud.nix index 9f02a75..949832c 100644 --- a/modules/services/nextcloud.nix +++ b/modules/services/nextcloud.nix @@ -1,131 +1,145 @@ -{ config, pkgs, ... }: +{ config, pkgs, lib, ... }: + +with lib; let - container_name = "nextcloud"; - compose_file = "podman/nextcloud/compose.yaml"; - data_dir = "/mnt/data/nextcloud"; + nextcloudVersion = "32.0.6"; + redisVersion = "8.6-alpine"; + databaseVersion = "11.4"; + onlyofficeVersion = "9.2"; + whiteboardVersion = "v1.5.6"; + helper = import ./lib.nix { inherit config pkgs lib; }; + cfg = config.numbus.services.nextcloud; + cfg2 = config.numbus.services.onlyoffice; + cfg3 = config.numbus.services.whiteboard; in -{ - config = { - environment.etc."${compose_file}".text = - /* - yaml - */ - '' - services: - nextcloud-server: - image: docker.io/library/nextcloud:latest - container_name: nextcloud-server - restart: unless-stopped - networks: - nextcloud_frontend: - nextcloud_backend: - volumes: - - nextcloud_data:/var/www/html - - ${data_dir}:/var/www/html/data - environment: - MYSQL_HOST: nextcloud-database - MYSQL_DATABASE: $MYSQL_DATABASE - MYSQL_USER: $MYSQL_USER - MYSQL_PASSWORD: $MYSQL_PASSWORD - REDIS_HOST: nextcloud-redis - REDIS_HOST_PASSWORD: $REDIS_HOST_PASSWORD - NEXTCLOUD_TRUSTED_DOMAINS: $DOMAIN_NAME - SMTP_HOST: $SMTP_HOST - SMTP_SECURE: tls - SMTP_PORT: $SMTP_PORT - SMTP_NAME: $SMTP_NAME - SMTP_PASSWORD: $SMTP_PASSWORD - MAIL_FROM_ADDRESS: $MAIL_FROM_ADDRESS - MAIL_DOMAIN: $DOMAIN_NAME - APACHE_DISABLE_REWRITE_IP: 1 - TRUSTED_PROXIES: traefik - OVERWRITEPROTOCOL: https - labels: - - traefik.enable=true - - traefik.docker.network=nextcloud_frontend - - traefik.http.services.nextcloud.loadbalancer.server.port=80 - - traefik.http.services.nextcloud.loadbalancer.server.scheme=http - - traefik.http.routers.nextcloud-https.entrypoints=websecure - - traefik.http.routers.nextcloud-https.rule=Host(`nextcloud.$DOMAIN_NAME`) - - traefik.http.routers.nextcloud-https.tls=true - - traefik.http.routers.nextcloud-https.tls.certresolver=cloudflare - depends_on: - - nextcloud-database - - nextcloud-redis: - image: docker.io/library/redis:alpine - name: nextcloud-redis - restart: unless-stopped - networks: - nextcloud_backend: - command: redis-server --requirepass $REDIS_HOST_PASSWORD - - nextcloud-database: - image: docker.io/library/mariadb:latest - container_name: nextcloud-database - restart: unless-stopped - networks: - nextcloud_backend: - volumes: - - nextcloud_database:/var/lib/mysql - environment: - MARIADB_DATABASE: $MYSQL_DATABASE - MARIADB_USER: $MYSQL_USER - MARIADB_PASSWORD: $MYSQL_PASSWORD - MARIADB_RANDOM_ROOT_PASSWORD: true - +helper.mkPodmanService { + description = "Nextcloud, your own online office suite"; + name = "nextcloud"; + pod = "nextcloud"; + secondName = "onlyoffice"; + thirdName = "whiteboard"; + defaultPort = "11000"; + secondDefaultPort = "9980"; + thirdDefaultPort = "3002"; + secondReverseProxied = true; + thirdReverseProxied = true; + secondConfigDirEnabled = true; + thirdConfigDirEnabled = false; + secondDataDirEnabled = false; + thirdDataDirEnabled = false; + +# Compose file good + composeText = '' + services: + nextcloud-server: + image: docker.io/library/nextcloud:${nextcloudVersion} + container_name: nextcloud-server + hostname: nextcloud-server networks: - nextcloud_frontend: - external: true - nextcloud_backend: - external: true - + nextcloud: + ports: + - "${cfg.port}:80/tcp" volumes: - nextcloud_data: - nextcloud_database: - ''; + - ${cfg.configDir}/web:/var/www/html + - ${cfg.dataDir}:/mnt/ncdata + environment: + MYSQL_HOST: nextcloud-database + MYSQL_DATABASE: $MYSQL_DATABASE + MYSQL_USER: $MYSQL_USER + MYSQL_PASSWORD: $MYSQL_PASSWORD + REDIS_HOST: nextcloud-redis + REDIS_HOST_PASSWORD: $REDIS_HOST_PASSWORD + NEXTCLOUD_TRUSTED_DOMAINS: ${cfg.subdomain}.${config.numbus.services.domain} + NEXTCLOUD_DATA_DIR: /mnt/ncdata + SMTP_HOST: $SMTP_HOST + SMTP_SECURE: tls + SMTP_PORT: $SMTP_PORT + SMTP_NAME: $SMTP_NAME + SMTP_PASSWORD: $SMTP_PASSWORD + MAIL_FROM_ADDRESS: nextcloud-noreply + MAIL_DOMAIN: ${config.numbus.services.domain} + APACHE_DISABLE_REWRITE_IP: 1 + TRUSTED_PROXIES: 192.168.11.5 + OVERWRITEPROTOCOL: https + depends_on: + - nextcloud-database + security_opt: + - no-new-privileges:true + cap_drop: + - NET_RAW + restart: unless-stopped + nextcloud-redis: + image: docker.io/library/redis:${redisVersion} + container_name: nextcloud-redis + hostname: nextcloud-redis + user: '1000:1000' + networks: + nextcloud: + volumes: + - ${cfg.configDir}/redis:/data + command: redis-server --requirepass $REDIS_HOST_PASSWORD --save 60 1 --loglevel warning + security_opt: + - no-new-privileges:true + cap_drop: + - NET_RAW + restart: unless-stopped + nextcloud-database: + image: docker.io/library/mariadb:${databaseVersion} + container_name: nextcloud-database + hostname: nextcloud-database + user: '1000:1000' + networks: + nextcloud: + volumes: + - ${cfg.configDir}/database:/var/lib/mysql + environment: + MARIADB_DATABASE: $MYSQL_DATABASE + MARIADB_USER: $MYSQL_USER + MARIADB_PASSWORD: $MYSQL_PASSWORD + MARIADB_RANDOM_ROOT_PASSWORD: true + security_opt: + - no-new-privileges:true + cap_drop: + - NET_RAW + restart: unless-stopped + nextcloud-onlyoffice: + container_name: nextcloud-onlyoffice + hostname: nextcloud-onlyoffice + image: docker.io/onlyoffice/documentserver:${onlyofficeVersion} + environment: + - JWT_SECRET=$JWT_SECRET + ports: + - "${cfg2.port}:80/tcp" + volumes: + - ${cfg2.configDir}/log:/var/log/onlyoffice + - ${cfg2.configDir}/cache:/var/lib/onlyoffice + - ${cfg2.configDir}/database:/var/lib/postgresql + security_opt: + - no-new-privileges:true + cap_drop: + - NET_RAW + restart: unless-stopped + nextcloud-whiteboard: + image: ghcr.io/nextcloud-releases/whiteboard:${whiteboardVersion} + container_name: nextcloud-whiteboard + hostname: nextcloud-whiteboard + user: '1000:1000' + ports: + - "${cfg3.port}:3002/tcp" + environment: + NEXTCLOUD_URL: https://${cfg.subdomain}.${config.numbus.services.domain} + JWT_SECRET_KEY: $JWT_SECRET + security_opt: + - no-new-privileges:true + cap_drop: + - NET_RAW + restart: unless-stopped + networks: + nextcloud: + name: nextcloud + driver: bridge + ''; - systemd.services."${container_name}" = { - description = "Podman container : ${container_name}"; - after = [ "network.target" "traefik.service" "pi-hole.service" ]; - requires = [ "traefik.service" ]; - wantedBy = [ "multi-user.target" ]; - path = [ pkgs.podman pkgs.coreutils ]; - - serviceConfig = { - User = "numbus-admin"; - Environment = [ "XDG_RUNTIME_DIR=/run/user/1000" ]; - Type = "exec"; - TimeoutStartSec = "600"; - ExecStartPre = [ - "${pkgs.bash}/bin/bash -c 'sleep $((RANDOM % 180))'" - "-${pkgs.podman-compose}/bin/podman-compose -f /etc/${compose_file} pull" - ]; - ExecStart = "${pkgs.podman-compose}/bin/podman-compose -f /etc/${compose_file} up --remove-orphans"; - ExecStop = "${pkgs.podman-compose}/bin/podman-compose -f /etc/${compose_file} down"; - Restart = "on-failure"; - RestartSec = "5m"; - StartLimitBurst = "3"; - }; - }; - - systemd.services."update-${container_name}" = { - description = "Update ${container_name} container"; - serviceConfig = { - Type = "oneshot"; - ExecStart = "${pkgs.systemd}/bin/systemctl restart ${container_name}.service"; - }; - }; - - systemd.timers."update-${container_name}" = { - timerConfig = { - OnCalendar = "02:00"; - RandomizedDelaySec = "60m"; - Unit = "update-${container_name}.service"; - }; - wantedBy = [ "timers.target" ]; - }; - }; } \ No newline at end of file diff --git a/modules/services/passbolt.nix b/modules/services/passbolt.nix index 00d13bd..df5ae9c 100644 --- a/modules/services/passbolt.nix +++ b/modules/services/passbolt.nix @@ -3,23 +3,26 @@ with lib; let + passboltVersion = "5.9.0-1-ce-non-root"; + databaseVersion = "12.2"; helper = import ./lib.nix { inherit config pkgs lib; }; cfg = config.numbus.services.passbolt; in helper.mkPodmanService { - name = "passbolt"; description = "Passbolt, your password manager"; - defaultPort = "4433"; + name = "passbolt"; pod = "passbolt"; + defaultPort = "4433"; scheme = "https"; configDir = false; dataDir = false; +# Compose file good composeText = '' services: passbolt-server: - image: docker.io/passbolt/passbolt:latest-ce-non-root + image: docker.io/passbolt/passbolt:${passboltVersion} container_name: passbolt-server hostname: passbolt-server networks: @@ -42,7 +45,7 @@ helper.mkPodmanService { EMAIL_TRANSPORT_DEFAULT_USERNAME: $EMAIL_TRANSPORT_DEFAULT_USERNAME EMAIL_TRANSPORT_DEFAULT_PASSWORD: $EMAIL_TRANSPORT_DEFAULT_PASSWORD EMAIL_TRANSPORT_DEFAULT_TLS: true - EMAIL_DEFAULT_FROM: $EMAIL_ADDRESS + EMAIL_DEFAULT_FROM: passbolt-noreply@${config.numbus.services.domain} PASSBOLT_SSL_FORCE: true command: [ @@ -61,7 +64,7 @@ helper.mkPodmanService { - NET_RAW restart: unless-stopped passbolt-database: - image: docker.io/library/mariadb:12.2 + image: docker.io/library/mariadb:${databaseVersion} container_name: passbolt-database hostname: passbolt-database networks: @@ -80,8 +83,11 @@ helper.mkPodmanService { restart: unless-stopped volumes: passbolt-database: + name: passbolt-database passbolt-gpg: + name: passbolt-gpg passbolt-jwt: + name: passbolt-jwt networks: passbolt: name: passbolt diff --git a/modules/services/pi-hole.nix b/modules/services/pi-hole.nix index 263aa84..83e8416 100644 --- a/modules/services/pi-hole.nix +++ b/modules/services/pi-hole.nix @@ -3,24 +3,25 @@ with lib; let + piholeVersion = "2026.02.0"; helper = import ./lib.nix { inherit config pkgs lib; }; cfg = config.numbus.services.pi-hole; in helper.mkPodmanService { - name = "pi-hole"; description = "Pi-Hole, the ads black hole"; + name = "pi-hole"; defaultPort = "4443"; - pod = "false"; scheme = "https"; dependencies = [ "network.target" "multi-user.target" ]; dataDir = false; delaySec = 10; +# Compose file good composeText = '' services: pi-hole: - image: docker.io/pihole/pihole:latest + image: docker.io/pihole/pihole:${piholeVersion} container_name: pi-hole hostname: pi-hole network_mode: pasta diff --git a/modules/services/traefik.nix b/modules/services/traefik.nix index 760c789..6b91905 100644 --- a/modules/services/traefik.nix +++ b/modules/services/traefik.nix @@ -3,14 +3,14 @@ with lib; let + traefikVersion = "v3.6.8"; helper = import ./lib.nix { inherit config pkgs lib; }; cfg = config.numbus.services.traefik; in helper.mkPodmanService { - name = "traefik"; description = "Traefik reverse proxy, one to rule them all"; - pod = "false"; + name = "traefik"; reverseProxied = false; dependencies = [ "network.target" "multi-user.target" ]; configDir = false; @@ -28,13 +28,14 @@ helper.mkPodmanService { default = "ERROR"; description = "The level of detail Traefik should print in the logs."; }; - # traefikDynamicConfigDir referenced at global.nix + # traefikDynamicConfigDir defined at global.nix }; +# Compose file good composeText = '' services: traefik: - image: docker.io/library/traefik:latest + image: docker.io/library/traefik:${traefikVersion} container_name: traefik hostname: traefik network_mode: pasta