wip
This commit is contained in:
@@ -4,36 +4,60 @@ let
|
|||||||
serverCfg = config.syscfg.server;
|
serverCfg = config.syscfg.server;
|
||||||
|
|
||||||
in {
|
in {
|
||||||
sops = true;
|
vm = {
|
||||||
db = false;
|
portForward = [ 8123 ];
|
||||||
|
cfg = {cfg,...}:{
|
||||||
|
services.home-assistant = {
|
||||||
|
enable = true;
|
||||||
|
openFirewall = true;
|
||||||
|
|
||||||
paths = [{
|
extraComponents = [
|
||||||
path = "${serverCfg.configPath}/homeassistant/";
|
"matter" "thread" "cast" "zha"
|
||||||
mode = "0755";
|
"default_config" "met" "esphome" "radio_browser"
|
||||||
}];
|
"telegram_bot" "swiss_public_transport" "nextcloud" "jellyfin"
|
||||||
|
] ++ (if containerCfg.extra ? components then containerCfg.extra.components else []);
|
||||||
|
|
||||||
|
|
||||||
|
extraPackages = pp: with pp; [
|
||||||
|
python-telegram gtts
|
||||||
|
];
|
||||||
|
lovelaceConfig = {};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
homeassistant = {
|
||||||
|
name = "Home";
|
||||||
|
latitude = "${if containerCfg.extra ? latitude then toString containerCfg.extra.latitude else toString 0}";
|
||||||
|
longitude = "${if containerCfg.extra ? longitude then toString containerCfg.extra.longitude else toString 0}";
|
||||||
|
elevation = "${if containerCfg.extra ? elevation then toString containerCfg.extra.elevation else toString 0}";
|
||||||
|
unit_system = "metric";
|
||||||
|
time_zone = config.time.timeZone;
|
||||||
|
};
|
||||||
|
lovelace = { mode = "yaml"; };
|
||||||
|
customLovelaceModules = [];
|
||||||
|
|
||||||
|
# default_config = {};
|
||||||
|
http = {
|
||||||
|
use_x_forwarded_for = true;
|
||||||
|
trusted_proxies = [ "10.0.0.0/8" "127.0.0.1" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
containers = {
|
containers = {
|
||||||
server = builder.mkContainer {
|
dummy = builder.mkContainer {
|
||||||
subdomain = containerCfg.subdomain;
|
subdomain = containerCfg.subdomain;
|
||||||
image = "ghcr.io/home-assistant/home-assistant:${version}";
|
image = "alpine:latest";
|
||||||
port = 8123;
|
extraLabels = {
|
||||||
secret = name;
|
"traefik.http.services.${containerCfg.subdomain}.loadbalancer.server.url" = "http://${builder.hostIp}:8123";
|
||||||
extraOptions = [
|
|
||||||
"--network=host" # Shares host IP: fixes timeouts & MDNS discovery
|
|
||||||
"--cap-add=NET_ADMIN" # Grants administrative network rights to fix DHCP packets
|
|
||||||
"--cap-add=NET_RAW" # Allows raw socket parsing needed for network sniffing
|
|
||||||
];
|
|
||||||
overrides = {
|
|
||||||
volumes = [
|
|
||||||
"${serverCfg.configPath}/homeassistant/:/config"
|
|
||||||
"/run/dbus:/run/dbus:ro"
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
|
overrides = {cmd = [ "sleep" "infinity" ];};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
setup = {
|
setup = {
|
||||||
trigger = "server";
|
trigger = "dummy";
|
||||||
envFile = config.sops.secrets."CUSTOM".path;
|
envFile = config.sops.secrets."CUSTOM".path;
|
||||||
script = pkgs.writeShellScript "setup" ''
|
script = pkgs.writeShellScript "setup" ''
|
||||||
|
|
||||||
@@ -60,6 +84,7 @@ in {
|
|||||||
-H "Authorization: Bearer $ACCESS_TOKEN" \
|
-H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{"time_zone":"${config.time.timeZone}"}' > /dev/null 2>&1 || true
|
-d '{"time_zone":"${config.time.timeZone}"}' > /dev/null 2>&1 || true
|
||||||
|
# We can configure many more things above !
|
||||||
|
|
||||||
${pkgs.curl} -s -X POST "$HASS_URL/api/onboarding/analytics" \
|
${pkgs.curl} -s -X POST "$HASS_URL/api/onboarding/analytics" \
|
||||||
-H "Authorization: Bearer $ACCESS_TOKEN" \
|
-H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||||
@@ -69,7 +94,6 @@ in {
|
|||||||
-H "Authorization: Bearer $ACCESS_TOKEN" \
|
-H "Authorization: Bearer $ACCESS_TOKEN" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{"client_id":"'"$HASS_URL"'","redirect_uri":"'"$HASS_URL"'/?auth_callback=1"}' > /dev/null 2>&1 || true
|
-d '{"client_id":"'"$HASS_URL"'","redirect_uri":"'"$HASS_URL"'/?auth_callback=1"}' > /dev/null 2>&1 || true
|
||||||
|
|
||||||
fi
|
fi
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|||||||
3
modules/server/containers/apps/openhab.nix
Normal file
3
modules/server/containers/apps/openhab.nix
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{... }:{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -13,6 +13,9 @@ let
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
routerName = if subpath != null
|
||||||
|
then "${subdomain}-${lib.strings.sanitizeDerivationName subpath}"
|
||||||
|
else subdomain;
|
||||||
in {
|
in {
|
||||||
paths = [{
|
paths = [{
|
||||||
path = "${serverCfg.dataPath}/transmission/complete";
|
path = "${serverCfg.dataPath}/transmission/complete";
|
||||||
@@ -41,8 +44,12 @@ in {
|
|||||||
WHITELIST = "";# 127.0.0.1,::1,10.*";
|
WHITELIST = "";# 127.0.0.1,::1,10.*";
|
||||||
# HOST_WHITELIST = "traefik-server,authentik-server,authentik-worker";
|
# HOST_WHITELIST = "traefik-server,authentik-server,authentik-worker";
|
||||||
};
|
};
|
||||||
extraLabels = { } // (if serverCfg.containers ? authentik then {
|
extraLabels = {
|
||||||
"traefik.http.routers.${containerCfg.subdomain}.middlewares" = "authentik";
|
"traefik.http.routers.${routerName}.middlewares" = "transmission-rewrite";
|
||||||
|
"traefik.http.middlewares.transmission-rewrite.replacepathregex.regex=^/p2p(.*)"
|
||||||
|
"traefik.http.middlewares.transmission-rewrite.replacepathregex.replacement=/transmission/web$$1"
|
||||||
|
} // (if serverCfg.containers ? authentik then {
|
||||||
|
"traefik.http.routers.${routerName}.middlewares" = "authentik,transmission-rewrite";
|
||||||
} else {});
|
} else {});
|
||||||
|
|
||||||
overrides = {
|
overrides = {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
{ config, lib, pkgs, serverCfg }:
|
{ config, lib, pkgs, serverCfg }:
|
||||||
let
|
let
|
||||||
builder =
|
contBuilder =
|
||||||
{ image ? null, imageStream ? null, imageFile ? null
|
{ image ? null, imageStream ? null, imageFile ? null
|
||||||
, secret ? null
|
, secret ? null
|
||||||
, subdomain ? null, subpath?null, port ? 0
|
, subdomain ? null, subpath?null, port ? null
|
||||||
, extraEnv ? { }, extraLabels ? { }, extraOptions ? [ ]
|
, extraEnv ? { }, extraLabels ? { }, extraOptions ? [ ]
|
||||||
, overrides ? { }
|
, overrides ? { }
|
||||||
}:
|
}:
|
||||||
@@ -35,13 +35,40 @@ let
|
|||||||
"traefik.enable" = "false";
|
"traefik.enable" = "false";
|
||||||
}) // extraLabels;
|
}) // extraLabels;
|
||||||
|
|
||||||
extraOptions = extraOptions ++ [
|
extraOptions = [
|
||||||
"--add-host=host.containers.internal:host-gateway"
|
"--add-host=host.containers.internal:host-gateway"
|
||||||
];
|
] ++ extraOptions;
|
||||||
};
|
};
|
||||||
in lib.recursiveUpdate base overrides;
|
in lib.recursiveUpdate base overrides;
|
||||||
|
vmBuilder = { name, vm }: (import "${pkgs.path}/nixos/lib/eval-config.nix" {
|
||||||
|
system = "x86_64-linux";
|
||||||
|
modules = [ vm.cfg
|
||||||
|
({ config, lib, modulesPath, ... }: {
|
||||||
|
imports = [
|
||||||
|
"${modulesPath}/profiles/qemu-guest.nix"
|
||||||
|
"${modulesPath}/virtualisation/qemu-vm.nix"
|
||||||
|
];
|
||||||
|
networking.hostName = name;
|
||||||
|
networking.useDHCP = true;
|
||||||
|
networking.firewall.enable = false;
|
||||||
|
services.qemuGuest.enable = true;
|
||||||
|
system.stateVersion = "25.11";
|
||||||
|
virtualisation = {
|
||||||
|
memorySize = vm.memory or 2048;
|
||||||
|
cores = vm.cores or 2;
|
||||||
|
forwardPorts = let
|
||||||
|
parsePortString = port: {
|
||||||
|
from = "host";
|
||||||
|
host.port = port;
|
||||||
|
guest.port = port;
|
||||||
|
};
|
||||||
|
in if (vm ? portForward && vm.portForward != null) then map parsePortString vm.portForward else [];
|
||||||
|
};})
|
||||||
|
];
|
||||||
|
}.config.system.build.vm);
|
||||||
in {
|
in {
|
||||||
mkContainer = builder;
|
mkContainer = contBuilder;
|
||||||
|
mkVm = vmBuilder;
|
||||||
mkData = { name, dir, vars?{} }: pkgs.runCommand name vars ''
|
mkData = { name, dir, vars?{} }: pkgs.runCommand name vars ''
|
||||||
mkdir -p $out
|
mkdir -p $out
|
||||||
cp -r ${./data + "/${dir}"}/. $out/
|
cp -r ${./data + "/${dir}"}/. $out/
|
||||||
@@ -52,4 +79,7 @@ in {
|
|||||||
done
|
done
|
||||||
'';
|
'';
|
||||||
host = "host.containers.internal";
|
host = "host.containers.internal";
|
||||||
|
hostIp = if (config.virtualisation.podman.defaultNetwork.settings ? subnets)
|
||||||
|
then (builtins.elemAt config.virtualisation.podman.defaultNetwork.settings.subnets 0).gateway
|
||||||
|
else "10.88.0.1";
|
||||||
}
|
}
|
||||||
@@ -17,6 +17,7 @@ in{
|
|||||||
allPathConfigs = lib.concatMap (app: app.paths) appsList;
|
allPathConfigs = lib.concatMap (app: app.paths) appsList;
|
||||||
allSetupConfigs = lib.concatMap (app: if app.setup?script then [({name = app.name; envFile="";} // app.setup)] else []) appsList;
|
allSetupConfigs = lib.concatMap (app: if app.setup?script then [({name = app.name; envFile="";} // app.setup)] else []) appsList;
|
||||||
allCronsConfigs = lib.concatMap (app: app.cron) appsList;
|
allCronsConfigs = lib.concatMap (app: app.cron) appsList;
|
||||||
|
allVMConfigs = builtins.filter (app: app.vm != null) appsList;
|
||||||
in{
|
in{
|
||||||
virtualisation.oci-containers = {
|
virtualisation.oci-containers = {
|
||||||
backend = "podman";
|
backend = "podman";
|
||||||
@@ -47,7 +48,30 @@ in{
|
|||||||
'';
|
'';
|
||||||
startAt = "weekly";
|
startAt = "weekly";
|
||||||
};
|
};
|
||||||
} // lib.listToAttrs (lib.concatMap (e: [{
|
}
|
||||||
|
// lib.listToAttrs (lib.concatMap (e: [{
|
||||||
|
name = "${e.name}-vm";
|
||||||
|
value = {
|
||||||
|
description = "Isolated NixOS Guest VM for ${e.name}";
|
||||||
|
after = [ "network-online.target" ];
|
||||||
|
wants = [ "network-online.target" ];
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
environment = {
|
||||||
|
QEMU_VM_REG_SND = "0";
|
||||||
|
NIX_DISK_IMAGE = "/media/data/kvm/${e.name}-guest.qcw2";
|
||||||
|
};
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "simple";
|
||||||
|
Restart = "always";
|
||||||
|
RestartSec = "10s";
|
||||||
|
ExecStartPre = "${pkgs.coreutils}/bin/mkdir -p /media/data/kvm";
|
||||||
|
ExecStart = ''
|
||||||
|
${builder.mkVm { name = e.name; vm = e.vm; }}/bin/run-${e.name}-vm -nographic
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}]) allVMConfigs)
|
||||||
|
// lib.listToAttrs (lib.concatMap (e: [{
|
||||||
name = "${e.name}-setup";
|
name = "${e.name}-setup";
|
||||||
value = {
|
value = {
|
||||||
description = "Run ${e.name} setup";
|
description = "Run ${e.name} setup";
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ in with lib; {
|
|||||||
|
|
||||||
paths = lib.mkOption {type = lib.types.listOf lib.types.attrs; default = [ ];};
|
paths = lib.mkOption {type = lib.types.listOf lib.types.attrs; default = [ ];};
|
||||||
containers = lib.mkOption {type = lib.types.attrsOf lib.types.attrs; default = { };};
|
containers = lib.mkOption {type = lib.types.attrsOf lib.types.attrs; default = { };};
|
||||||
|
vm = lib.mkOption {type = lib.types.nullOr lib.types.attrs; default = null;};
|
||||||
cron = lib.mkOption {type = lib.types.listOf lib.types.str; default = [ ];};
|
cron = lib.mkOption {type = lib.types.listOf lib.types.str; default = [ ];};
|
||||||
|
|
||||||
setup = {
|
setup = {
|
||||||
|
|||||||
@@ -53,8 +53,7 @@
|
|||||||
# ===== DEV =====
|
# ===== DEV =====
|
||||||
gitea.subdomain = "git";
|
gitea.subdomain = "git";
|
||||||
# ===== HOME =====
|
# ===== HOME =====
|
||||||
# homeassistant.subdomain = "hass";
|
openhab.subdomain = "hass";
|
||||||
# frigate = { subdomain = "hass"; subpath = "cam"; };
|
|
||||||
# trmnl = { subdomain = "hass"; subpath = "trmnl"; };
|
# trmnl = { subdomain = "hass"; subpath = "trmnl"; };
|
||||||
# influx.subdomain = "metrum";
|
# influx.subdomain = "metrum";
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user