{ self, config, lib, pkgs, ... }: { imports = [ ./hardware-configuration.nix ./hetzner-disk.nix ]; networking = { hostName = "proxy"; interfaces.ens18.ipv4.addresses = [ { address = "141.56.51.1"; prefixLength = 24; } ]; defaultGateway.address = "141.56.51.254"; firewall = { allowedTCPPorts = [ 22 53 # DNS 80 443 1005 2142 ]; allowedUDPPorts = [ 53 # DNS 123 # NTP ]; }; nftables = { enable = true; }; }; # Phase 1: Kernel-Level TCP Tuning boot.kernel.sysctl = { # Connection tracking - prevents "table full" errors "net.netfilter.nf_conntrack_max" = 262144; # Conservative limit matching current kernel "net.netfilter.nf_conntrack_buckets" = 65536; # 4:1 ratio # Reduce connection tracking timeouts (defaults are excessive) "net.netfilter.nf_conntrack_tcp_timeout_established" = 600; # 10 min (down from 5 days) "net.netfilter.nf_conntrack_tcp_timeout_time_wait" = 30; # 30s "net.netfilter.nf_conntrack_tcp_timeout_close_wait" = 15; # 15s "net.netfilter.nf_conntrack_tcp_timeout_fin_wait" = 30; # 30s # TCP connection handling "net.core.somaxconn" = 65535; # Must be >= HAProxy maxconn "net.core.netdev_max_backlog" = 16384; "net.ipv4.tcp_max_syn_backlog" = 8192; # TCP buffer auto-tuning (16MB max) "net.ipv4.tcp_rmem" = "4096 87380 16777216"; "net.ipv4.tcp_wmem" = "4096 65536 16777216"; "net.core.rmem_max" = 16777216; "net.core.wmem_max" = 16777216; # TCP optimization "net.ipv4.tcp_fin_timeout" = 15; "net.ipv4.tcp_keepalive_time" = 300; # 5 min "net.ipv4.tcp_keepalive_probes" = 3; "net.ipv4.tcp_keepalive_intvl" = 15; # TCP Fast Open "net.ipv4.tcp_fastopen" = 3; # BBR congestion control for better throughput "net.ipv4.tcp_congestion_control" = "bbr"; "net.core.default_qdisc" = "fq"; # Ephemeral port range "net.ipv4.ip_local_port_range" = "10000 65535"; # TIME_WAIT socket reuse "net.ipv4.tcp_tw_reuse" = 1; }; # Enable BBR kernel module boot.kernelModules = [ "tcp_bbr" ]; # wenn instanzen in die flake migriert sind könnte man das autogenerierien services = let # Documentation site from flake package docsSite = self.packages.x86_64-linux.docs-site; # jeder Block beschreibt eine Weiterleitung von port 80 und 443 für einen fqdn forwards = { docs = { dest = "127.0.0.1"; domain = "docs.adm.htw.stura-dresden.de"; httpPort = 8080; httpsPort = 8443; sendProxy = false; }; plone = { dest = "141.56.51.3"; domain = "stura.htw-dresden.de"; httpPort = 80; httpsPort = 443; sendProxy = false; }; plone_alt = { dest = "141.56.51.3"; domain = "www.stura.htw-dresden.de"; httpPort = 80; httpsPort = 443; sendProxy = false; }; plone_neu = { dest = "141.56.51.3"; domain = "www.htw.stura-dresden.de"; httpPort = 80; httpsPort = 443; sendProxy = false; }; plone_neu2 = { dest = "141.56.51.3"; domain = "htw.stura-dresden.de"; httpPort = 80; httpsPort = 443; sendProxy = false; }; tix = { dest = "141.56.51.220"; domain = "tix.htw.stura-dresden.de"; httpPort = 80; httpsPort = 443; sendProxy = false; }; post = { dest = "141.56.51.56"; domain = "post.htw.stura-dresden.de"; httpPort = 80; httpsPort = 443; sendProxy = false; }; vot = { dest = "141.56.51.57"; domain = "vot.htw.stura-dresden.de"; httpPort = 80; httpsPort = 443; sendProxy = false; }; mail = { dest = "141.56.51.14"; domain = "mail.htw.stura-dresden.de"; httpPort = 80; httpsPort = 443; sendProxy = false; }; lists = { dest = "141.56.51.14"; domain = "lists.htw.stura-dresden.de"; httpPort = 80; httpsPort = 443; sendProxy = false; }; dat = { dest = "141.56.51.17"; domain = "dat.stu.htw.stura-dresden.de"; httpPort = 80; httpsPort = 443; sendProxy = false; }; pro = { dest = "141.56.51.15"; domain = "pro.htw.stura-dresden.de"; httpPort = 80; httpsPort = 443; sendProxy = false; }; wiki = { dest = "141.56.51.13"; domain = "wiki.htw.stura-dresden.de"; httpPort = 80; httpsPort = 443; sendProxy = false; }; beach = { dest = "141.56.51.51"; domain = "beach.htw.stura-dresden.de"; httpPort = 80; httpsPort = 443; sendProxy = false; }; studicloud = { dest = "141.56.51.17"; domain = "dat.stu.htw.stura-dresden.de"; httpPort = 80; httpsPort = 443; sendProxy = false; }; bbb = { dest = "141.56.51.94"; domain = "bbb.htw.stura-dresden.de"; httpPort = 80; httpsPort = 443; sendProxy = false; }; bbb-test = { dest = "141.56.51.94"; domain = "bbb.test.htw.stura-dresden.de"; httpPort = 80; httpsPort = 443; sendProxy = false; }; } # zusätzlich zu den oben definierten wird hier noch ein redirect für jeden nginx virtualhost in diese flake generiert // (builtins.foldl' ( prev: name: let cfg = self.nixosConfigurations.${name}.config; vhosts = builtins.attrNames cfg.services.nginx.virtualHosts; address = (builtins.head # dieser ausdruck ermittelt den interface namen und die ipv4 addresse als redirect ziel cfg.networking.interfaces.${builtins.head (builtins.attrNames cfg.networking.interfaces)}.ipv4.addresses ).address; in prev // (builtins.foldl' ( val: vhost: let proxyProtocol = if self.nixosConfigurations.${name}.config.services.nginx.virtualHosts.${vhost}.listen == [] then false else true; in val // { "${vhost}" = { dest = address; domain = vhost; httpsPort = 443; httpPort = 80; sendProxy = proxyProtocol; }; } ) { } vhosts) ) { } ( # alle nixosConfigurations auswählen, die nginx enabled haben builtins.filter (name: self.nixosConfigurations.${name}.config.services.nginx.enable) ( builtins.attrNames self.nixosConfigurations ) ) ); indexPage = pkgs.writeTextFile { name = "index.html"; text = '' StuRa HTWD Index

Du hast dich scheinbar verlaufen. Können wir dir hier möglicherweise weiter helfen?

''; }; in { # BIND DNS recursive resolver for the internal network bind = { enable = true; cacheNetworks = [ "127.0.0.0/8" "141.56.51.0/24" ]; # forwarders = [ # "9.9.9.9" # "1.1.1.1" # ]; listenOn = [ "141.56.51.1" "127.0.0.1" ]; listenOnIpv6 = [ ]; zones = { "htw.stura-dresden.de" = { master = true; file = pkgs.writeText "htw.stura-dresden.de.zone" '' $TTL 3600 @ IN SOA proxy.htw.stura-dresden.de. hostmaster.htw.stura-dresden.de. ( 2026031301 ; Serial (YYYYMMDDNN) 3600 ; Refresh (1 hour) 1800 ; Retry (30 minutes) 604800 ; Expire (1 week) 86400 ) ; Minimum TTL (1 day) ; Name servers @ IN NS proxy.htw.stura-dresden.de. ; Proxy host - main IPv4 gateway proxy IN A 141.56.51.1 proxy IN AAAA 2a01:4f8:1c19:96f8::1 ; Auto-generated CNAME records for all subdomains pointing to proxy ${lib.foldlAttrs ( prev: name: value: let zoneSuffix = ".htw.stura-dresden.de"; # Check if this domain belongs to our zone isInZone = lib.hasSuffix zoneSuffix value.domain; # Extract subdomain by removing the zone suffix subdomain = lib.removeSuffix zoneSuffix value.domain; in if isInZone && subdomain != "" && subdomain != "htw.stura-dresden.de" then prev + "${subdomain}${" "}IN${" "}CNAME${" "}proxy.htw.stura-dresden.de.\n" else prev ) "" forwards} ''; }; }; }; # Chrony NTP server for the internal network chrony = { enable = true; enableNTS = false; servers = [ "0.de.pool.ntp.org" "1.de.pool.ntp.org" "2.de.pool.ntp.org" "3.de.pool.ntp.org" ]; serverOption = "iburst"; extraConfig = '' # Allow NTP client access from local network allow 141.56.51.0/24 # Serve time even if not synced to a time source local stratum 10 ''; }; openssh = { # admin ssh access port listenAddresses = [ { addr = "141.56.51.1"; port = 1005; } ]; }; # Nginx to serve the documentation site nginx = { enable = true; virtualHosts."docs.adm.htw.stura-dresden.de" = { enableACME = true; listen = [ { addr = "127.0.0.1"; port = 8080; } ]; locations."/" = { root = docsSite; tryFiles = "$uri $uri/ $uri.html =404"; }; }; # HTTPS version for internal serving appendHttpConfig = '' server { listen 127.0.0.1:8443 ssl http2; server_name docs.adm.htw.stura-dresden.de; ssl_certificate ${config.security.acme.certs."docs.adm.htw.stura-dresden.de".directory}/cert.pem; ssl_certificate_key ${ config.security.acme.certs."docs.adm.htw.stura-dresden.de".directory }/key.pem; location / { root ${docsSite}; try_files $uri $uri/ $uri.html =404; } } ''; }; # ACME certificate for docs site haproxy = { enable = true; config = '' global # schreibe globalen log ins journal ip -> app log /dev/log format raw local0 maxconn 60000 # Safe limit below kernel conntrack (262144) # Buffer optimizations (Phase 2) tune.bufsize 32768 # Power of 2 (was 32762) tune.maxrewrite 8192 # Connection handling tune.maxaccept 500 # Prevent accept starvation tune.maxpollevents 300 # TCP buffer sizes (64KB) tune.rcvbuf.client 65536 tune.rcvbuf.server 65536 tune.sndbuf.client 65536 tune.sndbuf.server 65536 defaults log global mode tcp option tcplog # Optimized timeouts (Phase 5) timeout connect 3s # Reduce from 5s timeout client 60s # Increase from 30s timeout server 60s # Increase from 30s timeout queue 5s # Prevent indefinite queueing # Performance option splice-auto # Zero-copy kernel splicing # stats seite zeigt backend connection status, wenn check gesetzt ist frontend stats bind 127.0.0.1:8404 mode http stats enable stats uri /stats stats refresh 5s # Reduce from 10s for real-time monitoring stats show-legends stats show-node stats show-modules stats admin if TRUE # Enable admin operations frontend http-in bind *:80 maxconn 60000 backlog 8192 option dontlognull option http-keep-alive # Reuse connections for redirects # hier wird eine regel pro domain aus der forwarder liste generiert ${lib.foldlAttrs ( prev: name: value: prev + '' acl is_${name} hdr(host) -i ${value.domain} '' ) "" forwards} # ist request eine acme challenge? acl is_acme path_beg /.well-known/acme-challenge/ # pro domain wird ein backend festgelegt und auf https redirected wenn es keine acme request ist ${lib.foldlAttrs ( prev: name: value: prev + '' use_backend ${name}_80 if is_${name} http-request redirect scheme https code 301 if !is_acme is_${name} '' ) "" forwards} # das default backend zeigt die liste aller redirects an # die liste darf nicht auf 443 redirected werden, da cert fehlt default_backend default_backend # ssh redirect srs2 frontend ssh_jump_alt bind *:2142 mode tcp # gönn mal session timeout timeout client 30m log-format "%ci:%cp [%t] %ft %b/%s %Tw/%Tc/%Tt %B %ts %ac/%fc/%bc/%sc/%rc %sq/%bq dst:%[var(sess.dst)] " use_backend ssh_srs2 # ---- SNI routing (TCP, peek at handshake) ---- frontend sni_router bind *:443 mode tcp # Reduce inspection delay - SNI is in first packet (Phase 3) tcp-request inspect-delay 500ms # Was 1s tcp-request content accept if { req_ssl_hello_type 1 } # Connection handling option clitcpka # Enable client TCP keep-alive maxconn 60000 backlog 16384 # Increase from default 1024 option dontlognull # Skip logging of monitoring probes # tcp redirect der anwendung basierend auf ssl_sni handshake parameter ${lib.foldlAttrs ( prev: name: value: prev + "use_backend ${name}_443 if { req_ssl_sni -i ${value.domain} }\n" ) "" forwards} # default backend http static file generated above backend default_backend mode http http-request return status 200 content-type "text/html" file ${indexPage} # ssh srs2 backend backend ssh_srs2 mode tcp timeout server 30m timeout connect 10s option tcpka server srs2 141.56.51.2:80 check # ein backend pro forwards eintrag für port 80 und 443 ${lib.foldlAttrs ( prev: name: value: prev + '' backend ${name}_80 mode http server ${name} ${value.dest}:${builtins.toString value.httpPort} backend ${name}_443 mode tcp option tcpka # Enable server TCP keep-alive (Phase 4) timeout server 60s # Increase from 30s for long-lived HTTPS timeout connect 3s # Reduce from 5s (local network) server ${name} ${value.dest}:${builtins.toString value.httpsPort} ${if value.sendProxy == true then "send-proxy-v2" else ""} check inter 3000 rise 2 fall 3 maxconn 5000 '' ) "" forwards} ''; }; }; environment.systemPackages = with pkgs; [ ]; system.stateVersion = "25.11"; }