{ config, ... }: let settings = import ../settings.nix; domain = "mjallen.dev"; serverIp = settings.hostAddress; # Forward services authUrl = "http://${serverIp}:9000/outpost.goauthentik.io"; actualUrl = "http://${config.containers.actual.localAddress}:${toString config.containers.actual.config.services.actual.settings.port}"; authentikUrl = "http://${serverIp}:9000"; cacheUrl = "http://${serverIp}:9012"; cloudUrl = "http://${config.containers.nextcloud.localAddress}:80"; giteaUrl = "http://${config.containers.gitea.localAddress}:${toString config.containers.gitea.config.services.gitea.settings.server.HTTP_PORT}"; hassUrl = "http://homeassistant.local:8123"; immichUrl = "http://${serverIp}:${toString config.services.immich.port}"; jellyfinUrl = "http://${serverIp}:8096"; jellyseerrUrl = "http://${config.containers.jellyseerr.localAddress}:${toString config.containers.jellyseerr.config.services.jellyseerr.port}"; lubeloggerUrl = "http://${serverIp}:6754"; onlyofficeUrl = "http://${config.containers.nextcloud.localAddress}:${toString config.containers.nextcloud.config.services.onlyoffice.port}"; openWebUIUrl = "http://${serverIp}:8888"; paperlessUrl = "http://${config.containers.paperless.localAddress}:${toString config.containers.paperless.config.services.paperless.port}"; # Plugins traefikPlugins = { bouncer = { moduleName = "github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin"; version = "v1.4.2"; }; geoblock = { moduleName = "github.com/PascalMinder/geoblock"; version = "v0.2.5"; }; }; crowdsecAppsecHost = "${serverIp}:7422"; crowdsecLapiKeyFile = config.sops.secrets."jallen-nas/traefik/crowdsec-lapi-key".path; # Ports httpPort = 80; httpsPort = 443; traefikPort = 8080; metricsPort = 8082; forwardPorts = [ httpPort httpsPort traefikPort metricsPort ]; # misc letsEncryptEmail = "jalle008@proton.me"; dataDir = "/media/nas/ssd/nix-app-data/traefik"; authentikAddress = "http://${serverIp}:9000/outpost.goauthentik.io/auth/traefik"; in { sops = { secrets = { "jallen-nas/traefik/crowdsec-lapi-key" = { owner = config.users.users.traefik.name; group = config.users.users.traefik.group; restartUnits = [ "traefik.service" ]; }; "jallen-nas/traefik/cloudflare-dns-api-token" = { }; "jallen-nas/traefik/cloudflare-zone-api-token" = { }; "jallen-nas/traefik/cloudflare-api-key" = { }; "jallen-nas/traefik/cloudflare-email" = { }; }; 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 = { allowedTCPPorts = forwardPorts; allowedUDPPorts = forwardPorts; }; services.traefik = { enable = true; dataDir = dataDir; group = "jallen-nas";#group; environmentFiles = [ "${config.services.traefik.dataDir}/traefik.env" ]; # todo: sops staticConfigOptions = { 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" ]; }; }; api.dashboard = true; # Access the Traefik dashboard on :8080 of your server api.insecure = true; experimental = { plugins = traefikPlugins; }; }; dynamicConfigOptions = { http = { middlewares = { authentik = { forwardAuth = { tls.insecureSkipVerify = true; address = authentikAddress; 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" ]; }; }; onlyoffice-websocket = { headers.customrequestheaders = { X-Forwarded-Proto = "https"; }; }; crowdsec = { plugin = { bouncer = { crowdsecAppsecEnabled = true; crowdsecAppsecHost = crowdsecAppsecHost; crowdsecAppsecFailureBlock = true; crowdsecAppsecUnreachableBlock = true; crowdsecLapiKeyFile = crowdsecLapiKeyFile; }; }; }; 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 = [ "127.0.0.1/32" "10.0.1.0/24" ]; }; }; }; services = { auth.loadBalancer.servers = [ { url = authUrl; } ]; actual.loadBalancer.servers = [ { url = actualUrl; } ]; authentik.loadBalancer.servers = [ { url = authentikUrl; } ]; cache.loadBalancer.servers = [ { url = cacheUrl; } ]; chat.loadBalancer.servers = [ { url = openWebUIUrl; } ]; cloud.loadBalancer.servers = [ { url = cloudUrl; } ]; gitea.loadBalancer.servers = [ { url = giteaUrl; } ]; hass.loadBalancer.servers = [ { url = hassUrl; } ]; immich.loadBalancer.servers = [ { url = immichUrl; } ]; jellyfin.loadBalancer.servers = [ { url = jellyfinUrl; } ]; jellyseerr.loadBalancer.servers = [ { url = jellyseerrUrl; } ]; lubelogger.loadBalancer.servers = [ { url = lubeloggerUrl; } ]; onlyoffice.loadBalancer.servers = [ { url = onlyofficeUrl; } ]; paperless.loadBalancer.servers = [ { url = paperlessUrl; } ]; }; 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"; }; actual = { entryPoints = [ "websecure" ]; rule = "Host(`actual.${domain}`)"; service = "actual"; middlewares = [ "crowdsec" "whitelist-geoblock" ]; tls.certResolver = "letsencrypt"; }; authentik = { entryPoints = [ "websecure" ]; rule = "Host(`authentik.${domain}`)"; service = "authentik"; middlewares = [ "crowdsec" "whitelist-geoblock" ]; tls.certResolver = "letsencrypt"; }; cache = { entryPoints = [ "websecure" ]; rule = "Host(`cache.${domain}`)"; service = "cache"; middlewares = [ "crowdsec" "whitelist-geoblock" ]; priority = 10; tls.certResolver = "letsencrypt"; }; cloud = { entryPoints = [ "websecure" ]; rule = "Host(`cloud.${domain}`)"; service = "cloud"; middlewares = [ "crowdsec" "whitelist-geoblock" ]; tls.certResolver = "letsencrypt"; }; gitea = { entryPoints = [ "websecure" ]; rule = "Host(`gitea.${domain}`)"; service = "gitea"; middlewares = [ "crowdsec" "whitelist-geoblock" ]; tls.certResolver = "letsencrypt"; }; hass = { entryPoints = [ "websecure" ]; rule = "Host(`hass.${domain}`)"; service = "hass"; middlewares = [ "crowdsec" "whitelist-geoblock" "authentik" ]; priority = 10; tls.certResolver = "letsencrypt"; }; immich = { entryPoints = [ "websecure" ]; rule = "Host(`immich.${domain}`)"; service = "immich"; middlewares = [ "crowdsec" "whitelist-geoblock" ]; tls.certResolver = "letsencrypt"; }; jellyfin = { entryPoints = [ "websecure" ]; rule = "Host(`jellyfin.${domain}`)"; service = "jellyfin"; middlewares = [ "crowdsec" "whitelist-geoblock" ]; tls.certResolver = "letsencrypt"; }; jellyseerr = { entryPoints = [ "websecure" ]; rule = "Host(`jellyseerr.${domain}`)"; service = "jellyseerr"; middlewares = [ "crowdsec" "whitelist-geoblock" ]; tls.certResolver = "letsencrypt"; }; lubelogger = { entryPoints = [ "websecure" ]; rule = "Host(`lubelogger.${domain}`)"; service = "lubelogger"; middlewares = [ "crowdsec" "whitelist-geoblock" ]; tls.certResolver = "letsencrypt"; }; onlyoffice = { entryPoints = [ "websecure" ]; rule = "Host(`office.${domain}`)"; service = "onlyoffice"; middlewares = [ "crowdsec" "whitelist-geoblock" "onlyoffice-websocket" ]; tls.certResolver = "letsencrypt"; }; }; }; }; }; }