diff --git a/hosts/vm/README.md b/hosts/vm/README.md index 1e4607b..84466b6 100644 --- a/hosts/vm/README.md +++ b/hosts/vm/README.md @@ -22,6 +22,10 @@ Serveur Matrix, bridge IRC <-> Matrix et interface admin pour synapse, accessibl Serveur redlib (client WEB alternatif pour Reddit), accessible à . +## reverseproxy + +Serveur qui héberge un reverseproxy et une instance de anubis. + ## two Serveur NixOS de test. Vous pouvez vous en servir comme base pour la configuration d'une nouvelle machine. diff --git a/hosts/vm/reverseproxy/anubis.nix b/hosts/vm/reverseproxy/anubis.nix index 0c7edd7..3693ca8 100644 --- a/hosts/vm/reverseproxy/anubis.nix +++ b/hosts/vm/reverseproxy/anubis.nix @@ -1,15 +1,70 @@ -{ ... }: +{ 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 + + - 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: 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" '' + { + "bots": [ + { + "import": "${anubisBotsMirror}" + }, + { + "name": "allow-repo", + "path_regex": "^...*", + "action": "ALLOW" + }, + { + "name": "deny-other", + "path_regex": ".*", + "action": "ALLOW" + } + ] + } + ''; +in { services.anubis = { - instances."muraille" = { + instances."mirror" = { enable = true; settings = { BIND_NETWORK = "tcp"; - BIND = "127.0.0.1:7777"; - TARGET = "http://localhost:8888"; + BIND = "127.0.0.1:7779"; + TARGET = "http://localhost:8890"; COOKIE_DOMAIN = "crans.org"; - REDIRECT_DOMAINS = "install-party.crans.org,mediawiki.crans.org,wiki.crans.org"; + REDIRECT_DOMAINS = "eclat.crans.org,mirror.crans.org"; + POLICY_FNAME = "${anubisMirror}"; }; }; }; diff --git a/hosts/vm/reverseproxy/default.nix b/hosts/vm/reverseproxy/default.nix index 2b557c0..b6958fc 100644 --- a/hosts/vm/reverseproxy/default.nix +++ b/hosts/vm/reverseproxy/default.nix @@ -1,10 +1,87 @@ -{ ... }: +{ pkgs, ... }: -{ +let + 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" + } + ] + } + ''; + 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 { imports = [ - ./anubis.nix ./hardware-configuration.nix ./networking.nix + + ./anubis.nix ./reverseproxy.nix ]; @@ -12,6 +89,8 @@ networking.hostName = "reverseproxy"; boot.loader.grub.devices = [ "/dev/sda" ]; + users.users."nginx".home = "/var/lib/nginx"; + crans = { enable = true; @@ -27,6 +106,51 @@ resticClient.when = "03:42"; + reverseProxy = { + enable = true; + + virtualHosts = { + "eclats" = { + anubisConfig = "${anubisMirrors}"; + target = "172.16.10.104"; + }; + "install-party" = { + anubisConfig = "${anubisChallenge}"; + target = "/var/www/install-party.crans.org"; + serverAliases = [ + "i-p" + "adopteunmanchot" + "adopteunpingouin" + ]; + }; + "mediawiki" = { + anubisConfig = "${anubisChallenge}"; + target = "172.16.10.144"; + serverAliases = [ + "mediakiwi" + ]; + }; + "mirrors" = { + anubisConfig = "${anubisMirrors}"; + target = "172.16.10.104"; + }; + "perso" = { + anubisConfig = "${anubisChallenge}"; + target = "172.16.10.31"; + serverAliases = [ + "clubs" + ]; + }; + "wiki" = { + anubisConfig = "${anubisChallenge}"; + target = "172.16.10.161"; + serverAliases = [ + "wikipedia" + ]; + }; + }; + }; + services = { acme.enable = true; }; diff --git a/hosts/vm/reverseproxy/reverseproxy.nix b/hosts/vm/reverseproxy/reverseproxy.nix index d0bab65..067687b 100644 --- a/hosts/vm/reverseproxy/reverseproxy.nix +++ b/hosts/vm/reverseproxy/reverseproxy.nix @@ -1,100 +1,53 @@ { config, ... }: { - users.users."nginx".home = "/var/lib/nginx"; - - services.nginx = { - enable = true; - virtualHosts = - let anubisConf = [ - { - addr = "localhost"; - port = 8888; - } + services.nginx.virtualHosts = { + # redirection eclat + "eclat.crans.fr" = { + rejectSSL = true; + serverAliases = [ + "eclat.crans.eu" ]; - in { - # redirection install-party - "install-party.crans.fr" = { - enableACME = true; - forceSSL = true; - serverAliases = [ - "i-p.crans.org" - "adopteunmanchot.crans.org" - "adopteunpingouin.crans.org" - "i-p.crans.fr" - "adopteunmanchot.crans.fr" - "adopteunpingouin.crans.fr" - "i-p.crans.eu" - "install-party.crans.eu" - "adopteunmanchot.crans.eu" - "adopteunpingouin.crans.eu" - ]; - extraConfig = '' - return 301 https://install-party.crans.org$request_uri; - ''; - }; + extraConfig = '' + return 301 http://eclat.crans.org$request_uri; + ''; + }; - # redirection mediawiki - "mediawiki.crans.fr" = { - enableACME = true; - forceSSL = true; - serverAliases = [ - "mediakiwi.crans.org" - "mediakiwi.crans.fr" - "mediakiwi.crans.eu" - "mediawiki.crans.eu" - ]; - extraConfig = '' - return 301 https://mediawiki.crans.org$request_uri; - ''; - }; + # redirection mirror + "mirror.crans.fr" = { + rejectSSL = true; + serverAliases = [ + "mirror.crans.eu" + ]; + extraConfig = '' + return 301 http://mirror.crans.org$request_uri; + ''; + }; - # redirection wiki - "wiki.crans.fr" = { - enableACME = true; - forceSSL = true; - serverAliases = [ - "wikipedia.crans.org" - "wikipedia.crans.fr" - "wikipedia.crans.eu" - "wiki.crans.eu" - ]; - extraConfig = '' - return 301 https://wiki.crans.org$request_uri; - ''; + # redirection anubis mirrors + "anubis-mirror" = { + rejectSSL = true; + locations."/" = { + proxyPass = "http://${config.services.anubis.instances."mirror".settings.BIND}"; }; + serverName = "mirror.crans.org"; + serverAliases = [ + "eclat.crans.org" + ]; + }; - # redirection anubis - "anubis" = { - enableACME = true; - forceSSL = true; - locations."/" = { - proxyPass = "http://${config.services.anubis.instances."muraille".settings.BIND}"; - }; - serverName = "install-party.crans.org"; - serverAliases = [ - "mediawiki.crans.org" - "wiki.crans.org" - ]; - }; - - # install-party - "install-party.crans.org" = { - root = "/var/www/install-party.crans.org"; - listen = anubisConf; - }; - - # mediawiki - "mediawiki.crans.org" = { - locations."/".proxyPass = "http://172.16.10.144"; - listen = anubisConf; - }; - - # wiki - "wiki.crans.org" = { - locations."/".proxyPass = "http://172.16.10.161"; - listen = anubisConf; - }; + # mirror + "mirror.crans.org" = { + locations."/".proxyPass = "http://172.16.10.104"; + listen = [ + { + addr = "localhost"; + port = 8890; + } + ]; + serverAliases = [ + "eclat.crans.org" + ]; }; }; } diff --git a/modules/services/default.nix b/modules/services/default.nix index 9c1cafb..5c91cc2 100644 --- a/modules/services/default.nix +++ b/modules/services/default.nix @@ -6,5 +6,6 @@ ./coturn.nix ./nginx.nix ./restic.nix + ./reverseproxy.nix ]; } diff --git a/modules/services/reverseproxy.nix b/modules/services/reverseproxy.nix new file mode 100644 index 0000000..6bc96e8 --- /dev/null +++ b/modules/services/reverseproxy.nix @@ -0,0 +1,154 @@ +{ pkgs, lib, config, ... }: + +let + cfg = config.crans.reverseProxy; + + allowAll = pkgs.writeText "allow_all.json" + '' + { + "bots": [ + { + "name": "allow_all", + "path_regex": ".*", + "action": "ALLOW" + } + ] + } + ''; + inherit (lib) + cartesianProduct + literalExpression + mapAttrs + mapAttrs' + mkEnableOption + mkIf + mkOption + nameValuePair + substring + types + ; +in + +{ + options.crans.reverseProxy = { + enable = mkEnableOption "Configuration du reverseproxy."; + + virtualHosts = mkOption { + type = types.attrsOf ( + types.submodule { + options = { + serverAliases = mkOption { + type = types.listOf types.str; + default = [ ]; + example = [ + "everything" + "voyager" + ]; + description = '' + Déclaration des alias. + ''; + }; + + target = mkOption { + type = types.str; + default = ""; + description = '' + Indique la destination. Il peut s'agir du chemin vers des fichiers statiques. + ''; + example = "172.16.10.128:8000"; + }; + + anubisConfig = mkOption { + type = types.str; + default = ""; + description = '' + Chemin du fichier de configuration + ''; + example = "/var/www/anubis.conf"; + }; + }; + } + ); + default = {}; + example = literalExpression '' + { + "framadate" = { + host = "176.16.10.128:8000"; + serverAliases = [ + "everything" + "voyager" + ] + }; + }; + ''; + description = "Déclaration des machines."; + }; + }; + + config.services = mkIf cfg.enable { + anubis.instances = mapAttrs ( + vhostName: vhostConfig: { + enable = true; + settings = { + BIND_NETWORK = "unix"; + TARGET = "unix:/run/nginx/nginx-${vhostName}.sock"; + COOKIE_DOMAIN = "crans.org"; + REDIRECT_DOMAINS = "${vhostName}.crans.org"; + 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) != "/") { + "/".proxyPass = "http://${vhostConfig.target}"; + }; + root = mkIf ((substring 0 1 vhostConfig.target) == "/") vhostConfig.target; + listen = [ + { addr = "unix:/run/nginx/nginx-${vhostName}.sock"; } + ]; + } + ) cfg.virtualHosts; + aliasConfig = mapAttrs' ( + vhostName: vhostConfig: nameValuePair (vhostName + "-alias") { + enableACME = true; + forceSSL = true; + serverName = "${vhostName}.crans.fr"; + serverAliases = let + aliases = cartesianProduct { + name = vhostConfig.serverAliases; + domaine = domaines; + }; + in [ + "${vhostName}.crans.eu" + ] ++ map (value: value.name + "." + value.domaine) aliases; + extraConfig = '' + return 301 https://${vhostName}.crans.org$request_uri; + ''; + } + ) cfg.virtualHosts; + anubisConfig = mapAttrs' ( + vhostName: vhostConfig: nameValuePair (vhostName + "-anubis") { + enableACME = true; + forceSSL = true; + locations."/".proxyPass = "unix:/run/anubis/anubis-${vhostName}.sock"; + serverName = "${vhostName}.crans.org"; + } + ) cfg.virtualHosts; + in { + enable = true; + virtualHosts = redirectConfig // aliasConfig // anubisConfig; + }; + }; +}