diff --git a/hosts/vm/reverseproxy/reverseproxy.nix b/hosts/vm/reverseproxy/reverseproxy.nix index c3315cc..f2ca654 100644 --- a/hosts/vm/reverseproxy/reverseproxy.nix +++ b/hosts/vm/reverseproxy/reverseproxy.nix @@ -1,141 +1,149 @@ { pkgs, ... }: let - anubisBotsMirror = pkgs.writeText "anubis_bots_mirror.yaml" - '' - - name: whitelist-crans - action: ALLOW - remote_addresses: - - 185.230.79.0/22 - - 2a0c:700::/32 - - 46.105.102.188/32 - - 2001:41d0:2:d5bc::/128 + formatJSON = pkgs.formats.json { }; + formatYAML = pkgs.formats.yaml { }; - - name: no-user-agent-string - action: DENY - expression: userAgent == "" + anubisBotsMirror = formatYAML.generate "anubis_bots_mirror.yaml" [ + { + name = "whitelist-crans"; + action = "ALLOW"; + remote_addresses = [ + "185.230.79.0/22" + "2a0c:700::/32" + "46.105.102.188/32" + "2001:41d0:2:d5bc::/128" + ]; + } + { + name = "no-user-agent"; + action = "DENY"; + expression = "userAgent == \"\""; + } + { + name = "ban-gpt"; + action = "DENY"; + user_agent_regex = ".*gpt.*"; + } + { + name = "ban-bot"; + action = "DENY"; + user_agent_regex = ".*(b|B)ot.*"; + } + { + name = "ban-WebKit"; + action = "DENY"; + expression = { + all = [ + "userAgent.startsWith(\"Mozilla\")" + "userAgent.startsWith(\"AppleWebKit\")" + "userAgent.startsWith(\"Safari\")" + "userAgent.startsWith(\"Chrome\")" + ]; + }; + } + { + name = "ban-Barkrowler"; + action = "DENY"; + user_agent_regex = ".*Barkrowler.*"; + } + ]; - - name: ban-gpt - user_agent_regex: ".*gpt.*" - action: DENY - - - name: ban-bot - user_agent_regex: ".*(b|B)ot.*" - action: DENY - - - name: ban-WebKit - action: DENY - expression: - all: - - userAgent.startsWith("Mozilla") - - userAgent.matches("AppleWebKit") - - userAgent.matches("Safari") - - userAgent.matches("Chrome") - - - name: ban-Barkrowler - user_agent_regex: ".*Barkrowler.*" - action: DENY - ''; - anubisMirror = pkgs.writeText "anubis_mirror.json" - '' + anubisMirror = formatJSON.generate "anubis_mirror.json" { + bots = [ { - "bots": [ - { - "import": "${anubisBotsMirror}" - }, - { - "name": "allow-repo", - "path_regex": "^...*", - "action": "ALLOW" - }, - { - "name": "deny-other", - "path_regex": ".*", - "action": "ALLOW" - } - ] + import = "${anubisBotsMirror}"; } - ''; - antibot = pkgs.writeText "antibot.yaml" - '' - - name: whitelist-crans - action: ALLOW - remote_addresses: - - 185.230.79.0/22 - - 2a0c:700::/32 - - 46.105.102.188/32 - - 2001:41d0:2:d5bc::/128 - - - name: no-user-agent-string - action: DENY - expression: userAgent == "" - - - name: ban-gpt - user_agent_regex: ".*gpt.*" - action: DENY - - - name: ban-bot - user_agent_regex: ".*(b|B)ot.*" - action: DENY - - - name: ban-WebKit - action: CHALLENGE - expression: - all: - - userAgent.startsWith("Mozilla") - - userAgent.matches("AppleWebKit") - - userAgent.matches("Safari") - - userAgent.matches("Chrome") - - - name: ban-Barkrowler - user_agent_regex: ".*Barkrowler.*" - action: DENY - ''; - anubisChallenge = pkgs.writeText "anubis_challenge.json" - '' { - "bots": [ - { - "import": "${antibot}" - }, - { - "name": "challenge-other", - "path_regex": "^*", - "action": "CHALLENGE" - } - ] + name = "allow-repo"; + action = "ALLOW"; + path_regex = "^...*"; } - ''; - anubisMirrors = pkgs.writeText "anubis_mirrors.json" - '' { - "bots": [ - { - "import": "${antibot}" - }, - { - "name": "deny-other", - "path_regex": ".*cdimage-.*", - "action": "ALLOW" - }, - { - "name": "allow-repo", - "path_regex": "^...*", - "action": "ALLOW" - }, - { - "name": "deny-other", - "path_regex": ".*", - "action": "CHALLENGE" - } - ] - } - ''; -in { + name = "deny-other"; + path_regex = ".*"; + action = "ALLOW"; + } + ]; + }; + + antiBot = formatYAML.generate "antibot.yaml" [ + { + import = "${anubisBotsMirror}"; + } + { + # On refuse les bots qui font souvent de la merde. + # https://github.com/TecharoHQ/anubis/blob/main/data/bots/deny-pathological.yaml + import = "(data)/bots/_deny-pathological.yaml"; + } + { + # On autorise les indexers des moteurs de recherche. + # https://github.com/TecharoHQ/anubis/blob/main/data/crawlers/_allow-good.yaml + import = "(data)/crawlers/_allow-good.yaml"; + } + { + # On autorise l'accès à favicon, robots.txt, well-known, ... + # https://github.com/TecharoHQ/anubis/blob/main/data/common/keep-internet-working.yaml + import = "(data)/common/keep-internet-working.yaml"; + } + { + # On refuse si userAgent = "" + # https://github.com/TecharoHQ/anubis/blob/main/data/common/keep-internet-working.yaml + import = "(data)/common/rfc-violations.yaml"; + } + { + # On bloque les AI aggressivement (bots/agent, training et user search par IA) + # https://github.com/TecharoHQ/anubis/blob/main/data/meta/ai-block-aggressive.yaml + import = "(data)/meta/ai-block-aggressive.yaml"; + } + ]; + + anubisChallenge = formatJSON.generate "anubis_challenge.json" { + "bots" = [ + { + import = "${antiBot}"; + } + { + name = "challenge-other"; + path_regex = "^*"; + action = "CHALLENGE"; + } + ]; + }; + + anubisMirrors = formatJSON.generate "anubis_mirrors.json" { + "bots" = [ + { + import = "${antiBot}"; + } + { + name = "deny-other"; + path_regex = ".*cdimage-.*"; + action = "ALLOW"; + } + { + name = "allow-repo"; + path_regex = "^...*"; + action = "ALLOW"; + } + { + name = "deny-other"; + path_regex = ".*"; + action = "CHALLENGE"; + } + ]; + }; + +in +{ crans = { reverseProxy = { enable = true; virtualHosts = { + "collabora" = { + target = "172.16.10.149"; + proxyWebsockets = true; + }; "eclat" = { anubisConfig = "${anubisMirror}"; httpOnly = true; diff --git a/modules/services/reverseproxy.nix b/modules/services/reverseproxy.nix index 177093c..fac16cd 100644 --- a/modules/services/reverseproxy.nix +++ b/modules/services/reverseproxy.nix @@ -1,30 +1,36 @@ -{ pkgs, lib, config, ... }: +{ + pkgs, + lib, + config, + ... +}: let cfg = config.crans.reverseProxy; - allowAll = pkgs.writeText "allow_all.json" - '' + formatJSON = pkgs.formats.json { }; + + allowAll = formatJSON.generate "allow_all.json" { + bots = [ { - "bots": [ - { - "name": "allow_all", - "path_regex": ".*", - "action": "ALLOW" - } - ] + name = "allow_all"; + path_regex = ".*"; + action = "ALLOW"; } - ''; + ]; + }; + + mainTld = "org"; + otherTld = [ + "fr" + "eu" + ]; + inherit (lib) - cartesianProduct literalExpression - mapAttrs - mapAttrs' mkEnableOption mkIf mkOption - nameValuePair - substring types ; in @@ -75,10 +81,21 @@ in ''; example = "true"; }; + + proxyWebsockets = mkOption { + type = types.bool; + default = false; + description = '' + Activer les websockets + ''; + example = "true"; + }; }; } ); - default = {}; + + default = { }; + example = literalExpression '' { "framadate" = { @@ -95,82 +112,81 @@ in }; config = { - systemd.services = mapAttrs ( - vhostName: vhostConfig: { - wantedBy = [ "multi-user.target" ]; - } - ) cfg.virtualHosts; + systemd.services = lib.mapAttrs (vhostName: vhostConfig: { + wantedBy = [ "multi-user.target" ]; + }) cfg.virtualHosts; services = mkIf cfg.enable { anubis = { defaultOptions.group = "nginx"; - instances = mapAttrs ( - vhostName: vhostConfig: { - enable = true; - settings = { - BIND = "/run/anubis/anubis-${vhostName}.sock"; - BIND_NETWORK = "unix"; - TARGET = "unix:///run/nginx/nginx-${vhostName}.sock"; - COOKIE_DOMAIN = "crans.org"; - REDIRECT_DOMAINS = "${vhostName}.crans.org"; - SOCKET_MODE = "0660"; - POLICY_FNAME = - if (vhostConfig.anubisConfig == "") - then allowAll - else vhostConfig.anubisConfig; - }; - } - ) cfg.virtualHosts; + instances = lib.mapAttrs (vhostName: vhostConfig: { + enable = true; + settings = { + BIND = "/run/anubis/anubis-${vhostName}.sock"; + BIND_NETWORK = "unix"; + TARGET = "unix:///run/nginx/nginx-${vhostName}.sock"; + COOKIE_DOMAIN = "crans.org"; + REDIRECT_DOMAINS = "${vhostName}.crans.org"; + SOCKET_MODE = "0660"; + POLICY_FNAME = if (vhostConfig.anubisConfig == "") then "${allowAll}" else vhostConfig.anubisConfig; + }; + }) cfg.virtualHosts; }; nginx = let - domaines = [ - "crans.org" - "crans.fr" - "crans.eu" - ]; - redirectConfig = mapAttrs ( - vhostName: vhostConfig: { - locations = mkIf ((substring 0 1 vhostConfig.target) != "/") { - "/favicon.ico".root = "/var/www/logo/"; - "/".proxyPass = "http://${vhostConfig.target}"; + # Configuration du serveur principal. + mainConfig = lib.mapAttrs' ( + vhostName: vhostConfig: + lib.nameValuePair (vhostName + "-anubis") { + enableACME = !vhostConfig.httpOnly; + forceSSL = !vhostConfig.httpOnly; + rejectSSL = vhostConfig.httpOnly; + locations."/" = { + proxyPass = "http://unix:/run/anubis/anubis-${vhostName}.sock"; + proxyWebsockets = vhostConfig.proxyWebsockets; }; - root = mkIf ((substring 0 1 vhostConfig.target) == "/") vhostConfig.target; - listen = [ - { addr = "unix:/run/nginx/nginx-${vhostName}.sock"; } - ]; + serverName = "${vhostName}.crans.${mainTld}"; } ) cfg.virtualHosts; - aliasConfig = mapAttrs' ( - vhostName: vhostConfig: nameValuePair (vhostName + "-alias") { - enableACME = !vhostConfig.httpOnly; - forceSSL = !vhostConfig.httpOnly; - rejectSSL = vhostConfig.httpOnly; - serverName = "${vhostName}.crans.fr"; - serverAliases = let - aliases = cartesianProduct { - name = vhostConfig.serverAliases; - domaine = domaines; - }; - in [ - "${vhostName}.crans.eu" - ] ++ map (value: value.name + "." + value.domaine) aliases; - globalRedirect = "${vhostName}.crans.org"; - } - ) cfg.virtualHosts; - anubisConfig = mapAttrs' ( - vhostName: vhostConfig: nameValuePair (vhostName + "-anubis") { - enableACME = !vhostConfig.httpOnly; - forceSSL = !vhostConfig.httpOnly; - rejectSSL = vhostConfig.httpOnly; - locations."/".proxyPass = "http://unix:/run/anubis/anubis-${vhostName}.sock"; - serverName = "${vhostName}.crans.org"; - } - ) cfg.virtualHosts; - in { + + # Redirections + redirectConfig = lib.mapAttrs (vhostName: vhostConfig: { + # Redirection vers d'autres machines + locations = mkIf (!lib.strings.hasPrefix "/" vhostConfig.target) { + "/favicon.ico".root = "/var/www/logo/"; + "/" = { + proxyPass = "http://${vhostConfig.target}"; + proxyWebsockets = vhostConfig.proxyWebsockets; + }; + }; + # Redirection vers des fichiers locaux + root = mkIf (lib.strings.hasPrefix "/" vhostConfig.target) vhostConfig.target; + listen = [ + { addr = "unix:/run/nginx/nginx-${vhostName}.sock"; } + ]; + }) cfg.virtualHosts; + + # Configuration des alias .fr et .eu + aliasConfig = lib.fold ( + tld: acc: + acc + // lib.mapAttrs' ( + vhostName: vhostConfig: + lib.nameValuePair "${vhostName}-alias-${tld}" rec { + rejectSSL = vhostConfig.httpOnly; + forceSSL = !rejectSSL; + enableACME = !rejectSSL; + serverName = "${vhostName}.crans.${tld}"; + serverAliases = map (name: "${name}.crans.${tld}") vhostConfig.serverAliases; + globalRedirect = "${vhostName}.crans.${mainTld}"; + } + ) cfg.virtualHosts + ) { } otherTld; + in + { enable = true; - virtualHosts = redirectConfig // aliasConfig // anubisConfig; + virtualHosts = redirectConfig // aliasConfig // mainConfig; }; }; };