From 5faea30ad215bc41c783d50e9c8d3fa284cdb934 Mon Sep 17 00:00:00 2001 From: imterah Date: Wed, 7 May 2025 23:27:05 -0400 Subject: [PATCH] feature: Add Immich support --- README.md | 6 +- hosts/andromeda/configuration.nix | 6 +- .../stacks/immich/docker-compose.nix | 221 ++++++++++++++++++ secrets | 2 +- system/sops.nix | 2 + 5 files changed, 232 insertions(+), 5 deletions(-) create mode 100644 hosts/andromeda/stacks/immich/docker-compose.nix diff --git a/README.md b/README.md index 5e6a302..5d5789c 100644 --- a/README.md +++ b/README.md @@ -20,9 +20,9 @@ This is a work-in-progress and currently is not production ready. Please check b - [x] Install Forgejo - [x] Install Personal Website - [x] Install mCaptcha - - [ ] Install Passbolt - - [ ] Install Pterodactyl Panel - - [ ] Install Immich + - [x] Install Passbolt + - [x] Install Pterodactyl Panel + - [x] Install Immich - [ ] Restore Forgejo - [ ] Restore Passbolt - [ ] Restore Pterodactyl Panel diff --git a/hosts/andromeda/configuration.nix b/hosts/andromeda/configuration.nix index 809955f..83e0c84 100755 --- a/hosts/andromeda/configuration.nix +++ b/hosts/andromeda/configuration.nix @@ -16,14 +16,18 @@ ../../system/i18n.nix # Docker stacks + ## Bootstrap ./stacks/traefik/docker-compose.nix ./stacks/caddy/docker-compose.nix + ## Internal ./stacks/portainer/docker-compose.nix ./stacks/passbolt/docker-compose.nix ./stacks/pterodactyl/docker-compose.nix + ./stacks/immich/docker-compose.nix + ## Public + ./stacks/terah.dev/docker-compose.nix ./stacks/mcaptcha/docker-compose.nix ./stacks/forgejo/docker-compose.nix - ./stacks/terah.dev/docker-compose.nix ]; users.mutableUsers = false; diff --git a/hosts/andromeda/stacks/immich/docker-compose.nix b/hosts/andromeda/stacks/immich/docker-compose.nix new file mode 100644 index 0000000..d16242c --- /dev/null +++ b/hosts/andromeda/stacks/immich/docker-compose.nix @@ -0,0 +1,221 @@ +# Auto-generated using compose2nix v0.3.1. +{ config, pkgs, lib, ... }: + +{ + imports = [ + ../../../../system/sops.nix + ]; + + # Containers + virtualisation.oci-containers.containers."immich_machine_learning" = { + image = "ghcr.io/immich-app/immich-machine-learning:release"; + volumes = [ + "immich_model-cache:/cache:rw" + ]; + log-driver = "journald"; + extraOptions = [ + "--network-alias=immich-machine-learning" + "--network=immich_default" + ]; + }; + + systemd.services."docker-immich_machine_learning" = { + serviceConfig = { + Restart = lib.mkOverride 90 "always"; + RestartMaxDelaySec = lib.mkOverride 90 "1m"; + RestartSec = lib.mkOverride 90 "100ms"; + RestartSteps = lib.mkOverride 90 9; + }; + after = [ + "docker-network-immich_default.service" + "docker-volume-immich_model-cache.service" + ]; + requires = [ + "docker-network-immich_default.service" + "docker-volume-immich_model-cache.service" + ]; + partOf = [ + "docker-compose-immich-root.target" + ]; + wantedBy = [ + "docker-compose-immich-root.target" + ]; + }; + + virtualisation.oci-containers.containers."immich_postgres" = { + image = "docker.io/tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:739cdd626151ff1f796dc95a6591b55a714f341c737e27f045019ceabf8e8c52"; + environmentFiles = [ config.sops.secrets.immich_db_docker_env.path ]; + environment = { + "POSTGRES_DB" = "immich"; + "POSTGRES_INITDB_ARGS" = "--data-checksums"; + "POSTGRES_PASSWORD" = "pgpass"; + "POSTGRES_USER" = "postgres"; + }; + volumes = [ + "immich_db:/var/lib/postgresql/data:rw" + ]; + cmd = [ "postgres" "-c" "shared_preload_libraries=vectors.so" "-c" "search_path=\"$user\", public, vectors" "-c" "logging_collector=on" "-c" "max_wal_size=2GB" "-c" "shared_buffers=512MB" "-c" "wal_compression=on" ]; + log-driver = "journald"; + extraOptions = [ + "--health-cmd=pg_isready --dbname=\"immich\" --username=\"postgres\" || exit 1; Chksum=\"$(psql --dbname=\"immich\" --username=\"postgress\" --tuples-only --no-align --command='SELECT COALESCE(SUM(checksum_failures), 0) FROM pg_stat_database')\"; echo \"checksum failure count is $Chksum\"; [ \"$Chksum\" = '0' ] || exit 1" + "--health-interval=5m0s" + "--health-start-interval=30s" + "--health-start-period=5m0s" + "--network-alias=database" + "--network=immich_default" + ]; + }; + + systemd.services."docker-immich_postgres" = { + serviceConfig = { + Restart = lib.mkOverride 90 "always"; + RestartMaxDelaySec = lib.mkOverride 90 "1m"; + RestartSec = lib.mkOverride 90 "100ms"; + RestartSteps = lib.mkOverride 90 9; + }; + after = [ + "docker-network-immich_default.service" + "docker-volume-immich_db.service" + ]; + requires = [ + "docker-network-immich_default.service" + "docker-volume-immich_db.service" + ]; + partOf = [ + "docker-compose-immich-root.target" + ]; + wantedBy = [ + "docker-compose-immich-root.target" + ]; + }; + + virtualisation.oci-containers.containers."immich_redis" = { + image = "docker.io/valkey/valkey:8-bookworm@sha256:42cba146593a5ea9a622002c1b7cba5da7be248650cbb64ecb9c6c33d29794b1"; + log-driver = "journald"; + extraOptions = [ + "--health-cmd=redis-cli ping || exit 1" + "--network-alias=redis" + "--network=immich_default" + ]; + }; + + systemd.services."docker-immich_redis" = { + serviceConfig = { + Restart = lib.mkOverride 90 "always"; + RestartMaxDelaySec = lib.mkOverride 90 "1m"; + RestartSec = lib.mkOverride 90 "100ms"; + RestartSteps = lib.mkOverride 90 9; + }; + after = [ + "docker-network-immich_default.service" + ]; + requires = [ + "docker-network-immich_default.service" + ]; + partOf = [ + "docker-compose-immich-root.target" + ]; + wantedBy = [ + "docker-compose-immich-root.target" + ]; + }; + + virtualisation.oci-containers.containers."immich_server" = { + image = "ghcr.io/immich-app/immich-server:release"; + environmentFiles = [ config.sops.secrets.immich_immich_docker_env.path ]; + environment = { + "TZ" = "America/Indiana/Indianapolis"; + "DB_DATABASE_NAME" = "immich"; + "DB_USERNAME" = "postgres"; + }; + volumes = [ + "/etc/localtime:/etc/localtime:ro" + "/mnt/NASBox/immich/uploads:/usr/src/app/upload:rw" + ]; + labels = { + "traefik.http.routers.pterodactyl.rule" = "Host(`immich.hofers.cloud`)"; + }; + dependsOn = [ + "immich_postgres" + "immich_redis" + ]; + log-driver = "journald"; + extraOptions = [ + "--network-alias=immich-server" + "--network=immich_default" + ]; + }; + + systemd.services."docker-immich_server" = { + serviceConfig = { + Restart = lib.mkOverride 90 "always"; + RestartMaxDelaySec = lib.mkOverride 90 "1m"; + RestartSec = lib.mkOverride 90 "100ms"; + RestartSteps = lib.mkOverride 90 9; + }; + after = [ + "docker-network-immich_default.service" + ]; + requires = [ + "docker-network-immich_default.service" + ]; + partOf = [ + "docker-compose-immich-root.target" + ]; + wantedBy = [ + "docker-compose-immich-root.target" + ]; + }; + + # Networks + systemd.services."docker-network-immich_default" = { + path = [ pkgs.docker ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStop = "docker network rm -f immich_default"; + }; + script = '' + docker network inspect immich_default || docker network create immich_default + ''; + partOf = [ "docker-compose-immich-root.target" ]; + wantedBy = [ "docker-compose-immich-root.target" ]; + }; + + # Volumes + systemd.services."docker-volume-immich_db" = { + path = [ pkgs.docker ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + }; + script = '' + docker volume inspect immich_db || docker volume create immich_db + ''; + partOf = [ "docker-compose-immich-root.target" ]; + wantedBy = [ "docker-compose-immich-root.target" ]; + }; + + systemd.services."docker-volume-immich_model-cache" = { + path = [ pkgs.docker ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + }; + script = '' + docker volume inspect immich_model-cache || docker volume create immich_model-cache + ''; + partOf = [ "docker-compose-immich-root.target" ]; + wantedBy = [ "docker-compose-immich-root.target" ]; + }; + + # Root service + # When started, this will automatically create all resources and start + # the containers. When stopped, this will teardown all resources. + systemd.targets."docker-compose-immich-root" = { + unitConfig = { + Description = "Root target generated by compose2nix."; + }; + wantedBy = [ "multi-user.target" ]; + }; +} diff --git a/secrets b/secrets index 6784f0a..4cc9a1c 160000 --- a/secrets +++ b/secrets @@ -1 +1 @@ -Subproject commit 6784f0a795b318b75bf8f816900ee2b927f4df83 +Subproject commit 4cc9a1c088cd9c651b485e340eac6fdb26912d14 diff --git a/system/sops.nix b/system/sops.nix index 3002308..de10eb3 100755 --- a/system/sops.nix +++ b/system/sops.nix @@ -31,6 +31,8 @@ in passbolt_passbolt_docker_env = {}; pterodactyl_db_docker_env = {}; pterodactyl_pterodactyl_docker_env = {}; + immich_db_docker_env = {}; + immich_immich_docker_env = {}; }; }; }