Compare commits

...
Sign in to create a new pull request.

2 commits

Author SHA1 Message Date
d2a0da648c
feat(solidtime): Add module 2025-10-01 16:36:14 +02:00
bdb4ad8160
Updates 2025-10-01 16:33:55 +02:00
4 changed files with 249 additions and 17 deletions

View file

@ -343,7 +343,7 @@ in {
port = 7878; port = 7878;
in lib.mkIf cfg.radarr.enable { in lib.mkIf cfg.radarr.enable {
hostname = "radarr"; hostname = "radarr";
image = "ghcr.io/hotio/radarr:release-5.28.0.10205"; image = "ghcr.io/hotio/radarr:testing-5.28.0.10205";
autoStart = true; autoStart = true;
ports = lib.mkIf cfg.radarr.exposePorts [ ports = lib.mkIf cfg.radarr.exposePorts [
"${toString port}:${toString port}/tcp" "${toString port}:${toString port}/tcp"

View file

@ -4,6 +4,7 @@ let
cfg = config.homelab.apps.jellyfin; cfg = config.homelab.apps.jellyfin;
networkName = "jellyfin"; networkName = "jellyfin";
inherit (config.homelab.fileSystems) media;
UID = 3008; UID = 3008;
GID = config.users.groups.media.gid; GID = config.users.groups.media.gid;
@ -12,6 +13,11 @@ in {
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
homelab = { homelab = {
fileSystems.media.video = {
enable = true;
permissions = [ "read" ];
};
users = { users = {
apps.enable = true; apps.enable = true;
media.enable = true; media.enable = true;
@ -32,18 +38,6 @@ in {
]; ];
}; };
"/srv/video" = {
device = "192.168.0.11:/mnt/SMALL/MEDIA/VIDEO";
fsType = "nfs";
options = [
"ro"
"nfsvers=4.2"
"async" "soft"
"timeo=100" "retry=50" "actimeo=1800" "lookupcache=all"
"nosuid" "tcp"
];
};
"/srv/homevideo" = { "/srv/homevideo" = {
device = "192.168.0.11:/mnt/BIG/MEDIA/HOMEVIDEO/ARCHIVE"; device = "192.168.0.11:/mnt/BIG/MEDIA/HOMEVIDEO/ARCHIVE";
fsType = "nfs"; fsType = "nfs";
@ -101,7 +95,7 @@ in {
virtualisation.oci-containers.containers = { virtualisation.oci-containers.containers = {
jellyfin = { jellyfin = {
hostname = "jellyfin"; hostname = "jellyfin";
image = "jellyfin/jellyfin:10.10.0"; image = "jellyfin/jellyfin:10.10.7";
user = "${toString UID}:${toString GID}"; user = "${toString UID}:${toString GID}";
autoStart = true; autoStart = true;
ports = [ ports = [
@ -117,7 +111,7 @@ in {
"cache:/cache" "cache:/cache"
"/srv/audio:/media/audio" "/srv/audio:/media/audio"
"/srv/video:/media/video" "${media.video.hostPath}:/media/video"
"/srv/homevideo:/media/homevideo" "/srv/homevideo:/media/homevideo"
"/srv/photo:/media/photo" "/srv/photo:/media/photo"
]; ];
@ -144,7 +138,7 @@ in {
feishinPort = "9180"; feishinPort = "9180";
in { in {
hostname = "feishin"; hostname = "feishin";
image = "ghcr.io/jeffvli/feishin:0.7.1"; image = "ghcr.io/jeffvli/feishin:0.19.0";
autoStart = true; autoStart = true;
ports = [ ports = [
"${feishinPort}:9180/tcp" # Web player (HTTP) "${feishinPort}:9180/tcp" # Web player (HTTP)

View file

@ -0,0 +1,238 @@
{ config, lib, pkgs, ... }:
let
cfg = config.homelab.apps.solidtime;
networkName = "solidtime";
internalNetworkName = "solidtime-internal";
version = "0.8.0";
port = 8000;
user = "1000:1000";
# dbExternalPort = ...;
dbInternalPort = 5432;
gotenbergPort = 3000;
inherit (config.virtualisation.oci-containers) containers;
volumes = [
"solidtime-storage:/var/www/html/storage"
"solidtime-logs:/var/www/html/storage/logs"
"solidtime-app:/var/www/html/storage/app"
];
# laravel.env
laravelEnv = {
APP_NAME = "Solidtime";
VITE_APP_NAME = laravelEnv.APP_NAME;
APP_ENV = "production";
APP_DEBUG = "false";
APP_URL = "http://localhost:${toString port}";
APP_FORCE_HTTPS = "false";
APP_ENABLE_REGISTRATION = "false";
TRUSTED_PROXIES = "0.0.0.0/0,2000:0:0:0:0:0:0:0/3";
# Logging
LOG_CHANNEL = "stderr_daily";
LOG_LEVEL = "debug";
# Database
DB_CONNECTION = "pgsql";
DB_HOST = containers.solidtimeDb.hostname;
DB_PORT = toString dbInternalPort;
DB_SSL_MODE = "require";
DB_DATABASE = "solidtime";
DB_USERNAME = "solidtime";
DB_PASSWORD = "ChangeMe";
# Mail
#MAIL_MAILER = "smtp";
#MAIL_HOST = "smtp.gmail.com";
#MAIL_PORT = "465";
#MAIL_ENCRYPTION = "tls";
#MAIL_FROM_ADDRESS = "no-reply@time.depeuter.dev";
MAIL_FROM_NAME = laravelEnv.APP_NAME;
#MAIL_USERNAME = "kmtl.hugo@gmail.com";
#MAIL_PASSWORD = "fhfxoequhhqidrhd";
# Queue
QUEUE_CONNECTION = "database";
# File storage
FILESYSTEM_DISK = "local";
PUBLIC_FILESYSTEM_DISK = "public";
# Services
GOTENBERG_URL = "http://${containers.solidtimeGotenberg.hostname}:${toString gotenbergPort}";
};
in {
options.homelab.apps.solidtime.enable = lib.mkEnableOption "Solidtime time tracker using Docker";
config = lib.mkIf cfg.enable {
homelab.virtualisation.containers.enable = true;
# Make sure the Docker network exists.
systemd.services = {
"docker-${networkName}-create-network" = {
description = "Create Docker network for ${networkName}";
requiredBy = [
"${containers.solidtime.serviceName}.service"
];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = ''
if ! ${pkgs.docker}/bin/docker network ls | grep -q ${networkName}; then
${pkgs.docker}/bin/docker network create ${networkName}
fi
'';
};
"docker-${internalNetworkName}-create-network" = {
description = "Create Docker network for ${internalNetworkName}";
requiredBy = [
"${containers.solidtime.serviceName}.service"
"${containers.solidtimeScheduler.serviceName}.service"
"${containers.solidtimeQueue.serviceName}.service"
"${containers.solidtimeDb.serviceName}.service"
"${containers.solidtimeGotenberg.serviceName}.service"
];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = ''
if ! ${pkgs.docker}/bin/docker network ls | grep -q ${internalNetworkName}; then
${pkgs.docker}/bin/docker network create ${internalNetworkName}
fi
'';
};
};
virtualisation.oci-containers.containers = {
solidtime = {
hostname = "solidtime";
image = "solidtime/solidtime:${version}";
autoStart = true;
inherit user;
ports = [
# Open ports if you don't use Traefik
"${toString port}:8000"
];
extraOptions = [
"--network=${networkName}"
"--network=${internalNetworkName}"
# Healthecks
# test: [ "CMD-SHELL", "curl --fail http://localhost:8000/health-check/up || exit 1" ]
''--health-cmd=curl --fail http://localhost:8000/health-check/up || exit 1''
];
inherit volumes;
dependsOn = [
"solidtimeDb"
];
environmentFiles = [
"/home/admin/.solidtime.env"
];
environment = laravelEnv // {
CONTAINER_MODE = "http";
};
labels = {
"traefik.enable" = "true";
"traefik.http.routers.solidtime.rule" = "Host(`time.${config.networking.hostName}.depeuter.dev`)";
"traefik.http.services.solidtime.loadbalancer.server.port" = toString port;
};
};
solidtimeScheduler = {
hostname = "scheduler";
image = "solidtime/solidtime:${version}";
inherit user;
autoStart = true;
extraOptions = [
"--network=${internalNetworkName}"
# Healthchecks
# test: [ "CMD-SHELL", "supervisorctl status scheduler:scheduler_00" ]
''--health-cmd="supervisorctl status scheduler:scheduler_00"''
];
inherit volumes;
dependsOn = [
"solidtimeDb"
];
environmentFiles = [
"/home/admin/.solidtime.env"
];
environment = laravelEnv // {
CONTAINER_MODE = "scheduler";
};
};
solidtimeQueue = {
hostname = "queue";
image = "solidtime/solidtime:${version}";
inherit user;
autoStart = true;
extraOptions = [
"--network=${internalNetworkName}"
# Healthchecks
# test: [ "CMD-SHELL", "supervisorctl status worker:worker_00" ]
''--health-cmd="supervisorctl status worker:worker_00"''
];
inherit volumes;
dependsOn = [
"solidtimeDb"
];
environmentFiles = [
"/home/admin/.solidtime.env"
];
environment = laravelEnv // {
CONTAINER_MODE = "worker";
WORKER_COMMAND = "php /var/www/html/artisan queue:work";
};
};
solidtimeDb = {
hostname = "database";
image = "postgres:15";
autoStart = true;
ports = [
# "${toString dbExternalPort}:${toString dbInternalPort}"
];
extraOptions = [
"--network=${internalNetworkName}"
# Healthchecks
# test: - CMD - pg_isready - '-q' - '-d' - '${DB_DATABASE}' - '-U' - '${DB_USERNAME}' retries: 3 timeout: 5s
''--health-cmd="pg_isready -q -d ${laravelEnv.DB_DATABASE} -U ${laravelEnv.DB_USERNAME}"''
"--health-retries=3"
"--health-timeout=5s"
];
volumes = [
"solidtime-db:/var/lib/postgresql/data"
];
environment = {
PGPASSWORD = laravelEnv.DB_PASSWORD;
POSTGRES_DB = laravelEnv.DB_DATABASE;
POSTGRES_USER = laravelEnv.DB_USERNAME;
POSTGRES_PASSWORD = laravelEnv.DB_PASSWORD;
};
};
solidtimeGotenberg = {
hostname = "gotenberg";
image = "gotenberg/gotenberg:8";
autoStart = true;
extraOptions = [
"--network=${internalNetworkName}"
# Healthchecks
# test: [ "CMD", "curl", "--silent", "--fail", "http://localhost:3000/health" ]
''--health-cmd="curl --silent --fail http://localhost:${toString gotenbergPort}/health"''
];
};
};
};
}

View file

@ -44,6 +44,6 @@ in {
]; ];
}; };
}; };
}; };
} }