diff options
Diffstat (limited to 'nixops/modules/websites/default.nix')
-rw-r--r-- | nixops/modules/websites/default.nix | 341 |
1 files changed, 131 insertions, 210 deletions
diff --git a/nixops/modules/websites/default.nix b/nixops/modules/websites/default.nix index 627d01a..5b839af 100644 --- a/nixops/modules/websites/default.nix +++ b/nixops/modules/websites/default.nix | |||
@@ -3,104 +3,66 @@ let | |||
3 | cfg = config.services.myWebsites; | 3 | cfg = config.services.myWebsites; |
4 | www_root = "/run/current-system/webapps/_www"; | 4 | www_root = "/run/current-system/webapps/_www"; |
5 | theme_root = "/run/current-system/webapps/_theme"; | 5 | theme_root = "/run/current-system/webapps/_theme"; |
6 | makeService = name: cfg: let | 6 | apacheConfig = { |
7 | toVhost = vhostConf: { | 7 | gzip = { |
8 | enableSSL = true; | 8 | modules = [ "deflate" "filter" ]; |
9 | sslServerCert = "/var/lib/acme/${vhostConf.certName}/cert.pem"; | ||
10 | sslServerKey = "/var/lib/acme/${vhostConf.certName}/key.pem"; | ||
11 | sslServerChain = "/var/lib/acme/${vhostConf.certName}/chain.pem"; | ||
12 | logFormat = "combinedVhost"; | ||
13 | listen = map (ip: { inherit ip; port = 443; }) cfg.ips; | ||
14 | hostName = builtins.head vhostConf.hosts; | ||
15 | serverAliases = builtins.tail vhostConf.hosts or []; | ||
16 | documentRoot = vhostConf.root; | ||
17 | extraConfig = builtins.concatStringsSep "\n" vhostConf.extraConfig; | ||
18 | }; | ||
19 | nosslVhost = { | ||
20 | listen = map (ip: { inherit ip; port = 80; }) cfg.ips; | ||
21 | hostName = "nossl.immae.eu"; | ||
22 | enableSSL = false; | ||
23 | logFormat = "combinedVhost"; | ||
24 | documentRoot = www_root; | ||
25 | extraConfig = '' | 9 | extraConfig = '' |
26 | <Directory ${www_root}> | 10 | AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript |
27 | DirectoryIndex nossl.html | 11 | ''; |
28 | AllowOverride None | 12 | }; |
29 | Require all granted | 13 | macros = { |
30 | 14 | modules = [ "macro" ]; | |
31 | RewriteEngine on | ||
32 | RewriteRule ^/(.+) / [L] | ||
33 | </Directory> | ||
34 | ''; | ||
35 | }; | 15 | }; |
36 | redirectVhost = { # Should go last, catchall http -> https redirect | 16 | stats = { |
37 | listen = map (ip: { inherit ip; port = 80; }) cfg.ips; | ||
38 | hostName = "redirectSSL"; | ||
39 | serverAliases = [ "*" ]; | ||
40 | enableSSL = false; | ||
41 | logFormat = "combinedVhost"; | ||
42 | documentRoot = "/var/lib/acme/acme-challenge"; | ||
43 | extraConfig = '' | 17 | extraConfig = '' |
44 | RewriteEngine on | 18 | <Macro Stats %{domain}> |
45 | RewriteCond "%{REQUEST_URI}" "!^/\.well-known" | 19 | Alias /webstats ${config.services.webstats.dataDir}/%{domain} |
46 | RewriteRule ^(.+) https://%{HTTP_HOST}$1 [R=301] | 20 | <Directory ${config.services.webstats.dataDir}/%{domain}> |
47 | # To redirect in specific "VirtualHost *:80", do | 21 | DirectoryIndex index.html |
48 | # RedirectMatch 301 ^/((?!\.well-known.*$).*)$ https://host/$1 | 22 | AllowOverride None |
49 | # rather than rewrite | 23 | Require all granted |
24 | </Directory> | ||
25 | <Location /webstats> | ||
26 | Use LDAPConnect | ||
27 | Require ldap-group cn=%{domain},ou=stats,cn=httpd,ou=services,dc=immae,dc=eu | ||
28 | </Location> | ||
29 | </Macro> | ||
50 | ''; | 30 | ''; |
51 | }; | 31 | }; |
52 | fallbackVhost = toVhost { # Should go first, default choice | 32 | ldap = { |
53 | certName = "eldiron"; | 33 | modules = [ "ldap" "authnz_ldap" ]; |
54 | hosts = ["eldiron.immae.eu" ]; | 34 | extraConfig = '' |
55 | root = www_root; | 35 | <IfModule ldap_module> |
56 | extraConfig = [ "DirectoryIndex index.htm" ]; | 36 | LDAPSharedCacheSize 500000 |
37 | LDAPCacheEntries 1024 | ||
38 | LDAPCacheTTL 600 | ||
39 | LDAPOpCacheEntries 1024 | ||
40 | LDAPOpCacheTTL 600 | ||
41 | </IfModule> | ||
42 | |||
43 | Include /var/secrets/apache-ldap | ||
44 | ''; | ||
57 | }; | 45 | }; |
58 | in rec { | 46 | global = { |
59 | enable = true; | 47 | extraConfig = (pkgs.webapps.apache-default.override { inherit www_root;}).apacheConfig; |
60 | listen = map (ip: { inherit ip; port = 443; }) cfg.ips; | ||
61 | stateDir = "/run/httpd_${name}"; | ||
62 | logPerVirtualHost = true; | ||
63 | multiProcessingModule = "worker"; | ||
64 | adminAddr = "httpd@immae.eu"; | ||
65 | logFormat = "combinedVhost"; | ||
66 | extraModules = pkgs.lib.lists.unique (pkgs.lib.lists.flatten cfg.modules); | ||
67 | extraConfig = builtins.concatStringsSep "\n" cfg.extraConfig; | ||
68 | virtualHosts = [ fallbackVhost ] | ||
69 | ++ lib.optionals (name == "tools") [ nosslVhost ] | ||
70 | ++ (pkgs.lib.attrsets.mapAttrsToList (n: v: toVhost v) cfg.vhostConfs) | ||
71 | ++ [ redirectVhost ]; | ||
72 | }; | ||
73 | makeServiceOptions = name: { | ||
74 | enable = lib.mkEnableOption "enable websites in ${name}"; | ||
75 | ips = lib.mkOption { | ||
76 | type = lib.types.listOf lib.types.string; | ||
77 | default = let | ||
78 | ips = myconfig.env.servers.eldiron.ips.${name}; | ||
79 | in | ||
80 | [ips.ip4] ++ (ips.ip6 or []); | ||
81 | description = "${name} ips to listen to"; | ||
82 | }; | 48 | }; |
83 | modules = lib.mkOption { | 49 | apaxy = { |
84 | type = lib.types.listOf (lib.types.str); | 50 | extraConfig = (pkgs.webapps.apache-theme.override { inherit theme_root; }).apacheConfig; |
85 | default = []; | ||
86 | }; | 51 | }; |
87 | extraConfig = lib.mkOption { | 52 | http2 = { |
88 | type = lib.types.listOf (lib.types.lines); | 53 | modules = [ "http2" ]; |
89 | default = []; | 54 | extraConfig = '' |
55 | Protocols h2 http/1.1 | ||
56 | ''; | ||
90 | }; | 57 | }; |
91 | vhostConfs = lib.mkOption { | 58 | customLog = { |
92 | type = lib.types.attrsOf (lib.types.submodule { | 59 | extraConfig = '' |
93 | options = { | 60 | LogFormat "%v:%p %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combinedVhost |
94 | certName = lib.mkOption { type = lib.types.string; }; | 61 | ''; |
95 | hosts = lib.mkOption { type = lib.types.listOf lib.types.string; }; | ||
96 | root = lib.mkOption { type = lib.types.nullOr lib.types.path; }; | ||
97 | extraConfig = lib.mkOption { type = lib.types.listOf lib.types.lines; default = []; }; | ||
98 | }; | ||
99 | }); | ||
100 | }; | 62 | }; |
101 | }; | 63 | }; |
102 | makeModules = cfg: pkgs.lib.lists.flatten (pkgs.lib.attrsets.mapAttrsToList (n: v: v.modules or []) cfg.apacheConfig); | 64 | makeModules = lib.lists.flatten (lib.attrsets.mapAttrsToList (n: v: v.modules or []) apacheConfig); |
103 | makeExtraConfig = cfg: (builtins.filter (x: x != null) (pkgs.lib.attrsets.mapAttrsToList (n: v: v.extraConfig or null) cfg.apacheConfig)); | 65 | makeExtraConfig = (builtins.filter (x: x != null) (lib.attrsets.mapAttrsToList (n: v: v.extraConfig or null) apacheConfig)); |
104 | in | 66 | in |
105 | { | 67 | { |
106 | imports = [ | 68 | imports = [ |
@@ -135,30 +97,6 @@ in | |||
135 | ./phpfpm | 97 | ./phpfpm |
136 | ]; | 98 | ]; |
137 | 99 | ||
138 | options.services.myWebsites = { | ||
139 | production = makeServiceOptions "production"; | ||
140 | integration = makeServiceOptions "integration"; | ||
141 | tools = makeServiceOptions "main"; | ||
142 | |||
143 | apacheConfig = lib.mkOption { | ||
144 | type = lib.types.attrsOf (lib.types.submodule { | ||
145 | options = { | ||
146 | modules = lib.mkOption { | ||
147 | type = lib.types.listOf (lib.types.str); | ||
148 | default = []; | ||
149 | }; | ||
150 | extraConfig = lib.mkOption { | ||
151 | type = lib.types.nullOr lib.types.lines; | ||
152 | default = null; | ||
153 | }; | ||
154 | }; | ||
155 | }); | ||
156 | default = {}; | ||
157 | description = "Extra global config"; | ||
158 | }; | ||
159 | |||
160 | }; | ||
161 | |||
162 | config = { | 100 | config = { |
163 | users.users.wwwrun.extraGroups = [ "keys" ]; | 101 | users.users.wwwrun.extraGroups = [ "keys" ]; |
164 | networking.firewall.allowedTCPPorts = [ 80 443 ]; | 102 | networking.firewall.allowedTCPPorts = [ 80 443 ]; |
@@ -195,28 +133,28 @@ in | |||
195 | services.myWebsites.tools.etherpad-lite.enable = true; | 133 | services.myWebsites.tools.etherpad-lite.enable = true; |
196 | services.myWebsites.tools.peertube.enable = true; | 134 | services.myWebsites.tools.peertube.enable = true; |
197 | 135 | ||
198 | services.myWebsites.Chloe.production.enable = cfg.production.enable; | 136 | services.myWebsites.Chloe.production.enable = true; |
199 | services.myWebsites.Ludivine.production.enable = cfg.production.enable; | 137 | services.myWebsites.Ludivine.production.enable = true; |
200 | services.myWebsites.Aten.production.enable = cfg.production.enable; | 138 | services.myWebsites.Aten.production.enable = true; |
201 | services.myWebsites.PiedsJaloux.production.enable = cfg.production.enable; | 139 | services.myWebsites.PiedsJaloux.production.enable = true; |
202 | services.myWebsites.Connexionswing.production.enable = cfg.production.enable; | 140 | services.myWebsites.Connexionswing.production.enable = true; |
203 | services.myWebsites.Jerome.production.enable = cfg.production.enable; | 141 | services.myWebsites.Jerome.production.enable = true; |
204 | services.myWebsites.Nassime.production.enable = cfg.production.enable; | 142 | services.myWebsites.Nassime.production.enable = true; |
205 | services.myWebsites.Florian.production.enable = cfg.production.enable; | 143 | services.myWebsites.Florian.production.enable = true; |
206 | services.myWebsites.Leila.production.enable = cfg.production.enable; | 144 | services.myWebsites.Leila.production.enable = true; |
207 | services.myWebsites.Papa.production.enable = cfg.production.enable; | 145 | services.myWebsites.Papa.production.enable = true; |
208 | services.myWebsites.DeniseJerome.production.enable = cfg.production.enable; | 146 | services.myWebsites.DeniseJerome.production.enable = true; |
209 | services.myWebsites.Emilia.production.enable = cfg.production.enable; | 147 | services.myWebsites.Emilia.production.enable = true; |
210 | services.myWebsites.Capitaines.production.enable = cfg.production.enable; | 148 | services.myWebsites.Capitaines.production.enable = true; |
211 | services.myWebsites.Immae.production.enable = cfg.production.enable; | 149 | services.myWebsites.Immae.production.enable = true; |
212 | services.myWebsites.Release.production.enable = cfg.production.enable; | 150 | services.myWebsites.Release.production.enable = true; |
213 | services.myWebsites.Temp.production.enable = cfg.production.enable; | 151 | services.myWebsites.Temp.production.enable = true; |
214 | 152 | ||
215 | services.myWebsites.Chloe.integration.enable = cfg.integration.enable; | 153 | services.myWebsites.Chloe.integration.enable = true; |
216 | services.myWebsites.Ludivine.integration.enable = cfg.integration.enable; | 154 | services.myWebsites.Ludivine.integration.enable = true; |
217 | services.myWebsites.Aten.integration.enable = cfg.integration.enable; | 155 | services.myWebsites.Aten.integration.enable = true; |
218 | services.myWebsites.PiedsJaloux.integration.enable = cfg.integration.enable; | 156 | services.myWebsites.PiedsJaloux.integration.enable = true; |
219 | services.myWebsites.Connexionswing.integration.enable = cfg.integration.enable; | 157 | services.myWebsites.Connexionswing.integration.enable = true; |
220 | services.myWebsites.TellesFlorian.integration.enable = true; | 158 | services.myWebsites.TellesFlorian.integration.enable = true; |
221 | services.myWebsites.Florian.integration.enable = true; | 159 | services.myWebsites.Florian.integration.enable = true; |
222 | 160 | ||
@@ -239,65 +177,6 @@ in | |||
239 | ''; | 177 | ''; |
240 | }]; | 178 | }]; |
241 | 179 | ||
242 | services.myWebsites.apacheConfig = { | ||
243 | gzip = { | ||
244 | modules = [ "deflate" "filter" ]; | ||
245 | extraConfig = '' | ||
246 | AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript | ||
247 | ''; | ||
248 | }; | ||
249 | macros = { | ||
250 | modules = [ "macro" ]; | ||
251 | }; | ||
252 | stats = { | ||
253 | extraConfig = '' | ||
254 | <Macro Stats %{domain}> | ||
255 | Alias /webstats ${config.services.webstats.dataDir}/%{domain} | ||
256 | <Directory ${config.services.webstats.dataDir}/%{domain}> | ||
257 | DirectoryIndex index.html | ||
258 | AllowOverride None | ||
259 | Require all granted | ||
260 | </Directory> | ||
261 | <Location /webstats> | ||
262 | Use LDAPConnect | ||
263 | Require ldap-group cn=%{domain},ou=stats,cn=httpd,ou=services,dc=immae,dc=eu | ||
264 | </Location> | ||
265 | </Macro> | ||
266 | ''; | ||
267 | }; | ||
268 | ldap = { | ||
269 | modules = [ "ldap" "authnz_ldap" ]; | ||
270 | extraConfig = '' | ||
271 | <IfModule ldap_module> | ||
272 | LDAPSharedCacheSize 500000 | ||
273 | LDAPCacheEntries 1024 | ||
274 | LDAPCacheTTL 600 | ||
275 | LDAPOpCacheEntries 1024 | ||
276 | LDAPOpCacheTTL 600 | ||
277 | </IfModule> | ||
278 | |||
279 | Include /var/secrets/apache-ldap | ||
280 | ''; | ||
281 | }; | ||
282 | global = { | ||
283 | extraConfig = (pkgs.webapps.apache-default.override { inherit www_root;}).apacheConfig; | ||
284 | }; | ||
285 | apaxy = { | ||
286 | extraConfig = (pkgs.webapps.apache-theme.override { inherit theme_root; }).apacheConfig; | ||
287 | }; | ||
288 | http2 = { | ||
289 | modules = [ "http2" ]; | ||
290 | extraConfig = '' | ||
291 | Protocols h2 http/1.1 | ||
292 | ''; | ||
293 | }; | ||
294 | customLog = { | ||
295 | extraConfig = '' | ||
296 | LogFormat "%v:%p %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combinedVhost | ||
297 | ''; | ||
298 | }; | ||
299 | }; | ||
300 | |||
301 | system.activationScripts = { | 180 | system.activationScripts = { |
302 | httpd = '' | 181 | httpd = '' |
303 | install -d -m 0755 /var/lib/acme/acme-challenge | 182 | install -d -m 0755 /var/lib/acme/acme-challenge |
@@ -334,26 +213,68 @@ in | |||
334 | ''; | 213 | ''; |
335 | }; | 214 | }; |
336 | 215 | ||
337 | services.httpdProd = makeService "production" config.services.myWebsites.production; | 216 | services.websites.production = { |
338 | services.myWebsites.production.modules = makeModules cfg; | 217 | enable = true; |
339 | services.myWebsites.production.extraConfig = makeExtraConfig cfg; | 218 | adminAddr = "httpd@immae.eu"; |
219 | httpdName = "Prod"; | ||
220 | ips = | ||
221 | let ips = myconfig.env.servers.eldiron.ips.production; | ||
222 | in [ips.ip4] ++ (ips.ip6 or []); | ||
223 | modules = makeModules; | ||
224 | extraConfig = makeExtraConfig; | ||
225 | fallbackVhost = { | ||
226 | certName = "eldiron"; | ||
227 | hosts = ["eldiron.immae.eu" ]; | ||
228 | root = www_root; | ||
229 | extraConfig = [ "DirectoryIndex index.htm" ]; | ||
230 | }; | ||
231 | }; | ||
340 | 232 | ||
341 | services.httpdInte = makeService "integration" config.services.myWebsites.integration; | 233 | services.websites.integration = { |
342 | services.myWebsites.integration.modules = makeModules cfg; | 234 | enable = true; |
343 | services.myWebsites.integration.extraConfig = makeExtraConfig cfg; | 235 | adminAddr = "httpd@immae.eu"; |
236 | httpdName = "Inte"; | ||
237 | ips = | ||
238 | let ips = myconfig.env.servers.eldiron.ips.integration; | ||
239 | in [ips.ip4] ++ (ips.ip6 or []); | ||
240 | modules = makeModules; | ||
241 | extraConfig = makeExtraConfig; | ||
242 | fallbackVhost = { | ||
243 | certName = "eldiron"; | ||
244 | hosts = ["eldiron.immae.eu" ]; | ||
245 | root = www_root; | ||
246 | extraConfig = [ "DirectoryIndex index.htm" ]; | ||
247 | }; | ||
248 | }; | ||
344 | 249 | ||
345 | services.httpdTools = makeService "tools" config.services.myWebsites.tools; | 250 | services.websites.tools = { |
346 | services.myWebsites.tools.modules = makeModules cfg; | 251 | enable = true; |
347 | services.myWebsites.tools.extraConfig = makeExtraConfig cfg ++ | 252 | adminAddr = "httpd@immae.eu"; |
348 | [ '' | 253 | httpdName = "Tools"; |
349 | RedirectMatch ^/licen[cs]es?_et_tip(ping)?$ https://www.immae.eu/licences_et_tip.html | 254 | ips = |
350 | RedirectMatch ^/licen[cs]es?_and_tip(ping)?$ https://www.immae.eu/licenses_and_tipping.html | 255 | let ips = myconfig.env.servers.eldiron.ips.main; |
351 | RedirectMatch ^/licen[cs]es?$ https://www.immae.eu/licenses_and_tipping.html | 256 | in [ips.ip4] ++ (ips.ip6 or []); |
352 | RedirectMatch ^/tip(ping)?$ https://www.immae.eu/licenses_and_tipping.html | 257 | modules = makeModules; |
353 | RedirectMatch ^/(mentions|mentions_legales|legal)$ https://www.immae.eu/mentions.html | 258 | extraConfig = makeExtraConfig ++ |
354 | RedirectMatch ^/CGU$ https://www.immae.eu/CGU | 259 | [ '' |
355 | '' | 260 | RedirectMatch ^/licen[cs]es?_et_tip(ping)?$ https://www.immae.eu/licences_et_tip.html |
356 | ] | 261 | RedirectMatch ^/licen[cs]es?_and_tip(ping)?$ https://www.immae.eu/licenses_and_tipping.html |
357 | ; | 262 | RedirectMatch ^/licen[cs]es?$ https://www.immae.eu/licenses_and_tipping.html |
263 | RedirectMatch ^/tip(ping)?$ https://www.immae.eu/licenses_and_tipping.html | ||
264 | RedirectMatch ^/(mentions|mentions_legales|legal)$ https://www.immae.eu/mentions.html | ||
265 | RedirectMatch ^/CGU$ https://www.immae.eu/CGU | ||
266 | '' | ||
267 | ]; | ||
268 | nosslVhost = { | ||
269 | enable = true; | ||
270 | host = "nossl.immae.eu"; | ||
271 | }; | ||
272 | fallbackVhost = { | ||
273 | certName = "eldiron"; | ||
274 | hosts = ["eldiron.immae.eu" ]; | ||
275 | root = www_root; | ||
276 | extraConfig = [ "DirectoryIndex index.htm" ]; | ||
277 | }; | ||
278 | }; | ||
358 | }; | 279 | }; |
359 | } | 280 | } |