diff --git a/configuration.nix b/configuration.nix index 9a731f9..0292a3b 100644 --- a/configuration.nix +++ b/configuration.nix @@ -9,7 +9,7 @@ ./modules/users.nix ./modules/hardware.nix ./modules/services.nix - ./modules/nginx.nix + ./modules/proxy.nix ./modules/matrix.nix ./modules/fail2ban.nix ]; diff --git a/modules/networking.nix b/modules/networking.nix index 076bfb8..ff4059f 100644 --- a/modules/networking.nix +++ b/modules/networking.nix @@ -7,14 +7,4 @@ in networking.hostName = settings.hostname; networking.networkmanager.enable = true; - - networking.firewall = { - enable = true; - allowedTCPPorts = [ - 22 - 80 - 443 - ]; - allowedUDPPorts = [ ]; - }; } diff --git a/modules/proxy.nix b/modules/proxy.nix new file mode 100644 index 0000000..597c9fc --- /dev/null +++ b/modules/proxy.nix @@ -0,0 +1,177 @@ +{ + config, + lib, + ... +}: + +let + atriDotDad = "atri.dad"; + atashDotDev = "atash.dev"; + + matrixDomain = "matrix.${atriDotDad}"; + matrixRtcDomain = "matrixrtc.${atriDotDad}"; + + upstream = "lloyd.tadpole-pain.ts.net"; + streamPorts = [ + 69 + 420 + 25565 + 25566 + 25567 + ]; + + wellKnownServer = builtins.toJSON { + "m.server" = "${matrixDomain}:443"; + }; + + wellKnownClient = builtins.toJSON { + "m.homeserver" = { + base_url = "https://${matrixDomain}"; + }; + "org.matrix.msc4143.rtc_foci" = [ + { + type = "livekit"; + livekit_service_url = "https://${matrixDomain}/livekit/jwt"; + } + ]; + }; + + mkProxy = port: '' + reverse_proxy http://${upstream}:${toString port} + ''; + + aiBotsMatcher = '' + @fuckai { + header_regexp User-Agent "(?i)(GPTBot|ChatGPT-User|OAI-SearchBot|ChatGPT-Browser|ClaudeBot|Claude-Web|Claude-SearchBot|anthropic-ai|Anthropic-Claude|xAI-Bot|DeepseekBot|Google-Extended|Gemini-Ai|Gemini-Deep-Research|Google-CloudVertexBot|Google-NotebookLM|GoogleAgent-Mariner|Bard-Ai|FacebookBot|Meta-ExternalAgent|meta-webindexer|Applebot-Extended|bingbot|CCBot|PerplexityBot|Perplexity-User|Bytespider|Diffbot|Amazonbot|cohere-ai|Cohere-Command|YouBot|Omgilibot|ImagesiftBot|AI2Bot|Andibot|bigsur.ai|Brightbot|TerraCotta|Character-AI|Devin|Crawlspace|DuckAssistBot|FirecrawlAgent|Groq-Bot|HuggingFace-Bot|IbouBot|MistralAI-User|Replicate-Bot|RunPod-Bot|TimpiBot|Together-Bot|Kangaroo Bot|PanguBot|Cotoyogi|Webzio-Extended)" + } + abort @fuckai + ''; + + mkIptablesRule = + port: proto: action: + let + op = if action == "add" then "-A" else "-D"; + ignoreErr = if action == "remove" then "|| true" else ""; + in + '' + iptables -t nat ${op} PREROUTING -p ${proto} --dport ${toString port} -j DNAT --to-destination ${upstream}:${toString port} ${ignoreErr} + iptables -t nat ${op} POSTROUTING -p ${proto} -d ${upstream} --dport ${toString port} -j MASQUERADE ${ignoreErr} + ''; + +in +{ + services.caddy = { + enable = true; + email = "me@${atriDotDad}"; + + extraConfig = '' + ${atriDotDad} { + ${aiBotsMatcher} + + handle /.well-known/matrix/server { + header Content-Type application/json + header X-Content-Type-Options nosniff + respond `${wellKnownServer}` 200 + } + + handle /.well-known/matrix/client { + header Content-Type application/json + header Access-Control-Allow-Origin "*" + header Vary Origin + header X-Content-Type-Options nosniff + respond `${wellKnownClient}` 200 + } + + handle { + reverse_proxy http://${upstream}:3000 + } + } + + analytics.${atriDotDad} { ${aiBotsMatcher} ${mkProxy 30060} } + archive.${atriDotDad} { ${aiBotsMatcher} ${mkProxy 30288} } + ascently.${atriDotDad} { ${aiBotsMatcher} ${mkProxy 8838} } + chef.${atriDotDad} { ${aiBotsMatcher} ${mkProxy 30111} } + democlimb.${atriDotDad} { ${aiBotsMatcher} ${mkProxy 8008} } + fedi.${atriDotDad} { ${aiBotsMatcher} ${mkProxy 8181} } + gist.${atriDotDad} { ${aiBotsMatcher} ${mkProxy 1227} } + git.${atriDotDad} { ${aiBotsMatcher} ${mkProxy 30010} } + links.${atriDotDad} { ${aiBotsMatcher} ${mkProxy 30243} } + memos.${atriDotDad} { ${aiBotsMatcher} ${mkProxy 30311} } + mermaid.${atriDotDad} { ${aiBotsMatcher} ${mkProxy 8280} } + msrc.${atriDotDad} { ${aiBotsMatcher} ${mkProxy 3311} } + openclimb.${atriDotDad} { ${aiBotsMatcher} ${mkProxy 1337} } + photos.${atriDotDad} { ${aiBotsMatcher} ${mkProxy 30041} } + pods.${atriDotDad} { ${aiBotsMatcher} ${mkProxy 30067} } + requests.${atriDotDad} { ${aiBotsMatcher} ${mkProxy 30042} } + s3.${atriDotDad} { ${aiBotsMatcher} ${mkProxy 30188} } + search.${atriDotDad} { ${aiBotsMatcher} ${mkProxy 30053} } + vault.${atriDotDad} { ${aiBotsMatcher} ${mkProxy 30032} } + vids.${atriDotDad} { ${aiBotsMatcher} ${mkProxy 31008} } + music.${atriDotDad} { ${aiBotsMatcher} ${mkProxy 30043} } + books.${atriDotDad} { ${aiBotsMatcher} ${mkProxy 31067} } + + tv.${atriDotDad} { + ${aiBotsMatcher} + request_body { + max_size 20GB + } + reverse_proxy http://${upstream}:30013 { + flush_interval -1 + } + } + + ${matrixDomain} { + request_body { + max_size 100MB + } + + handle_path /livekit/jwt/* { + @allowed path /sfu/get /get_token /healthz + handle @allowed { + reverse_proxy http://[::1]:${toString config.services.lk-jwt-service.port} + } + handle { + respond 404 + } + } + + handle { + reverse_proxy http://[::1]:6167 + } + } + + ${matrixRtcDomain} { + reverse_proxy http://[::1]:${toString config.services.livekit.settings.port} { + flush_interval -1 + } + } + + ripkyle.org { ${aiBotsMatcher} ${mkProxy 4321} } + ${atashDotDev} { ${aiBotsMatcher} ${mkProxy 6969} } + chronus.${atashDotDev} { ${aiBotsMatcher} ${mkProxy 7337} } + ''; + }; + + boot.kernel.sysctl = { + "net.ipv4.ip_forward" = 1; + }; + + networking.firewall = { + allowedTCPPorts = [ + 80 + 443 + ] + ++ streamPorts; + allowedUDPPorts = streamPorts; + + extraCommands = lib.concatStringsSep "\n" ( + (map (port: mkIptablesRule port "tcp" "add") streamPorts) + ++ (map (port: mkIptablesRule port "udp" "add") streamPorts) + ); + + extraStopCommands = lib.concatStringsSep "\n" ( + (map (port: mkIptablesRule port "tcp" "remove") streamPorts) + ++ (map (port: mkIptablesRule port "udp" "remove") streamPorts) + ); + }; +}