This commit is contained in:
mjallen18
2026-02-11 22:23:00 -06:00
parent 89275509f3
commit 92b6e7a822
12 changed files with 702 additions and 529 deletions

View File

@@ -7,13 +7,19 @@
}: }:
with lib; with lib;
let let
inherit (lib.${namespace}) mkOpt;
cfg = config.${namespace}.services.ai; cfg = config.${namespace}.services.ai;
aiConfig = lib.${namespace}.mkModule { aiConfig = lib.${namespace}.mkModule {
inherit config; inherit config;
name = "ai"; name = "ai";
description = "AI Services"; description = "AI Services";
options = { }; options = {
llama-cpp = {
model = mkOpt types.str "Qwen3-Coder-Next-UD-Q3_K_XL" "";
};
};
moduleConfig = { moduleConfig = {
services = { services = {
ollama = { ollama = {
@@ -34,7 +40,7 @@ let
port = 8127; port = 8127;
host = "0.0.0.0"; host = "0.0.0.0";
openFirewall = cfg.openFirewall; openFirewall = cfg.openFirewall;
model = "${cfg.configDir}/llama-cpp/models/Qwen3-Coder-Next-Q4_0.gguf"; model = "${cfg.configDir}/llama-cpp/models/${cfg.llama-cpp.model}.gguf";
package = pkgs.llama-cpp-rocm; package = pkgs.llama-cpp-rocm;
extraFlags = [ extraFlags = [
"--fit" "--fit"
@@ -105,7 +111,7 @@ let
set -euo pipefail set -euo pipefail
MODEL_DIR="${cfg.configDir}/llama-cpp/models" MODEL_DIR="${cfg.configDir}/llama-cpp/models"
MODEL_NAME="Qwen3-Coder-Next-Q4_0.gguf" MODEL_NAME="${cfg.llama-cpp.model}.gguf"
REPO_ID="unsloth/Qwen3-Coder-Next-GGUF" REPO_ID="unsloth/Qwen3-Coder-Next-GGUF"
# Create model directory if it doesn't exist # Create model directory if it doesn't exist

View File

@@ -11,10 +11,13 @@ let
cfg = config.${namespace}.services.${name}; cfg = config.${namespace}.services.${name};
caddyPackage = pkgs.caddy.withPlugins { caddyPackage = pkgs.caddy.withPlugins {
plugins = [ "github.com/caddy-dns/cloudflare@v0.2.2" ]; plugins = [
"github.com/caddy-dns/cloudflare@v0.2.2"
];
hash = "sha256-dnhEjopeA0UiI+XVYHYpsjcEI6Y1Hacbi28hVKYQURg="; hash = "sha256-dnhEjopeA0UiI+XVYHYpsjcEI6Y1Hacbi28hVKYQURg=";
}; };
# "github.com/hslatman/caddy-crowdsec-bouncer/http@v0.9.2"
caddy = lib.${namespace}.mkModule { caddy = lib.${namespace}.mkModule {
inherit config name; inherit config name;
description = "caddy Service"; description = "caddy Service";
@@ -87,14 +90,14 @@ let
package = caddyPackage; package = caddyPackage;
environmentFile = config.sops.templates."caddy.env".path; environmentFile = config.sops.templates."caddy.env".path;
email = "jalle008@proton.me"; email = "jalle008@proton.me";
enableReload = false; enableReload = true;
dataDir = "${cfg.configDir}/caddy"; dataDir = "${cfg.configDir}/caddy";
globalConfig = '' globalConfig = ''
metrics metrics
http_port 80 http_port 80
https_port 443 https_port 443
default_bind 0.0.0.0 default_bind 0.0.0.0
''; # b710da1b0182eadcb1e569408de778f9f3c50 '';
virtualHosts = { virtualHosts = {
"*.mjallen.dev" = { "*.mjallen.dev" = {
extraConfig = '' extraConfig = ''
@@ -102,19 +105,54 @@ let
dns cloudflare {$CLOUDFLARE_DNS_API_TOKEN} dns cloudflare {$CLOUDFLARE_DNS_API_TOKEN}
} }
@gitea host gitea.mjallen.dev @authentik host authentik.mjallen.dev
handle @gitea { handle @authentik {
reverse_proxy http://10.0.1.3:3000 reverse_proxy http://10.0.1.3:${toString config.${namespace}.services.authentik.port}
} }
@jellyfin host jellyfin.mjallen.dev @cache host cache.mjallen.dev
handle @jellyfin { handle @cache {
reverse_proxy http://10.0.1.3:8096 reverse_proxy http://10.0.1.3:${toString config.${namespace}.services.attic.port}
}
@gitea host gitea.mjallen.dev
handle @gitea {
reverse_proxy http://10.0.1.3:${toString config.${namespace}.services.gitea.port}
} }
@homeassistant host hass.mjallen.dev @homeassistant host hass.mjallen.dev
handle @homeassistant { handle @homeassistant {
reverse_proxy http://10.0.1.4:8123 reverse_proxy http://nuc-nixos.local:8123
}
@immich host immich.mjallen.dev
handle @immich {
reverse_proxy http://10.0.1.3:${toString config.${namespace}.services.immich.port}
}
@jellyfin host jellyfin.mjallen.dev
handle @jellyfin {
reverse_proxy http://10.0.1.3:${toString config.${namespace}.services.jellyfin.port}
}
@jellyseerr host jellyseerr.mjallen.dev
handle @jellyseerr {
reverse_proxy http://10.0.1.3:${toString config.${namespace}.services.jellyseerr.port}
}
@lubelogger host lubelogger.mjallen.dev
handle @lubelogger {
reverse_proxy http://10.0.1.3:${toString config.${namespace}.services.lubelogger.port}
}
@matrix host matrix.mjallen.dev
handle @matrix {
reverse_proxy http://10.0.1.3:${toString config.${namespace}.services.matrix.port}
}
@ntfy host ntfy.mjallen.dev
handle @ntfy {
reverse_proxy http://10.0.1.3:${toString config.${namespace}.services.ntfy.port}
} }
''; '';
}; };

View File

@@ -14,38 +14,59 @@ let
description = "config"; description = "config";
options = { }; options = { };
moduleConfig = { moduleConfig = {
# Add ACME certificate configuration for TLS support
# security.acme.certs."turn.mjallen.dev" = {
# group = "turnserver";
# dnsProvider = "cloudflare";
# credentialsFile = config.sops.templates."traefik.env".path;
# dnsPropagationCheck = true;
# };
services.coturn = rec { services.coturn = rec {
enable = true; enable = true;
no-cli = true; no-cli = true;
no-tcp-relay = true; # Removed no-tcp-relay to enable TCP relay for better VoIP support
min-port = 49000; min-port = 49000;
max-port = 50000; max-port = 50000;
use-auth-secret = true; use-auth-secret = true;
static-auth-secret = "Lucifer008!"; static-auth-secret = "Lucifer008!";
listening-port = cfg.port; listening-port = cfg.port;
realm = "turn.mjallen.dev"; realm = "turn.mjallen.dev";
# cert = "${config.security.acme.certs.${realm}.directory}/full.pem"; # Enable TLS support with ACME certificates
# cert = "${config.security.acme.certs.${realm}.directory}/fullchain.pem";
# pkey = "${config.security.acme.certs.${realm}.directory}/key.pem"; # pkey = "${config.security.acme.certs.${realm}.directory}/key.pem";
extraConfig = '' extraConfig = ''
# for debugging # for debugging
verbose verbose
# ban private IP ranges
# Add public IP address for NAT traversal
external-ip=73.242.17.96
# Allow localhost for testing
allowed-peer-ip=127.0.0.0-127.255.255.255
allowed-peer-ip=::1
# ban private IP ranges - modified to allow local connections
no-multicast-peers no-multicast-peers
denied-peer-ip=0.0.0.0-0.255.255.255 denied-peer-ip=0.0.0.0-0.255.255.255
denied-peer-ip=10.0.0.0-10.255.255.255 # Allow internal networks for testing
# denied-peer-ip=10.0.0.0-10.255.255.255
denied-peer-ip=100.64.0.0-100.127.255.255 denied-peer-ip=100.64.0.0-100.127.255.255
denied-peer-ip=127.0.0.0-127.255.255.255 # Localhost now explicitly allowed above
# denied-peer-ip=127.0.0.0-127.255.255.255
denied-peer-ip=169.254.0.0-169.254.255.255 denied-peer-ip=169.254.0.0-169.254.255.255
denied-peer-ip=172.16.0.0-172.31.255.255 denied-peer-ip=172.16.0.0-172.31.255.255
denied-peer-ip=192.0.0.0-192.0.0.255 denied-peer-ip=192.0.0.0-192.0.0.255
denied-peer-ip=192.0.2.0-192.0.2.255 denied-peer-ip=192.0.2.0-192.0.2.255
denied-peer-ip=192.88.99.0-192.88.99.255 denied-peer-ip=192.88.99.0-192.88.99.255
denied-peer-ip=192.168.0.0-192.168.255.255 # Allow local network
# denied-peer-ip=192.168.0.0-192.168.255.255
denied-peer-ip=198.18.0.0-198.19.255.255 denied-peer-ip=198.18.0.0-198.19.255.255
denied-peer-ip=198.51.100.0-198.51.100.255 denied-peer-ip=198.51.100.0-198.51.100.255
denied-peer-ip=203.0.113.0-203.0.113.255 denied-peer-ip=203.0.113.0-203.0.113.255
denied-peer-ip=240.0.0.0-255.255.255.255 denied-peer-ip=240.0.0.0-255.255.255.255
denied-peer-ip=::1 # Localhost now explicitly allowed above
# denied-peer-ip=::1
denied-peer-ip=64:ff9b::-64:ff9b::ffff:ffff denied-peer-ip=64:ff9b::-64:ff9b::ffff:ffff
denied-peer-ip=::ffff:0.0.0.0-::ffff:255.255.255.255 denied-peer-ip=::ffff:0.0.0.0-::ffff:255.255.255.255
denied-peer-ip=100::-100::ffff:ffff:ffff:ffff denied-peer-ip=100::-100::ffff:ffff:ffff:ffff
@@ -53,9 +74,30 @@ let
denied-peer-ip=2002::-2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff denied-peer-ip=2002::-2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff
denied-peer-ip=fc00::-fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff denied-peer-ip=fc00::-fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
denied-peer-ip=fe80::-febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff denied-peer-ip=fe80::-febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff
# Add better logging for debugging
log-file=/var/log/turnserver.log
syslog
''; '';
}; };
networking.firewall = { networking.firewall = {
# Open ports on all interfaces for better connectivity
allowedUDPPortRanges = with config.services.coturn; [
{
from = min-port;
to = max-port;
}
];
allowedUDPPorts = [
3478 # STUN/TURN standard port
5349 # STUN/TURN TLS port
];
allowedTCPPorts = [
3478 # STUN/TURN standard port
5349 # STUN/TURN TLS port
];
# Keep the specific interface rules too for backward compatibility
interfaces.enp197s0 = interfaces.enp197s0 =
let let
range = with config.services.coturn; [ range = with config.services.coturn; [

View File

@@ -119,6 +119,15 @@ let
capi.credentialsFile = lib.mkDefault "${cfg.configDir}/crowdsec/capi.yaml"; capi.credentialsFile = lib.mkDefault "${cfg.configDir}/crowdsec/capi.yaml";
}; };
}; };
crowdsec-firewall-bouncer = {
enable = true;
registerBouncer = {
enable = true;
bouncerName = "nas-bouncer";
};
# secrets.apiKeyPath = config.sops.secrets."jallen-nas/crowdsec-firewall-bouncer-api-key".path;
};
}; };
}; };
}; };

View File

@@ -122,9 +122,11 @@ let
turn_uris = [ turn_uris = [
"turn:${config.services.coturn.realm}:3478?transport=udp" "turn:${config.services.coturn.realm}:3478?transport=udp"
"turn:${config.services.coturn.realm}:3478?transport=tcp" "turn:${config.services.coturn.realm}:3478?transport=tcp"
"turns:${config.services.coturn.realm}:5349?transport=tcp" # TLS version for secure connections
]; ];
turn_shared_secret = config.services.coturn.static-auth-secret; turn_shared_secret = config.services.coturn.static-auth-secret;
turn_user_lifetime = "1h"; turn_user_lifetime = "1h";
turn_allow_guests = true; # Allow guest users to use TURN server
}; };
}; };

View File

@@ -58,70 +58,12 @@ let
configDir = "/media/nas/main/appdata"; configDir = "/media/nas/main/appdata";
in in
{ {
imports = [ ./options.nix ]; imports = [
./options.nix
./sops.nix
];
config = mkIf cfg.enable { config = mkIf cfg.enable {
sops = {
secrets = {
"jallen-nas/traefik/crowdsec/lapi-key" = {
sopsFile = (lib.snowfall.fs.get-file "secrets/nas-secrets.yaml");
owner = config.users.users.traefik.name;
group = config.users.users.traefik.group;
restartUnits = [ "traefik.service" ];
};
"jallen-nas/traefik/crowdsec/capi-machine-id" = {
sopsFile = (lib.snowfall.fs.get-file "secrets/nas-secrets.yaml");
owner = config.users.users.traefik.name;
group = config.users.users.traefik.group;
restartUnits = [ "traefik.service" ];
};
"jallen-nas/traefik/crowdsec/capi-password" = {
sopsFile = (lib.snowfall.fs.get-file "secrets/nas-secrets.yaml");
owner = config.users.users.traefik.name;
group = config.users.users.traefik.group;
restartUnits = [ "traefik.service" ];
};
"jallen-nas/traefik/cloudflare-dns-api-token" = {
sopsFile = (lib.snowfall.fs.get-file "secrets/nas-secrets.yaml");
owner = config.users.users.traefik.name;
group = config.users.users.traefik.group;
restartUnits = [ "traefik.service" ];
};
"jallen-nas/traefik/cloudflare-zone-api-token" = {
sopsFile = (lib.snowfall.fs.get-file "secrets/nas-secrets.yaml");
owner = config.users.users.traefik.name;
group = config.users.users.traefik.group;
restartUnits = [ "traefik.service" ];
};
"jallen-nas/traefik/cloudflare-api-key" = {
sopsFile = (lib.snowfall.fs.get-file "secrets/nas-secrets.yaml");
owner = config.users.users.traefik.name;
group = config.users.users.traefik.group;
restartUnits = [ "traefik.service" ];
};
"jallen-nas/traefik/cloudflare-email" = {
sopsFile = (lib.snowfall.fs.get-file "secrets/nas-secrets.yaml");
owner = config.users.users.traefik.name;
group = config.users.users.traefik.group;
restartUnits = [ "traefik.service" ];
};
};
templates = {
"traefik.env" = {
content = ''
CLOUDFLARE_DNS_API_TOKEN=${config.sops.placeholder."jallen-nas/traefik/cloudflare-dns-api-token"}
CLOUDFLARE_ZONE_API_TOKEN=${config.sops.placeholder."jallen-nas/traefik/cloudflare-zone-api-token"}
CLOUDFLARE_API_KEY=${config.sops.placeholder."jallen-nas/traefik/cloudflare-api-key"}
CLOUDFLARE_EMAIL=${config.sops.placeholder."jallen-nas/traefik/cloudflare-email"}
'';
owner = config.users.users.traefik.name;
group = config.users.users.traefik.group;
restartUnits = [ "traefik.service" ];
};
};
};
networking.firewall = { networking.firewall = {
allowedTCPPorts = forwardPorts; allowedTCPPorts = forwardPorts;
@@ -131,240 +73,295 @@ in
services.traefik = { services.traefik = {
enable = true; enable = true;
dataDir = "${configDir}/traefik"; dataDir = "${configDir}/traefik";
dynamic.dir = "${configDir}/traefik";
group = "jallen-nas"; # group; group = "jallen-nas"; # group;
environmentFiles = [ config.sops.templates."traefik.env".path ]; environmentFiles = [ config.sops.templates."traefik.env".path ];
staticConfigOptions = { static = {
entryPoints = { # dir = "${configDir}/traefik";
web = { settings = {
address = ":${toString httpPort}"; entryPoints = {
asDefault = true; web = {
http.redirections.entrypoint = { address = ":${toString httpPort}";
to = "websecure"; asDefault = true;
scheme = "https"; http.redirections.entrypoint = {
to = "websecure";
scheme = "https";
};
};
websecure = {
address = ":${toString httpsPort}";
asDefault = true;
http.tls.certResolver = "letsencrypt";
};
metrics = {
address = ":${toString metricsPort}"; # Port for metrics
}; };
}; };
websecure = { log = {
address = ":${toString httpsPort}"; level = "INFO";
asDefault = true;
http.tls.certResolver = "letsencrypt";
}; };
metrics = { metrics = {
address = ":${toString metricsPort}"; # Port for metrics prometheus = {
entryPoint = "metrics";
addEntryPointsLabels = true;
addServicesLabels = true;
buckets = [
0.1
0.3
1.2
5.0
]; # Response time buckets
};
}; };
};
log = { certificatesResolvers.letsencrypt.acme = {
level = "INFO"; email = letsEncryptEmail;
}; storage = "${config.services.traefik.dataDir}/acme.json";
dnsChallenge = {
metrics = { provider = "cloudflare";
prometheus = { resolvers = [
entryPoint = "metrics"; "1.1.1.1:53"
addEntryPointsLabels = true; "8.8.8.8:53"
addServicesLabels = true; ];
buckets = [ };
0.1
0.3
1.2
5.0
]; # Response time buckets
}; };
};
certificatesResolvers.letsencrypt.acme = { # Access the Traefik dashboard on <Traefik IP>:8080
email = letsEncryptEmail; api = {
storage = "${config.services.traefik.dataDir}/acme.json"; dashboard = true;
dnsChallenge = { insecure = true;
provider = "cloudflare";
resolvers = [
"1.1.1.1:53"
"8.8.8.8:53"
];
}; };
};
# Access the Traefik dashboard on <Traefik IP>:8080 experimental = {
api = { plugins = traefikPlugins;
dashboard = true; };
insecure = true;
};
experimental = {
plugins = traefikPlugins;
}; };
}; };
dynamicConfigOptions = { dynamic = {
http = { dir = "/run/traefik";
serversTransports = { files = {
internal-https = { "serversTransports".settings.http = {
insecureSkipVerify = true; serversTransports = {
}; internal-https = {
http1 = { insecureSkipVerify = true;
serverName = "localhost"; };
disableHTTP2 = true; http1 = {
serverName = "localhost";
disableHTTP2 = true;
};
}; };
}; };
middlewares = { "middlewares-authentik".settings.http = {
authentik = { middlewares = {
forwardAuth = { authentik = {
tls.insecureSkipVerify = true; forwardAuth = {
address = "${authUrl}/auth/traefik"; tls.insecureSkipVerify = true;
trustForwardHeader = true; address = "${authUrl}/auth/traefik";
authResponseHeaders = [ trustForwardHeader = true;
"X-authentik-username" authResponseHeaders = [
"X-authentik-groups" "X-authentik-username"
"X-authentik-email" "X-authentik-groups"
"X-authentik-name" "X-authentik-email"
"X-authentik-uid" "X-authentik-name"
"X-authentik-jwt" "X-authentik-uid"
"X-authentik-meta-jwks" "X-authentik-jwt"
"X-authentik-meta-outpost" "X-authentik-meta-jwks"
"X-authentik-meta-provider" "X-authentik-meta-outpost"
"X-authentik-meta-app" "X-authentik-meta-provider"
"X-authentik-meta-version" "X-authentik-meta-app"
]; "X-authentik-meta-version"
};
};
crowdsec = {
plugin = {
bouncer = {
enabled = true;
crowdsecLapiKeyFile = config.sops.secrets."jallen-nas/traefik/crowdsec/lapi-key".path;
crowdsecLapiScheme = "http";
crowdsecLapiHost = "localhost:8181";
crowdsecLapiPath = "/";
crowdsecLapiTLSInsecureVerify = false;
crowdsecCapiMachineIdFile = config.sops.secrets."jallen-nas/traefik/crowdsec/capi-machine-id".path;
crowdsecCapiPasswordFile = config.sops.secrets."jallen-nas/traefik/crowdsec/capi-password".path;
crowdsecCapiScenarios = [ ];
};
};
};
whitelist-geoblock = {
plugin = {
geoblock = {
silentStartUp = false;
allowLocalRequests = true;
logLocalRequests = false;
logAllowedRequests = false;
logApiRequests = false;
api = "https://get.geojs.io/v1/ip/country/{ip}";
apiTimeoutMs = 500;
cacheSize = 25;
forceMonthlyUpdate = true;
allowUnknownCountries = false;
unknownCountryApiResponse = "nil";
blackListMode = false;
countries = [
"CA"
"US"
]; ];
}; };
}; };
}; };
internal-ipallowlist = { };
ipAllowList = {
sourceRange = [ "middlewares-crowdsec".settings.http = {
"127.0.0.1/32" middlewares = {
"10.0.1.0/24" crowdsec = {
]; plugin = {
bouncer = {
enabled = true;
crowdsecLapiKeyFile = config.sops.secrets."jallen-nas/traefik/crowdsec/lapi-key".path;
crowdsecLapiScheme = "http";
crowdsecLapiHost = "localhost:8181";
crowdsecLapiPath = "/";
crowdsecLapiTLSInsecureVerify = false;
crowdsecCapiMachineIdFile = config.sops.secrets."jallen-nas/traefik/crowdsec/capi-machine-id".path;
crowdsecCapiPasswordFile = config.sops.secrets."jallen-nas/traefik/crowdsec/capi-password".path;
crowdsecCapiScenarios = [ ];
};
};
}; };
}; };
}; };
services = { "middlewares-geoblock".settings.http = {
auth.loadBalancer.servers = [ middlewares = {
{ whitelist-geoblock = {
url = authUrl; plugin = {
} geoblock = {
]; silentStartUp = false;
cache.loadBalancer = { allowLocalRequests = true;
servers = [ logLocalRequests = false;
logAllowedRequests = false;
logApiRequests = false;
api = "https://get.geojs.io/v1/ip/country/{ip}";
apiTimeoutMs = 500;
cacheSize = 25;
forceMonthlyUpdate = true;
allowUnknownCountries = false;
unknownCountryApiResponse = "nil";
blackListMode = false;
countries = [
"CA"
"US"
];
};
};
};
};
};
"middlewares-ipallowlist".settings.http = {
middlewares = {
internal-ipallowlist = {
ipAllowList = {
sourceRange = [
"127.0.0.1/32"
"10.0.1.0/24"
];
};
};
};
};
"services-auth".settings.http = {
services = {
auth.loadBalancer.servers = [
{ {
url = cacheUrl; url = authUrl;
} }
]; ];
serversTransport = "http1";
}; };
hass.loadBalancer.servers = [ };
{
url = hassUrl;
}
];
nginx.loadBalancer.servers = [
{
url = "http://localhost:8188";
}
];
}
// reverseProxyServiceConfigs;
routers = { "services-cache".settings.http = {
auth = { services = {
entryPoints = [ "websecure" ]; cache.loadBalancer = {
rule = "HostRegexp(`{subdomain:[a-z]+}.mjallen.dev`) && PathPrefix(`/outpost.goauthentik.io/`)"; servers = [
service = "auth"; {
middlewares = [ url = cacheUrl;
"crowdsec" }
"whitelist-geoblock" ];
serversTransport = "http1";
};
};
};
"services-nginx".settings.http = {
services = {
nginx.loadBalancer.servers = [
{
url = "http://localhost:8188";
}
]; ];
priority = 15;
tls.certResolver = "letsencrypt";
}; };
};
matrix2 = { "services-generated".settings.http = reverseProxyServiceConfigs;
entryPoints = [ "websecure" ];
rule = "Host(`matrix.mjallen.dev`) && PathPrefix(`/.well-known/matrix/`)"; "routers-auth".settings.http = {
service = "nginx"; routers = {
middlewares = [ auth = {
"crowdsec" entryPoints = [ "websecure" ];
"whitelist-geoblock" rule = "HostRegexp(`{subdomain:[a-z]+}.mjallen.dev`) && PathPrefix(`/outpost.goauthentik.io/`)";
service = "auth";
middlewares = [
"crowdsec"
"whitelist-geoblock"
];
priority = 15;
tls.certResolver = "letsencrypt";
};
};
};
"routers-matrix2".settings.http = {
routers = {
matrix2 = {
entryPoints = [ "websecure" ];
rule = "Host(`matrix.mjallen.dev`) && PathPrefix(`/.well-known/matrix/`)";
service = "nginx";
middlewares = [
"crowdsec"
"whitelist-geoblock"
];
priority = 1;
tls.certResolver = "letsencrypt";
};
};
};
"routers-matrix3".settings.http = {
routers = {
matrix3 = {
entryPoints = [ "websecure" ];
rule = "Host(`mjallen.dev`) && PathPrefix(`/.well-known/matrix/`)";
service = "nginx";
middlewares = [
"crowdsec"
"whitelist-geoblock"
];
priority = 1;
tls.certResolver = "letsencrypt";
};
};
};
"routers-cache".settings.http = {
routers = {
cache = {
entryPoints = [ "websecure" ];
rule = "Host(`cache.${domain}`)";
service = "cache";
middlewares = [ ];
priority = 10;
tls.certResolver = "letsencrypt";
};
};
};
"home-assistant".settings.http = {
services = {
hass.loadBalancer.servers = [
{
url = hassUrl;
}
]; ];
priority = 1;
tls.certResolver = "letsencrypt";
}; };
routers = {
matrix3 = { hass = {
entryPoints = [ "websecure" ]; entryPoints = [ "websecure" ];
rule = "Host(`mjallen.dev`) && PathPrefix(`/.well-known/matrix/`)"; rule = "Host(`hass.${domain}`)";
service = "nginx"; service = "hass";
middlewares = [ middlewares = [
"crowdsec" "crowdsec"
"whitelist-geoblock" "whitelist-geoblock"
]; # "authentik"
priority = 1; ];
tls.certResolver = "letsencrypt"; priority = 10;
tls.certResolver = "letsencrypt";
};
}; };
};
cache = { "routers-generated".settings.http = reverseProxyRouterConfigs;
entryPoints = [ "websecure" ];
rule = "Host(`cache.${domain}`)";
service = "cache";
middlewares = [ ];
priority = 10;
tls.certResolver = "letsencrypt";
};
hass = {
entryPoints = [ "websecure" ];
rule = "Host(`hass.${domain}`)";
service = "hass";
middlewares = [
"crowdsec"
"whitelist-geoblock"
# "authentik"
];
priority = 10;
tls.certResolver = "letsencrypt";
};
}
// reverseProxyRouterConfigs;
}; };
}; };
}; };

View File

@@ -0,0 +1,76 @@
{
config,
lib,
namespace,
...
}:
with lib;
let
cfg = config.${namespace}.services.traefik;
in
{
config = mkIf cfg.enable {
sops = {
secrets = {
"jallen-nas/traefik/crowdsec/lapi-key" = {
sopsFile = (lib.snowfall.fs.get-file "secrets/nas-secrets.yaml");
owner = config.users.users.traefik.name;
group = config.users.users.traefik.group;
restartUnits = [ "traefik.service" ];
};
"jallen-nas/traefik/crowdsec/capi-machine-id" = {
sopsFile = (lib.snowfall.fs.get-file "secrets/nas-secrets.yaml");
owner = config.users.users.traefik.name;
group = config.users.users.traefik.group;
restartUnits = [ "traefik.service" ];
};
"jallen-nas/traefik/crowdsec/capi-password" = {
sopsFile = (lib.snowfall.fs.get-file "secrets/nas-secrets.yaml");
owner = config.users.users.traefik.name;
group = config.users.users.traefik.group;
restartUnits = [ "traefik.service" ];
};
"jallen-nas/traefik/cloudflare-dns-api-token" = {
sopsFile = (lib.snowfall.fs.get-file "secrets/nas-secrets.yaml");
owner = config.users.users.traefik.name;
group = config.users.users.traefik.group;
restartUnits = [ "traefik.service" ];
};
"jallen-nas/traefik/cloudflare-zone-api-token" = {
sopsFile = (lib.snowfall.fs.get-file "secrets/nas-secrets.yaml");
owner = config.users.users.traefik.name;
group = config.users.users.traefik.group;
restartUnits = [ "traefik.service" ];
};
"jallen-nas/traefik/cloudflare-api-key" = {
sopsFile = (lib.snowfall.fs.get-file "secrets/nas-secrets.yaml");
owner = config.users.users.traefik.name;
group = config.users.users.traefik.group;
restartUnits = [ "traefik.service" ];
};
"jallen-nas/traefik/cloudflare-email" = {
sopsFile = (lib.snowfall.fs.get-file "secrets/nas-secrets.yaml");
owner = config.users.users.traefik.name;
group = config.users.users.traefik.group;
restartUnits = [ "traefik.service" ];
};
};
templates = {
"traefik.env" = {
content = ''
CLOUDFLARE_DNS_API_TOKEN=${config.sops.placeholder."jallen-nas/traefik/cloudflare-dns-api-token"}
CLOUDFLARE_ZONE_API_TOKEN=${config.sops.placeholder."jallen-nas/traefik/cloudflare-zone-api-token"}
CLOUDFLARE_API_KEY=${config.sops.placeholder."jallen-nas/traefik/cloudflare-api-key"}
CLOUDFLARE_EMAIL=${config.sops.placeholder."jallen-nas/traefik/cloudflare-email"}
'';
owner = config.users.users.traefik.name;
group = config.users.users.traefik.group;
restartUnits = [ "traefik.service" ];
};
};
};
};
}

View File

@@ -19,10 +19,7 @@ let
autoStart = true; autoStart = true;
image = "josh5/unmanic"; image = "josh5/unmanic";
devices = [ devices = [
"/dev/dri/renderD128:/dev/dri/renderD128" "/dev/dri:/dev/dri"
"/dev/dri/card0:/dev/dri/card0"
"/dev/dri/renderD129:/dev/dri/renderD129"
"/dev/dri/card1:/dev/dri/card1"
]; ];
volumes = [ volumes = [
"${cfg.configDir}/unmanic:/config" "${cfg.configDir}/unmanic:/config"

File diff suppressed because one or more lines are too long

View File

@@ -11,13 +11,13 @@ in
${namespace} = { ${namespace} = {
services = { services = {
actual = { actual = {
enable = true; enable = false;
port = 3333; port = 3333;
createUser = true; createUser = true;
reverseProxy = enabled; reverseProxy = enabled;
}; };
ai = { ai = {
enable = true; enable = false;
}; };
arrs = { arrs = {
enable = true; enable = true;
@@ -49,7 +49,7 @@ in
enable = true; enable = true;
port = 6066; port = 6066;
}; };
caddy = disabled; caddy = enabled;
calibre = { calibre = {
enable = false; enable = false;
port = 8084; port = 8084;
@@ -197,7 +197,7 @@ in
port = 8265; port = 8265;
serverPort = 8266; serverPort = 8266;
}; };
traefik = enabled; traefik = disabled;
unmanic = { unmanic = {
enable = true; enable = true;
port = 8265; port = 8265;

View File

@@ -137,6 +137,7 @@ in
allowedTCPPorts = [ allowedTCPPorts = [
80 80
443 443
8080
8008 # restic 8008 # restic
9000 # authentik 9000 # authentik
2342 # grafana 2342 # grafana

View File

@@ -98,6 +98,10 @@ in
# crowdsec # crowdsec
# ------------------------------ # ------------------------------
# "jallen-nas/crowdsec-firewall-bouncer-api-key" = {
# restartUnits = [ "crowdsec-firewall-bouncer.service" ];
# };
# "jallen-nas/crowdsec-capi" = { # "jallen-nas/crowdsec-capi" = {
# sopsFile = defaultSops; # sopsFile = defaultSops;
# owner = "crowdsec"; # owner = "crowdsec";