Files
2025-07-29 18:38:43 +02:00

164 lines
5.1 KiB
Nix

{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.dov.reverse-proxy.traefik;
domain = "susano-nixos.duckdns.org";
configFile = pkgs.writeText "duckdns-options"
''
DUCKDNS_PROPAGATION_TIMEOUT=120
'';
in {
options.dov.reverse-proxy.traefik = { enable = mkEnableOption "traefik config"; };
config = mkIf cfg.enable {
networking.firewall.allowedTCPPorts = [ 80 443 53 ];
sops.secrets.duckdns-token = {
owner = "traefik";
group = config.services.traefik.group;
};
services.traefik = {
enable = true;
# Load the DuckDNS token as an environment variable for Traefik.
environmentFiles = [ config.sops.secrets.duckdns-token.path configFile ];
# Static configuration (traefik.yml) - defines entrypoints and certificate resolvers.
staticConfigOptions = {
# -- EntryPoints: Where Traefik listens for traffic --
entryPoints = {
# Unsecured HTTP on port 80, mainly for redirection
web = {
address = ":80";
# Redirect all traffic from this entrypoint to the 'websecure' (HTTPS) entrypoint
http.redirections.entryPoint = {
to = "websecure";
scheme = "https";
permanent = true;
};
};
# Secured HTTPS on port 443
websecure = {
address = ":443";
};
};
# -- Certificate Resolver: How Traefik gets SSL certs --
certificatesResolvers = {
# We'll name our resolver 'duckdns'
duckdns = {
acme = {
email = "susano@local.com";
storage = "/var/lib/traefik/acme.json"; # Where Traefik stores certs
dnsChallenge = {
provider = "duckdns";
#disablePropagationCheck = true;
};
};
};
};
# Optional but recommended: Enable the Traefik Dashboard
api.dashboard = true;
};
# Dynamic configuration - defines the actual routers and services.
dynamicConfigOptions = {
http = {
routers = {
authelia-router = mkIf config.dov.auth.authelia.enable {
rule = "Host(`auth.${domain}`)";
entryPoints = [ "websecure" ];
service = "authelia-service"; # Points to the Authelia service below
tls.certResolver = "duckdns";
};
dashboard-router = {
rule = "Host(`traefik.${domain}`)";
entryPoints = [ "websecure" ];
service = "api@internal";
tls = {
certResolver = "duckdns";
domains = [
{
main = "susano-nixos.duckdns.org";
sans = [
"*.susano-nixos.duckdns.org"
];
}
];
};
};
copyparty = mkIf config.dov.file-server.copyparty.enable {
rule = "Host(`copyparty.${domain}`)";
entryPoints = [ "websecure" ];
service = "copyparty-service";
tls.certResolver = "duckdns";
};
searxng = mkIf config.dov.searxng.enable {
rule = "Host(`searxng.${domain}`)";
entryPoints = [ "websecure" ];
service = "serxng-service";
tls.certResolver = "duckdns";
};
};
services = {
authelia-service = mkIf config.dov.auth.authelia.enable {
loadBalancer.servers = [
# Points to the Authelia instance defined in authelia.nix
{ url = "http://127.0.0.1:9091"; }
];
};
copyparty-service = mkIf config.dov.file-server.copyparty.enable {
loadBalancer.servers = [
# The backend URL for Immich
{ url = "http://susano:3923"; }
];
};
serxng-service = mkIf config.dov.searxng.enable {
loadBalancer.servers = [
# The backend URL for Immich
{ url = "http://susano:8888"; }
];
};
};
middlewares = {
# --- Middleware for dashboard authentication (optional) ---
auth = {
# Run `nix-shell -p apacheHttpdTools --run "htpasswd -nb your-user your-password"`
# to generate the user:password hash.
basicAuth.users = [
"your-user:$apr1$....some-hash-here...."
];
};
authelia-mw = mkIf config.dov.auth.authelia.enable {
forwardAuth = {
# This address MUST match the Authelia service URL
address = "http://127.0.0.1:9091/api/verify?rd=https%3A%2F%2Fauth.${domain}%2F";
trustForwardHeader = true;
authResponseHeaders = [
"Remote-User"
"Remote-Groups"
"Remote-Name"
"Remote-Email"
];
};
};
};
};
};
};
};
}