Skip to content

Commit

Permalink
feat: add immich
Browse files Browse the repository at this point in the history
  • Loading branch information
ajgon committed Nov 2, 2024
1 parent 8b99f33 commit 4c08c17
Show file tree
Hide file tree
Showing 11 changed files with 624 additions and 43 deletions.
1 change: 1 addition & 0 deletions .github/renovate.json5
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
":timezone(Europe/Warsaw)",
"github>deedee-ops/nixlab//.github/renovate/autoMerge.json5",
"github>deedee-ops/nixlab//.github/renovate/commitMessage.json5",
"github>deedee-ops/nixlab//.github/renovate/groups.json5",
"github>deedee-ops/nixlab//.github/renovate/labels.json5",
"github>deedee-ops/nixlab//.github/renovate/semanticCommits.json5",
],
Expand Down
15 changes: 15 additions & 0 deletions .github/renovate/groups.json5
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"packageRules": [
{
"description": ["Immich Group"],
"groupName": "Immich",
"matchPackagePatterns": ["ghcr\\.io/immich-app"],
"matchDatasources": ["docker"],
"group": {
"commitMessageTopic": "{{{groupName}}} group"
},
"separateMinorPatch": true
},
]
}
6 changes: 6 additions & 0 deletions machines/deedee/configuration.nix
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ _:
let
mediaPath = "/mnt/media";
audiobooksPath = "${mediaPath}/audiobooks";
photosPath = "${mediaPath}/photos";
podcastsPath = "${mediaPath}/podcasts";
torrentsPath = "${mediaPath}/torrents";
videoPath = "${mediaPath}/video";
Expand Down Expand Up @@ -193,6 +194,11 @@ rec {
DATA = "/";
};
};
immich = {
inherit photosPath;
enable = true;
dataPath = "/mnt/media/immich";
};
jellyfin = {
inherit videoPath;
enable = true;
Expand Down
11 changes: 9 additions & 2 deletions machines/deedee/secrets.sops.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,13 @@ system:
WIREGUARD_ADDRESSES: ENC[AES256_GCM,data:uucQ8ck/exE9Umjjk8Y2,iv:PlW7cvJFbPp2S9kdXcDRkONbBXt05CE5jpKlRfCdk8A=,tag:Oaya22wc2cBAI3XbCDJWJQ==,type:str]
WIREGUARD_PRESHARED_KEY: ENC[AES256_GCM,data:ccFq1OEwRe27ftytoiV6MatZmwKCZGJ7DTUq5va0OOkMJdzQWrr/mshdRPE=,iv:QKko2rmjyvgW0LQnLzl7IHChBvMoioTRt00RxbXkTGQ=,tag:aFp5TclfzaDIHZriebaVKA==,type:str]
WIREGUARD_PRIVATE_KEY: ENC[AES256_GCM,data:uHtJ5bUdfqCHb8lD2FjK90qTy+ydnHuIrJZEYskUR/oofZRabqyTJdURuoE=,iv:uQHoOogAJeX/lTIVff/ypGYyXx9FeZJicHytrHMo3ig=,tag:UlftPN9DyS/RM5rSeLouOw==,type:str]
immich:
env:
AJGON_API_KEY: ENC[AES256_GCM,data:1tIppPz0jciMFcB2WWc56sUNPtvifjsURDSHSSEPLDV+QzEGQkNvfDlpPw==,iv:ySZSNnXkfO2ZbrSD3/++7peZu5W1XxmyNXVw1RvuM14=,tag:NaGvmleBJFCtMwFHBHNXNQ==,type:str]
ADMIN_API_KEY: ENC[AES256_GCM,data:SES8kFGi6R943cRewbJIxhSK/MMRo2jmAW/yseyPUlAm/OetgLRC+IJG3A==,iv:CZMhyitXLpoTS5keISPVVmjKqV9kxZOa1aIsHctOaOA=,tag:E2OybJAdma586RroJcmxqw==,type:str]
DB_PASSWORD: ENC[AES256_GCM,data:mbC7eRSCB99A5VkhCK7BL4oQh5T8k+wbQZPcsReKtHjQtO/4PIanww==,iv:Bhp2whhp7MWBgPwbVWG/79S/ZA7UOCtwNFYhqTbfImQ=,tag:nNoNloIEe6lUKt7Fh2aUPA==,type:str]
OIDC_SECRET_ENCRYPTED: ENC[AES256_GCM,data:HNwOGx5f6g7NTFi7Xk7lRWFpPgqH+2sAZXE4wGPsTdOXZtl/EsQFFP6x5kG/L0UvC+WcpmqP9M2RrN70pvNfpR5DZtAx91owYYgnhQ9jBvNgCb0cgyEf9IO0n5YWZ5dGlYN7DrwXYPZ5UAbNl4QGMoYq93BSUo6Ob9KYw6r+PJKvmK8=,iv:AiMZO4itdkNCdUlJ2JfruYwzi1viA3xYbmDnC/vcD9c=,tag:pK3UsufBQ3rKUhaMdAM0AA==,type:str]
OIDC_SECRET_RAW: ENC[AES256_GCM,data:JMA2jwiSTCtP0bJzXiPawWLfkKtLJMDDIcwJbTBhzKlxiL8YE0NwXz098CRwd2o3sUxoyZa6CrygTUuq3GDUopwHVX7ZsQn2,iv:iU06dfr+g9mK3ZwwvZqkn1NxjbtErG/UQnefTTqJonM=,tag:8msqG8E+rIHFXyLAgWBrQg==,type:str]
jellyfin:
env:
OIDC_SECRET_ENCRYPTED: ENC[AES256_GCM,data:hRAudzG+gyAW5he21z2aY191Qon56UQxOdQanjWc9qC7ToPTqoVQQUsSwN6T8n4hCLSwfOEXZF6jQUFFQocnvMHfz/IjZGrhl2uGR/wOm8bADYU9UUuyJCB1mdq8wBWbi22hv+V1unl0uWDz/6GMLv4VVouwN6y7fqk7FLpwbQkeT1g=,iv:Ck3iV8ySo9t8MYjqZeTC0Kpe+srolUjg5FabKMBM5+k=,tag:C/d3sFzmeBJDS2iMryQ9zA==,type:str]
Expand Down Expand Up @@ -162,8 +169,8 @@ sops:
c3FoaFNzbjJubzlBckdDb2lNOUZtOGMKRbHxa1B3QAdredBMTd7W7g3kRz6l8uyV
bBclsA8Gm7p+6ndV39sN+Daqm5MyggY1Prwv/Ukdd5Q+1C+XsEW6OQ==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2024-11-01T19:53:58Z"
mac: ENC[AES256_GCM,data:KUCjZMJQyfWKKMzPCvL4jRqmMpBoDV2jgz2V5fr1rzMKm1PgtO95c6au4rpcv/f1ZhwbGVHwqOtVyrOu2dbBM5bNFgcAnwhGicCv4ssoHniBtatxnL9zptMIolRaXkIZP1I5Z71BTw/DUkFfcHnVv9dthyJSf85hzW/XGdkYhNA=,iv:IeNRUlXPNcIVm1c3R2SVmEBAto66qNdZWNSQ9RlB82w=,tag:cN7dPy7p73XJvfqDdfXkSg==,type:str]
lastmodified: "2024-11-02T12:05:25Z"
mac: ENC[AES256_GCM,data:0LiAii5u81XllLcKkcTHS31SDyDhy2ZV7/IWIrx4htOS45RZKYFwmLEErFJp4AWhw+BWGbDieH+yNKHzXJ/6WPH9L8V1r9jGU8AesyV5Fi9ltqHI14+GOwL0YBZjmDRfQoI9lFIsp9Q6DifWvIcrzvB0cLWTHwopzfVmKhVgR4s=,iv:RP5L7d6rz79X50H/j6FSozAKhll8wXsZm4d/Hp6wLwY=,tag:Bq77IOHVAEz5QiuhSISwfQ==,type:str]
pgp: []
unencrypted_suffix: _unencrypted
version: 3.8.1
111 changes: 70 additions & 41 deletions modules/system/apps/postgresql/default.nix
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
config,
lib,
pkgs,
svc,
...
}:
Expand All @@ -13,6 +14,20 @@ in
backup = lib.mkEnableOption "postgresql backup" // {
default = true;
};
enablePgVectoRs = lib.mkOption {
type = lib.types.bool;
description = "Enable pg-vecto.rs extension.";
default = false;
example = true;
};
initSQL = lib.mkOption {
type = lib.types.attrsOf lib.types.str;
description = "Per-database list of init SQL scripts, where key is databases name.";
example = {
immich = "CREATE EXTENSION IF NOT EXISTS vectors;";
};
default = { };
};
userDatabases = lib.mkOption {
type = lib.types.listOf (
lib.types.submodule {
Expand Down Expand Up @@ -45,30 +60,38 @@ in
backupPath = "/var/lib/postgresql/backups";
in
{
postgresql = {
enable = true;
identMap = ''
# ArbitraryMapName systemUser DBUser
superuser_map root postgres
superuser_map postgres postgres
postgresql =
{
enable = true;
identMap = ''
# ArbitraryMapName systemUser DBUser
superuser_map root postgres
superuser_map postgres postgres
# Let other names login as themselves
superuser_map /^(.*)$ \1
'';
authentication = ''
#type database DBuser host-mask auth-method optional_ident_map
local sameuser all peer map=superuser_map
host sameuser all ${config.mySystemApps.docker.network.private.subnet} scram-sha-256
'';
# Let other names login as themselves
superuser_map /^(.*)$ \1
'';
authentication = ''
#type database DBuser host-mask auth-method optional_ident_map
local sameuser all peer map=superuser_map
host sameuser all ${config.mySystemApps.docker.network.private.subnet} scram-sha-256
'';

enableTCPIP = true;
ensureDatabases = lib.flatten (builtins.map (opt: opt.databases) cfg.userDatabases);
ensureUsers = builtins.map (opt: { name = opt.username; }) cfg.userDatabases;
enableTCPIP = true;
ensureDatabases = lib.flatten (builtins.map (opt: opt.databases) cfg.userDatabases);
ensureUsers = builtins.map (opt: { name = opt.username; }) cfg.userDatabases;

settings = {
password_encryption = "scram-sha-256";
settings = {
password_encryption = "scram-sha-256";
};
}
// lib.optionalAttrs cfg.enablePgVectoRs {
extraPlugins = ps: [ ps.pgvecto-rs ];
settings = {
shared_preload_libraries = [ "vectors.so" ];
search_path = "\"$user\", public, vectors";
};
};
};

postgresqlBackup = lib.mkIf cfg.backup {
enable = true;
Expand All @@ -86,27 +109,33 @@ in

users.users.postgres.extraGroups = [ "abc" ];

systemd.services.postgresql.postStart = ''
$PSQL -tA <<'EOF'
DO $$
DECLARE password TEXT;
BEGIN
${
builtins.concatStringsSep "\n" (
builtins.map (opt: ''
password := trim(both from replace(pg_read_file('${opt.passwordFile}'), E'\n', '''));
EXECUTE format('ALTER ROLE ${opt.username} WITH PASSWORD '''%s''';', password);
${builtins.concatStringsSep "\n" (
builtins.map (db: ''
ALTER DATABASE "${db}" OWNER TO "${opt.username}";
'') opt.databases
)}
'') cfg.userDatabases
)
}
END $$;
EOF
'';
systemd.services.postgresql.postStart =
''
$PSQL -tA <<'EOF'
DO $$
DECLARE password TEXT;
BEGIN
${
builtins.concatStringsSep "\n" (
builtins.map (opt: ''
password := trim(both from replace(pg_read_file('${opt.passwordFile}'), E'\n', '''));
EXECUTE format('ALTER ROLE ${opt.username} WITH PASSWORD '''%s''';', password);
${builtins.concatStringsSep "\n" (
builtins.map (db: ''
ALTER DATABASE "${db}" OWNER TO "${opt.username}";
'') opt.databases
)}
'') cfg.userDatabases
)
}
END $$;
EOF
''
+ builtins.concatStringsSep "\n" (
builtins.map (db: ''
$PSQL -d ${db} -f "${(pkgs.writeText "init-${db}.sql" (builtins.getAttr db cfg.initSQL))}"
'') (builtins.attrNames cfg.initSQL)
);

environment.persistence."${config.mySystem.impermanence.persistPath}" =
lib.mkIf config.mySystem.impermanence.enable
Expand Down
1 change: 1 addition & 0 deletions modules/system/containers/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ _: {
./forgejo
./gluetun
./homepage
./immich
./jellyfin
./lldap
./maddy
Expand Down
55 changes: 55 additions & 0 deletions modules/system/containers/immich/album-creator.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
config,
lib,
pkgs,
...
}:
let
cfg = config.mySystemApps.immich;
in
{
config = lib.mkIf cfg.enable {
systemd =
let
image = "ghcr.io/salvoxia/immich-folder-album-creator:0.15.0@sha256:0454e88b26298abe2ae546f64dd16c40357352b853712d1200b1d002df8198a8";
in
{
services.docker-immich-album-creator = {
description = "Run immich album creator";
path = [ pkgs.docker ];
serviceConfig.Type = "simple";
script = ''
exec docker \
run \
--rm \
--name=immich-album-creator \
--log-driver=journald \
-e ALBUM_LEVELS=1 \
-e API_KEY=$(cat ${config.sops.secrets."${cfg.sopsSecretPrefix}/AJGON_API_KEY".path}) \
-e API_URL=http://immich-server:2283/api/ \
-e MODE=CREATE \
-e ROOT_PATH=/external \
-e SYNC_MODE=1 \
-e UNATTENDED=1 \
-e TZ=Europe/Warsaw \
--mount type=tmpfs,destination=/tmp,tmpfs-mode=1777 \
-v ${cfg.photosPath}:/external:ro \
--read-only \
'--cap-drop=all' \
'--security-opt=no-new-privileges' \
'--add-host=host.docker.internal:172.30.0.1' \
'--network=private' \
${image} /script/immich_auto_album.sh
'';
};

timers.docker-immich-album-creator = {
description = "Immich album creator timer.";
wantedBy = [ "timers.target" ];
partOf = [ "docker-recyclarr.service" ];
timerConfig.OnCalendar = "daily";
timerConfig.Persistent = "true";
};
};
};
}
Loading

0 comments on commit 4c08c17

Please sign in to comment.