From daf64e3f7de98e4267823d14fa34891b27b5f657 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Isma=C3=ABl=20Bouya?= Date: Tue, 14 May 2019 08:47:00 +0200 Subject: Start moving websites configuration to modules --- modules/websites/default.nix | 148 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 modules/websites/default.nix (limited to 'modules/websites/default.nix') diff --git a/modules/websites/default.nix b/modules/websites/default.nix new file mode 100644 index 0000000..6a18c8a --- /dev/null +++ b/modules/websites/default.nix @@ -0,0 +1,148 @@ +{ lib, config, ... }: with lib; +let + cfg = config.services.websites; +in +{ + options.services.websites = with types; mkOption { + default = {}; + description = "Each type of website to enable will target a distinct httpd server"; + type = attrsOf (submodule { + options = { + enable = mkEnableOption "Enable websites of this type"; + adminAddr = mkOption { + type = str; + description = "Admin e-mail address of the instance"; + }; + httpdName = mkOption { + type = str; + description = "Name of the httpd instance to assign this type to"; + }; + ips = mkOption { + type = listOf string; + default = []; + description = "ips to listen to"; + }; + modules = mkOption { + type = listOf str; + default = []; + description = "Additional modules to load in Apache"; + }; + extraConfig = mkOption { + type = listOf lines; + default = []; + description = "Additional configuration to append to Apache"; + }; + nosslVhost = mkOption { + description = "A default nossl vhost for captive portals"; + default = {}; + type = submodule { + options = { + enable = mkEnableOption "Add default no-ssl vhost for this instance"; + host = mkOption { + type = string; + description = "The hostname to use for this vhost"; + }; + root = mkOption { + type = path; + default = ./nosslVhost; + description = "The root folder to serve"; + }; + indexFile = mkOption { + type = string; + default = "index.html"; + description = "The index file to show."; + }; + }; + }; + }; + fallbackVhost = mkOption { + description = "The fallback vhost that will be defined as first vhost in Apache"; + type = submodule { + options = { + certName = mkOption { type = string; }; + hosts = mkOption { type = listOf string; }; + root = mkOption { type = nullOr path; }; + extraConfig = mkOption { type = listOf lines; default = []; }; + }; + }; + }; + vhostConfs = mkOption { + default = {}; + description = "List of vhosts to define for Apache"; + type = attrsOf (submodule { + options = { + certName = mkOption { type = string; }; + hosts = mkOption { type = listOf string; }; + root = mkOption { type = nullOr path; }; + extraConfig = mkOption { type = listOf lines; default = []; }; + }; + }); + }; + }; + }); + }; + + config.services.httpd = let + redirectVhost = ips: { # Should go last, catchall http -> https redirect + listen = map (ip: { inherit ip; port = 80; }) ips; + hostName = "redirectSSL"; + serverAliases = [ "*" ]; + enableSSL = false; + logFormat = "combinedVhost"; + documentRoot = "/var/lib/acme/acme-challenge"; + extraConfig = '' + RewriteEngine on + RewriteCond "%{REQUEST_URI}" "!^/\.well-known" + RewriteRule ^(.+) https://%{HTTP_HOST}$1 [R=301] + # To redirect in specific "VirtualHost *:80", do + # RedirectMatch 301 ^/((?!\.well-known.*$).*)$ https://host/$1 + # rather than rewrite + ''; + }; + nosslVhost = ips: cfg: { + listen = map (ip: { inherit ip; port = 80; }) ips; + hostName = cfg.host; + enableSSL = false; + logFormat = "combinedVhost"; + documentRoot = cfg.root; + extraConfig = '' + + DirectoryIndex ${cfg.indexFile} + AllowOverride None + Require all granted + + RewriteEngine on + RewriteRule ^/(.+) / [L] + + ''; + }; + toVhost = ips: vhostConf: { + enableSSL = true; + sslServerCert = "/var/lib/acme/${vhostConf.certName}/cert.pem"; + sslServerKey = "/var/lib/acme/${vhostConf.certName}/key.pem"; + sslServerChain = "/var/lib/acme/${vhostConf.certName}/chain.pem"; + logFormat = "combinedVhost"; + listen = map (ip: { inherit ip; port = 443; }) ips; + hostName = builtins.head vhostConf.hosts; + serverAliases = builtins.tail vhostConf.hosts or []; + documentRoot = vhostConf.root; + extraConfig = builtins.concatStringsSep "\n" vhostConf.extraConfig; + }; + in attrsets.mapAttrs' (name: icfg: attrsets.nameValuePair + icfg.httpdName (mkIf icfg.enable { + enable = true; + listen = map (ip: { inherit ip; port = 443; }) icfg.ips; + stateDir = "/run/httpd_${name}"; + logPerVirtualHost = true; + multiProcessingModule = "worker"; + inherit (icfg) adminAddr; + logFormat = "combinedVhost"; + extraModules = lists.unique icfg.modules; + extraConfig = builtins.concatStringsSep "\n" icfg.extraConfig; + virtualHosts = [ (toVhost icfg.ips icfg.fallbackVhost) ] + ++ optionals (icfg.nosslVhost.enable) [ (nosslVhost icfg.ips icfg.nosslVhost) ] + ++ (attrsets.mapAttrsToList (n: v: toVhost icfg.ips v) icfg.vhostConfs) + ++ [ (redirectVhost icfg.ips) ]; + }) + ) cfg; +} -- cgit v1.2.3