summary refs log tree commit diff
path: root/services/immich.nix
blob: b1a6a6fea0d1a340d1563eea796027fb43dce69c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
{ me, auxiliaryPkgs, ... }:

let
  inherit (auxiliaryPkgs) common;

  immichVersion = "v1.122.2";
  immichDir = "/srv/immich";
  immichLocalPort = 2283;

  immichImage = common.pullImage {
    registry = "github";
    name = "immich-app/immich-server";
    tag = immichVersion;
    digest = "sha256:27ceb1867f5501818c86188c62924bbfd3024d8f74395cd66d6a302b01d1b2cd";
    x86.sha256 = "sha256-JuImkiprPsleM3GWGwgFHLZ7M3JbQag+sOajocrgeH8=";
  };

  databaseImage = common.pullImage {
    name = "tensorchord/pgvecto-rs";
    tag = "pg14-v0.2.0";
    digest = "sha256:90724186f0a3517cf6914295b5ab410db9ce23190a2d9d0b9dd6463e3fa298f0";
    x86.sha256 = "0h1s11z5d4svg2whm7gw11dwpddg5k90fp62q3zirycms787f4d3";
  };

  redisImage = common.pullImage {
    name = "redis";
    tag = "6.2-alpine";
    digest = "sha256:eaba718fecd1196d88533de7ba49bf903ad33664a92debb24660a922ecd9cac8";
    x86.sha256 = "0fsx6vyfg3v5w0f46kniiyzik4anfsdih9pnnrf967dd0db78c8a";
  };

  immichMlImage = common.pullImage {
    registry = "github";
    name = "immich-app/immich-machine-learning";
    tag = immichVersion;
    digest = "sha256:5c4e7a25a01e4dd52e9b919a277a2d870af0a08094e4089c85708e402512a8aa";
    x86.sha256 = "sha256-CK+nJorxS7yC6F/Vr7hAt7KH3bGqEFqzvYu88aWU/Ls=";
  };

in
{
  foundation.service.immich = {
    immich = {
      fullImage = immichImage;
      environment = {
        "IMMICH_MACHINE_LEARNING_URL" = "http://ml:3003";
        "DB_HOSTNAME" = "db";
        "REDIS_HOSTNAME" = "kv";
        "DB_DATABASE_NAME" = "immich";
        "DB_PASSWORD" = "immich";
        "DB_USERNAME" = "immich";
      };
      volumes = [
        [ "/etc/localtime" "/etc/localtime:ro" ]
        [ "${immichDir}/upload" "/usr/src/app/upload" ]
      ];
      # expose through tailscale, so it can be accessed both through
      # reverse proxy, and directly from a tailnet device.
      ports = [ (common.tailnetPort me immichLocalPort) ];
    };

    db = {
      fullImage = databaseImage;
      environment = {
        "POSTGRES_DB" = "immich";
        "POSTGRES_INITDB_ARGS" = "--data-checksums";
        "POSTGRES_PASSWORD" = "immich";
        "POSTGRES_USER" = "immich";
      };
      volumes = [
        [ "${immichDir}/pgdata" "/var/lib/postgresql/data" ]
      ];
      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"
      ];
    };

    kv = {
      fullImage = redisImage;
    };

    ml = {
      fullImage = immichMlImage;
      volumes = [
        [ "${immichDir}/ml-cache" "/cache" ]
      ];
    };
  };

  services.nginx.virtualHosts = {
    "img.rnrd.eu" = {
      enableACME = true;
      forceSSL = true;
      locations."/" = {
        proxyPass = "http://${me.tailscale.ip}:${toString immichLocalPort}";
        proxyWebsockets = true;
      };
      extraConfig = ''
        client_max_body_size 10G;

        proxy_buffering off;
        proxy_request_buffering off;

        proxy_read_timeout 600s;
        proxy_send_timeout 600s;
        send_timeout       600s;

        access_log /var/log/nginx/immich.access.log json_combined;
      '';
    };
  };
}