{config, ...}: { networking.firewall.allowedTCPPorts = [22 80 443 2222 5222]; # web-internal/ssh binden an tailnetIPs.blunix, das erst existiert, sobald # tailscaled eingeloggt ist; tailscaled wiederum braucht headscale/dex über # den websecure-Entrypoint. Ohne diesen Sysctl blockiert ein gleichzeitiger # Neustart von traefik/tailscaled/headscale sich gegenseitig dauerhaft # (verifiziert am 29.07.2026). ip_nonlocal_bind erlaubt den Bind schon # bevor die Adresse auf einem Interface liegt; der Listener wird aktiv, # sobald tailscale0 die IP später bekommt. boot.kernel.sysctl."net.ipv4.ip_nonlocal_bind" = 1; services.traefik = { enable = true; staticConfigOptions = { log = { level = "TRACE"; }; api = {}; # enable API handler entryPoints = { web = { address = ":80"; http.redirections.entryPoint = { to = "websecure"; scheme = "https"; }; }; web-internal = { address = "${config.tailnetIPs.blunix}:443"; }; websecure = { address = "${config.publicIPv4}:443"; # forwardedHeaders = { # insecure = true; # }; }; xmpp = { address= ":5222"; }; ssh = { address = "${config.tailnetIPs.blunix}:2222"; }; # TCP EntryPoint für SSH }; certificatesResolvers = { cloudflare = { acme = { email = config.adminEmail; storage = "/var/lib/traefik/acme.json"; caserver = "https://acme-v02.api.letsencrypt.org/directory"; dnsChallenge = { provider = "cloudflare"; resolvers = [ "1.1.1.1:53" "8.8.8.8:53" ]; propagation.delayBeforeChecks = 60; # Important: Increase delay for slow DNS propagation }; }; }; }; tls.certificates = [ { certResolver = "cloudflare"; domains = [ { main = "${config.domain}"; sans = [ "*.${config.domain}" ]; } ]; } ]; }; dynamicConfigOptions = { tcp = { routers = { forgejo-ssh = { entryPoints = [ "ssh" ]; # TCP-EntryPoint rule = "HostSNI(`*`)"; # SSH hat kein SNI, also Wildcard service = "forgejo-ssh"; }; xmpp-service = { service = "xmpp-service"; rule = "HostSNI(`*`)"; entryPoints = ["xmpp"]; }; }; services = { forgejo-ssh = { loadBalancer = { servers = [ { address = "${config.tailnetIPs.pinix}:2222"; } # Pi mit SSH-Port 2222 ]; }; }; xmpp-service = { loadbalancer = { servers = [ { address = "${config.tailnetIPs.pinix}:5222";}]; }; }; }; }; http = { middlewares = { auth = { basicAuth = { usersFile = config.age.secrets.traefikBasicAuth.path; }; }; }; routers = { api = { rule = "Host(`traefik.${config.domain}`)"; service = "api@internal"; entrypoints = ["websecure"]; middlewares = ["auth"]; tls = { certResolver = "cloudflare"; }; }; }; }; }; }; systemd.services.traefik.serviceConfig = { EnvironmentFile = ["${config.age.secrets.traefik.path}"]; }; }