librechat: add meilisearch #48

Merged
sid merged 2 commits from develop into release-25.11 2026-05-19 20:54:21 +02:00
Showing only changes of commit dd7fea5711 - Show all commits

View file

@ -8,7 +8,8 @@
let let
cfg = config.services.librechat-oci; cfg = config.services.librechat-oci;
image = pkgs.dockerTools.pullImage { defaultImages = {
librechat = pkgs.dockerTools.pullImage {
imageName = "ghcr.io/danny-avila/librechat"; imageName = "ghcr.io/danny-avila/librechat";
imageDigest = "sha256:a46254938507971e0d4f7ed3f9d116bd9b118f4810b5b75eb716baf575645068"; imageDigest = "sha256:a46254938507971e0d4f7ed3f9d116bd9b118f4810b5b75eb716baf575645068";
hash = "sha256-zevUN6vrs3hymwCGFmk/YXlUzYjN37H+EO5aLxYchyc="; hash = "sha256-zevUN6vrs3hymwCGFmk/YXlUzYjN37H+EO5aLxYchyc=";
@ -16,7 +17,7 @@ let
finalImageTag = "v0.8.5"; finalImageTag = "v0.8.5";
}; };
meiliImage = pkgs.dockerTools.pullImage { meilisearch = pkgs.dockerTools.pullImage {
imageName = "getmeili/meilisearch"; imageName = "getmeili/meilisearch";
imageDigest = "sha256:b839a48d008d4e67e57f78dcff5b21d5e8b8fa066bacd11f97824d6307abb0dd"; imageDigest = "sha256:b839a48d008d4e67e57f78dcff5b21d5e8b8fa066bacd11f97824d6307abb0dd";
hash = "sha256-+hypvjFDSdnnWAO4tARTnjNd/6HlF6pMg1L6UUffdYM="; hash = "sha256-+hypvjFDSdnnWAO4tARTnjNd/6HlF6pMg1L6UUffdYM=";
@ -24,16 +25,137 @@ let
finalImageTag = "v1.44.0"; finalImageTag = "v1.44.0";
}; };
mongodb = pkgs.dockerTools.pullImage {
imageName = "mongo";
imageDigest = "sha256:098862b1339f031900ca66cf8fef799e616d6324fa41b9a263f2ec899552c1ef";
hash = "sha256-XuWnvcqAAkAGshdQtnngKOOJP2Bd33FXTbGHTRX3nUc=";
finalImageName = "mongo";
finalImageTag = "8.0.20";
};
vectordb = pkgs.dockerTools.pullImage {
imageName = "pgvector/pgvector";
imageDigest = "sha256:8809cfffff0082cf260c9ac752f1dd1afc77f6f0a55c4e6411321e78efc3d9a5";
hash = "sha256-rc6gQLMzv8UOZVLmWKGUESNIo+iPf5DR7T79AmbzWc4=";
finalImageName = "pgvector/pgvector";
finalImageTag = "0.8.0-pg15-trixie";
};
ragApi = pkgs.dockerTools.pullImage {
imageName = "registry.librechat.ai/danny-avila/librechat-rag-api-dev-lite";
imageDigest = "sha256:6dfb6832661ff9c26fa329c823ce266059e33567670a763e9ecb9b566b8daa68";
hash = "sha256-k8pkEgbqT4NU2+2ZjdRFlfFvMUk/1p+pkysbELh95pM=";
finalImageName = "registry.librechat.ai/danny-avila/librechat-rag-api-dev-lite";
finalImageTag = "latest";
};
};
defaultEnv = { defaultEnv = {
# Server
HOST = "0.0.0.0"; HOST = "0.0.0.0";
PORT = "3080"; PORT = toString cfg.port;
NO_INDEX = "true"; NO_INDEX = "true";
DEBUG_LOGGING = "false"; TRUST_PROXY = "1";
# Logging
CONSOLE_JSON = "false"; CONSOLE_JSON = "false";
ALLOW_REGISTRATION = "true"; DEBUG_LOGGING = "true";
ALLOW_EMAIL_LOGIN = "true"; DEBUG_CONSOLE = "false";
AGENT_DEBUG_LOGGING = "false";
DEBUG_OPENAI = "false";
# Node
NODE_MAX_OLD_SPACE_SIZE = "6144";
# Search
SEARCH = "true"; SEARCH = "true";
MEILI_NO_ANALYTICS = "true"; MEILI_NO_ANALYTICS = "true";
# Moderation
OPENAI_MODERATION = "false";
BAN_VIOLATIONS = "true";
BAN_DURATION = "1000 * 60 * 60 * 2";
BAN_INTERVAL = "20";
LOGIN_VIOLATION_SCORE = "1";
REGISTRATION_VIOLATION_SCORE = "1";
CONCURRENT_VIOLATION_SCORE = "1";
MESSAGE_VIOLATION_SCORE = "1";
NON_BROWSER_VIOLATION_SCORE = "20";
TTS_VIOLATION_SCORE = "0";
STT_VIOLATION_SCORE = "0";
FORK_VIOLATION_SCORE = "0";
IMPORT_VIOLATION_SCORE = "0";
FILE_UPLOAD_VIOLATION_SCORE = "0";
LOGIN_MAX = "7";
LOGIN_WINDOW = "5";
REGISTER_MAX = "5";
REGISTER_WINDOW = "60";
LIMIT_CONCURRENT_MESSAGES = "true";
CONCURRENT_MESSAGE_MAX = "2";
LIMIT_MESSAGE_IP = "true";
MESSAGE_IP_MAX = "40";
MESSAGE_IP_WINDOW = "1";
LIMIT_MESSAGE_USER = "false";
MESSAGE_USER_MAX = "40";
MESSAGE_USER_WINDOW = "1";
ILLEGAL_MODEL_REQ_SCORE = "5";
# Registration and login
ALLOW_EMAIL_LOGIN = "true";
ALLOW_REGISTRATION = "false";
ALLOW_SOCIAL_LOGIN = "false";
ALLOW_SOCIAL_REGISTRATION = "false";
ALLOW_PASSWORD_RESET = "false";
ALLOW_UNVERIFIED_EMAIL_LOGIN = "true";
SESSION_EXPIRY = "1000 * 60 * 15";
REFRESH_TOKEN_EXPIRY = "(1000 * 60 * 60 * 24) * 7";
# OpenID
OPENID_SCOPE = "openid profile email";
OPENID_CALLBACK_URL = "/oauth/openid/callback";
OPENID_AUTO_REDIRECT = "false";
OPENID_USE_PKCE = "false";
OPENID_ON_BEHALF_FLOW_USERINFO_SCOPE = "user.read";
# OAuth callback URLs
DISCORD_CALLBACK_URL = "/oauth/discord/callback";
FACEBOOK_CALLBACK_URL = "/oauth/facebook/callback";
GITHUB_CALLBACK_URL = "/oauth/github/callback";
GOOGLE_CALLBACK_URL = "/oauth/google/callback";
APPLE_CALLBACK_URL = "/oauth/apple/callback";
SAML_CALLBACK_URL = "/oauth/saml/callback";
# Entra ID
USE_ENTRA_ID_FOR_PEOPLE_SEARCH = "false";
ENTRA_ID_INCLUDE_OWNERS_AS_MEMBERS = "false";
OPENID_GRAPH_SCOPES = "User.Read,People.Read,GroupMember.Read.All";
# Shared links
ALLOW_SHARED_LINKS = "true";
ALLOW_SHARED_LINKS_PUBLIC = "false";
# UI
APP_TITLE = "LibreChat";
HELP_AND_FAQ_URL = "https://librechat.ai";
# Flux
FLUX_API_BASE_URL = "https://api.us1.bfl.ai";
# Email
EMAIL_PORT = "25";
EMAIL_FROM = "noreply@librechat.ai";
# Azure Blob Storage
AZURE_STORAGE_PUBLIC_ACCESS = "false";
AZURE_CONTAINER_NAME = "files";
};
mkImageOption =
name: description:
mkOption {
type = types.package;
default = defaultImages.${name};
description = description;
}; };
inherit (lib) inherit (lib)
@ -42,51 +164,67 @@ let
mkIf mkIf
mkOption mkOption
mkOverride mkOverride
optional
types types
; ;
in in
{ {
options.services.librechat-oci = { options.services.librechat-oci = {
enable = mkEnableOption "LibreChat container with Podman."; enable = mkEnableOption "LibreChat container with Podman.";
image = mkOption {
type = types.package; images = {
default = image; librechat = mkImageOption "librechat" "The LibreChat Docker image (`pkgs.dockerTools.pullImage`).";
description = "The Docker image to use (`pkgs.dockerTools.pullImage`)."; meilisearch = mkImageOption "meilisearch" "The Meilisearch Docker image (`pkgs.dockerTools.pullImage`).";
}; mongodb = mkImageOption "mongodb" "The MongoDB Docker image (`pkgs.dockerTools.pullImage`).";
meiliImage = mkOption { vectordb = mkImageOption "vectordb" "The pgvector Docker image (`pkgs.dockerTools.pullImage`).";
type = types.package; ragApi = mkImageOption "ragApi" "The LibreChat RAG API Docker image (`pkgs.dockerTools.pullImage`).";
default = meiliImage;
description = "The Meilisearch Docker image to use (`pkgs.dockerTools.pullImage`).";
}; };
externalUrl = mkOption { externalUrl = mkOption {
type = types.nullOr types.str; type = types.nullOr types.str;
default = null; default = null;
example = literalExpression "http://${config.networking.domain}"; example = literalExpression ''"https://chat.example.com"'';
description = "Public URL to configure for LibreChat."; description = "Public URL to configure for LibreChat (sets DOMAIN_CLIENT and DOMAIN_SERVER).";
}; };
port = mkOption { port = mkOption {
type = types.port; type = types.port;
default = 3080; default = 3080;
description = "Which port the LibreChat server listens to."; description = "Which port the LibreChat server listens on.";
}; };
meiliPort = mkOption { meiliPort = mkOption {
type = types.port; type = types.port;
default = 7700; default = 7700;
description = "Which port Meilisearch listens to."; description = "Which port Meilisearch listens on.";
}; };
ragPort = mkOption {
type = types.port;
default = 8000;
description = "Which port the RAG API listens on.";
};
environment = mkOption { environment = mkOption {
default = { }; default = { };
type = types.attrsOf types.str; type = types.attrsOf types.str;
description = '' description = ''
Extra environment variables for LibreChat. Extra environment variables for LibreChat.
For more details see <https://docs.librechat.ai/docs/configuration/dotenv> These are merged on top of the defaults and can override them.
For secrets use <option>environmentFile</option> instead.
See <https://docs.librechat.ai/docs/configuration/dotenv>.
''; '';
}; };
environmentFile = mkOption { environmentFile = mkOption {
description = "Environment file to be passed to the LibreChat container.";
type = types.nullOr types.path; type = types.nullOr types.path;
default = null; default = null;
example = "config.sops.templates.librechat-env.path"; example = literalExpression "config.sops.templates.librechat-env.path";
description = ''
Environment file passed to the LibreChat, Meilisearch, and RAG API
containers. Use this for secrets such as JWT_SECRET, CREDS_KEY,
MEILI_MASTER_KEY, and API keys.
'';
}; };
}; };
@ -107,209 +245,273 @@ in
virtualisation.oci-containers.backend = "podman"; virtualisation.oci-containers.backend = "podman";
virtualisation.oci-containers.containers."librechat-mongodb" = { virtualisation.oci-containers.containers.librechat-mongodb = {
image = "mongo:7.0"; image = with cfg.images.mongodb; "${imageName}:${imageTag}";
environment = { imageFile = cfg.images.mongodb;
MONGO_INITDB_ROOT_USERNAME = "root"; cmd = [
MONGO_INITDB_ROOT_PASSWORD = "librechat"; "mongod"
MONGO_INITDB_DATABASE = "LibreChat"; "--noauth"
}; ];
volumes = [ volumes = [
"librechat_mongodb_data:/data/db:rw" "librechat_mongodb_data:/data/db:rw"
]; ];
log-driver = "journald"; log-driver = "journald";
extraOptions = [ extraOptions = [
"--network=host" "--network-alias=mongodb"
"--network=librechat_default"
]; ];
}; };
virtualisation.oci-containers.containers."librechat-meilisearch" = { virtualisation.oci-containers.containers.librechat-meilisearch = {
image = with cfg.meiliImage; imageName + ":" + imageTag; image = with cfg.images.meilisearch; "${imageName}:${imageTag}";
imageFile = cfg.meiliImage; imageFile = cfg.images.meilisearch;
environment = { environment = {
MEILI_NO_ANALYTICS = "true"; MEILI_NO_ANALYTICS = "true";
MEILI_HOST = "http://meilisearch:${toString cfg.meiliPort}";
}; };
environmentFiles = optional (cfg.environmentFile != null) cfg.environmentFile;
volumes = [ volumes = [
"librechat_meili_data:/meili_data:rw" "librechat_meili_data:/meili_data:rw"
]; ];
log-driver = "journald"; log-driver = "journald";
extraOptions = [ extraOptions = [
"--network=host" "--network-alias=meilisearch"
"--network=librechat_default"
];
};
virtualisation.oci-containers.containers.librechat-vectordb = {
image = with cfg.images.vectordb; "${imageName}:${imageTag}";
imageFile = cfg.images.vectordb;
environment = {
POSTGRES_DB = "mydatabase";
POSTGRES_USER = "myuser";
POSTGRES_PASSWORD = "mypassword";
};
volumes = [
"librechat_pgdata:/var/lib/postgresql/data:rw"
];
log-driver = "journald";
extraOptions = [
"--network-alias=vectordb"
"--network=librechat_default"
];
};
virtualisation.oci-containers.containers.librechat-rag-api = {
image = with cfg.images.ragApi; "${imageName}:${imageTag}";
imageFile = cfg.images.ragApi;
environment = {
DB_HOST = "vectordb";
RAG_PORT = toString cfg.ragPort;
};
environmentFiles = optional (cfg.environmentFile != null) cfg.environmentFile;
dependsOn = [ "librechat-vectordb" ];
log-driver = "journald";
extraOptions = [
"--network-alias=rag_api"
"--network=librechat_default"
]; ];
}; };
virtualisation.oci-containers.containers.librechat = { virtualisation.oci-containers.containers.librechat = {
image = with cfg.image; imageName + ":" + imageTag; image = with cfg.images.librechat; "${imageName}:${imageTag}";
imageFile = cfg.image; imageFile = cfg.images.librechat;
environment = environment =
defaultEnv defaultEnv
// { // {
MONGO_URI = "mongodb://root:librechat@localhost:27017/LibreChat?authSource=admin"; MONGO_URI = "mongodb://mongodb:27017/LibreChat";
MEILI_HOST = "http://localhost:${toString cfg.meiliPort}"; MEILI_HOST = "http://meilisearch:${toString cfg.meiliPort}";
RAG_PORT = toString cfg.ragPort;
RAG_API_URL = "http://rag_api:${toString cfg.ragPort}";
DOMAIN_CLIENT =
if cfg.externalUrl != null then cfg.externalUrl else "http://localhost:${toString cfg.port}";
DOMAIN_SERVER =
if cfg.externalUrl != null then cfg.externalUrl else "http://localhost:${toString cfg.port}";
} }
// cfg.environment; // cfg.environment;
environmentFiles = lib.optional (cfg.environmentFile != null) cfg.environmentFile; environmentFiles = optional (cfg.environmentFile != null) cfg.environmentFile;
volumes = [ volumes = [
"librechat_data:/app/client/data:rw"
"librechat_images:/app/client/public/images:rw" "librechat_images:/app/client/public/images:rw"
"librechat_uploads:/app/api/server/files/uploads:rw" "librechat_uploads:/app/uploads:rw"
"librechat_logs:/app/logs:rw" "librechat_logs:/app/logs:rw"
]; ];
ports = [ ports = [
"${toString cfg.port}:${toString cfg.port}" "127.0.0.1:${toString cfg.port}:${toString cfg.port}/tcp"
];
dependsOn = [
"librechat-mongodb"
"librechat-rag-api"
]; ];
log-driver = "journald"; log-driver = "journald";
extraOptions = [ extraOptions = [
"--network=host" "--network-alias=api"
"--network=librechat_default"
]; ];
}; };
systemd.services."podman-librechat-mongodb" = { systemd.services.podman-librechat-mongodb = {
serviceConfig = { serviceConfig.Restart = mkOverride 90 "always";
Restart = mkOverride 90 "always";
};
after = [ after = [
"podman-network-librechat_default.service"
"podman-volume-librechat_mongodb_data.service" "podman-volume-librechat_mongodb_data.service"
]; ];
requires = [ requires = [
"podman-network-librechat_default.service"
"podman-volume-librechat_mongodb_data.service" "podman-volume-librechat_mongodb_data.service"
]; ];
partOf = [ partOf = [ "podman-compose-librechat-root.target" ];
"podman-compose-librechat-root.target" wantedBy = [ "podman-compose-librechat-root.target" ];
];
wantedBy = [
"podman-compose-librechat-root.target"
];
}; };
systemd.services."podman-librechat-meilisearch" = { systemd.services.podman-librechat-meilisearch = {
serviceConfig = { serviceConfig.Restart = mkOverride 90 "always";
Restart = mkOverride 90 "always";
};
after = [ after = [
"podman-network-librechat_default.service"
"podman-volume-librechat_meili_data.service" "podman-volume-librechat_meili_data.service"
]; ];
requires = [ requires = [
"podman-network-librechat_default.service"
"podman-volume-librechat_meili_data.service" "podman-volume-librechat_meili_data.service"
]; ];
partOf = [ partOf = [ "podman-compose-librechat-root.target" ];
"podman-compose-librechat-root.target" wantedBy = [ "podman-compose-librechat-root.target" ];
];
wantedBy = [
"podman-compose-librechat-root.target"
];
}; };
systemd.services."podman-librechat" = { systemd.services.podman-librechat-vectordb = {
serviceConfig = { serviceConfig.Restart = mkOverride 90 "always";
Restart = mkOverride 90 "always";
};
after = [ after = [
"podman-volume-librechat_data.service" "podman-network-librechat_default.service"
"podman-volume-librechat_pgdata.service"
];
requires = [
"podman-network-librechat_default.service"
"podman-volume-librechat_pgdata.service"
];
partOf = [ "podman-compose-librechat-root.target" ];
wantedBy = [ "podman-compose-librechat-root.target" ];
};
systemd.services.podman-librechat-rag-api = {
serviceConfig.Restart = mkOverride 90 "always";
after = [
"podman-network-librechat_default.service"
"podman-librechat-vectordb.service"
];
requires = [
"podman-network-librechat_default.service"
"podman-librechat-vectordb.service"
];
partOf = [ "podman-compose-librechat-root.target" ];
wantedBy = [ "podman-compose-librechat-root.target" ];
};
systemd.services.podman-librechat = {
serviceConfig.Restart = mkOverride 90 "always";
after = [
"podman-network-librechat_default.service"
"podman-volume-librechat_images.service" "podman-volume-librechat_images.service"
"podman-volume-librechat_uploads.service" "podman-volume-librechat_uploads.service"
"podman-volume-librechat_logs.service" "podman-volume-librechat_logs.service"
"podman-librechat-mongodb.service" "podman-librechat-mongodb.service"
"podman-librechat-meilisearch.service" "podman-librechat-meilisearch.service"
"podman-librechat-rag-api.service"
]; ];
requires = [ requires = [
"podman-volume-librechat_data.service" "podman-network-librechat_default.service"
"podman-volume-librechat_images.service" "podman-volume-librechat_images.service"
"podman-volume-librechat_uploads.service" "podman-volume-librechat_uploads.service"
"podman-volume-librechat_logs.service" "podman-volume-librechat_logs.service"
"podman-librechat-mongodb.service" "podman-librechat-mongodb.service"
"podman-librechat-meilisearch.service" "podman-librechat-meilisearch.service"
"podman-librechat-rag-api.service"
]; ];
partOf = [ partOf = [ "podman-compose-librechat-root.target" ];
"podman-compose-librechat-root.target" wantedBy = [ "podman-compose-librechat-root.target" ];
];
wantedBy = [
"podman-compose-librechat-root.target"
];
}; };
systemd.services."podman-volume-librechat_data" = { systemd.services.podman-network-librechat_default = {
path = [ pkgs.podman ]; path = [ pkgs.podman ];
serviceConfig = { serviceConfig = {
Type = "oneshot"; Type = "oneshot";
RemainAfterExit = true; RemainAfterExit = true;
ExecStop = "podman network rm -f librechat_default";
}; };
script = '' script = ''
podman volume inspect librechat_data || podman volume create librechat_data podman network inspect librechat_default || podman network create librechat_default
''; '';
partOf = [ "podman-compose-librechat-root.target" ]; partOf = [ "podman-compose-librechat-root.target" ];
wantedBy = [ "podman-compose-librechat-root.target" ]; wantedBy = [ "podman-compose-librechat-root.target" ];
}; };
systemd.services."podman-volume-librechat_images" = { systemd.services.podman-volume-librechat_mongodb_data = {
path = [ pkgs.podman ]; path = [ pkgs.podman ];
serviceConfig = { serviceConfig = {
Type = "oneshot"; Type = "oneshot";
RemainAfterExit = true; RemainAfterExit = true;
}; };
script = '' script = "podman volume inspect librechat_mongodb_data || podman volume create librechat_mongodb_data";
podman volume inspect librechat_images || podman volume create librechat_images
'';
partOf = [ "podman-compose-librechat-root.target" ]; partOf = [ "podman-compose-librechat-root.target" ];
wantedBy = [ "podman-compose-librechat-root.target" ]; wantedBy = [ "podman-compose-librechat-root.target" ];
}; };
systemd.services."podman-volume-librechat_uploads" = { systemd.services.podman-volume-librechat_meili_data = {
path = [ pkgs.podman ]; path = [ pkgs.podman ];
serviceConfig = { serviceConfig = {
Type = "oneshot"; Type = "oneshot";
RemainAfterExit = true; RemainAfterExit = true;
}; };
script = '' script = "podman volume inspect librechat_meili_data || podman volume create librechat_meili_data";
podman volume inspect librechat_uploads || podman volume create librechat_uploads
'';
partOf = [ "podman-compose-librechat-root.target" ]; partOf = [ "podman-compose-librechat-root.target" ];
wantedBy = [ "podman-compose-librechat-root.target" ]; wantedBy = [ "podman-compose-librechat-root.target" ];
}; };
systemd.services."podman-volume-librechat_logs" = { systemd.services.podman-volume-librechat_pgdata = {
path = [ pkgs.podman ]; path = [ pkgs.podman ];
serviceConfig = { serviceConfig = {
Type = "oneshot"; Type = "oneshot";
RemainAfterExit = true; RemainAfterExit = true;
}; };
script = '' script = "podman volume inspect librechat_pgdata || podman volume create librechat_pgdata";
podman volume inspect librechat_logs || podman volume create librechat_logs
'';
partOf = [ "podman-compose-librechat-root.target" ]; partOf = [ "podman-compose-librechat-root.target" ];
wantedBy = [ "podman-compose-librechat-root.target" ]; wantedBy = [ "podman-compose-librechat-root.target" ];
}; };
systemd.services."podman-volume-librechat_mongodb_data" = { systemd.services.podman-volume-librechat_images = {
path = [ pkgs.podman ]; path = [ pkgs.podman ];
serviceConfig = { serviceConfig = {
Type = "oneshot"; Type = "oneshot";
RemainAfterExit = true; RemainAfterExit = true;
}; };
script = '' script = "podman volume inspect librechat_images || podman volume create librechat_images";
podman volume inspect librechat_mongodb_data || podman volume create librechat_mongodb_data
'';
partOf = [ "podman-compose-librechat-root.target" ]; partOf = [ "podman-compose-librechat-root.target" ];
wantedBy = [ "podman-compose-librechat-root.target" ]; wantedBy = [ "podman-compose-librechat-root.target" ];
}; };
systemd.services."podman-volume-librechat_meili_data" = { systemd.services.podman-volume-librechat_uploads = {
path = [ pkgs.podman ]; path = [ pkgs.podman ];
serviceConfig = { serviceConfig = {
Type = "oneshot"; Type = "oneshot";
RemainAfterExit = true; RemainAfterExit = true;
}; };
script = '' script = "podman volume inspect librechat_uploads || podman volume create librechat_uploads";
podman volume inspect librechat_meili_data || podman volume create librechat_meili_data
'';
partOf = [ "podman-compose-librechat-root.target" ]; partOf = [ "podman-compose-librechat-root.target" ];
wantedBy = [ "podman-compose-librechat-root.target" ]; wantedBy = [ "podman-compose-librechat-root.target" ];
}; };
systemd.targets."podman-compose-librechat-root" = { systemd.services.podman-volume-librechat_logs = {
unitConfig = { path = [ pkgs.podman ];
Description = "Root target generated by compose2nix."; serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
}; };
script = "podman volume inspect librechat_logs || podman volume create librechat_logs";
partOf = [ "podman-compose-librechat-root.target" ];
wantedBy = [ "podman-compose-librechat-root.target" ];
};
systemd.targets.podman-compose-librechat-root = {
unitConfig.Description = "Root target generated by compose2nix.";
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
}; };
}; };