caddy
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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}
|
||||||
}
|
}
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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; [
|
||||||
|
|||||||
@@ -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;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
76
modules/nixos/services/traefik/sops.nix
Normal file
76
modules/nixos/services/traefik/sops.nix
Normal 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" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -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
@@ -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;
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ in
|
|||||||
allowedTCPPorts = [
|
allowedTCPPorts = [
|
||||||
80
|
80
|
||||||
443
|
443
|
||||||
|
8080
|
||||||
8008 # restic
|
8008 # restic
|
||||||
9000 # authentik
|
9000 # authentik
|
||||||
2342 # grafana
|
2342 # grafana
|
||||||
|
|||||||
@@ -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";
|
||||||
|
|||||||
Reference in New Issue
Block a user