This commit is contained in:
mjallen18
2026-03-16 16:41:46 -05:00
parent 742e1703d8
commit 7538f734f1
19 changed files with 259 additions and 851 deletions

View File

@@ -5,6 +5,9 @@
...
}:
with lib;
# NOTE: AUTHENTIK_TOKEN for the RAC outpost is stored in sops.
# Add jallen-nas/authentik-rac/token to secrets/nas-secrets.yaml and ensure
# jallen-nas/sops.nix declares the "authentik-rac.env" template before deploying.
let
name = "authentik";
cfg = config.${namespace}.services.${name};
@@ -41,10 +44,12 @@ let
volumes = [
"${cfg.configDir}/authentik-rac:/media"
];
# AUTHENTIK_TOKEN is injected via the sops template "authentik-rac.env"
# defined in systems/x86_64-linux/jallen-nas/sops.nix
environmentFiles = [ config.sops.templates."authentik-rac.env".path ];
environment = {
AUTHENTIK_HOST = "https://${name}.mjallen.dev";
AUTHENTIK_TOKEN = "0XGkB2pXoOTqcCMAjucAtfamvlsIZCPmy1Zri54Ozjj3zzMCvcLwkQPrukfx";
AUTHENTIK_INSECURE = "false"; # Set to true for self-signed certs
AUTHENTIK_INSECURE = "false";
PUID = toString cfg.puid;
PGID = toString cfg.pgid;
TZ = cfg.timeZone;

View File

@@ -1,369 +0,0 @@
{
config,
lib,
namespace,
...
}:
with lib;
let
cfg = config.${namespace}.services.traefik;
# Process reverseProxies into service and router configurations
reverseProxyServiceConfigs =
let
makeService = reverseProxy: nameValuePair reverseProxy.service.name reverseProxy.service.config;
in
listToAttrs (map makeService cfg.reverseProxies);
reverseProxyRouterConfigs =
let
makeRouter = reverseProxy: nameValuePair reverseProxy.router.subdomain reverseProxy.router.config;
in
listToAttrs (map makeRouter cfg.reverseProxies);
domain = "mjallen.dev";
# Forward services
authUrl = "http://localhost:9000/outpost.goauthentik.io";
cacheUrl = "http://localhost:9012";
hassUrl = "http://nuc-nixos.local:8123";
# Plugins
traefikPlugins = {
bouncer = {
moduleName = "github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin";
version = "v1.4.5";
};
geoblock = {
moduleName = "github.com/PascalMinder/geoblock";
version = "v0.2.5";
};
};
# Ports
httpPort = 80;
httpsPort = 443;
traefikPort = 8080;
metricsPort = 8082;
forwardPorts = [
httpPort
httpsPort
traefikPort
metricsPort
];
# misc
letsEncryptEmail = "jalle008@proton.me";
configDir = "/media/nas/main/appdata";
in
{
imports = [
./options.nix
./sops.nix
];
config = mkIf cfg.enable {
networking.firewall = {
allowedTCPPorts = forwardPorts;
allowedUDPPorts = forwardPorts;
};
# services.traefik = {
# enable = true;
# dataDir = "${configDir}/traefik";
# group = "jallen-nas"; # group;
# environmentFiles = [ config.sops.templates."traefik.env".path ];
# static = {
# # dir = "${configDir}/traefik";
# settings = {
# entryPoints = {
# web = {
# address = ":${toString httpPort}";
# asDefault = true;
# http.redirections.entrypoint = {
# to = "websecure";
# scheme = "https";
# };
# };
# websecure = {
# address = ":${toString httpsPort}";
# asDefault = true;
# http.tls.certResolver = "letsencrypt";
# };
# metrics = {
# address = ":${toString metricsPort}"; # Port for metrics
# };
# };
# log = {
# level = "INFO";
# };
# metrics = {
# prometheus = {
# entryPoint = "metrics";
# addEntryPointsLabels = true;
# addServicesLabels = true;
# buckets = [
# 0.1
# 0.3
# 1.2
# 5.0
# ]; # Response time buckets
# };
# };
# certificatesResolvers.letsencrypt.acme = {
# email = letsEncryptEmail;
# storage = "${config.services.traefik.dataDir}/acme.json";
# dnsChallenge = {
# provider = "cloudflare";
# resolvers = [
# "1.1.1.1:53"
# "8.8.8.8:53"
# ];
# };
# };
# # Access the Traefik dashboard on <Traefik IP>:8080
# api = {
# dashboard = true;
# insecure = true;
# };
# experimental = {
# plugins = traefikPlugins;
# };
# };
# };
# dynamic = {
# dir = "/run/traefik";
# files = {
# "serversTransports".settings.http = {
# serversTransports = {
# internal-https = {
# insecureSkipVerify = true;
# };
# http1 = {
# serverName = "localhost";
# disableHTTP2 = true;
# };
# };
# };
# "middlewares-authentik".settings.http = {
# middlewares = {
# authentik = {
# forwardAuth = {
# tls.insecureSkipVerify = true;
# address = "${authUrl}/auth/traefik";
# trustForwardHeader = true;
# authResponseHeaders = [
# "X-authentik-username"
# "X-authentik-groups"
# "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"
# ];
# };
# };
# };
# };
# "middlewares-crowdsec".settings.http = {
# middlewares = {
# 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 = [ ];
# };
# };
# };
# };
# };
# "middlewares-geoblock".settings.http = {
# middlewares = {
# 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"
# ];
# };
# };
# };
# };
# };
# "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 = authUrl;
# }
# ];
# };
# };
# "services-cache".settings.http = {
# services = {
# cache.loadBalancer = {
# servers = [
# {
# url = cacheUrl;
# }
# ];
# serversTransport = "http1";
# };
# };
# };
# "services-nginx".settings.http = {
# services = {
# nginx.loadBalancer.servers = [
# {
# url = "http://localhost:8188";
# }
# ];
# };
# };
# "services-generated".settings.http = reverseProxyServiceConfigs;
# "routers-auth".settings.http = {
# routers = {
# auth = {
# entryPoints = [ "websecure" ];
# 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;
# }
# ];
# };
# routers = {
# hass = {
# entryPoints = [ "websecure" ];
# rule = "Host(`hass.${domain}`)";
# service = "hass";
# middlewares = [
# "crowdsec"
# "whitelist-geoblock"
# # "authentik"
# ];
# priority = 10;
# tls.certResolver = "letsencrypt";
# };
# };
# };
# "routers-generated".settings.http = reverseProxyRouterConfigs;
# };
# };
# };
};
}

View File

@@ -1,42 +0,0 @@
{ lib, namespace, ... }:
with lib;
let
inherit (lib.${namespace}) mkOpt;
in
{
options.${namespace}.services.traefik = {
enable = mkEnableOption "enable traefik";
extraServices = mkOpt (types.listOf (
types.submodule {
options = {
name = mkOpt types.str "" "Name of the service";
url = mkOpt types.str "http://localhost:8080" "Url of the service";
};
}
)) [ ] "List of extra services to forward";
extraRouters = mkOpt (types.listOf (
types.submodule {
options = {
entryPoints = mkOpt (types.listOf types.str) [ "websecure" ] "Entrypoint";
subdomain = mkOpt types.str "" "subdomain of the service";
service = mkOpt types.str "" "name of the service";
middlewares = mkOpt (types.listOf (
types.enum [
"authentik"
"onlyoffice-websocket"
"crowdsec"
"whitelist-geoblock"
"internal-ipallowlist"
]
)) [ ] "List of middlewares to enable";
};
}
)) [ ] "List of extra services to forward";
reverseProxies =
mkOpt (types.listOf types.attrs) [ ]
"List of reverse proxy configurations from mkReverseProxy";
};
}

View File

@@ -1,76 +0,0 @@
{
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" ];
};
};
};
};
}