Added mail notifications on failure. Needs more work on lib.nix and the services/*.nix.

This commit is contained in:
Raphaël Numbus
2026-02-23 16:36:40 +01:00
parent f445bd8659
commit 944ffcea85
14 changed files with 460 additions and 147 deletions
+6
View File
@@ -4,6 +4,12 @@ with lib;
{
options.numbus = {
owner = {
type = type.str;
example = "Alex";
default = "Numbus";
description = "The name of the person who owns this server";
};
services = {
domain = mkOption {
+2
View File
@@ -2,6 +2,8 @@
{
imports = [
./smart.nix
./systemd-failures.nix
./smtp.nix
];
}
+61
View File
@@ -0,0 +1,61 @@
{ config, pkgs, ... }:
let
smartd_notifier = pkgs.writeScript "smartd-notify.sh" ''
#!${pkgs.bash}/bin/bash
# 1. Send Technical Email to Admin
ADMIN_EMAIL="${config.numbus.mail.adminAddress}"
SUBJECT="Numbus Server Alert: $SMARTD_FAILTYPE on $SMARTD_DEVICE"
TECH_BODY="
SMARTD Alert Details:
Server owner: $OWNER_NAME
Device: $SMARTD_DEVICE
Type: $SMARTD_DEVICETYPE
Failure Type: $SMARTD_FAILTYPE
Message: $SMARTD_MESSAGE
Full Message:
$SMARTD_FULLMESSAGE
"
printf "Subject: [ADMIN] $SUBJECT\n\n$TECH_BODY" | /run/wrappers/bin/sendmail -t "$ADMIN_EMAIL"
# 2. Send Friendly Email to Owner
USER_EMAIL="${config.numbus.mail.userAddress}"
OWNER_NAME="${config.numbus.owner}"
FRIENDLY_BODY="Cher/Chère $OWNER_NAME,
Votre serveur a automatiquement détecté une panne matérielle de disque dur.
Ce genre de panne est tout à fait normal selon l'âge de votre matériel et n'entraîne
dans la grande majorité des cas aucune perte de données grâce au système de
stockage redondant préventif.
Votre administrateur a été notifié de cette panne. Il vous recontactera dans de très
brefs délais afin de procéder au remplacement, si nécessaire, du disque dur défaillant.
Merci de votre confiance,
L'équipe de support,
Numbus-Server."
printf "Subject: [Alerte] Défaillance matérielle sur votre serveur Numbus\n\n$FRIENDLY_BODY" | /run/wrappers/bin/sendmail -t "$USER_EMAIL"
'';
in
{
services.smartd = {
enable = true;
defaults.autodetected = "-a -o on -S on -s (S/../.././00|L/../../6/01) -n standby,q -M exec ${smartd_notifier}";
notifications = {
wall = {
enable = true;
};
mail = {
enable = true;
sender = config.numbus.mail.fromAddress;
recipient = "${config.numbus.mail.userAddress},${config.numbus.mail.adminAddress}";
};
};
};
}
+3 -3
View File
@@ -3,11 +3,11 @@
with lib;
let
cfg = config.numbus.services.mail;
cfg = config.numbus.mail;
in
{
options.numbus.services.mail = {
options.numbus.mail = {
enable = mkEnableOption "Email sending functionality";
userAddress = mkOption {
@@ -31,7 +31,7 @@ in
smtpPasswordPath = mkOption {
description = "The path to a file containing the password that will be use to authenticate to the SMTP server";
type = types.path;
example = "/run/secrets/smtp-password";
example = /run/secrets/smtp-password;
};
fromAddress = mkOption {
+55
View File
@@ -0,0 +1,55 @@
{ config, pkgs, ... }:
let
systemd_notifier = pkgs.writeScript "systemd-email-notify.sh" ''
#!${pkgs.bash}/bin/bash
# The failing service name is passed as the first argument
UNIT=$1
# 1. Send Technical Email to Admin
ADMIN_EMAIL="${config.numbus.mail.adminAddress}"
SUBJECT="Numbus Server Alert: Service $UNIT Failed"
# Retrieve recent logs for context
LOGS=$(journalctl -u "$UNIT" -n 20 --no-pager)
TECH_BODY="
Systemd Service Failure Alert:
Server owner: ${config.numbus.owner}
Service: $UNIT
Recent Logs:
$LOGS
"
printf "Subject: [ADMIN] $SUBJECT\n\n$TECH_BODY" | /run/wrappers/bin/sendmail -t "$ADMIN_EMAIL"
# 2. Send Friendly Email to Owner
USER_EMAIL="${config.numbus.mail.userAddress}"
OWNER_NAME="${config.numbus.owner}"
FRIENDLY_BODY="Cher/Chère $OWNER_NAME,
Votre serveur a détecté une défaillance du service $UNIT.
Le système a tenté de gérer l'erreur, mais une intervention peut être nécessaire.
Votre administrateur a été notifié de cet incident avec les détails techniques nécessaires.
Il interviendra si une action manuelle est requise.
Merci de votre confiance,
L'équipe de support,
Numbus-Server."
printf "Subject: [Alerte] Erreur sur votre serveur Numbus\n\n$FRIENDLY_BODY" | /run/wrappers/bin/sendmail -t "$USER_EMAIL"
'';
in
{
systemd.services."service-failure-notify@" = {
description = "Email notification for failed service %i";
onFailure = [ ];
serviceConfig = {
Type = "oneshot";
ExecStart = "${systemd_notifier} %i";
};
};
}
+2 -2
View File
@@ -3,11 +3,11 @@
with lib;
let
cfg = config.numbus.services.networking;
cfg = config.numbus.networking;
in
{
options.numbus.services.networking = {
options.numbus.networking = {
ipAddress = mkOption {
description = "The IP address that this server will use";
type = types.str;
+1
View File
@@ -5,5 +5,6 @@
./packages.nix
./podman.nix
./ssh.nix
./terminal.nix
];
}
+24
View File
@@ -0,0 +1,24 @@
{ config, pkgs, ... }:
{
environment.systemPackages = with pkgs; [
fish
fishPlugins.fzf-fish
fishPlugins.grc
grc
fzf
];
programs.fish = {
enable = true;
interactiveShellInit = ''
set fish_greeting # Disable greeting
fastfetch
echo -e "\n\nWelcome to your Numbus-Server !\n\n- This system is managed by NixOS\n- All changes are futile\n- Please consider buying support if you can't get your server running\n- Have a nice day and enjoy !"
'';
shellAliases = {
nixup = "cd /etc/nixos/ && sudo nix flake update && sudo nixos-rebuild --flake . switch --upgrade && cd -";
nixwitch = "cd /etc/nixos/ && sudo nix flake update && sudo nixos-rebuild --flake . switch && cd -";
};
};
}
+5 -2
View File
@@ -3,7 +3,9 @@
with lib;
let
# Version tagging
frigateVersion = "0.16.4";
# Helper
helper = import ./lib.nix { inherit config pkgs lib; };
cfg = config.numbus.services.frigate;
in
@@ -15,6 +17,7 @@ helper.mkPodmanService {
defaultPort = "8971";
scheme = "https";
dependencies = [ "traefik.service" "${config.numbus.services.dns}.service" "home-assistant.service" ];
envFile = "/var/lib/numbus-server/home-assistant/.env";
extraOptions = {
devices = mkOption {
@@ -45,8 +48,8 @@ helper.mkPodmanService {
tmpfs:
size: 1000000000
environment:
- FRIGATE_MQTT_USER=$FRIGATE_MQTT_USER
- FRIGATE_MQTT_PASSWORD=$FRIGATE_MQTT_PASSWORD
- FRIGATE_MQTT_USER=$HOME_ASSISTANT_MQTT_USER
- FRIGATE_MQTT_PASSWORD=$HOME_ASSISTANT_MQTT_PASSWORD
${lib.optionalString (cfg.devices != []) ''
devices:
${lib.concatStringsSep "\n" (map (d: " - \"${d}\"") cfg.devices)}
+17 -1
View File
@@ -3,8 +3,10 @@
with lib;
let
# Version tagging
giteaVersion = "1.25.4-rootless";
databaseVersion = "18-alpine";
# Helper
helper = import ./lib.nix { inherit config pkgs lib; };
cfg = config.numbus.services.gitea;
in
@@ -14,6 +16,20 @@ helper.mkPodmanService {
name = "gitea";
pod = "gitea";
defaultPort = "3000";
dataDirEnabled = false;
generatedSecrets = {
DB_NAME = "xkcdpass -n 2 -d -";
DB_USERNAME = "xkcdpass -n 2 -d -";
DB_PASSWORD = "xkcdpass -n 8 -d -";
};
importedSecrets = {
DOMAIN_NAME = "${config.numbus.services.domain}";
POSTGRES_HOST="gitea-database";
POSTGRES_PORT=5432;
};
dirPermissions = [
"100999:users ${cfg.configDir}"
];
composeText = ''
services:
@@ -49,7 +65,7 @@ helper.mkPodmanService {
image: docker.io/library/postgres:${databaseVersion}
container_name: gitea-database
hostname: gitea-database
user: '999:999'
user: '1000:1000'
networks:
gitea:
volumes:
+79 -2
View File
@@ -14,7 +14,15 @@ helper.mkPodmanService {
name = "home-assistant";
pod = "home-assistant";
defaultPort = "8123";
dataDir = false;
dataDirEnabled = false;
generatedSecrets = {
HOME_ASSISTANT_MQTT_USER = "xkcdpass -n 2 -d -";
HOME_ASSISTANT_MQTT_PASSWORD = "xkcdpass -n 8 -d -";
};
dirPermissions = [
"numbus-admin:users ${cfg.configDir}/home-assistant"
"100999:users ${cfg.configDir}/mqtt"
];
extraOptions = {
devices = mkOption {
@@ -25,6 +33,75 @@ helper.mkPodmanService {
};
};
extraConfig = {
systemd.services."${name}-quirk-1" = {
description = "Podman container quirk 1 : ${name}";
wantedBy = [ "multi-user.target" ];
after = [ "${name}.service" ];
onFailure = [ "service-failure-notify@%n.service" ];
startLimitBurst = 5;
startLimitIntervalSec = 600;
path = [ pkgs.coreutils pkgs.systemd ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = ''
mkdir -p /var/lib/numbus-server/${name}
if [[ -e /var/lib/numbus-server/${name}/quirk-1.true ]]; then
exit 0
fi
until [[ -e ${cfg.configDir}/home-assistant/configuration.yaml ]]; do
sleep 15
done
cat << 'EOF' >> ${cfg.configDir}/home-assistant/configuration.yaml
http:
use_x_forwarded_for: true
trusted_proxies: ${config.numbus.networking.ipAddress}/24
zha:
EOF
systemctl restart ${name}.service
touch /var/lib/numbus-server/${name}/quirk-1.true
'';
};
};
systemd.services."${name}-quirk-2" = {
description = "Podman container quirk 2 : ${name}";
wantedBy = [ "multi-user.target" "${name}.service" ];
after = [ "${name}-secrets.service" ];
before = [ "${name}.service" "${name}-permissions.service" ];
onFailure = [ "service-failure-notify@%n.service" ];
startLimitBurst = 5;
startLimitIntervalSec = 600;
path = [ pkgs.coreutils pkgs.mosquitto ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = ''
mkdir -p /var/lib/numbus-server/${name}
if [[ -e /var/lib/numbus-server/${name}/quirk.true ]]; then
exit 0
fi
cat << EOF >> ${cfg.configDir}/mqtt/mosquitto.conf
persistence true
persistence_location /mosquitto/data/
log_dest file /mosquitto/log/mosquitto.log
listener 1883
## Authentication ##
allow_anonymous false
password_file /mosquitto/password.txt
EOF
source /var/lib/numbus-server/${name}/.env
mosquitto_passwd -b ${cfg.configDir}/mqtt/password.txt "$HOME_ASSISTANT_MQTT_USER" "$HOME_ASSISTANT_MQTT_PASSWORD"
chmod 600 ${cfg.configDir}/mqtt/password.txt
touch /var/lib/numbus-server/${name}/quirk.true
'';
};
# Compose file good
composeText = ''
services:
@@ -37,7 +114,7 @@ helper.mkPodmanService {
ports:
- "${cfg.port}:8123/tcp"
volumes:
- ${cfg.configDir}/config:/config
- ${cfg.configDir}/home-assistant:/config
- /etc/localtime:/etc/localtime:ro
- /run/dbus:/run/dbus:ro
${lib.optionalString (cfg.devices != []) ''
+26 -13
View File
@@ -3,26 +3,39 @@
with lib;
let
# Version tagging
immichVersion = "v2.5.6";
redisVersion = "9@sha256:546304417feac0874c3dd576e0952c6bb8f06bb4093ea0c9ca303c73cf458f63";
databaseVersion = "14-vectorchord0.4.3-pgvectors0.2.0@sha256:bcf63357191b76a916ae5eb93464d65c07511da41e3bf7a8416db519b40b1c23";
# Helper
helper = import ./lib.nix { inherit config pkgs lib; };
cfg = config.numbus.services.immich;
cfg = config.numbus.services.${name};
# Container configuration
name = "immich";
in
helper.mkPodmanService {
description = "Immich, Google Photos but better";
name = "immich";
inherit name;
pod = "immich";
defaultPort = "2283";
useSopsSecrets = true;
extraConfig = {
numbus.services.immich.secretMapping = {
DB_PASSWORD = "db_password";
DB_USERNAME = "db_username"; # Assuming you add this to schema
};
generatedSecrets = {
DB_NAME = "xkcdpass -n 2 -d -";
DB_USERNAME = "xkcdpass -n 2 -d -";
DB_PASSWORD = "xkcdpass -n 8 -d -";
};
importedSecrets = {
DOMAIN_NAME = "${config.numbus.services.domain}";
REDIS_HOSTNAME = "immich-redis";
DB_HOSTNAME = "immich-database";
UPLOAD_LOCATION = "${cfg.dataDir}";
DB_DATA_LOCATION = "${cfg.configDir}/database";
TZ = "${time.timeZone}";
};
dirPermissions = [
"100999:users ${cfg.dataDir}"
"100999:users ${cfg.configDir}"
];
# Compose file good
composeText = ''
@@ -37,7 +50,7 @@ helper.mkPodmanService {
ports:
- "${cfg.port}:2283/tcp"
volumes:
- $UPLOAD_LOCATION:/data
- ${cfg.dataDir}:/data
- /etc/localtime:/etc/localtime:ro
env_file:
- .env
@@ -85,16 +98,16 @@ helper.mkPodmanService {
container_name: immich-database
hostname: immich-database
image: ghcr.io/immich-app/postgres:${databaseVersion}
user: '999:999'
user: '1000:1000'
networks:
immich:
environment:
POSTGRES_PASSWORD: $DB_PASSWORD
POSTGRES_USER: $DB_USERNAME
POSTGRES_DB: $DB_DATABASE_NAME
POSTGRES_DB: $DB_NAME
POSTGRES_INITDB_ARGS: '--data-checksums'
volumes:
- $DB_DATA_LOCATION:/var/lib/postgresql/data
- ${cfg.configDir}/database:/var/lib/postgresql/data
shm_size: 128mb
healthcheck:
disable: false
+157 -110
View File
@@ -4,147 +4,194 @@ with lib;
{
mkPodmanService = {
description,
name,
secondName ? null,
thirdName ? null,
description,
defaultPort ? "0",
defaultSubdomain ? name,
secondDefaultSubdomain ? secondName,
thirdDefaultSubdomain ? thirdName,
defaultPort ? "",
secondDefaultPort ? "",
thirdDefaultPort ? "",
scheme ? "http",
secondScheme ? "http",
thirdScheme ? "http",
pod ? name,
reverseProxied ? true,
secondReverseProxied ? false,
thirdReverseProxied ? false,
configDirEnabled ? true,
secondConfigDirEnabled ? false,
thirdConfigDirEnabled ? false,
dataDirEnabled ? true,
secondDataDirEnabled ? false,
thirdDataDirEnabled ? false,
pod ? "false",
composeText,
extraOptions ? {},
extraConfig ? {},
delaySec ? 180,
useSopsSecrets ? false, # New argument to enable sops integration
scheme ? "http",
middlewares ? [ "secureHeaders" ],
dependencies ? [ "traefik.service" "${config.numbus.services.dns}.service" ],
extraOptions ? {},
extraConfig ? {},
configDirEnabled ? true,
dataDirEnabled ? true,
startDelay ? 180,
dirPermissions ? [],
generatedSecrets ? {},
importedSecrets ? {},
envFile ? null,
}:
let
mkServiceOpts = svcName: svcDesc: svcPort: svcSubdomain: svcReverseProxied: svcConfigDir: svcDataDir:
{
numbus.services.${svcName} = {
enable = mkEnableOption svcDesc;
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:
${svcName}:
rule: "Host(`${svcCfg.subdomain}.${config.numbus.services.domain}`)"
entrypoints:
- "websecure"
service: ${svcName}
middlewares:
${concatStringsSep "\n" (map (m: " - ${m}") middlewares)}
tls:
certresolver: "cloudflare"
options: "secureTLS"
services:
${svcName}:
loadBalancer:
servers:
- url: "${svcScheme}://host.containers.internal:${svcCfg.port}"
'';
};
hasSecrets = (generatedSecrets != {}) || (importedSecrets != {});
envFilePath = if envFile == null then "/var/lib/numbus-server/${name}/.env" else envFile;
envFileArg = if hasSecrets || envFile != null then "--env-file ${envFilePath}" else "";
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; }
];
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;
example = reverseProxied;
description = "Whether to create a Traefik reverse proxy configuration for this service.";
};
} // (optionalAttrs configDirEnabled {
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 dataDirEnabled {
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 [
{
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;
})
];
environment.etc."${config.numbus.traefikDynamicConfigDir}/${name}.yaml" = mkIf cfg.reverseProxied {
text = ''
http:
routers:
${name}:
rule: "Host(`${cfg.subdomain}.${config.numbus.services.domain}`)"
entrypoints:
- "websecure"
service: ${name}
middlewares:
${concatStringsSep "\n" (map (m: " - ${m}") middlewares)}
tls:
certresolver: "cloudflare"
options: "secureTLS"
services:
${name}:
loadBalancer:
servers:
- url: "${scheme}://host.containers.internal:${cfg.port}"
'';
};
systemd.services."${name}" = {
description = "Podman container : ${name}";
requires = dependencies;
after = dependencies;
wantedBy = [ "multi-user.target" ];
onFailure = [ "service-failure-notify@%n.service" ];
startLimitBurst = 5;
startLimitIntervalSec = 600;
path = [ pkgs.podman pkgs.podman-compose pkgs.coreutils pkgs.sudo ];
serviceConfig = {
Type = "exec";
ExecStartPre = [
"bash -c 'sleep $((RANDOM % ${toString delaySec}))'"
"- sudo -u numbus-admin podman-compose -f /etc/podman/${name}/compose.yaml pull"
"bash -c 'sleep $((RANDOM % ${toString startDelay}))'"
"- sudo -u numbus-admin podman-compose ${envFileArg} -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";
ExecStart = "sudo -u numbus-admin podman-compose ${envFileArg} --in-pod ${toString pod} -f /etc/podman/${name}/compose.yaml up --remove-orphans";
ExecStop = "sudo -u numbus-admin podman-compose ${envFileArg} --in-pod ${toString pod} -f /etc/podman/${name}/compose.yaml down";
Restart = "on-failure";
RestartSec = "1m";
StartLimitBurst = "5";
};
};
systemd.services."${name}-permissions" = mkIf dirPermissions != [] {
description = "Podman container : ${name} : check and fix permissions";
before = [ "${name}.service" ];
wantedBy = [ "multi-user.target" "${name}.service" ];
onFailure = [ "service-failure-notify@%n.service" ];
startLimitBurst = 5;
startLimitIntervalSec = 600;
path = [ pkgs.coreutils ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
Restart = "on-failure";
RestartSec = "1m";
};
script = ''
mkdir -p /var/lib/numbus-server/${name}
${concatStringsSep "\n" (map (perm: ''
set -- ${perm}
MARKER="/var/lib/numbus-server/${name}/.perm-fixed-$(echo "$1:$2" | md5sum | cut -d' ' -f1)"
if [ ! -f "$MARKER" ]; then
rm -f /var/lib/numbus-server/${name}/.perm-fixed-*
mkdir -p "$2"
chown -R "$1" "$2"
touch "$MARKER"
fi
'') dirPermissions)}
exit 0
'';
};
systemd.services."${name}-secrets" = mkIf hasSecrets {
description = "Podman container create secrets : ${name}";
before = [ "${name}.service" ];
wantedBy = [ "multi-user.target" "${name}.service" ];
onFailure = [ "service-failure-notify@%n.service" ];
startLimitBurst = 5;
startLimitIntervalSec = 600;
path = [ pkgs.coreutils pkgs.xkcdpass pkgs.gnugrep ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
Restart = "on-failure";
RestartSec = "1m";
};
script = ''
mkdir -p /var/lib/numbus-server/${name}
SECRETS_FILE="${envFilePath}"
if [[ ! -f "$SECRETS_FILE" ]]; then
touch "$SECRETS_FILE"
fi
# Generated Secrets (only if missing)
${concatStringsSep "\n" (mapAttrsToList (k: v: ''
if ! grep -q "^${k}=" "$SECRETS_FILE"; then
echo "${k}=$(${v})" >> "$SECRETS_FILE"
fi
'') generatedSecrets)}
# Imported Secrets (update or append)
${concatStringsSep "\n" (mapAttrsToList (k: v: ''
if grep -q "^${k}=" "$SECRETS_FILE"; then
grep -v "^${k}=" "$SECRETS_FILE" > "$SECRETS_FILE.tmp"
mv "$SECRETS_FILE.tmp" "$SECRETS_FILE"
fi
echo "${k}=${lib.escapeShellArg v}" >> "$SECRETS_FILE"
'') importedSecrets)}
chown numbus-admin:users "$SECRETS_FILE"
chmod 600 "$SECRETS_FILE"
'';
};
}
extraConfig
]);
+22 -14
View File
@@ -18,17 +18,25 @@ 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;
generatedSecrets = {
DB_NAME = "xkcdpass -n 2 -d -";
DB_USERNAME = "xkcdpass -n 2 -d -";
DB_PASSWORD = "xkcdpass -n 8 -d -";
REDIS_PASSWORD = "xkcdpass -n 8 -d -";
};
importedSecrets = {
DOMAIN_NAME = "${config.numbus.services.domain}";
REDIS_HOSTNAME = "immich-redis";
DB_HOSTNAME = "immich-database";
UPLOAD_LOCATION = "${cfg.dataDir}";
DB_DATA_LOCATION = "${cfg.configDir}/database";
TZ = "${time.timeZone}";
};
dirPermissions = [
"100999:users ${cfg.dataDir}"
"100999:users ${cfg.configDir}"
];
# Compose file good
composeText = ''
@@ -46,11 +54,11 @@ helper.mkPodmanService {
- ${cfg.dataDir}:/mnt/ncdata
environment:
MYSQL_HOST: nextcloud-database
MYSQL_DATABASE: $MYSQL_DATABASE
MYSQL_USER: $MYSQL_USER
MYSQL_PASSWORD: $MYSQL_PASSWORD
MYSQL_DATABASE: $DB_NAME
MYSQL_USER: $DB_USERNAME
MYSQL_PASSWORD: $DB_PASSWORD
REDIS_HOST: nextcloud-redis
REDIS_HOST_PASSWORD: $REDIS_HOST_PASSWORD
REDIS_HOST_PASSWORD: $REDIS_PASSWORD
NEXTCLOUD_TRUSTED_DOMAINS: ${cfg.subdomain}.${config.numbus.services.domain}
NEXTCLOUD_DATA_DIR: /mnt/ncdata
SMTP_HOST: $SMTP_HOST