aboutsummaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorIsmaël Bouya <ismael.bouya@normalesup.org>2019-05-14 08:47:00 +0200
committerIsmaël Bouya <ismael.bouya@normalesup.org>2019-05-14 09:41:18 +0200
commitdaf64e3f7de98e4267823d14fa34891b27b5f657 (patch)
tree82a3bc59b1bff35b7cd2fc4aeb02e0485e5b37a0 /modules
parent017cb76f3355369a57cee7e851e013fbe7b265b7 (diff)
downloadNix-daf64e3f7de98e4267823d14fa34891b27b5f657.tar.gz
Nix-daf64e3f7de98e4267823d14fa34891b27b5f657.tar.zst
Nix-daf64e3f7de98e4267823d14fa34891b27b5f657.zip
Start moving websites configuration to modules
Diffstat (limited to 'modules')
-rw-r--r--modules/default.nix2
-rw-r--r--modules/private/default.nix2
-rw-r--r--modules/private/httpd-service-builder.nix8
-rw-r--r--modules/websites/default.nix148
-rw-r--r--modules/websites/nosslVhost/index.html11
5 files changed, 166 insertions, 5 deletions
diff --git a/modules/default.nix b/modules/default.nix
index 6c49160..acb0bb5 100644
--- a/modules/default.nix
+++ b/modules/default.nix
@@ -8,4 +8,6 @@
8 mastodon = ./webapps/mastodon.nix; 8 mastodon = ./webapps/mastodon.nix;
9 mediagoblin = ./webapps/mediagoblin.nix; 9 mediagoblin = ./webapps/mediagoblin.nix;
10 peertube = ./webapps/peertube.nix; 10 peertube = ./webapps/peertube.nix;
11
12 websites = ./websites;
11} // (if builtins.pathExists ./private then import ./private else {}) 13} // (if builtins.pathExists ./private then import ./private else {})
diff --git a/modules/private/default.nix b/modules/private/default.nix
index ba46374..6c71af3 100644
--- a/modules/private/default.nix
+++ b/modules/private/default.nix
@@ -1,6 +1,6 @@
1{ 1{
2 # adatped from nixpkgs/nixos/modules/services/web-servers/apache-httpd/default.nix 2 # adatped from nixpkgs/nixos/modules/services/web-servers/apache-httpd/default.nix
3 httpdProd = import ./httpd-service-builder.nix { httpdName = "Prod"; withUsers = false; };
4 httpdInte = import ./httpd-service-builder.nix { httpdName = "Inte"; withUsers = false; }; 3 httpdInte = import ./httpd-service-builder.nix { httpdName = "Inte"; withUsers = false; };
4 httpdProd = import ./httpd-service-builder.nix { httpdName = "Prod"; withUsers = false; };
5 httpdTools = import ./httpd-service-builder.nix { httpdName = "Tools"; withUsers = true; }; 5 httpdTools = import ./httpd-service-builder.nix { httpdName = "Tools"; withUsers = true; };
6} 6}
diff --git a/modules/private/httpd-service-builder.nix b/modules/private/httpd-service-builder.nix
index 0f0fe22..d049202 100644
--- a/modules/private/httpd-service-builder.nix
+++ b/modules/private/httpd-service-builder.nix
@@ -7,7 +7,7 @@ with lib;
7 7
8let 8let
9 9
10 mainCfg = config.services."httpd${httpdName}"; 10 mainCfg = config.services.httpd."${httpdName}";
11 11
12 httpd = mainCfg.package.out; 12 httpd = mainCfg.package.out;
13 13
@@ -438,7 +438,7 @@ in
438 438
439 options = { 439 options = {
440 440
441 services."httpd${httpdName}" = { 441 services.httpd."${httpdName}" = {
442 442
443 enable = mkOption { 443 enable = mkOption {
444 type = types.bool; 444 type = types.bool;
@@ -655,7 +655,7 @@ in
655 655
656 ###### implementation 656 ###### implementation
657 657
658 config = mkIf config.services."httpd${httpdName}".enable { 658 config = mkIf config.services.httpd."${httpdName}".enable {
659 659
660 assertions = [ { assertion = mainCfg.enableSSL == true 660 assertions = [ { assertion = mainCfg.enableSSL == true
661 -> mainCfg.sslServerCert != null 661 -> mainCfg.sslServerCert != null
@@ -679,7 +679,7 @@ in
679 679
680 environment.systemPackages = [httpd] ++ concatMap (svc: svc.extraPath) allSubservices; 680 environment.systemPackages = [httpd] ++ concatMap (svc: svc.extraPath) allSubservices;
681 681
682 services."httpd${httpdName}".phpOptions = 682 services.httpd."${httpdName}".phpOptions =
683 '' 683 ''
684 ; Needed for PHP's mail() function. 684 ; Needed for PHP's mail() function.
685 sendmail_path = sendmail -t -i 685 sendmail_path = sendmail -t -i
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 @@
1{ lib, config, ... }: with lib;
2let
3 cfg = config.services.websites;
4in
5{
6 options.services.websites = with types; mkOption {
7 default = {};
8 description = "Each type of website to enable will target a distinct httpd server";
9 type = attrsOf (submodule {
10 options = {
11 enable = mkEnableOption "Enable websites of this type";
12 adminAddr = mkOption {
13 type = str;
14 description = "Admin e-mail address of the instance";
15 };
16 httpdName = mkOption {
17 type = str;
18 description = "Name of the httpd instance to assign this type to";
19 };
20 ips = mkOption {
21 type = listOf string;
22 default = [];
23 description = "ips to listen to";
24 };
25 modules = mkOption {
26 type = listOf str;
27 default = [];
28 description = "Additional modules to load in Apache";
29 };
30 extraConfig = mkOption {
31 type = listOf lines;
32 default = [];
33 description = "Additional configuration to append to Apache";
34 };
35 nosslVhost = mkOption {
36 description = "A default nossl vhost for captive portals";
37 default = {};
38 type = submodule {
39 options = {
40 enable = mkEnableOption "Add default no-ssl vhost for this instance";
41 host = mkOption {
42 type = string;
43 description = "The hostname to use for this vhost";
44 };
45 root = mkOption {
46 type = path;
47 default = ./nosslVhost;
48 description = "The root folder to serve";
49 };
50 indexFile = mkOption {
51 type = string;
52 default = "index.html";
53 description = "The index file to show.";
54 };
55 };
56 };
57 };
58 fallbackVhost = mkOption {
59 description = "The fallback vhost that will be defined as first vhost in Apache";
60 type = submodule {
61 options = {
62 certName = mkOption { type = string; };
63 hosts = mkOption { type = listOf string; };
64 root = mkOption { type = nullOr path; };
65 extraConfig = mkOption { type = listOf lines; default = []; };
66 };
67 };
68 };
69 vhostConfs = mkOption {
70 default = {};
71 description = "List of vhosts to define for Apache";
72 type = attrsOf (submodule {
73 options = {
74 certName = mkOption { type = string; };
75 hosts = mkOption { type = listOf string; };
76 root = mkOption { type = nullOr path; };
77 extraConfig = mkOption { type = listOf lines; default = []; };
78 };
79 });
80 };
81 };
82 });
83 };
84
85 config.services.httpd = let
86 redirectVhost = ips: { # Should go last, catchall http -> https redirect
87 listen = map (ip: { inherit ip; port = 80; }) ips;
88 hostName = "redirectSSL";
89 serverAliases = [ "*" ];
90 enableSSL = false;
91 logFormat = "combinedVhost";
92 documentRoot = "/var/lib/acme/acme-challenge";
93 extraConfig = ''
94 RewriteEngine on
95 RewriteCond "%{REQUEST_URI}" "!^/\.well-known"
96 RewriteRule ^(.+) https://%{HTTP_HOST}$1 [R=301]
97 # To redirect in specific "VirtualHost *:80", do
98 # RedirectMatch 301 ^/((?!\.well-known.*$).*)$ https://host/$1
99 # rather than rewrite
100 '';
101 };
102 nosslVhost = ips: cfg: {
103 listen = map (ip: { inherit ip; port = 80; }) ips;
104 hostName = cfg.host;
105 enableSSL = false;
106 logFormat = "combinedVhost";
107 documentRoot = cfg.root;
108 extraConfig = ''
109 <Directory ${cfg.root}>
110 DirectoryIndex ${cfg.indexFile}
111 AllowOverride None
112 Require all granted
113
114 RewriteEngine on
115 RewriteRule ^/(.+) / [L]
116 </Directory>
117 '';
118 };
119 toVhost = ips: vhostConf: {
120 enableSSL = true;
121 sslServerCert = "/var/lib/acme/${vhostConf.certName}/cert.pem";
122 sslServerKey = "/var/lib/acme/${vhostConf.certName}/key.pem";
123 sslServerChain = "/var/lib/acme/${vhostConf.certName}/chain.pem";
124 logFormat = "combinedVhost";
125 listen = map (ip: { inherit ip; port = 443; }) ips;
126 hostName = builtins.head vhostConf.hosts;
127 serverAliases = builtins.tail vhostConf.hosts or [];
128 documentRoot = vhostConf.root;
129 extraConfig = builtins.concatStringsSep "\n" vhostConf.extraConfig;
130 };
131 in attrsets.mapAttrs' (name: icfg: attrsets.nameValuePair
132 icfg.httpdName (mkIf icfg.enable {
133 enable = true;
134 listen = map (ip: { inherit ip; port = 443; }) icfg.ips;
135 stateDir = "/run/httpd_${name}";
136 logPerVirtualHost = true;
137 multiProcessingModule = "worker";
138 inherit (icfg) adminAddr;
139 logFormat = "combinedVhost";
140 extraModules = lists.unique icfg.modules;
141 extraConfig = builtins.concatStringsSep "\n" icfg.extraConfig;
142 virtualHosts = [ (toVhost icfg.ips icfg.fallbackVhost) ]
143 ++ optionals (icfg.nosslVhost.enable) [ (nosslVhost icfg.ips icfg.nosslVhost) ]
144 ++ (attrsets.mapAttrsToList (n: v: toVhost icfg.ips v) icfg.vhostConfs)
145 ++ [ (redirectVhost icfg.ips) ];
146 })
147 ) cfg;
148}
diff --git a/modules/websites/nosslVhost/index.html b/modules/websites/nosslVhost/index.html
new file mode 100644
index 0000000..4401a80
--- /dev/null
+++ b/modules/websites/nosslVhost/index.html
@@ -0,0 +1,11 @@
1<!DOCTYPE html>
2<html>
3 <head>
4 <title>No SSL site</title>
5 </head>
6 <body>
7 <h1>No SSL on this site</h1>
8 <p>Use for wifi networks with login page that doesn't work well with
9 https.</p>
10 </body>
11</html>