top level restructure

This commit is contained in:
2026-04-22 08:25:10 -05:00
parent 846d33ac50
commit 63559c16ac
163 changed files with 0 additions and 288 deletions

View File

@@ -0,0 +1,44 @@
{ ... }: {
flake.nixosModules.default = { config, lib, ... }: {
options.sysconfig.containers.code-server.enable = lib.options.mkOption {
type = lib.types.bool;
default = false;
};
config = lib.mkIf config.sysconfig.containers.code-server.enable {
containers.code-server = {
autoStart = true;
privateNetwork = true;
hostAddress = "192.168.100.10";
localAddress = "192.168.100.31";
config = {
services.code-server = {
enable = true;
hashedPassword = "1$WFYzcW1TNmpYM1ZKU3lielNCaXAyRkF2K3FjPQ$bSeeV4bvL2uiDYKiQjBLJPAO13/gNjYVgw8YKFtTQDI";
disableUpdateCheck = true;
disableTelemetry = true;
disableGettingStartedOverride = true;
auth = "none";
host = "0.0.0.0";
};
networking.firewall.allowedTCPPorts = [ 4444 ];
system.stateVersion = "25.05";
};
};
};
};
}

View File

@@ -0,0 +1,115 @@
{ ... }: {
flake.nixosModules.default = { config, lib, ... }: {
options.sysconfig.containers.gitea.enable = lib.options.mkOption {
type = lib.types.bool;
default = false;
};
config = lib.mkIf config.sysconfig.containers.gitea.enable {
networking = {
nat.internalInterfaces = [ "ve-gitea" ];
};
sops.secrets = {
"gitea/dbpass" = {};
};
containers.gitea = {
autoStart = true;
privateNetwork = true;
hostAddress = "192.168.100.10";
localAddress = "192.168.100.20";
bindMounts = {
"/etc/gitea/data" = {
hostPath = "/ssd1/Gitea/data";
isReadOnly = false;
};
};
extraFlags = [
"--load-credential=dbpass:${config.sops.secrets."gitea/dbpass".path}"
];
config = {
systemd.services.secrets_setup = {
wantedBy = [ "gitea.service" ];
serviceConfig = {
LoadCredential = [
"dbpass"
];
};
script = ''
cat ''${CREDENTIALS_DIRECTORY}/dbpass > /etc/gitea/dbpass
chown gitea:gitea /etc/gitea/*
'';
};
services.gitea = {
enable = true;
stateDir = "/etc/gitea/data";
dump.enable = false;
appName = "Gitea";
settings = {
server = {
DOMAIN = "gitea.esotericbytes.com";
HTTP_PORT = 3000;
ROOT_URL = "https://gitea.esotericbytes.com/";
};
service = {
DISABLE_REGISTRATION = false;
ALLOW_ONLY_EXTERNAL_REGISTRATION = true;
REQUIRE_SIGNIN_VIEW = false;
};
oauth2_client = {
ENABLE_AUTO_REGISTRATION = true;
};
session.COOKIE_SECURE = true;
cron = {
ENABLED = true;
RUN_AT_START = true;
};
repository = {
DEFAULT_BRANCH = "master";
};
};
database = {
passwordFile = "/etc/gitea/dbpass";
type = "postgres";
};
};
services.openssh = {
enable = true;
openFirewall = true;
settings = {
PermitRootLogin = lib.mkForce "no";
PasswordAuthentication = false;
KbdInteractiveAuthentication = false;
};
ports = [ 2222 ];
};
networking.firewall.allowedTCPPorts = [ 3000 ];
system.stateVersion = "24.11";
};
};
};
};
}

View File

@@ -0,0 +1,46 @@
{ ... }: {
flake.nixosModules.default = { config, lib, ... }: {
options.sysconfig.containers."esotericbytes.com".enable = lib.mkOption {
type = lib.types.bool;
default = false;
};
config = lib.mkIf config.sysconfig.containers."esotericbytes.com".enable {
containers.esotericbytes-com = {
autoStart = true;
privateNetwork = true;
hostAddress = "192.168.100.10";
localAddress = "192.168.100.13";
bindMounts = {
"/var/www/data" = {
hostPath = "/ssd1/esotericbytes-com/data";
isReadOnly = false;
};
};
config = {
services.nginx = {
enable = true;
virtualHosts = {
"esotericbytes.com" = {
enableACME = false;
forceSSL = false;
root = "/var/www/data";
};
};
};
networking.firewall.allowedTCPPorts = [ 80 ];
system.stateVersion = "24.05";
};
};
};
};
}

View File

@@ -0,0 +1,55 @@
{ ... }: {
flake.nixosModules.default = { config, lib, pkgs, ... }: {
options.sysconfig.containers.novnc.enable = lib.mkOption {
type = lib.types.bool;
default = false;
};
config = lib.mkIf config.sysconfig.containers.novnc.enable {
networking = {
firewall.interfaces."ve-novnc" = {
allowedTCPPorts = [ 5900 ];
allowedUDPPorts = [ 5900 ];
};
};
containers.novnc = {
autoStart = true;
privateNetwork = true;
hostAddress = "192.168.100.10";
localAddress = "192.168.100.30";
config = {
systemd.services.novnc = {
enable = true;
path = with pkgs; [
novnc
ps
];
script = ''
novnc --listen 80 --vnc 192.168.100.10:5900
'';
serviceConfig = {
Type = "exec";
};
wantedBy = [ "multi-user.target" ];
};
networking.firewall.allowedTCPPorts = [ 80 ];
system.stateVersion = "25.05";
};
};
};
};
}

View File

@@ -0,0 +1,46 @@
{ ... }: {
flake.nixosModules.default = { config, lib, ... }: {
options.sysconfig.containers.ntfy.enable = lib.mkOption {
type = lib.types.bool;
default = false;
};
config = lib.mkIf config.sysconfig.containers.ntfy.enable {
containers.ntfy = {
autoStart = true;
privateNetwork = true;
hostAddress = "192.168.100.10";
localAddress = "192.168.100.19";
config = {
services.ntfy-sh = {
enable = true;
settings = {
base-url = "https://ntfy.esotericbytes.com";
listen-http = ":80";
behind-proxy = true;
upstream-base-url = "https://ntfy.sh";
auth-default-access = "deny-all";
};
};
networking.firewall.allowedTCPPorts = [ 80 ];
system.stateVersion = "24.05";
};
};
};
};
}

View File

@@ -0,0 +1,88 @@
{ ... }: {
flake.nixosModules.default = { config, lib, ... }: {
options.sysconfig.containers.rustdesk.enable = lib.options.mkOption {
type = lib.types.bool;
default = false;
};
config = lib.mkIf config.sysconfig.containers.rustdesk.enable {
/*networking = {
firewall.allowedTCPPorts = [ 21115 21116 21117 21118 21119 ];
firewall.allowedUDPPorts = [ 21116 ];
};*/
containers.rustdesk = {
autoStart = true;
privateNetwork = true;
hostAddress = "192.168.100.10";
localAddress = "192.168.100.27";
/* forwardPorts = [
{
containerPort = 21115;
hostPort = 21115;
protocol = "tcp";
}
{
containerPort = 21116;
hostPort = 21116;
protocol = "tcp";
}
{
containerPort = 21116;
hostPort = 21116;
protocol = "udp";
}
{
containerPort = 21117;
hostPort = 21117;
protocol = "tcp";
}
{
containerPort = 21118;
hostPort = 21118;
protocol = "tcp";
}
{
containerPort = 21119;
hostPort = 21119;
protocol = "tcp";
}
];*/
config = {
services.rustdesk-server = {
enable = true;
openFirewall = true;
relay = {
enable = true;
extraArgs = [
"-k"
"AAAAC3NzaC1lZDI1NTE5AAAAIIPztDjwgB3xCza5+p5z1jpGVYoVQNl3fqD69pPCm0NA"
];
};
signal = {
enable = true;
#relayHosts = [ "esotericbytes.com" ];
relayHosts = [ "192.168.100.27" ];
extraArgs = [
"-k"
"AAAAC3NzaC1lZDI1NTE5AAAAIIPztDjwgB3xCza5+p5z1jpGVYoVQNl3fqD69pPCm0NA"
];
};
};
system.stateVersion = "24.05";
};
};
};
};
}

View File

@@ -0,0 +1,82 @@
{ ... }: {
flake.nixosModules.default = { config, lib, self, ... }: {
options.sysconfig.containers.sandbox.enable = lib.mkOption {
type = lib.types.bool;
default = false;
};
config = lib.mkIf config.sysconfig.containers.sandbox.enable {
networking = {
nat.internalInterfaces = [ "ve-sandbox" ];
};
containers.sandbox = {
autoStart = true;
privateNetwork = true;
hostAddress = "192.168.100.10";
localAddress = "192.168.100.32";
ephemeral = true;
timeoutStartSec = "3min";
flake = "${self}";
/*bindMounts = {
"/dev/nvidia0" = {
hostPath = "/dev/nvidia0";
isReadOnly = false;
};
"/dev/nvidiactl" = {
hostPath = "/dev/nvidiactl";
isReadOnly = false;
};
"/dev/nvidia-uvm" = {
hostPath = "/dev/nvidia-uvm";
isReadOnly = false;
};
"/dev/nvidia-modeset" = {
hostPath = "/dev/nvidia-modeset";
isReadOnly = false;
};
"/dev/nvidia-uvm-tools" = {
hostPath = "/dev/nvidia-uvm-tools";
isReadOnly = false;
};
};
allowedDevices = [
{
node = "/dev/nvidia0";
modifier = "rw";
}
{
node = "/dev/nvidiactl";
modifier = "rw";
}
{
node = "/dev/nvidia-uvm";
modifier = "rw";
}
{
node = "/dev/nvidia-modeset";
modifier = "rw";
}
{
node = "/dev/nvidia-uvm-tools";
modifier = "rw";
}
];*/
config = {
};
};
};
};
}

View File

@@ -0,0 +1,134 @@
{ ... }: {
flake.nixosModules.default = { config, lib, ... }: {
options.sysconfig.containers.wyoming = {
enable = lib.options.mkOption {
type = lib.types.bool;
default = false;
};
piper = lib.options.mkOption {
type = lib.types.bool;
default = false;
};
openwakeword = lib.options.mkOption {
type = lib.types.bool;
default = false;
};
faster-whisper = lib.options.mkOption {
type = lib.types.bool;
default = false;
};
satellite = lib.options.mkOption {
type = lib.types.bool;
default = false;
};
};
config = lib.mkIf config.sysconfig.containers.wyoming.enable {
containers.wyoming = {
autoStart = true;
privateNetwork = true;
hostAddress = "192.168.100.10";
localAddress = "192.168.100.26";
bindMounts = lib.mkIf config.sysconfig.containers.wyoming.faster-whisper {
"/dev/nvidia0" = {
hostPath = "/dev/nvidia0";
isReadOnly = false;
};
"/dev/nvidiactl" = {
hostPath = "/dev/nvidiactl";
isReadOnly = false;
};
"/dev/nvidia-uvm" = {
hostPath = "/dev/nvidia-uvm";
isReadOnly = false;
};
"/dev/nvidia-modeset" = {
hostPath = "/dev/nvidia-modeset";
isReadOnly = false;
};
"/dev/nvidia-uvm-tools" = {
hostPath = "/dev/nvidia-uvm-tools";
isReadOnly = false;
};
};
allowedDevices = lib.mkIf config.sysconfig.containers.wyoming.faster-whisper [
{
node = "/dev/nvidia0";
modifier = "rw";
}
{
node = "/dev/nvidiactl";
modifier = "rw";
}
{
node = "/dev/nvidia-uvm";
modifier = "rw";
}
{
node = "/dev/nvidia-modeset";
modifier = "rw";
}
{
node = "/dev/nvidia-uvm-tools";
modifier = "rw";
}
];
config = {
networking.firewall = {
allowedTCPPorts = [ 11431 11432 11433 11435 ];
};
services.wyoming = {
piper = lib.mkIf config.sysconfig.containers.wyoming.piper {
servers.piper = {
enable = true;
voice = "en-us-ryan-medium";
uri = "tcp://0.0.0.0:11435";
};
};
openwakeword = lib.mkIf config.sysconfig.containers.wyoming.openwakeword {
enable = true;
uri = "tcp://0.0.0.0:11432";
threshold = 0.5;
customModelsDirectories = [
#./wake_words
];
};
faster-whisper = lib.mkIf config.sysconfig.containers.wyoming.faster-whisper {
servers.whisper = {
enable = true;
device = "auto";
language = "en";
model = "medium.en";
uri = "tcp://0.0.0.0:11433";
};
};
satellite = lib.mkIf config.sysconfig.containers.wyoming.satellite {
enable = true;
uri = "tcp://0.0.0.0:11431";
#user = "nathan";
vad.enable = false;
};
};
system.stateVersion = "25.05";
};
};
};
};
}

View File

@@ -0,0 +1,241 @@
{ ... }: {
flake.nixosModules.default = { config, lib, pkgs, ... }: let
hostPort = 9005;
subdomain = "auth";
name = "authentik";
in {
options.sysconfig.docker.authentik.enable = with lib; mkOption {
type = with types; bool;
default = false;
};
config = lib.mkIf (config.sysconfig.docker.authentik.enable && config.sysconfig.docker.enable) {
networking.firewall.interfaces = {
"ve-traefik" = {
allowedTCPPorts = [ hostPort ];
};
};
sops.secrets = {
"authentik/pass" = {};
"authentik/secret_key" = {};
};
sops.templates."authentik.env" = {
content = ''
PG_PASS=${config.sops.placeholder."authentik/pass"}
SECRET_KEY=${config.sops.placeholder."authentik/secret_key"}
'';
};
virtualisation.oci-containers.containers."authentik-postgresql" = {
image = "docker.io/library/postgres:16-alpine";
environment = {
"POSTGRES_DB" = "authentik";
"POSTGRES_PASSWORD" = "\${PG_PASS}";
"POSTGRES_USER" = "authentik";
};
environmentFiles = [ config.sops.templates."authentik.env".path ];
volumes = [
"authentik_database:/var/lib/postgresql/data:rw"
];
log-driver = "journald";
extraOptions = [
"--health-cmd=pg_isready -d \${POSTGRES_DB} -U \${POSTGRES_USER}"
"--health-interval=30s"
"--health-retries=5"
"--health-start-period=20s"
"--health-timeout=5s"
"--network-alias=postgresql"
"--network=authentik_default"
];
};
systemd.services."docker-authentik-postgresql" = {
serviceConfig = {
Restart = lib.mkOverride 90 "always";
RestartMaxDelaySec = lib.mkOverride 90 "1m";
RestartSec = lib.mkOverride 90 "100ms";
RestartSteps = lib.mkOverride 90 9;
};
after = [
"docker-network-authentik_default.service"
"docker-volume-authentik_database.service"
];
requires = [
"docker-network-authentik_default.service"
"docker-volume-authentik_database.service"
];
partOf = [
"docker-compose-authentik-root.target"
];
wantedBy = [
"docker-compose-authentik-root.target"
];
};
virtualisation.oci-containers.containers."authentik-server" = {
image = "ghcr.io/goauthentik/server:2025.12.2";
environment = {
"AUTHENTIK_POSTGRESQL__HOST" = "postgresql";
"AUTHENTIK_POSTGRESQL__NAME" = "authentik";
"AUTHENTIK_POSTGRESQL__PASSWORD" = "\${PG_PASS}";
"AUTHENTIK_POSTGRESQL__USER" = "authentik";
"AUTHENTIK_SECRET_KEY" = "\${SECRET_KEY}";
};
environmentFiles = [ config.sops.templates."authentik.env".path ];
labels = {
"traefik.enable" = "true";
"traefik.http.routers.${name}.entrypoints" = "websecure,localsecure";
"traefik.http.routers.${name}.rule" = "Host(`${subdomain}.esotericbytes.com`)";
"traefik.http.routers.${name}.service" = "${name}";
"traefik.http.routers.${name}.tls.certResolver" = "cloudflare";
"traefik.http.services.${name}.loadbalancer.server.url" = "http://192.168.101.1:${builtins.toString hostPort}";
"traefik.http.middlewares.authentik.forwardauth.address" = "https://auth.esotericbytes.com/outpost.goauthentik.io/auth/traefik";
"traefik.http.middlewares.authentik.forwardauth.trustForwardHeader" = "true";
"traefik.http.middlewares.authentik.forwardauth.authResponseHeaders" = "X-authentik-username,X-authentik-groups,X-authentik-entitlements,X-authentik-email,X-authentik-name,X-authentik-uid,X-authentik-jwt,X-authentik-meta-jwks,X-authentik-meta-outpost,X-authentik-meta-provider,X-authentik-meta-app,X-authentik-meta-version";
};
volumes = [
"/etc/Authentik/custom-templates:/templates:rw"
"/etc/Authentik/data:/data:rw"
];
ports = [
"${builtins.toString hostPort}:9000/tcp"
#"9443:9443/tcp"
];
cmd = [ "server" ];
dependsOn = [
"authentik-postgresql"
];
log-driver = "journald";
extraOptions = [
"--network-alias=server"
"--network-alias=authentik-server"
"--network-alias=${name}"
"--ip=192.168.101.6"
];
networks = [
"docker-main"
"authentik_default"
];
};
systemd.services."docker-authentik-server" = {
serviceConfig = {
Restart = lib.mkOverride 90 "always";
RestartMaxDelaySec = lib.mkOverride 90 "1m";
RestartSec = lib.mkOverride 90 "100ms";
RestartSteps = lib.mkOverride 90 9;
};
after = [
"docker-network-authentik_default.service"
"docker-network-setup.service"
];
requires = [
"docker-network-authentik_default.service"
"docker-network-setup.service"
];
partOf = [
"docker-compose-authentik-root.target"
];
wantedBy = [
"docker-compose-authentik-root.target"
];
};
virtualisation.oci-containers.containers."authentik-worker" = {
image = "ghcr.io/goauthentik/server:2025.12.2";
environment = {
"AUTHENTIK_POSTGRESQL__HOST" = "postgresql";
"AUTHENTIK_POSTGRESQL__NAME" = "authentik";
"AUTHENTIK_POSTGRESQL__PASSWORD" = "\${PG_PASS}";
"AUTHENTIK_POSTGRESQL__USER" = "authentik";
"AUTHENTIK_SECRET_KEY" = "\${SECRET_KEY}";
};
environmentFiles = [ config.sops.templates."authentik.env".path ];
volumes = [
"/etc/Authentik/certs:/certs:rw"
"/etc/Authentik/custom-templates:/templates:rw"
"/etc/Authentik/data:/data:rw"
"/var/run/docker.sock:/var/run/docker.sock:rw"
];
cmd = [ "worker" ];
dependsOn = [
"authentik-postgresql"
];
user = "root";
log-driver = "journald";
extraOptions = [
"--network-alias=worker"
"--network=authentik_default"
];
};
systemd.services."docker-authentik-worker" = {
serviceConfig = {
Restart = lib.mkOverride 90 "always";
RestartMaxDelaySec = lib.mkOverride 90 "1m";
RestartSec = lib.mkOverride 90 "100ms";
RestartSteps = lib.mkOverride 90 9;
};
after = [
"docker-network-authentik_default.service"
];
requires = [
"docker-network-authentik_default.service"
];
partOf = [
"docker-compose-authentik-root.target"
];
wantedBy = [
"docker-compose-authentik-root.target"
];
};
# Networks
systemd.services."docker-network-authentik_default" = {
path = [ pkgs.docker ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStop = "docker network rm -f authentik_default";
};
script = ''
docker network inspect authentik_default || docker network create authentik_default
'';
partOf = [ "docker-compose-authentik-root.target" ];
wantedBy = [ "docker-compose-authentik-root.target" ];
};
# Volumes
systemd.services."docker-volume-authentik_database" = {
path = [ pkgs.docker ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = ''
docker volume inspect authentik_database || docker volume create authentik_database --driver=local
'';
partOf = [ "docker-compose-authentik-root.target" ];
wantedBy = [ "docker-compose-authentik-root.target" ];
};
# Root service
# When started, this will automatically create all resources and start
# the containers. When stopped, this will teardown all resources.
systemd.targets."docker-compose-authentik-root" = {
unitConfig = {
Description = "Root target generated by compose2nix.";
};
wantedBy = [ "multi-user.target" ];
};
};
};
}

View File

@@ -0,0 +1,58 @@
{ ... }: {
flake.nixosModules.default = { config, lib, pkgs, ... }: {
options.sysconfig.docker = {
enable = with lib; mkOption {
type = with types; bool;
default = false;
};
nvidia = with lib; mkOption {
type = with types; bool;
default = false;
};
};
config = lib.mkIf config.sysconfig.docker.enable {
networking.nat.internalInterfaces = [ "docker0" "docker-main" ];
virtualisation = {
docker = {
enable = true;
storageDriver = "btrfs";
};
oci-containers = {
backend = "docker";
};
};
hardware.nvidia-container-toolkit.enable = config.sysconfig.docker.nvidia;
systemd.services."docker-network-setup" = {
path = [ pkgs.docker ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStop = "docker network rm -f docker-main";
};
script = ''
docker network inspect docker-main ||
docker network create -d bridge docker-main \
--attachable --subnet 192.168.101.0/24 --ip-range 192.168.101.0/24 \
--gateway 192.168.101.1 \
-o "com.docker.network.bridge.name"="docker-main" \
-o "com.docker.network.bridge.trusted_host_interfaces"="wt0:ve-netbird:ve-traefik"
'';
wantedBy = [ "docker-net.target" ];
};
systemd.targets."docker-net" = {
wantedBy = [ "multi-user.target" ];
};
};
};
}

View File

@@ -0,0 +1,154 @@
{ ... }: {
flake.nixosModules.default = { config, lib, pkgs, ... }: let
subdomain = "gitea";
name = "gitea";
in {
options.sysconfig.docker."${name}".enable = with lib; mkOption {
type = with types; bool;
default = false;
};
config = lib.mkIf (config.sysconfig.docker."${name}".enable && config.sysconfig.docker.enable) {
virtualisation.oci-containers.containers."${name}" = {
image = "docker.gitea.com/gitea:1.25.4";
# unstable, waiting for 26.05
#pull = "newer";
hostname = "${subdomain}.esotericbytes.com";
networks = [
"docker-main"
];
labels = {
"traefik.enable" = "true";
"traefik.http.routers.${name}.entrypoints" = "localsecure";
"traefik.http.routers.${name}.rule" = "Host(`${subdomain}.esotericbytes.com`)";
"traefik.http.routers.${name}.service" = "${name}";
"traefik.http.routers.${name}.tls.certResolver" = "cloudflare";
"traefik.http.services.${name}.loadbalancer.server.port" = "3000";
"traefik.tcp.routers.${name}-ssh.entrypoints" = "gitea-ssh";
"traefik.tcp.routers.${name}-ssh.rule" = "HostSNI(`*`)";
"traefik.tcp.routers.${name}-ssh.service" = "${name}-ssh";
"traefik.tcp.services.${name}-ssh.loadbalancer.server.port" = "22";
};
ports = [
];
extraOptions = [
"--ip=192.168.101.20"
];
volumes = [
"vol_gitea:/data"
];
environment = {
};
};
virtualisation.oci-containers.containers."${name}-db" = {
image = "docker.io/library/postgres:14";
# unstable, waiting for 26.05
#pull = "newer";
hostname = "${name}-db";
networks = [
"docker-main"
];
labels = {
};
ports = [
];
extraOptions = [
"--ip=192.168.101.21"
];
volumes = [
"/etc/gitea/db:/var/lib/postgresql/data"
];
environment = {
};
};
systemd.services."docker-gitea" = {
serviceConfig = {
Restart = lib.mkOverride 90 "always";
RestartMaxDelaySec = lib.mkOverride 90 "1m";
RestartSec = lib.mkOverride 90 "100ms";
RestartSteps = lib.mkOverride 90 9;
};
after = [
"docker-network-setup.service"
"docker-volume-gitea.service"
"docker-gitea-db.service"
];
requires = [
"docker-network-setup.service"
"docker-volume-gitea.service"
"docker-gitea-db.service"
];
partOf = [
"docker-compose-gitea-root.target"
];
wantedBy = [
"docker-compose-gitea-root.target"
];
};
systemd.services."docker-gitea-db" = {
serviceConfig = {
Restart = lib.mkOverride 90 "always";
RestartMaxDelaySec = lib.mkOverride 90 "1m";
RestartSec = lib.mkOverride 90 "100ms";
RestartSteps = lib.mkOverride 90 9;
};
after = [
"docker-network-setup.service"
];
requires = [
"docker-network-setup.service"
];
partOf = [
"docker-compose-gitea-root.target"
];
wantedBy = [
"docker-compose-gitea-root.target"
];
};
systemd.services."docker-volume-gitea" = {
path = [ pkgs.docker ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = ''
docker volume inspect vol_gitea || docker volume create vol_gitea --driver=local
'';
partOf = [ "docker-compose-gitea-root.target" ];
wantedBy = [ "docker-compose-gitea-root.target" ];
};
};
};
}

View File

@@ -0,0 +1,16 @@
# Loads default set of integrations. Do not remove.
default_config:
# Load frontend themes from the themes folder
frontend:
themes: !include_dir_merge_named themes
automation: !include automations.yaml
script: !include scripts.yaml
scene: !include scenes.yaml
http:
use_x_forwarded_for: true
trusted_proxies:
- 192.168.101.11

View File

@@ -0,0 +1,61 @@
{ ... }: {
flake.nixosModules.default = { config, lib, ... }: let
subdomain = "hass";
name = "home-assistant";
in {
options.sysconfig.docker.home-assistant.enable = with lib; mkOption {
type = with types; bool;
default = false;
};
config = lib.mkIf (config.sysconfig.docker.home-assistant.enable && config.sysconfig.docker.enable) {
environment.etc."home-assistant/configuration.yaml".source = ./configuration.yaml;
virtualisation.oci-containers.containers.home-assistant = {
image = "ghcr.io/home-assistant/home-assistant:stable";
# unstable, waiting for 26.05
#pull = "newer";
hostname = "${subdomain}.esotericbytes.com";
networks = [
"docker-main"
];
labels = {
"traefik.enable" = "true";
"traefik.http.routers.${name}.entrypoints" = "localsecure";
"traefik.http.routers.${name}.rule" = "Host(`${subdomain}.esotericbytes.com`)";
"traefik.http.routers.${name}.service" = "${name}";
"traefik.http.routers.${name}.tls.certResolver" = "cloudflare";
#"traefik.http.services.${name}.loadbalancer.server.url" = "http://192.168.100.10:${builtins.toString hostPort}";
"traefik.http.services.${name}.loadbalancer.server.port" = "8123";
};
environment = {
TZ = "America/Chicago";
};
extraOptions = [
"--ip=192.168.101.13"
];
ports = [
];
volumes = [
"vol_home-assistant:/config/"
"/etc/home-assistant/configuration.yaml:/config/configuration.yaml"
];
};
};
};
}

View File

@@ -0,0 +1,120 @@
{ ... }: {
flake.nixosModules.default = { config, lib, pkgs, ... }: let
subdomain = "watch";
name = "jellyfin";
in {
options.sysconfig.docker.jellyfin.enable = with lib; mkOption {
type = with types; bool;
default = false;
};
config = lib.mkIf (config.sysconfig.docker.jellyfin.enable && config.sysconfig.docker.enable) {
networking.firewall.allowedUDPPorts = [ 7359 ];
virtualisation.oci-containers.containers.jellyfin = {
image = "jellyfin/jellyfin:10.11.6";
# unstable, waiting for 26.05
#pull = "newer";
hostname = "${subdomain}.esotericbytes.com";
networks = [
"docker-main"
];
ports = [
"7359:7359/udp"
];
volumes = [
"vol_jellyfin-config:/config"
"vol_jellyfin-cache:/cache"
"/etc/jellyfin/media:/media"
];
labels = {
"traefik.enable" = "true";
"traefik.http.routers.${name}.entrypoints" = "websecure,localsecure";
"traefik.http.routers.${name}.rule" = "Host(`${subdomain}.esotericbytes.com`)";
"traefik.http.routers.${name}.service" = "${name}";
"traefik.http.routers.${name}.tls.certResolver" = "cloudflare";
"traefik.http.services.${name}.loadbalancer.server.port" = "8096";
};
extraOptions = lib.mkIf config.sysconfig.docker.nvidia [
"--device=nvidia.com/gpu=all"
"--ip=192.168.101.21"
];
environment = {
JELLYFIN_PublishedServerUrl = "https://${subdomain}.esotericbytes.com";
};
};
systemd.services."docker-jellyfin" = {
serviceConfig = {
Restart = lib.mkOverride 90 "always";
RestartMaxDelaySec = lib.mkOverride 90 "1m";
RestartSec = lib.mkOverride 90 "100ms";
RestartSteps = lib.mkOverride 90 9;
};
after = [
"docker-network-setup.service"
"docker-volume-jellyfin-config.service"
"docker-volume-jellyfin-cache.service"
];
requires = [
"docker-network-setup.service"
"docker-volume-jellyfin-config.service"
"docker-volume-jellyfin-cache.service"
];
partOf = [
"docker-compose-jellyfin-root.target"
];
wantedBy = [
"docker-compose-jellyfin-root.target"
];
};
systemd.services."docker-volume-jellyfin-config" = {
path = [ pkgs.docker ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = ''
docker volume inspect vol_jellyfin-config || docker volume create vol_jellyfin-config --driver=local
'';
partOf = [ "docker-compose-jellyfin-root.target" ];
wantedBy = [ "docker-compose-jellyfin-root.target" ];
};
systemd.services."docker-volume-jellyfin-cache" = {
path = [ pkgs.docker ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = ''
docker volume inspect vol_jellyfin-cache || docker volume create vol_jellyfin-cache --driver=local
'';
partOf = [ "docker-compose-jellyfin-root.target" ];
wantedBy = [ "docker-compose-jellyfin-root.target" ];
};
systemd.targets."docker-compose-jellyfin-root" = {
wantedBy = [ "multi-user.target" ];
};
};
};
}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1,105 @@
{ ... }: {
flake.nixosModules.default = { config, lib, pkgs, ... }: let
subdomain = "n8n";
name = "n8n";
in {
options.sysconfig.docker."${name}".enable = with lib; mkOption {
type = with types; bool;
default = false;
};
config = lib.mkIf (config.sysconfig.docker."${name}".enable && config.sysconfig.docker.enable) {
virtualisation.oci-containers.containers."${name}" = {
image = "docker.n8n.io/n8nio/n8n";
# unstable, waiting for 26.05
#pull = "newer";
hostname = "${subdomain}.esotericbytes.com";
networks = [
"docker-main"
];
labels = {
"traefik.enable" = "true";
"traefik.http.routers.${name}.entrypoints" = "localsecure";
"traefik.http.routers.${name}.rule" = "Host(`${subdomain}.esotericbytes.com`)";
"traefik.http.routers.${name}.service" = "${name}";
"traefik.http.routers.${name}.tls.certResolver" = "cloudflare";
"traefik.http.services.${name}.loadbalancer.server.port" = "5678";
};
ports = [
];
extraOptions = [
"--ip=192.168.101.2"
];
volumes = [
"vol_n8n:/etc/n8n"
];
environment = {
GENERIC_TIMEZONE = "America/Chicago";
TZ = "America/Chicago";
N8N_DIAGNOSTICS_ENABLED = "false";
N8N_VERSION_NOTIFICATIONS_ENABLED = "false";
N8N_TEMPLATES_ENABLED = "false";
EXTERNAL_FRONTEND_HOOKS_URLS = "";
N8N_DIAGNOSTICS_CONFIG_FRONTEND = "";
N8N_DIAGNOSTICS_CONFIG_BACKEND = "";
N8N_SECURE_COOKIE = "false";
};
};
systemd.services."docker-n8n" = {
serviceConfig = {
Restart = lib.mkOverride 90 "always";
RestartMaxDelaySec = lib.mkOverride 90 "1m";
RestartSec = lib.mkOverride 90 "100ms";
RestartSteps = lib.mkOverride 90 9;
};
after = [
"docker-network-setup.service"
"docker-volume-n8n.service"
];
requires = [
"docker-network-setup.service"
"docker-volume-n8n.service"
];
partOf = [
"docker-compose-n8n-root.target"
];
wantedBy = [
"docker-compose-n8n-root.target"
];
};
systemd.services."docker-volume-n8n" = {
path = [ pkgs.docker ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = ''
docker volume inspect vol_n8n || docker volume create vol_n8n --driver=local
'';
partOf = [ "docker-compose-n8n-root.target" ];
wantedBy = [ "docker-compose-n8n-root.target" ];
};
};
};
}

View File

@@ -0,0 +1,27 @@
{
"Stuns": [
{
"Proto": "udp",
"URI": "stun:vpn.esotericbytes.com:3478"
}
],
"Relay": {
"Addresses": ["rels://vpn.esotericbytes.com:443"],
"CredentialsTTL": "24h",
"Secret": "0qSIu/S2sXHJbo0SyBNm4SFxAItRoPLKR4wjnW/Zsgc"
},
"Signal": {
"Proto": "https",
"URI": "vpn.esotericbytes.com:443"
},
"Datadir": "/var/lib/netbird",
"DataStoreEncryptionKey": "FZnQt+JqAC8GEXUSJwhrgo0vn4PoDetoAhjUx9nSJR0=",
"EmbeddedIdP": {
"Enabled": true,
"Issuer": "https://vpn.esotericbytes.com/oauth2",
"DashboardRedirectURIs": [
"https://vpn.esotericbytes.com/nb-auth",
"https://vpn.esotericbytes.com/nb-silent-auth"
]
}
}

View File

@@ -0,0 +1,232 @@
{ ... }: {
flake.nixosModules.default = { config, lib, pkgs, ... }: {
options.sysconfig.docker.netbird.enable = with lib; mkOption {
type = with types; bool;
default = false;
};
config = lib.mkIf (config.sysconfig.docker.netbird.enable && config.sysconfig.docker.enable) {
networking.firewall.allowedUDPPorts = [ 3478 ];
sops.secrets."netbird/secret_key" = {};
sops.templates."netbird-relay.env" = {
content = ''
NB_AUTH_SECRET=${config.sops.placeholder."netbird/secret_key"}
NB_LOG_LEVEL=info
NB_LISTEN_ADDRESS=:80
NB_EXPOSED_ADDRESS=rels://vpn.esotericbytes.com:443
NB_ENABLE_STUN=true
NB_STUN_LOG_LEVEL=info
NB_STUN_PORTS=3478
'';
};
environment.etc."netbird/management.json".source = ./config/management.json;
# Containers
virtualisation.oci-containers.containers."netbird-dashboard" = {
image = "netbirdio/dashboard:v2.30.1";
environment = {
"AUTH_AUDIENCE" = "netbird-dashboard";
"AUTH_AUTHORITY" = "https://vpn.esotericbytes.com/oauth2";
"AUTH_CLIENT_ID" = "netbird-dashboard";
"AUTH_CLIENT_SECRET" = "";
"AUTH_REDIRECT_URI" = "/nb-auth";
"AUTH_SILENT_REDIRECT_URI" = "/nb-silent-auth";
"AUTH_SUPPORTED_SCOPES" = "openid profile email groups";
"LETSENCRYPT_DOMAIN" = "none";
"NETBIRD_MGMT_API_ENDPOINT" = "https://vpn.esotericbytes.com";
"NETBIRD_MGMT_GRPC_API_ENDPOINT" = "https://vpn.esotericbytes.com";
"NGINX_SSL_PORT" = "443";
"USE_AUTH0" = "false";
};
labels = {
"traefik.enable" = "true";
"traefik.http.routers.netbird-dashboard.entrypoints" = "websecure";
"traefik.http.routers.netbird-dashboard.priority" = "1";
"traefik.http.routers.netbird-dashboard.rule" = "Host(`vpn.esotericbytes.com`)";
"traefik.http.routers.netbird-dashboard.tls" = "true";
"traefik.http.services.netbird-dashboard.loadbalancer.server.port" = "80";
};
log-driver = "journald";
extraOptions = [
"--network-alias=dashboard"
"--network=docker-main"
"--ip=192.168.101.5"
];
};
systemd.services."docker-netbird-dashboard" = {
serviceConfig = {
Restart = lib.mkOverride 90 "always";
RestartMaxDelaySec = lib.mkOverride 90 "1m";
RestartSec = lib.mkOverride 90 "100ms";
RestartSteps = lib.mkOverride 90 9;
};
partOf = [
"docker-compose-netbird-root.target"
];
wantedBy = [
"docker-compose-netbird-root.target"
];
};
virtualisation.oci-containers.containers."netbird-management" = {
image = "netbirdio/management:0.64.4";
volumes = [
"/etc/netbird/management.json:/etc/netbird/management.json:rw"
"netbird_netbird_management:/var/lib/netbird:rw"
];
cmd = [ "--port" "80" "--log-file" "console" "--log-level" "info" "--disable-anonymous-metrics=false" "--single-account-mode-domain=netbird.selfhosted" "--dns-domain=netbird.selfhosted" "--idp-sign-key-refresh-enabled" ];
labels = {
"traefik.enable" = "true";
"traefik.http.routers.netbird-api.entrypoints" = "websecure";
"traefik.http.routers.netbird-api.rule" = "Host(`vpn.esotericbytes.com`) && PathPrefix(`/api`)";
"traefik.http.routers.netbird-api.service" = "netbird-api";
"traefik.http.routers.netbird-api.tls" = "true";
"traefik.http.routers.netbird-mgmt-grpc.entrypoints" = "websecure";
"traefik.http.routers.netbird-mgmt-grpc.rule" = "Host(`vpn.esotericbytes.com`) && PathPrefix(`/management.ManagementService/`)";
"traefik.http.routers.netbird-mgmt-grpc.service" = "netbird-mgmt-grpc";
"traefik.http.routers.netbird-mgmt-grpc.tls" = "true";
"traefik.http.routers.netbird-mgmt-ws.entrypoints" = "websecure";
"traefik.http.routers.netbird-mgmt-ws.rule" = "Host(`vpn.esotericbytes.com`) && PathPrefix(`/ws-proxy/management`)";
"traefik.http.routers.netbird-mgmt-ws.service" = "netbird-mgmt-ws";
"traefik.http.routers.netbird-mgmt-ws.tls" = "true";
"traefik.http.routers.netbird-oauth2.entrypoints" = "websecure";
"traefik.http.routers.netbird-oauth2.rule" = "Host(`vpn.esotericbytes.com`) && PathPrefix(`/oauth2`)";
"traefik.http.routers.netbird-oauth2.service" = "netbird-oauth2";
"traefik.http.routers.netbird-oauth2.tls" = "true";
"traefik.http.services.netbird-api.loadbalancer.server.port" = "80";
"traefik.http.services.netbird-mgmt-grpc.loadbalancer.server.port" = "80";
"traefik.http.services.netbird-mgmt-grpc.loadbalancer.server.scheme" = "h2c";
"traefik.http.services.netbird-mgmt-ws.loadbalancer.server.port" = "80";
"traefik.http.services.netbird-oauth2.loadbalancer.server.port" = "80";
};
log-driver = "journald";
extraOptions = [
"--network-alias=management"
"--network=docker-main"
"--ip=192.168.101.4"
];
};
systemd.services."docker-netbird-management" = {
serviceConfig = {
Restart = lib.mkOverride 90 "always";
RestartMaxDelaySec = lib.mkOverride 90 "1m";
RestartSec = lib.mkOverride 90 "100ms";
RestartSteps = lib.mkOverride 90 9;
};
after = [
"docker-volume-netbird_netbird_management.service"
];
requires = [
"docker-volume-netbird_netbird_management.service"
];
partOf = [
"docker-compose-netbird-root.target"
];
wantedBy = [
"docker-compose-netbird-root.target"
];
};
virtualisation.oci-containers.containers."netbird-relay" = {
image = "netbirdio/relay:0.64.4";
environmentFiles = [ config.sops.templates."netbird-relay.env".path ];
ports = [
"3478:3478/udp"
];
labels = {
"traefik.enable" = "true";
"traefik.http.routers.netbird-relay.entrypoints" = "websecure";
"traefik.http.routers.netbird-relay.rule" = "Host(`vpn.esotericbytes.com`) && PathPrefix(`/relay`)";
"traefik.http.routers.netbird-relay.tls" = "true";
"traefik.http.services.netbird-relay.loadbalancer.server.port" = "80";
};
log-driver = "journald";
extraOptions = [
"--network-alias=relay"
"--network=docker-main"
"--ip=192.168.101.3"
];
};
systemd.services."docker-netbird-relay" = {
serviceConfig = {
Restart = lib.mkOverride 90 "always";
RestartMaxDelaySec = lib.mkOverride 90 "1m";
RestartSec = lib.mkOverride 90 "100ms";
RestartSteps = lib.mkOverride 90 9;
};
partOf = [
"docker-compose-netbird-root.target"
];
wantedBy = [
"docker-compose-netbird-root.target"
];
};
virtualisation.oci-containers.containers."netbird-signal" = {
image = "netbirdio/signal:0.64.4";
labels = {
"traefik.enable" = "true";
"traefik.http.routers.netbird-signal-grpc.entrypoints" = "websecure";
"traefik.http.routers.netbird-signal-grpc.rule" = "Host(`vpn.esotericbytes.com`) && PathPrefix(`/signalexchange.SignalExchange/`)";
"traefik.http.routers.netbird-signal-grpc.service" = "netbird-signal-grpc";
"traefik.http.routers.netbird-signal-grpc.tls" = "true";
"traefik.http.routers.netbird-signal-ws.entrypoints" = "websecure";
"traefik.http.routers.netbird-signal-ws.rule" = "Host(`vpn.esotericbytes.com`) && PathPrefix(`/ws-proxy/signal`)";
"traefik.http.routers.netbird-signal-ws.service" = "netbird-signal-ws";
"traefik.http.routers.netbird-signal-ws.tls" = "true";
"traefik.http.services.netbird-signal-grpc.loadbalancer.server.port" = "10000";
"traefik.http.services.netbird-signal-grpc.loadbalancer.server.scheme" = "h2c";
"traefik.http.services.netbird-signal-ws.loadbalancer.server.port" = "80";
};
log-driver = "journald";
extraOptions = [
"--network-alias=signal"
"--network=docker-main"
];
};
systemd.services."docker-netbird-signal" = {
serviceConfig = {
Restart = lib.mkOverride 90 "always";
RestartMaxDelaySec = lib.mkOverride 90 "1m";
RestartSec = lib.mkOverride 90 "100ms";
RestartSteps = lib.mkOverride 90 9;
};
partOf = [
"docker-compose-netbird-root.target"
];
wantedBy = [
"docker-compose-netbird-root.target"
];
};
# Volumes
systemd.services."docker-volume-netbird_netbird_management" = {
path = [ pkgs.docker ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = ''
docker volume inspect netbird_netbird_management || docker volume create netbird_netbird_management
'';
partOf = [ "docker-compose-netbird-root.target" ];
wantedBy = [ "docker-compose-netbird-root.target" ];
};
# Root service
# When started, this will automatically create all resources and start
# the containers. When stopped, this will teardown all resources.
systemd.targets."docker-compose-netbird-root" = {
unitConfig = {
Description = "Root target generated by compose2nix.";
};
wantedBy = [ "multi-user.target" ];
};
};
};
}

View File

@@ -0,0 +1,118 @@
{ ... }: {
flake.nixosModules.default = { config, lib, pkgs, ... }: let
subdomain = "cloud";
name = "nextcloud";
in {
options.sysconfig.docker.nextcloud.enable = with lib; mkOption {
type = with types; bool;
default = false;
};
config = lib.mkIf (config.sysconfig.docker.nextcloud.enable && config.sysconfig.docker.enable) {
virtualisation.oci-containers.containers."nextcloud-aio-mastercontainer" = {
image = "ghcr.io/nextcloud-releases/all-in-one:20260122_105751";
serviceName = "docker-nextcloud";
# unstable, waiting for 26.05
#pull = "newer";
hostname = "${subdomain}.esotericbytes.com";
networks = [
"docker-main"
];
ports = [
];
volumes = [
"nextcloud_aio_mastercontainer:/mnt/docker-aio-config"
"/run/docker.sock:/var/run/docker.sock:ro"
];
labels = {
"traefik.enable" = "true";
"traefik.http.routers.${name}.entrypoints" = "websecure,localsecure";
"traefik.http.routers.${name}.rule" = "Host(`${subdomain}.esotericbytes.com`)";
"traefik.http.routers.${name}.service" = "${name}";
"traefik.http.routers.${name}.tls.certResolver" = "cloudflare";
"traefik.http.routers.${name}.middlewares" = "nextcloud-chain";
"traefik.http.middlewares.https-redirect.redirectScheme.scheme" = "https";
"traefik.http.middlewares.nextcloud-secure-headers.headers.hostsProxyHeaders" = "X-Forwarded-Host";
"traefik.http.middlewares.nextcloud-secure-headers.headers.referrerPolicy" = "same-origin";
"traefik.http.middlewares.nextcloud-chain.chain.middlewares" = "https-redirect,nextcloud-secure-headers";
#"traefik.http.services.${name}.loadbalancer.server.port" = "11000";
"traefik.http.services.${name}.loadbalancer.server.url" = "http://192.168.101.1:11000";
};
extraOptions = [
"--ip=192.168.101.17"
];
environment = {
APACHE_PORT = "11000";
APACHE_IP = "0.0.0.0";
APACHE_ADDITIONAL_NETWORK = "docker-main";
SKIP_DOMAIN_VALIDATION = "true";
TALK_PORT = "3479";
};
};
systemd.services."docker-nextcloud" = {
serviceConfig = {
Restart = lib.mkOverride 90 "always";
RestartMaxDelaySec = lib.mkOverride 90 "1m";
RestartSec = lib.mkOverride 90 "100ms";
RestartSteps = lib.mkOverride 90 9;
};
after = [
"docker-network-setup.service"
"docker-volume-nextcloud.service"
];
requires = [
"docker-network-setup.service"
"docker-volume-nextcloud.service"
];
partOf = [
"docker-compose-nextcloud-root.target"
];
wantedBy = [
"docker-compose-nextcloud-root.target"
];
};
systemd.services."docker-volume-nextcloud" = {
path = [ pkgs.docker ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = ''
docker volume inspect nextcloud_aio_mastercontainer || docker volume create nextcloud_aio_mastercontainer --driver=local
'';
partOf = [ "docker-compose-nextcloud-root.target" ];
wantedBy = [ "docker-compose-nextcloud-root.target" ];
};
systemd.targets."docker-compose-nextcloud-root" = {
wantedBy = [ "multi-user.target" ];
};
};
};
}

View File

@@ -0,0 +1,76 @@
{ ... }: {
flake.nixosModules.default = { config, lib, pkgs, ... }: let
hostPort = 11434;
subdomain = "ollama";
name = "ollama";
in {
options.sysconfig.docker.ollama.enable = with lib; mkOption {
type = with types; bool;
default = false;
};
config = lib.mkIf (config.sysconfig.docker.ollama.enable && config.sysconfig.docker.enable) {
environment.systemPackages = with pkgs; [
ollama
];
networking.firewall.interfaces = {
"ve-traefik" = {
allowedTCPPorts = [ hostPort ];
};
"ve-openwebui" = {
allowedTCPPorts = [ hostPort ];
};
};
virtualisation.oci-containers.containers.ollama = {
image = "ollama/ollama:latest";
# unstable, waiting for 26.05
#pull = "newer";
hostname = "${subdomain}.esotericbytes.com";
networks = [
"docker-main"
];
ports = [
"${builtins.toString hostPort}:11434"
];
volumes = [
"vol_ollama:/root/.ollama"
];
labels = {
"traefik.enable" = "true";
"traefik.http.routers.${name}.entrypoints" = "localsecure";
"traefik.http.routers.${name}.rule" = "Host(`${subdomain}.esotericbytes.com`)";
"traefik.http.routers.${name}.service" = "${name}";
"traefik.http.routers.${name}.tls.certResolver" = "cloudflare";
#"traefik.http.services.ollama.loadbalancer.server.url" = "http://192.168.100.10:${builtins.toString hostPort}";
"traefik.http.services.${name}.loadbalancer.server.port" = "11434";
};
extraOptions = lib.mkIf config.sysconfig.docker.nvidia [
"--device=nvidia.com/gpu=all"
"--ip=192.168.101.22"
];
environment = {
OLLAMA_CONTEXT_LENGTH = lib.mkDefault "32000";
};
};
};
};
}

View File

@@ -0,0 +1,99 @@
{ ... }: {
flake.nixosModules.default = { config, lib, pkgs, ... }: let
subdomain = "ai";
name = "openwebui";
in {
options.sysconfig.docker.openwebui.enable = with lib; mkOption {
type = with types; bool;
default = false;
};
config = lib.mkIf (config.sysconfig.docker.openwebui.enable && config.sysconfig.docker.enable) {
virtualisation.oci-containers.containers.openwebui = {
image = "ghcr.io/open-webui/open-webui:v0.7.2";
# unstable, waiting for 26.05
#pull = "newer";
hostname = "${subdomain}.esotericbytes.com";
networks = [
"docker-main"
];
/*ports = [
"${builtins.toString hostPort}:8080"
];*/
volumes = [
"vol_openwebui:/app/backend/data"
];
labels = {
"traefik.enable" = "true";
"traefik.http.routers.${name}.entrypoints" = "localsecure";
"traefik.http.routers.${name}.rule" = "Host(`${subdomain}.esotericbytes.com`)";
"traefik.http.routers.${name}.service" = "${name}";
"traefik.http.routers.${name}.tls.certResolver" = "cloudflare";
"traefik.http.services.${name}.loadbalancer.server.port" = "8080";
};
extraOptions = lib.mkIf config.sysconfig.docker.nvidia [
"--device=nvidia.com/gpu=all"
"--ip=192.168.101.8"
];
environment = {
};
};
systemd.services."docker-openwebui" = {
serviceConfig = {
Restart = lib.mkOverride 90 "always";
RestartMaxDelaySec = lib.mkOverride 90 "1m";
RestartSec = lib.mkOverride 90 "100ms";
RestartSteps = lib.mkOverride 90 9;
};
after = [
"docker-network-setup.service"
"docker-volume-openwebui.service"
];
requires = [
"docker-network-setup.service"
"docker-volume-openwebui.service"
];
partOf = [
"docker-compose-openwebui-root.target"
];
wantedBy = [
"docker-compose-openwebui-root.target"
];
};
systemd.services."docker-volume-openwebui" = {
path = [ pkgs.docker ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = ''
docker volume inspect vol_openwebui || docker volume create vol_openwebui --driver=local
'';
partOf = [ "docker-compose-openwebui-root.target" ];
wantedBy = [ "docker-compose-openwebui-root.target" ];
};
systemd.targets."docker-compose-openwebui-root" = {
wantedBy = [ "multi-user.target" ];
};
};
};
}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1,167 @@
# Auto-generated by compose2nix.
{ pkgs, lib, ... }:
{
# Runtime
virtualisation.docker = {
enable = true;
autoPrune.enable = true;
};
virtualisation.oci-containers.backend = "docker";
# Containers
virtualisation.oci-containers.containers."passbolt-db" = {
image = "mariadb:10.11";
environment = {
"MYSQL_DATABASE" = "passbolt";
"MYSQL_PASSWORD" = "P4ssb0lt";
"MYSQL_RANDOM_ROOT_PASSWORD" = "true";
"MYSQL_USER" = "passbolt";
};
volumes = [
"passbolt_database_volume:/var/lib/mysql:rw"
];
log-driver = "journald";
extraOptions = [
"--network-alias=db"
"--network=passbolt_default"
];
};
systemd.services."docker-passbolt-db" = {
serviceConfig = {
Restart = lib.mkOverride 90 "always";
RestartMaxDelaySec = lib.mkOverride 90 "1m";
RestartSec = lib.mkOverride 90 "100ms";
RestartSteps = lib.mkOverride 90 9;
};
after = [
"docker-network-passbolt_default.service"
"docker-volume-passbolt_database_volume.service"
];
requires = [
"docker-network-passbolt_default.service"
"docker-volume-passbolt_database_volume.service"
];
partOf = [
"docker-compose-passbolt-root.target"
];
wantedBy = [
"docker-compose-passbolt-root.target"
];
};
virtualisation.oci-containers.containers."passbolt-passbolt" = {
image = "passbolt/passbolt:latest-ce";
environment = {
"APP_FULL_BASE_URL" = "https://passbolt.local";
"DATASOURCES_DEFAULT_DATABASE" = "passbolt";
"DATASOURCES_DEFAULT_HOST" = "db";
"DATASOURCES_DEFAULT_PASSWORD" = "P4ssb0lt";
"DATASOURCES_DEFAULT_USERNAME" = "passbolt";
};
volumes = [
"passbolt_gpg_volume:/etc/passbolt/gpg:rw"
"passbolt_jwt_volume:/etc/passbolt/jwt:rw"
];
ports = [
"80:80/tcp"
"443:443/tcp"
];
cmd = [ "/usr/bin/wait-for.sh" "-t" "0" "db:3306" "--" "/docker-entrypoint.sh" ];
dependsOn = [
"passbolt-db"
];
log-driver = "journald";
extraOptions = [
"--network-alias=passbolt"
"--network=passbolt_default"
];
};
systemd.services."docker-passbolt-passbolt" = {
serviceConfig = {
Restart = lib.mkOverride 90 "always";
RestartMaxDelaySec = lib.mkOverride 90 "1m";
RestartSec = lib.mkOverride 90 "100ms";
RestartSteps = lib.mkOverride 90 9;
};
after = [
"docker-network-passbolt_default.service"
"docker-volume-passbolt_gpg_volume.service"
"docker-volume-passbolt_jwt_volume.service"
];
requires = [
"docker-network-passbolt_default.service"
"docker-volume-passbolt_gpg_volume.service"
"docker-volume-passbolt_jwt_volume.service"
];
partOf = [
"docker-compose-passbolt-root.target"
];
wantedBy = [
"docker-compose-passbolt-root.target"
];
};
# Networks
systemd.services."docker-network-passbolt_default" = {
path = [ pkgs.docker ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStop = "docker network rm -f passbolt_default";
};
script = ''
docker network inspect passbolt_default || docker network create passbolt_default
'';
partOf = [ "docker-compose-passbolt-root.target" ];
wantedBy = [ "docker-compose-passbolt-root.target" ];
};
# Volumes
systemd.services."docker-volume-passbolt_database_volume" = {
path = [ pkgs.docker ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = ''
docker volume inspect passbolt_database_volume || docker volume create passbolt_database_volume
'';
partOf = [ "docker-compose-passbolt-root.target" ];
wantedBy = [ "docker-compose-passbolt-root.target" ];
};
systemd.services."docker-volume-passbolt_gpg_volume" = {
path = [ pkgs.docker ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = ''
docker volume inspect passbolt_gpg_volume || docker volume create passbolt_gpg_volume
'';
partOf = [ "docker-compose-passbolt-root.target" ];
wantedBy = [ "docker-compose-passbolt-root.target" ];
};
systemd.services."docker-volume-passbolt_jwt_volume" = {
path = [ pkgs.docker ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = ''
docker volume inspect passbolt_jwt_volume || docker volume create passbolt_jwt_volume
'';
partOf = [ "docker-compose-passbolt-root.target" ];
wantedBy = [ "docker-compose-passbolt-root.target" ];
};
# Root service
# When started, this will automatically create all resources and start
# the containers. When stopped, this will teardown all resources.
systemd.targets."docker-compose-passbolt-root" = {
unitConfig = {
Description = "Root target generated by compose2nix.";
};
wantedBy = [ "multi-user.target" ];
};
}

View File

@@ -0,0 +1,85 @@
{ ... }: {
flake.nixosModules.default = { config, lib, ... }: let
hostPort = 9001;
subdomain = "pihole";
name = "pihole";
in {
options.sysconfig.docker.pihole.enable = with lib; mkOption {
type = with types; bool;
default = false;
};
config = lib.mkIf (config.sysconfig.docker.pihole.enable && config.sysconfig.docker.enable) {
virtualisation.docker.daemon.settings.dns = [ "192.168.101.12" ];
environment.etc."resolv.conf" = {
enable = true;
text = ''
nameserver 127.0.0.1
nameserver 1.1.1.1
nameserver 1.0.0.1
options edns0
'';
user = "root";
mode = "0664";
};
networking.firewall.interfaces = {
"ve-traefik" = {
allowedTCPPorts = [ hostPort ];
};
};
virtualisation.oci-containers.containers.pihole = {
image = "pihole/pihole:latest";
# unstable, waiting for 26.05
#pull = "newer";
hostname = "${subdomain}.esotericbytes.com";
networks = [
"docker-main"
];
labels = {
"traefik.enable" = "true";
"traefik.http.routers.${name}.entrypoints" = "localsecure";
"traefik.http.routers.${name}.rule" = "Host(`${subdomain}.esotericbytes.com`)";
"traefik.http.routers.${name}.service" = "${name}";
"traefik.http.routers.${name}.tls.certResolver" = "cloudflare";
#"traefik.http.services.${name}.loadbalancer.server.url" = "http://192.168.100.10:${builtins.toString hostPort}";
"traefik.http.services.${name}.loadbalancer.server.port" = "80";
};
extraOptions = [
"--ip=192.168.101.12"
];
ports = [
"${builtins.toString hostPort}:80"
"127.0.0.1:53:53/tcp"
"127.0.0.1:53:53/udp"
];
volumes = [
"vol_pihole:/etc/pihole"
];
environment = {
FTLCONF_webserver_api_password = "7567";
FTLCONF_dns_listeningMode = "ALL";
};
};
};
};
}

View File

@@ -0,0 +1,65 @@
{ ... }: {
flake.nixosModules.default = { config, lib, ... }: let
hostPort = 9000;
subdomain = "portainer";
name = "portainer";
in {
options.sysconfig.docker.portainer.enable = with lib; mkOption {
type = with types; bool;
default = true;
};
config = lib.mkIf (config.sysconfig.docker.portainer.enable && config.sysconfig.docker.enable) {
networking.firewall.interfaces = {
"ve-traefik" = {
allowedTCPPorts = [ hostPort ];
};
};
virtualisation.oci-containers.containers.portainer = {
image = "portainer/portainer-ce:latest";
# unstable, waiting for 26.05
#pull = "newer";
hostname = "${subdomain}.esotericbytes.com";
networks = [
"docker-main"
];
labels = {
"traefik.enable" = "true";
"traefik.http.routers.${name}.entrypoints" = "localsecure";
"traefik.http.routers.${name}.rule" = "Host(`${subdomain}.esotericbytes.com`)";
"traefik.http.routers.${name}.service" = "${name}";
"traefik.http.routers.${name}.tls.certResolver" = "cloudflare";
#"traefik.http.services.${name}.loadbalancer.server.url" = "http://192.168.100.10:${builtins.toString hostPort}";
"traefik.http.services.${name}.loadbalancer.server.port" = "9000";
};
ports = [
"127.0.0.1:8000:8000"
"${builtins.toString hostPort}:9000"
];
extraOptions = [
"--ip=192.168.101.10"
];
volumes = [
"vol_portainer:/data"
"/run/docker.sock:/var/run/docker.sock"
];
};
};
};
}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1,77 @@
# Auto-generated by compose2nix.
{ pkgs, lib, ... }:
{
# Runtime
virtualisation.docker = {
enable = true;
autoPrune.enable = true;
};
virtualisation.oci-containers.backend = "docker";
# Containers
virtualisation.oci-containers.containers."hbbr" = {
image = "rustdesk/rustdesk-server:latest";
volumes = [
"/home/nathan/Projects/Olympus/system/virtualization/docker/rustdesk/data:/root:rw"
];
cmd = [ "hbbr" ];
log-driver = "journald";
extraOptions = [
"--network=host"
];
};
systemd.services."docker-hbbr" = {
serviceConfig = {
Restart = lib.mkOverride 90 "always";
RestartMaxDelaySec = lib.mkOverride 90 "1m";
RestartSec = lib.mkOverride 90 "100ms";
RestartSteps = lib.mkOverride 90 9;
};
partOf = [
"docker-compose-rustdesk-root.target"
];
wantedBy = [
"docker-compose-rustdesk-root.target"
];
};
virtualisation.oci-containers.containers."hbbs" = {
image = "rustdesk/rustdesk-server:latest";
volumes = [
"/home/nathan/Projects/Olympus/system/virtualization/docker/rustdesk/data:/root:rw"
];
cmd = [ "hbbs" ];
dependsOn = [
"hbbr"
];
log-driver = "journald";
extraOptions = [
"--network=host"
];
};
systemd.services."docker-hbbs" = {
serviceConfig = {
Restart = lib.mkOverride 90 "always";
RestartMaxDelaySec = lib.mkOverride 90 "1m";
RestartSec = lib.mkOverride 90 "100ms";
RestartSteps = lib.mkOverride 90 9;
};
partOf = [
"docker-compose-rustdesk-root.target"
];
wantedBy = [
"docker-compose-rustdesk-root.target"
];
};
# Root service
# When started, this will automatically create all resources and start
# the containers. When stopped, this will teardown all resources.
systemd.targets."docker-compose-rustdesk-root" = {
unitConfig = {
Description = "Root target generated by compose2nix.";
};
wantedBy = [ "multi-user.target" ];
};
}

View File

@@ -0,0 +1,62 @@
{ ... }: {
flake.nixosModules.default = { config, lib, ... }: let
subdomain = "searxng";
name = "searxng";
in {
options.sysconfig.docker.searxng.enable = with lib; mkOption {
type = with types; bool;
default = false;
};
config = lib.mkIf (config.sysconfig.docker.searxng.enable && config.sysconfig.docker.enable) {
environment.etc."searxng/settings.yml".source = ./settings.yml;
virtualisation.oci-containers.containers.searxng = {
image = "searxng/searxng:latest";
# unstable, waiting for 26.05
#pull = "newer";
hostname = "${subdomain}.esotericbytes.com";
networks = [
"docker-main"
];
labels = {
"traefik.enable" = "true";
"traefik.http.routers.${name}.entrypoints" = "localsecure";
"traefik.http.routers.${name}.rule" = "Host(`${subdomain}.esotericbytes.com`)";
"traefik.http.routers.${name}.service" = "${name}";
"traefik.http.routers.${name}.tls.certResolver" = "cloudflare";
#"traefik.http.services.${name}.loadbalancer.server.url" = "http://192.168.100.10:${builtins.toString hostPort}";
"traefik.http.services.${name}.loadbalancer.server.port" = "8080";
};
ports = [
];
extraOptions = [
"--ip=192.168.101.9"
];
volumes = [
"vol_searxng_settings:/etc/searxng/"
"vol_searxng_data:/var/cache/searxng/"
"/etc/searxng/settings.yml:/etc/searxng/settings.yml"
];
environment = {
SEARXNG_SECRET = "2e8b4fcf4c0f46b097496f2d5715dbb061bd5cac78c64d0f5a0bee27f013f3c0";
};
};
};
};
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,75 @@
http:
routers:
homepageSecure:
entryPoints:
- "websecure"
- "localsecure"
rule: "Host(`esotericbytes.com`) || Host(`www.esotericbytes.com`)"
service: "homepage"
middlewares:
- authentik
tls:
certResolver: "cloudflare"
code-server:
entryPoints:
- "localsecure"
rule: "Host(`code.esotericbytes.com`)"
service: "code-server"
tls:
certResolver: "cloudflare"
gitea:
entryPoints:
- "localsecure"
- "websecure"
rule: "Host(`gitea.esotericbytes.com`)"
service: "gitea"
tls:
certResolver: "cloudflare"
octoprint:
entryPoints:
- "localsecure"
#- "websecure"
rule: "Host(`3dp.esotericbytes.com`)"
service: "octoprint"
tls:
certResolver: "cloudflare"
services:
homepage:
loadBalancer:
servers:
- url: "http://192.168.100.13:80"
code-server:
loadBalancer:
servers:
- url: "http://192.168.100.31:4444"
gitea:
loadBalancer:
servers:
- url: "http://192.168.100.20:3000"
octoprint:
loadBalancer:
servers:
- url: "http://rpi-3dp.local"
passHostHeader: true
tcp:
routers:
gitea-ssh:
entryPoints:
- "gitea-ssh"
rule: "HostSNI(`*`)"
service: "gitea-ssh"
services:
gitea-ssh:
loadBalancer:
servers:
- address: "192.168.100.20:2222"

View File

@@ -0,0 +1,87 @@
providers:
docker:
exposedByDefault: false
file:
filename: "/etc/traefik/routing.yml"
serversTransport:
insecureSkipVerify: true
api:
dashboard: true
global:
checknewversion: true
sendanonymoususage: false
entryPoints:
web:
address: ":81"
http:
redirections:
entryPoint:
to: "websecure"
scheme: "https"
websecure:
address: ":444"
asDefault: true
transport:
respondingTimeouts:
readTimeout: 24h
http:
tls:
certResolver: "cloudflare"
domains:
main: "esotericbytes.com"
sans:
- "*.esotericbytes.com"
encodedCharacters:
allowEncodedSlash: true
allowEncodedQuestionMark: true
allowEncodedPercent: true
local:
address: ":80"
http:
redirections:
entryPoint:
to: "localsecure"
scheme: "https"
localsecure:
address: ":443"
asDefault: true
transport:
respondingTimeouts:
readTimeout: 24h
http:
tls:
certResolver: "cloudflare"
domains:
main: "esotericbytes.com"
sans:
- "*.esotericbytes.com"
encodedCharacters:
allowEncodedSlash: true
allowEncodedQuestionMark: true
allowEncodedPercent: true
gitea-ssh:
address: ":2222"
log:
level: "INFO"
filePath: "/etc/traefik/logs/traefik.log"
format: "json"
certificatesResolvers:
cloudflare:
acme:
storage: "/etc/traefik/acme.json"
keyType: "EC256"
dnsChallenge:
provider: "cloudflare"
resolvers:
- "1.1.1.1:53"
- "1.0.0.1:53"

View File

@@ -0,0 +1,111 @@
{ ... }: {
flake.nixosModules.default = { config, lib, ... }: {
options.sysconfig.docker.traefik.enable = with lib; mkOption {
type = with types; bool;
default = false;
};
config = lib.mkIf (config.sysconfig.docker.traefik.enable && config.sysconfig.docker.enable) {
networking.firewall.allowedTCPPorts = [ 80 81 443 444 2222 ];
sops.secrets = {
"traefik/cf_email" = {};
"traefik/cf_api_key" = {};
};
sops.templates."traefik.env" = {
content = ''
CF_API_EMAIL=${config.sops.placeholder."traefik/cf_email"}
CF_DNS_API_TOKEN=${config.sops.placeholder."traefik/cf_api_key"}
'';
};
environment.etc = (builtins.listToAttrs (builtins.map (x: {
name = "traefik/${x}";
value = {
source = ./config/${x};
mode = "0664";
};
}) (builtins.attrNames (builtins.readDir ./config))));
/*environment.etc."traefik/traefik.yml" = {
source = ./config/traefik.yml;
};
environment.etc."traefik/routing.yml" = {
source = ./config/routing.yml;
};*/
virtualisation.oci-containers.containers.traefik = {
image = "traefik:v3.6";
environment = {
TRAEFIK_CERTIFICATESRESOLVERS_CLOUDFLARE_ACME_EMAIL = "\${CF_API_EMAIL}";
};
environmentFiles = [ config.sops.templates."traefik.env".path ];
volumes = [
"/etc/traefik/:/etc/traefik/"
"/run/docker.sock:/var/run/docker.sock"
];
networks = [
"docker-main"
];
ports = [
"80:80"
"81:81"
"443:443"
"444:444"
"2222:2222"
];
labels = {
"traefik.enable" = "true";
"traefik.http.routers.dashboard.rule" = "Host(`traefik.esotericbytes.com`)";
"traefik.http.routers.dashboard.entrypoints" = "websecure,localsecure";
"traefik.http.routers.dashboard.service" = "api@internal";
"traefik.http.routers.dashboard.tls.certResolver" = "cloudflare";
};
extraOptions = [
"--ip=192.168.101.11"
];
log-driver = "journald";
};
systemd.services."docker-traefik" = {
serviceConfig = {
Restart = lib.mkOverride 90 "always";
RestartMaxDelaySec = lib.mkOverride 90 "1m";
RestartSec = lib.mkOverride 90 "100ms";
RestartSteps = lib.mkOverride 90 9;
};
after = [
"docker-network-setup.service"
];
requires = [
"docker-network-setup.service"
];
partOf = [
"docker-compose-traefik-root.target"
];
wantedBy = [
"docker-compose-traefik-root.target"
];
};
# Root service
# When started, this will automatically create all resources and start
# the containers. When stopped, this will teardown all resources.
systemd.targets."docker-compose-traefik-root" = {
wantedBy = [ "multi-user.target" ];
};
};
};
}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1,27 @@
{ ... }: {
flake.nixosModules.default = { config, lib, pkgs, ... }: {
options.sysconfig.virtual-machines.enable = with lib; mkOption {
type = with types; bool;
default = false;
};
config = lib.mkIf config.sysconfig.virtual-machines.enable {
programs.virt-manager.enable = true;
virtualisation = {
libvirtd = {
enable = true;
qemu.swtpm.enable = true;
};
spiceUSBRedirection.enable = true;
};
environment.systemPackages = with pkgs; lib.mkIf config.sysconfig.graphical [
virt-viewer
];
};
};
}

View File

@@ -0,0 +1,17 @@
{ ... }: {
flake.nixosModules.default = { config, lib, ... }: {
options.sysconfig.virtual-machines.home-assistant = {
enable = lib.options.mkOption {
type = lib.types.bool;
default = false;
};
};
config = lib.mkIf config.sysconfig.virtual-machines.home-assistant.enable {
};
};
}