feat: several updates

This commit is contained in:
Xavier Morel
2025-12-09 14:35:20 +01:00
parent aec2e5bf63
commit a78704f30f
36 changed files with 826 additions and 150 deletions

View File

@@ -1 +0,0 @@
/home/xmorel/homelab-private/_ids.nix

22
config/_ids.nix Normal file
View File

@@ -0,0 +1,22 @@
{ ... }:
{
id = {
git = 1017;
mqtt = 1018;
metrics = 1019;
frigate = 1020;
power = 1021;
monitoring = 1022;
media = 1023;
vault = 1024;
proxy = 1025;
matrix = 1026;
db = 1027;
finances = 1028;
yarrr = 1029;
auth = 1030;
music = 1031;
dns = 1042;
z2m = 1016;
};
}

View File

@@ -6,14 +6,14 @@
}:
{
out = ''
prometheus.exporter.unix "default" {
include_exporter_metrics = true
disable_collectors = ["mdadm"]
}
// prometheus.exporter.unix "default" {
// include_exporter_metrics = true
// disable_collectors = ["mdadm"]
// }
prometheus.scrape "default" {
targets = array.concat(
prometheus.exporter.unix.default.targets,
// prometheus.exporter.unix.default.targets,
[{
// Self-collect metrics
job = "alloy",

View File

@@ -12,6 +12,7 @@ let
proxy_addr = ip "proxy";
domain_ext = config.globals.domains.external;
domain_int = config.globals.domains.internal;
json = pkgs.formats.json { };
in
{
environment.etc."alloy/logs-adguardhome.alloy".text =
@@ -41,13 +42,43 @@ in
}
'';
}).out;
environment.etc."AdGuardHome/data/leases.json".source = json.generate "leases.json" {
version = 1;
leases = (
lib.filter (x: x.mac != null) (
lib.mapAttrsToList (host: h: {
expires = "";
ip = tools.build_ip h.ip;
hostname = host;
mac = h.mac;
static = true;
}) config.globals.other_hosts
)
);
};
systemd.services.adguardhome.preStart = ''
cp /etc/AdGuardHome/data/leases.json /var/lib/AdGuardHome/data/leases.json
chown adguardhome:adguardhome /var/lib/AdGuardHome/data/leases.json
'';
services.adguardhome = {
enable = true;
allowDHCP = true;
host = "0.0.0.0";
port = 80;
openFirewall = true;
mutableSettings = true; # ??
settings = {
dhcp = {
enabled = true;
interface_name = "eth0";
dhcpv4 = {
gateway_ip = config.globals.gateway;
subnet_mask = config.globals.mask;
range_start = tools.build_ip 150;
range_end = tools.build_ip 199;
};
local_domain_name = lib.removePrefix "." config.globals.domains.internal;
};
http = {
address = "0.0.0.0:80";
session_ttl = "720h";
@@ -96,11 +127,13 @@ in
{
domain = "*${domain_ext}";
answer = proxy_addr;
enabled = true;
}
]
++ (lib.mapAttrsToList (d: id: {
domain = "${d}${domain_int}";
answer = "${ip d}";
enabled = true;
}) config.id);
};
};

View File

@@ -32,6 +32,9 @@ in
enable = true;
port = 9167;
openFirewall = true;
unbound = {
host = "unix:///run/unbound/unbound.ctl";
};
};
services.unbound = {
enable = true;
@@ -56,6 +59,7 @@ in
private-address = [
mask_cidr
];
do-udp = true;
do-ip6 = false;
so-sndbuf = 0;
access-control = [

View File

@@ -5,25 +5,32 @@
}:
let
name = "finances";
hostname = tools.build_hostname name;
ip = tools.build_ip name;
db_ip = tools.build_ip "db";
in
{
environment.etc."firefly-iii/app.key" = {
source = config.age.secrets.finances-app-key.path;
user = "firefly-iii";
group = "nginx";
};
services.firefly-iii = {
enable = true;
enableNginx = true;
settings = {
SITE_OWNER = config.globals.master.email;
DB_CONNECTION = "pgsql";
DB_HOST = ip;
DB_HOST = db_ip;
DB_PORT = 5432;
DB_DATABASE = hostname;
DB_USERNAME = hostname;
DB_DATABASE = name;
DB_USERNAME = name;
DB_PASSWORD = config.my-lxc.finances.db.password;
AUTHENTICATION_GUARD = "remote_user_guard";
AUTHENTICATION_GUARD_HEADER = "HTTP_REMOTE_EMAIL";
AUTHENTICATION_GUARD_EMAIL = "HTTP_REMOTE_EMAIL";
APP_KEY_FILE = config.age.secrets.finances-app-key.path;
APP_URL = "https://${tools.build_hostname "finances"}";
APP_KEY_FILE = "/etc/firefly-iii/app.key";
TRUSTED_PROXIES = tools.build_ip "proxy";
TZ = config.globals.default_tz;
};
};
}

View File

@@ -2,7 +2,7 @@
let
hostname = tools.build_hostname "frigate";
mask_cidr = tools.mask_cidr;
camera = tools.build_ip "camera";
camera = tools.build_ip "camera-entree-4";
user = "admin"; # use yours
pass = "admin"; # use yours
in
@@ -13,6 +13,7 @@ in
checkConfig = false;
settings = {
auth = {
enabled = false;
trusted_proxies = [
mask_cidr
];
@@ -25,6 +26,56 @@ in
separator = "|";
default_role = "admin";
};
# database.path => postgres ??
mqtt = {
enabled = true;
host = tools.build_hostname "mqtt";
user = "frigate";
password = "pouet";
# Auth ???
};
detect = {
enabled = true;
fps = 5;
};
detectors.cpu.type = "cpu";
objects.track = [
"person"
"car"
"bird"
"cat"
"dog"
];
motion.enabled = true;
# genai => ollama
semantic_search = {
enabled = true;
model_size = "small";
};
review.detections = {
enabled = true;
labels = [
"car"
"person"
"cat"
"dog"
];
};
record = {
enabled = true;
retain.days = 2;
preview.quality = "medium";
};
snapshots = {
enabled = true;
retain.default = 7;
};
# face_recognition = {
# enabled = true;
# model_size = "small";
# };
# lpr.enabled = true;
# classification.bird.enabled = true;
cameras = {
front = {
enabled = true;
@@ -45,6 +96,21 @@ in
user = user;
password = pass;
};
zones = {
ZoneA = {
coordinates = "0,0.036,0.985,0.041,0.985,0.494,0.01,0.496";
loitering_time = 0;
};
ZoneB = {
coordinates = "0,0.502,0,1,1,1,1,0.501";
inertia = 3;
loitering_time = 0;
};
};
# review.alerts.required_zones = [
# "ZoneA"
# "ZoneB"
# ];
};
};
};

13
config/media-jellyfin.nix Normal file
View File

@@ -0,0 +1,13 @@
{ ... }:
{
services.jellyfin = {
enable = true;
openFirewall = true;
# Manual bind-mount in proxmox
dataDir = "/mnt/nas/app-data/jellyfin";
configDir = "/etc/jellyfin/";
logDir = "/var/log/jellyfin";
# user = "root";
# group = "root";
};
}

View File

@@ -27,25 +27,27 @@ in
version = true;
};
configFile = config.age.secrets.metrics-pve.path;
listenAddress = "0.0.0.0";
openFirewall = true;
port = 9221;
};
globalConfig = {
scrape_interval = "30s";
};
scrapeConfigs = [
{
job_name = "prometheus";
static_configs = [
{
targets = [ "localhost:9090" ];
labels = {
host = tools.build_hostname "metrics";
host_ip = tools.build_ip "metrics";
service = "prometheus";
};
}
];
}
# {
# job_name = "prometheus";
# static_configs = [
# {
# targets = [ "localhost:9090" ];
# labels = {
# host = tools.build_hostname "metrics";
# host_ip = tools.build_ip "metrics";
# service = "prometheus";
# };
# }
# ];
# }
{
job_name = "proxmox";
static_configs = [

View File

@@ -36,6 +36,11 @@
retention_deletes_enabled = true;
retention_period = config.globals.retention;
};
pattern_ingester.enabled = true;
limits_config = {
allow_structured_metadata = true;
volume_enabled = true;
};
};
};
}

64
config/mqtt-mosquitto.nix Normal file
View File

@@ -0,0 +1,64 @@
{
pkgs,
config,
tools,
...
}:
{
services.mosquitto = {
enable = true;
logType = [
"error"
"warning"
"subscribe"
"unsubscribe"
"websockets"
];
settings = {
# ???
};
listeners = [
{
acl = [ "pattern readwrite #" ];
port = 1883;
omitPasswordAuth = false;
users = {
mqtt.passwordFile = config.age.secrets.mqtt-password-mqtt.path;
ha.passwordFile = config.age.secrets.mqtt-password-ha.path;
z2m.passwordFile = config.age.secrets.mqtt-password-z2m.path;
frigate.passwordFile = config.age.secrets.mqtt-password-frigate.path;
};
settings = {
allow_anonymous = false;
require_certificate = true;
use_identity_as_username = true;
};
}
{
acl = [ "pattern readwrite #" ];
port = 9001;
omitPasswordAuth = false;
users = {
mqtt.passwordFile = config.age.secrets.mqtt-password-mqtt.path;
ha.passwordFile = config.age.secrets.mqtt-password-ha.path;
z2m.passwordFile = config.age.secrets.mqtt-password-z2m.path;
frigate.passwordFile = config.age.secrets.mqtt-password-frigate.path;
};
settings = {
protocol = "websockets";
allow_anonymous = false;
require_certificate = true;
use_identity_as_username = true;
};
}
];
};
services.prometheus.exporters.mqtt = {
enable = true;
mqttUsername = "mqtt";
environmentFile = config.age.secrets.mqtt-exporter-environment.path;
openFirewall = true;
port = 9000;
zigbee2MqttAvailability = true;
};
}

View File

@@ -24,6 +24,9 @@ in
#
# '';
# }).out;
environment.systemPackages = with pkgs; [
openssl
];
services = {
traefik = {
@@ -92,10 +95,12 @@ in
addServicesLabels = true;
};
};
experimental.plugins = {
staticResponse = {
moduleName = "github.com/jdel/staticresponse";
version = "v0.0.1";
experimental = {
plugins = {
staticResponse = {
moduleName = "github.com/jdel/staticresponse";
version = "v0.0.1";
};
};
};
};
@@ -162,17 +167,23 @@ in
"X-authentik-meta-provider"
"X-authentik-meta-app"
"X-authentik-meta-version"
"X-Forwarded-Host"
"X-Forwarded-Proto"
"Remote-User"
"Remote-Group"
"Remote-Email"
"Remote-Name"
];
};
matrix-wellknown.plugin.staticResponse = {
statusCode = 200;
body = ''{"m.server": "${tools.build_hostname "matrix"}:443"}'';
headers = {
"Content-Type" = "application/json";
matrix-wellknown-mw = {
plugin = {
staticResponse = {
statusCode = 200;
body = ''{"m.server": "${tools.build_hostname "matrix"}:443"}'';
headers = {
"Content-Type" = "application/json";
};
};
};
};
};
@@ -211,15 +222,22 @@ in
]
) config.my-lxc)
++ [
(map (h: {
${h.hostname} = {
rule = "Host(`${h.hostname}${dmn}`) " + (if (h.private == true) then internal else "");
service = "${h.hostname}-service";
entryPoints = [ "websecure" ];
middlewares = if (h.auth) then [ "authentik" ] else [ ];
tls.certResolver = "letsencrypt";
};
}) config.globals.other_hosts)
(lib.mapAttrsToList
# mapAttrs?
(
hostname: h:
lib.optionalAttrs (h.port != null) {
${hostname} = {
rule = "Host(`${hostname}${dmn}`) " + (if (h.private == true) then internal else "");
service = "${hostname}-service";
entryPoints = [ "websecure" ];
middlewares = if (h.auth) then [ "authentik" ] else [ ];
tls.certResolver = "letsencrypt";
};
}
)
config.globals.other_hosts
)
]
)
)
@@ -228,7 +246,7 @@ in
rule = "Path(`/\.well-known/matrix/server`)";
entryPoints = [ "websecure" ];
service = "noop";
middlewares = [ "matrix-wellknown" ];
middlewares = [ "matrix-wellknown-mw" ];
tls.certResolver = "letsencrypt";
};
}
@@ -257,16 +275,19 @@ in
]
) config.my-lxc)
++ [
(map (h: {
"${h.hostname}-service" = {
loadBalancer = {
servers = [ { url = h.addr; } ];
}
// (lib.optionalAttrs (h.useCustomCA) {
serversTransport = "${h.hostname}-transport";
});
};
}) config.globals.other_hosts)
(lib.mapAttrsToList (
hostname: h:
lib.optionalAttrs (h.port != null) {
"${hostname}-service" = {
loadBalancer = {
servers = [ { url = "${h.protocol}://${ip h.ip}:${toString h.port}"; } ];
}
// (lib.optionalAttrs (h.useCustomCA) {
serversTransport = "${hostname}-transport";
});
};
}
) config.globals.other_hosts)
]
)
)
@@ -274,10 +295,10 @@ in
noop.loadBalancer.servers = [ ];
};
serversTransports = mergeConf (
(map (
h:
(lib.mapAttrsToList (
hostname: h:
lib.optionalAttrs (h.useCustomCA) {
"${h.hostname}-transport" = {
"${hostname}-transport" = {
rootCAs = customCAs;
};
}

111
config/z2m-zigbee2mqtt.nix Normal file
View File

@@ -0,0 +1,111 @@
{ tools, ... }:
{
services.zigbee2mqtt = {
enable = true;
settings = {
homeassistant.enabled = true;
frontend.enabled = true;
frontend.port = 80;
mqtt = {
base_topic = "zigbee2mqtt";
server = tools.build_proto_uri "mqtt" "mqtt" 1883;
user = "z2m";
password = "";
};
serial = {
adapter = "ember";
port = "/dev/serial/by-id/usb-1a86_USB_Serial-if00-port0";
rtscts = false;
};
device_options.homeassistant.last_seen.enabled_by_default = true;
availability.enabled = true;
groups = {
"1".friendly_name = "chambre_lily";
};
advanced = {
last_seen = "ISO_8601";
network_key = [
228
161
18
105
130
167
152
135
156
117
114
2
131
118
68
184
];
pan_id = 55857;
ext_pan_id = [
134
209
175
31
23
62
37
117
];
};
devices = {
"0xa4c1388417d4338b".friendly_name = "thermo.bureau";
"0xa4c13823a110391d".friendly_name = "porte.petit-salon";
"0xa4c1381dec6190b8".friendly_name = "prise.radiateur_bureau";
"0x8c8b48fffe0f7e7d".friendly_name = "prise.garage4";
"0x8c8b48fffe22bdad".friendly_name = "prise.piscine";
"0x94ec32fffe294a72".friendly_name = "prise.bureau-leds";
"0xa4c138fe8162b02f".friendly_name = "detect-mvmt.bureau";
"0xa4c138a2e759e4fe".friendly_name = "prise.salon-tv";
"0xa4c13882e2f0b9b0".friendly_name = "prise.salon-entree";
"0xfc4d6afffe9861ab".friendly_name = "detect-mvmt.couloir";
"0x0c2a6ffffe9427d7".friendly_name = "qual-air.chambre";
"0x6cfd22fffe741d4d".friendly_name = "lampe.couloir";
"0x8c8b48fffe22be29".friendly_name = "prise.vinyle";
"0xa4c138ad71c29b1a".friendly_name = "prise.dressing";
"0x94ec32fffe005a54".friendly_name = "telecommande.1";
"0xc4d8c8fffe8a77af".friendly_name = "telecommande.2";
"0xc4d8c8fffe75fc4e".friendly_name = "telecommande.3";
"0xc4d8c8fffe8aa9e9".friendly_name = "telecommande.4";
"0xc4d8c8fffe8a334f".friendly_name = "telecommande.5";
"0xa4c1383d67a9547f".friendly_name = "thermo.dressing";
"0xa4c13814c6451d10".friendly_name = "thermo.salle";
"0xa4c1384ad2338111".friendly_name = "thermo.cuisine";
"0xa4c138ca886990cd".friendly_name = "thermo.petit-salon";
"0xa4c1380843e93f46".friendly_name = "thermo.sdb";
"0xa4c1381224ba47e6".friendly_name = "detect-mvmt.test";
"0xa4c138cfc45b7415".friendly_name = "variateur.xav";
"0xa4c1380648c97928".friendly_name = "porte.entree2";
"0xa4c1383c9fe6e172".friendly_name = "detect-mvmt.wc-etg";
"0xa4c13830906a830d".friendly_name = "detect-mvmt.salon";
"0xa4c138dca3916211".friendly_name = "fenetre.chambre";
"0x286847fffec2e17e".friendly_name = "interrupteur.chambre";
"0x94a081fffe65644c".friendly_name = "lampe.chambre";
"0xc02cedfffe3fcf82".friendly_name = "lampe.xav";
"0xc02cedfffe451b62".friendly_name = "lampe.laeti";
"0xa4c138e32b55464b".friendly_name = "variateur.laeti";
"0xa4c138708bda69b4".friendly_name = "variateur.salledejeux";
"0x781c9dfffe07bf3a".friendly_name = "lampe.salledejeux";
"0xa4c138875f327aec".friendly_name = "thermo.dependance";
"0x00158d000638ef03".friendly_name = "linky";
"0xd4fe28fffe57a3a9".friendly_name = "interrupteur.chambre_lily";
"0xc02cedfffe0c3f58".friendly_name = "lampe.lily-chambre-2";
"0x70c59cfffe2bcbe0".friendly_name = "lampe.lily-chambre-1";
"0x94a081fffebb4a7a".friendly_name = "interrupteur.cuisine";
"0x08fd52fffe0f2220".friendly_name = "lampe.cuisine";
"0x58263afffe6b046e".friendly_name = "interrupteur.dressing";
"0xf0fd45fffe0b6e7f".friendly_name = "prise.dressing2";
"0x94a081fffe76656b".friendly_name = "lampe.dressing";
"0xf0fd45fffe0b6465".friendly_name = "prise.lave-linge";
"0xd4fe28fffe5850de".friendly_name = "interrupteur.bureau";
"0x8c8b48fffeba64d9".friendly_name = "lampe.bureau";
};
};
};
}

View File

@@ -0,0 +1,154 @@
version: 4
homeassistant:
enabled: true
frontend:
enabled: true
port: 80
mqtt:
base_topic: zigbee2mqtt
server: mqtt://192.168.68.18:1883
user: z2m
password: QhtY@gxy*7BcGZhA
serial:
adapter: ember
port: /dev/serial/by-id/usb-1a86_USB_Serial-if00-port0
rtscts: false
device_options:
homeassistant:
last_seen:
enabled_by_default: true
advanced:
last_seen: ISO_8601
network_key:
- 228
- 161
- 18
- 105
- 130
- 167
- 152
- 135
- 156
- 117
- 114
- 2
- 131
- 118
- 68
- 184
pan_id: 55857
ext_pan_id:
- 134
- 209
- 175
- 31
- 23
- 62
- 37
- 117
devices:
'0xa4c1388417d4338b':
friendly_name: thermo.bureau
'0xa4c13823a110391d':
friendly_name: porte.petit-salon
'0xa4c1381dec6190b8':
friendly_name: prise.radiateur_bureau
'0x8c8b48fffe0f7e7d':
friendly_name: prise.garage4
'0x8c8b48fffe22bdad':
friendly_name: prise.piscine
'0x94ec32fffe294a72':
friendly_name: prise.bureau-leds
'0xa4c138fe8162b02f':
friendly_name: detect-mvmt.bureau
'0xa4c138a2e759e4fe':
friendly_name: prise.salon-tv
'0xa4c13882e2f0b9b0':
friendly_name: prise.salon-entree
'0xfc4d6afffe9861ab':
friendly_name: detect-mvmt.couloir
'0x0c2a6ffffe9427d7':
friendly_name: qual-air.chambre
'0x6cfd22fffe741d4d':
friendly_name: lampe.couloir
'0x8c8b48fffe22be29':
friendly_name: prise.vinyle
'0xa4c138ad71c29b1a':
friendly_name: prise.dressing
'0x94ec32fffe005a54':
friendly_name: telecommande.1
'0xc4d8c8fffe8a77af':
friendly_name: telecommande.2
'0xc4d8c8fffe75fc4e':
friendly_name: telecommande.3
'0xc4d8c8fffe8aa9e9':
friendly_name: telecommande.4
'0xc4d8c8fffe8a334f':
friendly_name: telecommande.5
'0xa4c1383d67a9547f':
friendly_name: thermo.dressing
'0xa4c13814c6451d10':
friendly_name: thermo.salle
'0xa4c1384ad2338111':
friendly_name: thermo.cuisine
'0xa4c138ca886990cd':
friendly_name: thermo.petit-salon
'0xa4c1380843e93f46':
friendly_name: thermo.sdb
'0xa4c1381224ba47e6':
friendly_name: detect-mvmt.test
'0xa4c138cfc45b7415':
friendly_name: variateur.xav
'0xa4c1380648c97928':
friendly_name: porte.entree2
'0xa4c1383c9fe6e172':
friendly_name: detect-mvmt.wc-etg
'0xa4c13830906a830d':
friendly_name: detect-mvmt.salon
'0xa4c138dca3916211':
friendly_name: fenetre.chambre
'0x286847fffec2e17e':
friendly_name: interrupteur.chambre
'0x94a081fffe65644c':
friendly_name: lampe.chambre
'0xc02cedfffe3fcf82':
friendly_name: lampe.xav
'0xc02cedfffe451b62':
friendly_name: lampe.laeti
'0xa4c138e32b55464b':
friendly_name: variateur.laeti
'0xa4c138708bda69b4':
friendly_name: variateur.salledejeux
'0x781c9dfffe07bf3a':
friendly_name: lampe.salledejeux
'0xa4c138875f327aec':
friendly_name: thermo.dependance
'0x00158d000638ef03':
friendly_name: linky
'0xd4fe28fffe57a3a9':
friendly_name: interrupteur.chambre_lily
'0xc02cedfffe0c3f58':
friendly_name: lampe.lily-chambre-2
'0x70c59cfffe2bcbe0':
friendly_name: lampe.lily-chambre-1
'0x94a081fffebb4a7a':
friendly_name: interrupteur.cuisine
'0x08fd52fffe0f2220':
friendly_name: lampe.cuisine
'0x58263afffe6b046e':
friendly_name: interrupteur.dressing
'0xf0fd45fffe0b6e7f':
friendly_name: prise.dressing2
'0x94a081fffe76656b':
friendly_name: lampe.dressing
'0xf0fd45fffe0b6465':
friendly_name: prise.lave-linge
'0xd4fe28fffe5850de':
friendly_name: interrupteur.bureau
'0x8c8b48fffeba64d9':
friendly_name: lampe.bureau
availability:
enabled: true
groups:
'1':
friendly_name: chambre_lily