sf
This commit is contained in:
@@ -1,12 +1,21 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
namespace,
|
||||
...
|
||||
}:
|
||||
with lib;
|
||||
let
|
||||
cfg = config.${namespace}.services.home-assistant;
|
||||
|
||||
# ESPHome with littlefs-python added to PYTHONPATH so PlatformIO's
|
||||
# espressif32 platform builder can import it (needed for LittleFS support).
|
||||
esphomeWithLittlefs = pkgs.esphome.overridePythonAttrs (oldAttrs: {
|
||||
makeWrapperArgs = (oldAttrs.makeWrapperArgs or [ ]) ++ [
|
||||
"--prefix PYTHONPATH : ${pkgs.${namespace}.littlefs-python}/${pkgs.python3.sitePackages}"
|
||||
];
|
||||
});
|
||||
in
|
||||
{
|
||||
config = mkIf cfg.enable {
|
||||
@@ -15,6 +24,17 @@ in
|
||||
enable = true;
|
||||
openFirewall = true; # 6052
|
||||
address = "0.0.0.0";
|
||||
package = esphomeWithLittlefs;
|
||||
};
|
||||
};
|
||||
|
||||
# Add uv to the ESPHome service PATH so PlatformIO uses the Nix-provided
|
||||
# binary instead of downloading its own (which would fail due to permissions).
|
||||
# Also disable MemoryDenyWriteExecute so uv (a native Rust binary) can run.
|
||||
systemd.services.esphome = {
|
||||
path = [ pkgs.uv ];
|
||||
serviceConfig = {
|
||||
MemoryDenyWriteExecute = lib.mkForce false;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
# };
|
||||
# };
|
||||
# };
|
||||
};
|
||||
}
|
||||
@@ -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";
|
||||
};
|
||||
}
|
||||
@@ -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" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user