aboutsummaryrefslogtreecommitdiff
path: root/modules/websites
diff options
context:
space:
mode:
Diffstat (limited to 'modules/websites')
-rw-r--r--modules/websites/default.nix281
-rw-r--r--modules/websites/httpd-service-builder.nix735
-rw-r--r--modules/websites/httpd-service-builder.patch150
-rw-r--r--modules/websites/nosslVhost/index.html11
-rw-r--r--modules/websites/php-application.nix224
5 files changed, 0 insertions, 1401 deletions
diff --git a/modules/websites/default.nix b/modules/websites/default.nix
deleted file mode 100644
index 6658c66..0000000
--- a/modules/websites/default.nix
+++ /dev/null
@@ -1,281 +0,0 @@
1{ lib, config, pkgs, ... }: with lib;
2let
3 cfg = config.services.websites;
4in
5{
6 options.services.websites = with types; {
7 certs = mkOption {
8 description = "Default websites configuration for certificates as accepted by acme";
9 };
10 env = mkOption {
11 default = {};
12 description = "Each type of website to enable will target a distinct httpd server";
13 type = attrsOf (submodule {
14 options = {
15 enable = mkEnableOption "Enable websites of this type";
16 adminAddr = mkOption {
17 type = str;
18 description = "Admin e-mail address of the instance";
19 };
20 httpdName = mkOption {
21 type = str;
22 description = "Name of the httpd instance to assign this type to";
23 };
24 ips = mkOption {
25 type = listOf str;
26 default = [];
27 description = "ips to listen to";
28 };
29 modules = mkOption {
30 type = listOf str;
31 default = [];
32 description = "Additional modules to load in Apache";
33 };
34 extraConfig = mkOption {
35 type = listOf lines;
36 default = [];
37 description = "Additional configuration to append to Apache";
38 };
39 nosslVhost = mkOption {
40 description = "A default nossl vhost for captive portals";
41 default = {};
42 type = submodule {
43 options = {
44 enable = mkEnableOption "Add default no-ssl vhost for this instance";
45 host = mkOption {
46 type = str;
47 description = "The hostname to use for this vhost";
48 };
49 root = mkOption {
50 type = path;
51 default = ./nosslVhost;
52 description = "The root folder to serve";
53 };
54 indexFile = mkOption {
55 type = str;
56 default = "index.html";
57 description = "The index file to show.";
58 };
59 };
60 };
61 };
62 fallbackVhost = mkOption {
63 description = "The fallback vhost that will be defined as first vhost in Apache";
64 type = submodule {
65 options = {
66 certName = mkOption { type = str; };
67 hosts = mkOption { type = listOf str; };
68 root = mkOption { type = nullOr path; };
69 forceSSL = mkOption {
70 type = bool;
71 default = true;
72 description = ''
73 Automatically create a corresponding non-ssl vhost
74 that will only redirect to the ssl version
75 '';
76 };
77 extraConfig = mkOption { type = listOf lines; default = []; };
78 };
79 };
80 };
81 vhostNoSSLConfs = mkOption {
82 default = {};
83 description = "List of no ssl vhosts to define for Apache";
84 type = attrsOf (submodule {
85 options = {
86 hosts = mkOption { type = listOf str; };
87 root = mkOption { type = nullOr path; };
88 extraConfig = mkOption { type = listOf lines; default = []; };
89 };
90 });
91 };
92 vhostConfs = mkOption {
93 default = {};
94 description = "List of vhosts to define for Apache";
95 type = attrsOf (submodule {
96 options = {
97 certName = mkOption { type = str; };
98 addToCerts = mkOption {
99 type = bool;
100 default = false;
101 description = "Use these to certificates. Is ignored (considered true) if certMainHost is not null";
102 };
103 certMainHost = mkOption {
104 type = nullOr str;
105 description = "Use that host as 'main host' for acme certs";
106 default = null;
107 };
108 hosts = mkOption { type = listOf str; };
109 root = mkOption { type = nullOr path; };
110 forceSSL = mkOption {
111 type = bool;
112 default = true;
113 description = ''
114 Automatically create a corresponding non-ssl vhost
115 that will only redirect to the ssl version
116 '';
117 };
118 extraConfig = mkOption { type = listOf lines; default = []; };
119 };
120 });
121 };
122 watchPaths = mkOption {
123 type = listOf str;
124 default = [];
125 description = ''
126 Paths to watch that should trigger a reload of httpd
127 '';
128 };
129 };
130 });
131 };
132 };
133
134 config.services.httpd = let
135 nosslVhost = ips: cfg: {
136 listen = map (ip: { inherit ip; port = 80; }) ips;
137 hostName = cfg.host;
138 logFormat = "combinedVhost";
139 documentRoot = cfg.root;
140 extraConfig = ''
141 <Directory ${cfg.root}>
142 DirectoryIndex ${cfg.indexFile}
143 AllowOverride None
144 Require all granted
145
146 RewriteEngine on
147 RewriteRule ^/(.+) / [L]
148 </Directory>
149 '';
150 };
151 toVhost = ips: vhostConf: {
152 forceSSL = vhostConf.forceSSL or true;
153 useACMEHost = vhostConf.certName;
154 logFormat = "combinedVhost";
155 listen = if vhostConf.forceSSL
156 then lists.flatten (map (ip: [{ inherit ip; port = 443; ssl = true; } { inherit ip; port = 80; }]) ips)
157 else map (ip: { inherit ip; port = 443; ssl = true; }) ips;
158 hostName = builtins.head vhostConf.hosts;
159 serverAliases = builtins.tail vhostConf.hosts or [];
160 documentRoot = vhostConf.root;
161 extraConfig = builtins.concatStringsSep "\n" vhostConf.extraConfig;
162 };
163 toVhostNoSSL = ips: vhostConf: {
164 logFormat = "combinedVhost";
165 listen = map (ip: { inherit ip; port = 80; }) ips;
166 hostName = builtins.head vhostConf.hosts;
167 serverAliases = builtins.tail vhostConf.hosts or [];
168 documentRoot = vhostConf.root;
169 extraConfig = builtins.concatStringsSep "\n" vhostConf.extraConfig;
170 };
171 in attrsets.mapAttrs' (name: icfg: attrsets.nameValuePair
172 icfg.httpdName (mkIf icfg.enable {
173 enable = true;
174 logPerVirtualHost = true;
175 multiProcessingModule = "worker";
176 # https://ssl-config.mozilla.org/#server=apache&version=2.4.41&config=intermediate&openssl=1.0.2t&guideline=5.4
177 # test with https://www.ssllabs.com/ssltest/analyze.html?d=www.immae.eu&s=176.9.151.154&latest
178 sslProtocols = "all -SSLv3 -TLSv1 -TLSv1.1";
179 sslCiphers = builtins.concatStringsSep ":" [
180 "ECDHE-ECDSA-AES128-GCM-SHA256" "ECDHE-RSA-AES128-GCM-SHA256"
181 "ECDHE-ECDSA-AES256-GCM-SHA384" "ECDHE-RSA-AES256-GCM-SHA384"
182 "ECDHE-ECDSA-CHACHA20-POLY1305" "ECDHE-RSA-CHACHA20-POLY1305"
183 "DHE-RSA-AES128-GCM-SHA256" "DHE-RSA-AES256-GCM-SHA384"
184 ];
185 inherit (icfg) adminAddr;
186 logFormat = "combinedVhost";
187 extraModules = lists.unique icfg.modules;
188 extraConfig = builtins.concatStringsSep "\n" icfg.extraConfig;
189
190 virtualHosts = with attrsets; {
191 ___fallbackVhost = toVhost icfg.ips icfg.fallbackVhost;
192 } // (optionalAttrs icfg.nosslVhost.enable {
193 nosslVhost = nosslVhost icfg.ips icfg.nosslVhost;
194 }) // (mapAttrs' (n: v: nameValuePair ("nossl_" + n) (toVhostNoSSL icfg.ips v)) icfg.vhostNoSSLConfs)
195 // (mapAttrs' (n: v: nameValuePair ("ssl_" + n) (toVhost icfg.ips v)) icfg.vhostConfs);
196 })
197 ) cfg.env;
198
199 config.services.filesWatcher = attrsets.mapAttrs' (name: icfg: attrsets.nameValuePair
200 "httpd${icfg.httpdName}" {
201 paths = icfg.watchPaths;
202 waitTime = 5;
203 }
204 ) cfg.env;
205
206 config.security.acme.certs = let
207 typesToManage = attrsets.filterAttrs (k: v: v.enable) cfg.env;
208 flatVhosts = lists.flatten (attrsets.mapAttrsToList (k: v:
209 attrValues v.vhostConfs
210 ) typesToManage);
211 groupedCerts = attrsets.filterAttrs
212 (_: group: builtins.any (v: v.addToCerts || !isNull v.certMainHost) group)
213 (lists.groupBy (v: v.certName) flatVhosts);
214 groupToDomain = group:
215 let
216 nonNull = builtins.filter (v: !isNull v.certMainHost) group;
217 domains = lists.unique (map (v: v.certMainHost) nonNull);
218 in
219 if builtins.length domains == 0
220 then null
221 else assert (builtins.length domains == 1); (elemAt domains 0);
222 extraDomains = group:
223 let
224 mainDomain = groupToDomain group;
225 in
226 lists.remove mainDomain (
227 lists.unique (
228 lists.flatten (map (c: optionals (c.addToCerts || !isNull c.certMainHost) c.hosts) group)
229 )
230 );
231 in attrsets.mapAttrs (k: g:
232 if (!isNull (groupToDomain g))
233 then cfg.certs // {
234 domain = groupToDomain g;
235 extraDomains = builtins.listToAttrs (
236 map (d: attrsets.nameValuePair d null) (extraDomains g));
237 }
238 else {
239 extraDomains = builtins.listToAttrs (
240 map (d: attrsets.nameValuePair d null) (extraDomains g));
241 }
242 ) groupedCerts;
243
244 config.systemd.services = let
245 package = httpdName: config.services.httpd.${httpdName}.package.out;
246 cfgFile = httpdName: config.services.httpd.${httpdName}.configFile;
247 serviceChange = attrsets.mapAttrs' (name: icfg:
248 attrsets.nameValuePair
249 "httpd${icfg.httpdName}" {
250 stopIfChanged = false;
251 serviceConfig.ExecStart =
252 lib.mkForce "@${package icfg.httpdName}/bin/httpd httpd -f /etc/httpd/httpd_${icfg.httpdName}.conf";
253 serviceConfig.ExecStop =
254 lib.mkForce "${package icfg.httpdName}/bin/httpd -f /etc/httpd/httpd_${icfg.httpdName}.conf -k graceful-stop";
255 serviceConfig.ExecReload =
256 lib.mkForce "${package icfg.httpdName}/bin/httpd -f /etc/httpd/httpd_${icfg.httpdName}.conf -k graceful";
257 }
258 ) cfg.env;
259 serviceReload = attrsets.mapAttrs' (name: icfg:
260 attrsets.nameValuePair
261 "httpd${icfg.httpdName}-config-reload" {
262 wants = [ "httpd${icfg.httpdName}.service" ];
263 wantedBy = [ "multi-user.target" ];
264 restartTriggers = [ (cfgFile icfg.httpdName) ];
265 # commented, because can cause extra delays during activate for this config:
266 # services.nginx.virtualHosts."_".locations."/".proxyPass = "http://blabla:3000";
267 # stopIfChanged = false;
268 serviceConfig.Type = "oneshot";
269 serviceConfig.TimeoutSec = 60;
270 script = ''
271 if ${pkgs.systemd}/bin/systemctl -q is-active httpd${icfg.httpdName}.service ; then
272 ${package icfg.httpdName}/bin/httpd -f /etc/httpd/httpd_${icfg.httpdName}.conf -t && \
273 ${pkgs.systemd}/bin/systemctl reload httpd${icfg.httpdName}.service
274 fi
275 '';
276 serviceConfig.RemainAfterExit = true;
277 }
278 ) cfg.env;
279 in
280 serviceChange // serviceReload;
281}
diff --git a/modules/websites/httpd-service-builder.nix b/modules/websites/httpd-service-builder.nix
deleted file mode 100644
index 1f7488d..0000000
--- a/modules/websites/httpd-service-builder.nix
+++ /dev/null
@@ -1,735 +0,0 @@
1# to help backporting this builder should stay as close as possible to
2# nixos/modules/services/web-servers/apache-httpd/default.nix
3{ httpdName, withUsers ? true }:
4{ config, lib, pkgs, ... }:
5
6with lib;
7
8let
9
10 cfg = config.services.httpd."${httpdName}";
11
12 runtimeDir = "/run/httpd_${httpdName}";
13
14 pkg = cfg.package.out;
15
16 httpdConf = cfg.configFile;
17
18 php = cfg.phpPackage.override { apacheHttpd = pkg.dev; /* otherwise it only gets .out */ };
19
20 phpMajorVersion = lib.versions.major (lib.getVersion php);
21
22 mod_perl = pkgs.apacheHttpdPackages.mod_perl.override { apacheHttpd = pkg; };
23
24 vhosts = attrValues cfg.virtualHosts;
25
26 mkListenInfo = hostOpts:
27 if hostOpts.listen != [] then hostOpts.listen
28 else (
29 optional (hostOpts.onlySSL || hostOpts.addSSL || hostOpts.forceSSL) { ip = "*"; port = 443; ssl = true; } ++
30 optional (!hostOpts.onlySSL) { ip = "*"; port = 80; ssl = false; }
31 );
32
33 listenInfo = unique (concatMap mkListenInfo vhosts);
34
35 enableHttp2 = any (vhost: vhost.http2) vhosts;
36 enableSSL = any (listen: listen.ssl) listenInfo;
37 enableUserDir = any (vhost: vhost.enableUserDir) vhosts;
38
39 # NOTE: generally speaking order of modules is very important
40 modules =
41 [ # required apache modules our httpd service cannot run without
42 "authn_core" "authz_core"
43 "log_config"
44 "mime" "autoindex" "negotiation" "dir"
45 "alias" "rewrite"
46 "unixd" "slotmem_shm" "socache_shmcb"
47 "mpm_${cfg.multiProcessingModule}"
48 ]
49 ++ (if cfg.multiProcessingModule == "prefork" then [ "cgi" ] else [ "cgid" ])
50 ++ optional enableHttp2 "http2"
51 ++ optional enableSSL "ssl"
52 ++ optional enableUserDir "userdir"
53 ++ optional cfg.enableMellon { name = "auth_mellon"; path = "${pkgs.apacheHttpdPackages.mod_auth_mellon}/modules/mod_auth_mellon.so"; }
54 ++ optional cfg.enablePHP { name = "php${phpMajorVersion}"; path = "${php}/modules/libphp${phpMajorVersion}.so"; }
55 ++ optional cfg.enablePerl { name = "perl"; path = "${mod_perl}/modules/mod_perl.so"; }
56 ++ cfg.extraModules;
57
58 loggingConf = (if cfg.logFormat != "none" then ''
59 ErrorLog ${cfg.logDir}/error.log
60
61 LogLevel notice
62
63 LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
64 LogFormat "%h %l %u %t \"%r\" %>s %b" common
65 LogFormat "%{Referer}i -> %U" referer
66 LogFormat "%{User-agent}i" agent
67
68 CustomLog ${cfg.logDir}/access.log ${cfg.logFormat}
69 '' else ''
70 ErrorLog /dev/null
71 '');
72
73
74 browserHacks = ''
75 <IfModule mod_setenvif.c>
76 BrowserMatch "Mozilla/2" nokeepalive
77 BrowserMatch "MSIE 4\.0b2;" nokeepalive downgrade-1.0 force-response-1.0
78 BrowserMatch "RealPlayer 4\.0" force-response-1.0
79 BrowserMatch "Java/1\.0" force-response-1.0
80 BrowserMatch "JDK/1\.0" force-response-1.0
81 BrowserMatch "Microsoft Data Access Internet Publishing Provider" redirect-carefully
82 BrowserMatch "^WebDrive" redirect-carefully
83 BrowserMatch "^WebDAVFS/1.[012]" redirect-carefully
84 BrowserMatch "^gnome-vfs" redirect-carefully
85 </IfModule>
86 '';
87
88
89 sslConf = ''
90 <IfModule mod_ssl.c>
91 SSLSessionCache shmcb:${runtimeDir}/ssl_scache(512000)
92
93 Mutex posixsem
94
95 SSLRandomSeed startup builtin
96 SSLRandomSeed connect builtin
97
98 SSLProtocol ${cfg.sslProtocols}
99 SSLCipherSuite ${cfg.sslCiphers}
100 SSLHonorCipherOrder on
101 </IfModule>
102 '';
103
104
105 mimeConf = ''
106 TypesConfig ${pkg}/conf/mime.types
107
108 AddType application/x-x509-ca-cert .crt
109 AddType application/x-pkcs7-crl .crl
110 AddType application/x-httpd-php .php .phtml
111
112 <IfModule mod_mime_magic.c>
113 MIMEMagicFile ${pkg}/conf/magic
114 </IfModule>
115 '';
116
117 mkVHostConf = hostOpts:
118 let
119 adminAddr = if hostOpts.adminAddr != null then hostOpts.adminAddr else cfg.adminAddr;
120 listen = filter (listen: !listen.ssl) (mkListenInfo hostOpts);
121 listenSSL = filter (listen: listen.ssl) (mkListenInfo hostOpts);
122
123 useACME = hostOpts.enableACME || hostOpts.useACMEHost != null;
124 sslCertDir =
125 if hostOpts.enableACME then config.security.acme.certs.${hostOpts.hostName}.directory
126 else if hostOpts.useACMEHost != null then config.security.acme.certs.${hostOpts.useACMEHost}.directory
127 else abort "This case should never happen.";
128
129 sslServerCert = if useACME then "${sslCertDir}/full.pem" else hostOpts.sslServerCert;
130 sslServerKey = if useACME then "${sslCertDir}/key.pem" else hostOpts.sslServerKey;
131 sslServerChain = if useACME then "${sslCertDir}/fullchain.pem" else hostOpts.sslServerChain;
132
133 acmeChallenge = optionalString useACME ''
134 Alias /.well-known/acme-challenge/ "${hostOpts.acmeRoot}/.well-known/acme-challenge/"
135 <Directory "${hostOpts.acmeRoot}">
136 AllowOverride None
137 Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
138 Require method GET POST OPTIONS
139 Require all granted
140 </Directory>
141 '';
142 in
143 optionalString (listen != []) ''
144 <VirtualHost ${concatMapStringsSep " " (listen: "${listen.ip}:${toString listen.port}") listen}>
145 ServerName ${hostOpts.hostName}
146 ${concatMapStrings (alias: "ServerAlias ${alias}\n") hostOpts.serverAliases}
147 ServerAdmin ${adminAddr}
148 <IfModule mod_ssl.c>
149 SSLEngine off
150 </IfModule>
151 ${acmeChallenge}
152 ${if hostOpts.forceSSL then ''
153 <IfModule mod_rewrite.c>
154 RewriteEngine on
155 RewriteCond %{REQUEST_URI} !^/.well-known/acme-challenge [NC]
156 RewriteCond %{HTTPS} off
157 RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
158 </IfModule>
159 '' else mkVHostCommonConf hostOpts}
160 </VirtualHost>
161 '' +
162 optionalString (listenSSL != []) ''
163 <VirtualHost ${concatMapStringsSep " " (listen: "${listen.ip}:${toString listen.port}") listenSSL}>
164 ServerName ${hostOpts.hostName}
165 ${concatMapStrings (alias: "ServerAlias ${alias}\n") hostOpts.serverAliases}
166 ServerAdmin ${adminAddr}
167 SSLEngine on
168 SSLCertificateFile ${sslServerCert}
169 SSLCertificateKeyFile ${sslServerKey}
170 ${optionalString hostOpts.http2 "Protocols h2 h2c http/1.1"}
171 ${acmeChallenge}
172 ${mkVHostCommonConf hostOpts}
173 </VirtualHost>
174 ''
175 ;
176
177 mkVHostCommonConf = hostOpts:
178 let
179 documentRoot = if hostOpts.documentRoot != null
180 then hostOpts.documentRoot
181 else pkgs.runCommand "empty" { preferLocalBuild = true; } "mkdir -p $out"
182 ;
183
184 mkLocations = locations: concatStringsSep "\n" (map (config: ''
185 <Location ${config.location}>
186 ${optionalString (config.proxyPass != null) ''
187 <IfModule mod_proxy.c>
188 ProxyPass ${config.proxyPass}
189 ProxyPassReverse ${config.proxyPass}
190 </IfModule>
191 ''}
192 ${optionalString (config.index != null) ''
193 <IfModule mod_dir.c>
194 DirectoryIndex ${config.index}
195 </IfModule>
196 ''}
197 ${optionalString (config.alias != null) ''
198 <IfModule mod_alias.c>
199 Alias "${config.alias}"
200 </IfModule>
201 ''}
202 ${config.extraConfig}
203 </Location>
204 '') (sortProperties (mapAttrsToList (k: v: v // { location = k; }) locations)));
205 in
206 ''
207 ${optionalString cfg.logPerVirtualHost ''
208 ErrorLog ${cfg.logDir}/error-${hostOpts.hostName}.log
209 CustomLog ${cfg.logDir}/access-${hostOpts.hostName}.log ${hostOpts.logFormat}
210 ''}
211
212 ${optionalString (hostOpts.robotsEntries != "") ''
213 Alias /robots.txt ${pkgs.writeText "robots.txt" hostOpts.robotsEntries}
214 ''}
215
216 DocumentRoot "${documentRoot}"
217
218 <Directory "${documentRoot}">
219 Options Indexes FollowSymLinks
220 AllowOverride None
221 Require all granted
222 </Directory>
223
224 ${optionalString hostOpts.enableUserDir ''
225 UserDir public_html
226 UserDir disabled root
227 <Directory "/home/*/public_html">
228 AllowOverride FileInfo AuthConfig Limit Indexes
229 Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
230 <Limit GET POST OPTIONS>
231 Require all granted
232 </Limit>
233 <LimitExcept GET POST OPTIONS>
234 Require all denied
235 </LimitExcept>
236 </Directory>
237 ''}
238
239 ${optionalString (hostOpts.globalRedirect != null && hostOpts.globalRedirect != "") ''
240 RedirectPermanent / ${hostOpts.globalRedirect}
241 ''}
242
243 ${
244 let makeDirConf = elem: ''
245 Alias ${elem.urlPath} ${elem.dir}/
246 <Directory ${elem.dir}>
247 Options +Indexes
248 Require all granted
249 AllowOverride All
250 </Directory>
251 '';
252 in concatMapStrings makeDirConf hostOpts.servedDirs
253 }
254
255 ${mkLocations hostOpts.locations}
256 ${hostOpts.extraConfig}
257 ''
258 ;
259
260
261 confFile = pkgs.writeText "httpd.conf" ''
262
263 ServerRoot ${pkg}
264 ServerName ${config.networking.hostName}
265 DefaultRuntimeDir ${runtimeDir}/runtime
266
267 PidFile ${runtimeDir}/httpd.pid
268
269 ${optionalString (cfg.multiProcessingModule != "prefork") ''
270 # mod_cgid requires this.
271 ScriptSock ${runtimeDir}/cgisock
272 ''}
273
274 <IfModule prefork.c>
275 MaxClients ${toString cfg.maxClients}
276 MaxRequestsPerChild ${toString cfg.maxRequestsPerChild}
277 </IfModule>
278
279 ${let
280 toStr = listen: "Listen ${listen.ip}:${toString listen.port} ${if listen.ssl then "https" else "http"}";
281 uniqueListen = uniqList {inputList = map toStr listenInfo;};
282 in concatStringsSep "\n" uniqueListen
283 }
284
285 User ${cfg.user}
286 Group ${cfg.group}
287
288 ${let
289 mkModule = module:
290 if isString module then { name = module; path = "${pkg}/modules/mod_${module}.so"; }
291 else if isAttrs module then { inherit (module) name path; }
292 else throw "Expecting either a string or attribute set including a name and path.";
293 in
294 concatMapStringsSep "\n" (module: "LoadModule ${module.name}_module ${module.path}") (unique (map mkModule modules))
295 }
296
297 AddHandler type-map var
298
299 <Files ~ "^\.ht">
300 Require all denied
301 </Files>
302
303 ${mimeConf}
304 ${loggingConf}
305 ${browserHacks}
306
307 Include ${pkg}/conf/extra/httpd-default.conf
308 Include ${pkg}/conf/extra/httpd-autoindex.conf
309 Include ${pkg}/conf/extra/httpd-multilang-errordoc.conf
310 Include ${pkg}/conf/extra/httpd-languages.conf
311
312 TraceEnable off
313
314 ${sslConf}
315
316 # Fascist default - deny access to everything.
317 <Directory />
318 Options FollowSymLinks
319 AllowOverride None
320 Require all denied
321 </Directory>
322
323 ${cfg.extraConfig}
324
325 ${concatMapStringsSep "\n" mkVHostConf vhosts}
326 '';
327
328 # Generate the PHP configuration file. Should probably be factored
329 # out into a separate module.
330 phpIni = pkgs.runCommand "php.ini"
331 { options = cfg.phpOptions;
332 preferLocalBuild = true;
333 }
334 ''
335 cat ${php}/etc/php.ini > $out
336 echo "$options" >> $out
337 '';
338
339in
340
341
342{
343
344 imports = [
345 (mkRemovedOptionModule [ "services" "httpd" httpdName "extraSubservices" ] "Most existing subservices have been ported to the NixOS module system. Please update your configuration accordingly.")
346 (mkRemovedOptionModule [ "services" "httpd" httpdName "stateDir" ] "The httpd module now uses /run/httpd as a runtime directory.")
347
348 # virtualHosts options
349 (mkRemovedOptionModule [ "services" "httpd" httpdName "documentRoot" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
350 (mkRemovedOptionModule [ "services" "httpd" httpdName "enableSSL" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
351 (mkRemovedOptionModule [ "services" "httpd" httpdName "enableUserDir" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
352 (mkRemovedOptionModule [ "services" "httpd" httpdName "globalRedirect" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
353 (mkRemovedOptionModule [ "services" "httpd" httpdName "hostName" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
354 (mkRemovedOptionModule [ "services" "httpd" httpdName "listen" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
355 (mkRemovedOptionModule [ "services" "httpd" httpdName "robotsEntries" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
356 (mkRemovedOptionModule [ "services" "httpd" httpdName "servedDirs" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
357 (mkRemovedOptionModule [ "services" "httpd" httpdName "servedFiles" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
358 (mkRemovedOptionModule [ "services" "httpd" httpdName "serverAliases" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
359 (mkRemovedOptionModule [ "services" "httpd" httpdName "sslServerCert" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
360 (mkRemovedOptionModule [ "services" "httpd" httpdName "sslServerChain" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
361 (mkRemovedOptionModule [ "services" "httpd" httpdName "sslServerKey" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
362 ];
363
364 # interface
365
366 options = {
367
368 services.httpd."${httpdName}" = {
369
370 enable = mkEnableOption "the Apache HTTP Server";
371
372 package = mkOption {
373 type = types.package;
374 default = pkgs.apacheHttpd;
375 defaultText = "pkgs.apacheHttpd";
376 description = ''
377 Overridable attribute of the Apache HTTP Server package to use.
378 '';
379 };
380
381 configFile = mkOption {
382 type = types.path;
383 default = confFile;
384 defaultText = "confFile";
385 example = literalExample ''pkgs.writeText "httpd.conf" "# my custom config file ..."'';
386 description = ''
387 Override the configuration file used by Apache. By default,
388 NixOS generates one automatically.
389 '';
390 };
391
392 extraConfig = mkOption {
393 type = types.lines;
394 default = "";
395 description = ''
396 Configuration lines appended to the generated Apache
397 configuration file. Note that this mechanism will not work
398 when <option>configFile</option> is overridden.
399 '';
400 };
401
402 extraModules = mkOption {
403 type = types.listOf types.unspecified;
404 default = [];
405 example = literalExample ''
406 [
407 "proxy_connect"
408 { name = "jk"; path = "''${pkgs.tomcat_connectors}/modules/mod_jk.so"; }
409 ]
410 '';
411 description = ''
412 Additional Apache modules to be used. These can be
413 specified as a string in the case of modules distributed
414 with Apache, or as an attribute set specifying the
415 <varname>name</varname> and <varname>path</varname> of the
416 module.
417 '';
418 };
419
420 adminAddr = mkOption {
421 type = types.str;
422 example = "admin@example.org";
423 description = "E-mail address of the server administrator.";
424 };
425
426 logFormat = mkOption {
427 type = types.str;
428 default = "common";
429 example = "combined";
430 description = ''
431 Log format for log files. Possible values are: combined, common, referer, agent.
432 See <link xlink:href="https://httpd.apache.org/docs/2.4/logs.html"/> for more details.
433 '';
434 };
435
436 logPerVirtualHost = mkOption {
437 type = types.bool;
438 default = true;
439 description = ''
440 If enabled, each virtual host gets its own
441 <filename>access.log</filename> and
442 <filename>error.log</filename>, namely suffixed by the
443 <option>hostName</option> of the virtual host.
444 '';
445 };
446
447 user = mkOption {
448 type = types.str;
449 default = "wwwrun";
450 description = ''
451 User account under which httpd runs.
452 '';
453 };
454
455 group = mkOption {
456 type = types.str;
457 default = "wwwrun";
458 description = ''
459 Group under which httpd runs.
460 '';
461 };
462
463 logDir = mkOption {
464 type = types.path;
465 default = "/var/log/httpd";
466 description = ''
467 Directory for Apache's log files. It is created automatically.
468 '';
469 };
470
471 virtualHosts = mkOption {
472 type = with types; attrsOf (submodule (import <nixpkgs/nixos/modules/services/web-servers/apache-httpd/vhost-options.nix>));
473 default = {
474 localhost = {
475 documentRoot = "${pkg}/htdocs";
476 };
477 };
478 example = literalExample ''
479 {
480 "foo.example.com" = {
481 forceSSL = true;
482 documentRoot = "/var/www/foo.example.com"
483 };
484 "bar.example.com" = {
485 addSSL = true;
486 documentRoot = "/var/www/bar.example.com";
487 };
488 }
489 '';
490 description = ''
491 Specification of the virtual hosts served by Apache. Each
492 element should be an attribute set specifying the
493 configuration of the virtual host.
494 '';
495 };
496
497 enableMellon = mkOption {
498 type = types.bool;
499 default = false;
500 description = "Whether to enable the mod_auth_mellon module.";
501 };
502
503 enablePHP = mkOption {
504 type = types.bool;
505 default = false;
506 description = "Whether to enable the PHP module.";
507 };
508
509 phpPackage = mkOption {
510 type = types.package;
511 default = pkgs.php;
512 defaultText = "pkgs.php";
513 description = ''
514 Overridable attribute of the PHP package to use.
515 '';
516 };
517
518 enablePerl = mkOption {
519 type = types.bool;
520 default = false;
521 description = "Whether to enable the Perl module (mod_perl).";
522 };
523
524 phpOptions = mkOption {
525 type = types.lines;
526 default = "";
527 example =
528 ''
529 date.timezone = "CET"
530 '';
531 description = ''
532 Options appended to the PHP configuration file <filename>php.ini</filename>.
533 '';
534 };
535
536 multiProcessingModule = mkOption {
537 type = types.enum [ "event" "prefork" "worker" ];
538 default = "prefork";
539 example = "worker";
540 description =
541 ''
542 Multi-processing module to be used by Apache. Available
543 modules are <literal>prefork</literal> (the default;
544 handles each request in a separate child process),
545 <literal>worker</literal> (hybrid approach that starts a
546 number of child processes each running a number of
547 threads) and <literal>event</literal> (a recent variant of
548 <literal>worker</literal> that handles persistent
549 connections more efficiently).
550 '';
551 };
552
553 maxClients = mkOption {
554 type = types.int;
555 default = 150;
556 example = 8;
557 description = "Maximum number of httpd processes (prefork)";
558 };
559
560 maxRequestsPerChild = mkOption {
561 type = types.int;
562 default = 0;
563 example = 500;
564 description = ''
565 Maximum number of httpd requests answered per httpd child (prefork), 0 means unlimited.
566 '';
567 };
568
569 sslCiphers = mkOption {
570 type = types.str;
571 default = "HIGH:!aNULL:!MD5:!EXP";
572 description = "Cipher Suite available for negotiation in SSL proxy handshake.";
573 };
574
575 sslProtocols = mkOption {
576 type = types.str;
577 default = "All -SSLv2 -SSLv3 -TLSv1 -TLSv1.1";
578 example = "All -SSLv2 -SSLv3";
579 description = "Allowed SSL/TLS protocol versions.";
580 };
581 };
582
583 };
584
585 # implementation
586
587 config = mkIf cfg.enable {
588
589 assertions = [
590 {
591 assertion = all (hostOpts: !hostOpts.enableSSL) vhosts;
592 message = ''
593 The option `services.httpd.virtualHosts.<name>.enableSSL` no longer has any effect; please remove it.
594 Select one of `services.httpd.virtualHosts.<name>.addSSL`, `services.httpd.virtualHosts.<name>.forceSSL`,
595 or `services.httpd.virtualHosts.<name>.onlySSL`.
596 '';
597 }
598 {
599 assertion = all (hostOpts: with hostOpts; !(addSSL && onlySSL) && !(forceSSL && onlySSL) && !(addSSL && forceSSL)) vhosts;
600 message = ''
601 Options `services.httpd.virtualHosts.<name>.addSSL`,
602 `services.httpd.virtualHosts.<name>.onlySSL` and `services.httpd.virtualHosts.<name>.forceSSL`
603 are mutually exclusive.
604 '';
605 }
606 {
607 assertion = all (hostOpts: !(hostOpts.enableACME && hostOpts.useACMEHost != null)) vhosts;
608 message = ''
609 Options `services.httpd.virtualHosts.<name>.enableACME` and
610 `services.httpd.virtualHosts.<name>.useACMEHost` are mutually exclusive.
611 '';
612 }
613 ];
614
615 warnings =
616 mapAttrsToList (name: hostOpts: ''
617 Using config.services.httpd.virtualHosts."${name}".servedFiles is deprecated and will become unsupported in a future release. Your configuration will continue to work as is but please migrate your configuration to config.services.httpd.virtualHosts."${name}".locations before the 20.09 release of NixOS.
618 '') (filterAttrs (name: hostOpts: hostOpts.servedFiles != []) cfg.virtualHosts);
619
620 users.users = optionalAttrs (withUsers && cfg.user == "wwwrun") {
621 wwwrun = {
622 group = cfg.group;
623 description = "Apache httpd user";
624 uid = config.ids.uids.wwwrun;
625 };
626 };
627
628 users.groups = optionalAttrs (withUsers && cfg.group == "wwwrun") {
629 wwwrun.gid = config.ids.gids.wwwrun;
630 };
631
632 security.acme.certs = mapAttrs (name: hostOpts: {
633 user = cfg.user;
634 group = mkDefault cfg.group;
635 email = if hostOpts.adminAddr != null then hostOpts.adminAddr else cfg.adminAddr;
636 webroot = hostOpts.acmeRoot;
637 extraDomains = genAttrs hostOpts.serverAliases (alias: null);
638 postRun = "systemctl reload httpd.service";
639 }) (filterAttrs (name: hostOpts: hostOpts.enableACME) cfg.virtualHosts);
640
641 environment.systemPackages = [ pkg ];
642
643 # required for "apachectl configtest"
644 environment.etc."httpd/httpd_${httpdName}.conf".source = httpdConf;
645
646 services.httpd."${httpdName}" = { phpOptions =
647 ''
648 ; Needed for PHP's mail() function.
649 sendmail_path = sendmail -t -i
650
651 ; Don't advertise PHP
652 expose_php = off
653 '' + optionalString (config.time.timeZone != null) ''
654
655 ; Apparently PHP doesn't use $TZ.
656 date.timezone = "${config.time.timeZone}"
657 '';
658
659 extraModules = mkBefore [
660 # HTTP authentication mechanisms: basic and digest.
661 "auth_basic" "auth_digest"
662
663 # Authentication: is the user who he claims to be?
664 "authn_file" "authn_dbm" "authn_anon"
665
666 # Authorization: is the user allowed access?
667 "authz_user" "authz_groupfile" "authz_host"
668
669 # Other modules.
670 "ext_filter" "include" "env" "mime_magic"
671 "cern_meta" "expires" "headers" "usertrack" "setenvif"
672 "dav" "status" "asis" "info" "dav_fs"
673 "vhost_alias" "imagemap" "actions" "speling"
674 "proxy" "proxy_http"
675 "cache" "cache_disk"
676
677 # For compatibility with old configurations, the new module mod_access_compat is provided.
678 "access_compat"
679 ];
680 };
681
682 systemd.tmpfiles.rules =
683 let
684 svc = config.systemd.services."httpd${httpdName}".serviceConfig;
685 in
686 [
687 "d '${cfg.logDir}' 0700 ${svc.User} ${svc.Group}"
688 "Z '${cfg.logDir}' - ${svc.User} ${svc.Group}"
689 ];
690
691 systemd.services."httpd${httpdName}" =
692 let
693 vhostsACME = filter (hostOpts: hostOpts.enableACME) vhosts;
694 in
695 { description = "Apache HTTPD";
696
697 wantedBy = [ "multi-user.target" ];
698 wants = concatLists (map (hostOpts: [ "acme-${hostOpts.hostName}.service" "acme-selfsigned-${hostOpts.hostName}.service" ]) vhostsACME);
699 after = [ "network.target" "fs.target" ] ++ map (hostOpts: "acme-selfsigned-${hostOpts.hostName}.service") vhostsACME;
700
701 path =
702 [ pkg pkgs.coreutils pkgs.gnugrep ]
703 ++ optional cfg.enablePHP pkgs.system-sendmail; # Needed for PHP's mail() function.
704
705 environment =
706 optionalAttrs cfg.enablePHP { PHPRC = phpIni; }
707 // optionalAttrs cfg.enableMellon { LD_LIBRARY_PATH = "${pkgs.xmlsec}/lib"; };
708
709 preStart =
710 ''
711 # Get rid of old semaphores. These tend to accumulate across
712 # server restarts, eventually preventing it from restarting
713 # successfully.
714 for i in $(${pkgs.utillinux}/bin/ipcs -s | grep ' ${cfg.user} ' | cut -f2 -d ' '); do
715 ${pkgs.utillinux}/bin/ipcrm -s $i
716 done
717 '';
718
719 serviceConfig = {
720 ExecStart = "@${pkg}/bin/httpd httpd -f ${httpdConf}";
721 ExecStop = "${pkg}/bin/httpd -f ${httpdConf} -k graceful-stop";
722 ExecReload = "${pkg}/bin/httpd -f ${httpdConf} -k graceful";
723 User = "root";
724 Group = cfg.group;
725 Type = "forking";
726 PIDFile = "${runtimeDir}/httpd.pid";
727 Restart = "always";
728 RestartSec = "5s";
729 RuntimeDirectory = "httpd_${httpdName} httpd_${httpdName}/runtime";
730 RuntimeDirectoryMode = "0750";
731 };
732 };
733
734 };
735}
diff --git a/modules/websites/httpd-service-builder.patch b/modules/websites/httpd-service-builder.patch
deleted file mode 100644
index f0ad836..0000000
--- a/modules/websites/httpd-service-builder.patch
+++ /dev/null
@@ -1,150 +0,0 @@
1--- /nix/store/xj651aslybfsma20hpbi5nznfcffq8ky-nixexprs.tar.xz/nixos/modules/services/web-servers/apache-httpd/default.nix 1970-01-01 01:00:01.000000000 +0100
2+++ modules/websites/httpd-service-builder.nix 2020-04-04 03:08:29.068490345 +0200
3@@ -1,12 +1,15 @@
4+# to help backporting this builder should stay as close as possible to
5+# nixos/modules/services/web-servers/apache-httpd/default.nix
6+{ httpdName, withUsers ? true }:
7 { config, lib, pkgs, ... }:
8
9 with lib;
10
11 let
12
13- cfg = config.services.httpd;
14+ cfg = config.services.httpd."${httpdName}";
15
16- runtimeDir = "/run/httpd";
17+ runtimeDir = "/run/httpd_${httpdName}";
18
19 pkg = cfg.package.out;
20
21@@ -318,13 +321,6 @@
22 Require all denied
23 </Directory>
24
25- # But do allow access to files in the store so that we don't have
26- # to generate <Directory> clauses for every generated file that we
27- # want to serve.
28- <Directory /nix/store>
29- Require all granted
30- </Directory>
31-
32 ${cfg.extraConfig}
33
34 ${concatMapStringsSep "\n" mkVHostConf vhosts}
35@@ -347,30 +343,30 @@
36 {
37
38 imports = [
39- (mkRemovedOptionModule [ "services" "httpd" "extraSubservices" ] "Most existing subservices have been ported to the NixOS module system. Please update your configuration accordingly.")
40- (mkRemovedOptionModule [ "services" "httpd" "stateDir" ] "The httpd module now uses /run/httpd as a runtime directory.")
41+ (mkRemovedOptionModule [ "services" "httpd" httpdName "extraSubservices" ] "Most existing subservices have been ported to the NixOS module system. Please update your configuration accordingly.")
42+ (mkRemovedOptionModule [ "services" "httpd" httpdName "stateDir" ] "The httpd module now uses /run/httpd as a runtime directory.")
43
44 # virtualHosts options
45- (mkRemovedOptionModule [ "services" "httpd" "documentRoot" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
46- (mkRemovedOptionModule [ "services" "httpd" "enableSSL" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
47- (mkRemovedOptionModule [ "services" "httpd" "enableUserDir" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
48- (mkRemovedOptionModule [ "services" "httpd" "globalRedirect" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
49- (mkRemovedOptionModule [ "services" "httpd" "hostName" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
50- (mkRemovedOptionModule [ "services" "httpd" "listen" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
51- (mkRemovedOptionModule [ "services" "httpd" "robotsEntries" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
52- (mkRemovedOptionModule [ "services" "httpd" "servedDirs" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
53- (mkRemovedOptionModule [ "services" "httpd" "servedFiles" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
54- (mkRemovedOptionModule [ "services" "httpd" "serverAliases" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
55- (mkRemovedOptionModule [ "services" "httpd" "sslServerCert" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
56- (mkRemovedOptionModule [ "services" "httpd" "sslServerChain" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
57- (mkRemovedOptionModule [ "services" "httpd" "sslServerKey" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
58+ (mkRemovedOptionModule [ "services" "httpd" httpdName "documentRoot" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
59+ (mkRemovedOptionModule [ "services" "httpd" httpdName "enableSSL" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
60+ (mkRemovedOptionModule [ "services" "httpd" httpdName "enableUserDir" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
61+ (mkRemovedOptionModule [ "services" "httpd" httpdName "globalRedirect" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
62+ (mkRemovedOptionModule [ "services" "httpd" httpdName "hostName" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
63+ (mkRemovedOptionModule [ "services" "httpd" httpdName "listen" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
64+ (mkRemovedOptionModule [ "services" "httpd" httpdName "robotsEntries" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
65+ (mkRemovedOptionModule [ "services" "httpd" httpdName "servedDirs" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
66+ (mkRemovedOptionModule [ "services" "httpd" httpdName "servedFiles" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
67+ (mkRemovedOptionModule [ "services" "httpd" httpdName "serverAliases" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
68+ (mkRemovedOptionModule [ "services" "httpd" httpdName "sslServerCert" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
69+ (mkRemovedOptionModule [ "services" "httpd" httpdName "sslServerChain" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
70+ (mkRemovedOptionModule [ "services" "httpd" httpdName "sslServerKey" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
71 ];
72
73 # interface
74
75 options = {
76
77- services.httpd = {
78+ services.httpd."${httpdName}" = {
79
80 enable = mkEnableOption "the Apache HTTP Server";
81
82@@ -622,7 +618,7 @@
83 Using config.services.httpd.virtualHosts."${name}".servedFiles is deprecated and will become unsupported in a future release. Your configuration will continue to work as is but please migrate your configuration to config.services.httpd.virtualHosts."${name}".locations before the 20.09 release of NixOS.
84 '') (filterAttrs (name: hostOpts: hostOpts.servedFiles != []) cfg.virtualHosts);
85
86- users.users = optionalAttrs (cfg.user == "wwwrun") {
87+ users.users = optionalAttrs (withUsers && cfg.user == "wwwrun") {
88 wwwrun = {
89 group = cfg.group;
90 description = "Apache httpd user";
91@@ -630,7 +626,7 @@
92 };
93 };
94
95- users.groups = optionalAttrs (cfg.group == "wwwrun") {
96+ users.groups = optionalAttrs (withUsers && cfg.group == "wwwrun") {
97 wwwrun.gid = config.ids.gids.wwwrun;
98 };
99
100@@ -646,9 +642,9 @@
101 environment.systemPackages = [ pkg ];
102
103 # required for "apachectl configtest"
104- environment.etc."httpd/httpd.conf".source = httpdConf;
105+ environment.etc."httpd/httpd_${httpdName}.conf".source = httpdConf;
106
107- services.httpd.phpOptions =
108+ services.httpd."${httpdName}" = { phpOptions =
109 ''
110 ; Needed for PHP's mail() function.
111 sendmail_path = sendmail -t -i
112@@ -661,7 +657,7 @@
113 date.timezone = "${config.time.timeZone}"
114 '';
115
116- services.httpd.extraModules = mkBefore [
117+ extraModules = mkBefore [
118 # HTTP authentication mechanisms: basic and digest.
119 "auth_basic" "auth_digest"
120
121@@ -682,17 +678,18 @@
122 # For compatibility with old configurations, the new module mod_access_compat is provided.
123 "access_compat"
124 ];
125+ };
126
127 systemd.tmpfiles.rules =
128 let
129- svc = config.systemd.services.httpd.serviceConfig;
130+ svc = config.systemd.services."httpd${httpdName}".serviceConfig;
131 in
132 [
133 "d '${cfg.logDir}' 0700 ${svc.User} ${svc.Group}"
134 "Z '${cfg.logDir}' - ${svc.User} ${svc.Group}"
135 ];
136
137- systemd.services.httpd =
138+ systemd.services."httpd${httpdName}" =
139 let
140 vhostsACME = filter (hostOpts: hostOpts.enableACME) vhosts;
141 in
142@@ -730,7 +727,7 @@
143 PIDFile = "${runtimeDir}/httpd.pid";
144 Restart = "always";
145 RestartSec = "5s";
146- RuntimeDirectory = "httpd httpd/runtime";
147+ RuntimeDirectory = "httpd_${httpdName} httpd_${httpdName}/runtime";
148 RuntimeDirectoryMode = "0750";
149 };
150 };
diff --git a/modules/websites/nosslVhost/index.html b/modules/websites/nosslVhost/index.html
deleted file mode 100644
index 4401a80..0000000
--- a/modules/websites/nosslVhost/index.html
+++ /dev/null
@@ -1,11 +0,0 @@
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>
diff --git a/modules/websites/php-application.nix b/modules/websites/php-application.nix
deleted file mode 100644
index 3a43a45..0000000
--- a/modules/websites/php-application.nix
+++ /dev/null
@@ -1,224 +0,0 @@
1{ lib, config, pkgs, ... }:
2with lib;
3let
4 cfg = config.services.phpApplication;
5 cfgByEnv = lists.groupBy (x: x.websiteEnv) (builtins.attrValues cfg.apps);
6in
7{
8 options = with types; {
9 services.phpApplication.apps = mkOption {
10 default = {};
11 description = ''
12 php applications to define
13 '';
14 type = attrsOf (submodule {
15 options = {
16 varDir = mkOption {
17 type = nullOr path;
18 description = ''
19 Path to application’s vardir.
20 '';
21 };
22 varDirPaths = mkOption {
23 type = attrsOf str;
24 default = {};
25 description = ''
26 Map of additional folders => mode to create under varDir
27 '';
28 };
29 mode = mkOption {
30 type = str;
31 default = "0700";
32 description = ''
33 Mode to apply to the vardir
34 '';
35 };
36 phpSession = mkOption {
37 type = bool;
38 default = true;
39 description = "Handle phpsession files separately in vardir";
40 };
41 phpListen = mkOption {
42 type = nullOr str;
43 default = null;
44 description = "Name of the socket to listen to. Defaults to app name if null";
45 };
46 phpPool = mkOption {
47 type = attrsOf str;
48 default = {};
49 description = "Pool configuration to append";
50 };
51 phpEnv = mkOption {
52 type = attrsOf str;
53 default = {};
54 description = "Pool environment to append";
55 };
56 phpPackage = mkOption {
57 type = attrsOf str;
58 default = pkgs.php;
59 description = "Php package to use";
60 };
61 phpOptions = mkOption {
62 type = lines;
63 default = "";
64 description = "php configuration to append";
65 };
66 phpOpenbasedir = mkOption {
67 type = listOf path;
68 default = [];
69 description = ''
70 paths to add to php open_basedir configuration in addition to app and vardir
71 '';
72 };
73 phpWatchFiles = mkOption {
74 type = listOf path;
75 default = [];
76 description = ''
77 Path to other files to watch to trigger preStart scripts
78 '';
79 };
80 websiteEnv = mkOption {
81 type = str;
82 description = ''
83 website instance name to use
84 '';
85 };
86 httpdUser = mkOption {
87 type = str;
88 default = config.services.httpd.user;
89 description = ''
90 httpd user to run the prestart scripts as.
91 '';
92 };
93 httpdGroup = mkOption {
94 type = str;
95 default = config.services.httpd.group;
96 description = ''
97 httpd group to run the prestart scripts as.
98 '';
99 };
100 httpdWatchFiles = mkOption {
101 type = listOf path;
102 default = [];
103 description = ''
104 Path to other files to watch to trigger httpd reload
105 '';
106 };
107 app = mkOption {
108 type = path;
109 description = ''
110 Path to application root
111 '';
112 };
113 webRoot = mkOption {
114 type = nullOr path;
115 description = ''
116 Path to the web root path of the application. May differ from the application itself (usually a subdirectory)
117 '';
118 };
119 preStartActions = mkOption {
120 type = listOf str;
121 default = [];
122 description = ''
123 List of actions to run as apache user at preStart when
124 whatchFiles or app dir changed.
125 '';
126 };
127 serviceDeps = mkOption {
128 type = listOf str;
129 default = [];
130 description = ''
131 List of systemd services this application depends on
132 '';
133 };
134 };
135 });
136 };
137 # Read-only variables
138 services.phpApplication.phpListenPaths = mkOption {
139 type = attrsOf path;
140 default = attrsets.mapAttrs' (name: icfg: attrsets.nameValuePair
141 name config.services.phpfpm.pools."${name}".socket
142 ) cfg.apps;
143 readOnly = true;
144 description = ''
145 Full paths to listen for php
146 '';
147 };
148 };
149
150 config = {
151 services.websites.env = attrsets.mapAttrs' (name: cfgs: attrsets.nameValuePair
152 name {
153 modules = [ "proxy_fcgi" ];
154 watchPaths = builtins.concatLists (map (c: c.httpdWatchFiles) cfgs);
155 }
156 ) cfgByEnv;
157
158 services.phpfpm.pools = attrsets.mapAttrs' (name: icfg: attrsets.nameValuePair
159 name {
160 user = icfg.httpdUser;
161 group = icfg.httpdUser;
162 settings = {
163 "listen.owner" = icfg.httpdUser;
164 "listen.group" = icfg.httpdGroup;
165 "php_admin_value[open_basedir]" = builtins.concatStringsSep ":" ([icfg.app icfg.varDir] ++ icfg.phpWatchFiles ++ icfg.phpOpenbasedir);
166 }
167 // optionalAttrs (icfg.phpSession) { "php_admin_value[session.save_path]" = "${icfg.varDir}/phpSessions"; }
168 // icfg.phpPool;
169 phpOptions = config.services.phpfpm.phpOptions + icfg.phpOptions;
170 inherit (icfg) phpEnv phpPackage;
171 }
172 ) cfg.apps;
173
174 services.filesWatcher = attrsets.mapAttrs' (name: icfg: attrsets.nameValuePair
175 "phpfpm-${name}" {
176 restart = true;
177 paths = icfg.phpWatchFiles;
178 }
179 ) (attrsets.filterAttrs (n: v: builtins.length v.phpWatchFiles > 0) cfg.apps);
180
181 systemd.services = attrsets.mapAttrs' (name: icfg: attrsets.nameValuePair
182 "phpfpm-${name}" {
183 after = lib.mkAfter icfg.serviceDeps;
184 wants = icfg.serviceDeps;
185 preStart = lib.mkAfter (optionalString (!isNull icfg.varDir) ''
186 watchFilesChanged() {
187 ${optionalString (builtins.length icfg.phpWatchFiles == 0) "return 1"}
188 [ ! -f "${icfg.varDir}"/watchedFiles ] \
189 || ! sha512sum -c --status ${icfg.varDir}/watchedFiles
190 }
191 appDirChanged() {
192 [ ! -f "${icfg.varDir}/currentWebappDir" -o \
193 "${icfg.app}" != "$(cat ${icfg.varDir}/currentWebappDir 2>/dev/null)" ]
194 }
195 updateWatchFiles() {
196 ${optionalString (builtins.length icfg.phpWatchFiles == 0) "return 0"}
197 sha512sum ${builtins.concatStringsSep " " icfg.phpWatchFiles} > ${icfg.varDir}/watchedFiles
198 }
199
200 if watchFilesChanged || appDirChanged; then
201 pushd ${icfg.app} > /dev/null
202 ${builtins.concatStringsSep "\n " (map (c: "/run/wrappers/bin/sudo -u ${icfg.httpdUser} ${c}") icfg.preStartActions) }
203 popd > /dev/null
204 echo -n "${icfg.app}" > ${icfg.varDir}/currentWebappDir
205 updateWatchFiles
206 fi
207 '');
208 }
209 ) cfg.apps;
210
211 system.activationScripts = attrsets.mapAttrs' (name: icfg: attrsets.nameValuePair
212 name {
213 deps = [];
214 text = optionalString (!isNull icfg.varDir) ''
215 install -m ${icfg.mode} -o ${icfg.httpdUser} -g ${icfg.httpdGroup} -d ${icfg.varDir}
216 '' + optionalString (icfg.phpSession) ''
217 install -m 0700 -o ${icfg.httpdUser} -g ${icfg.httpdGroup} -d ${icfg.varDir}/phpSessions
218 '' + builtins.concatStringsSep "\n" (attrsets.mapAttrsToList (n: v: ''
219 install -m ${v} -o ${icfg.httpdUser} -g ${icfg.httpdGroup} -d ${icfg.varDir}/${n}
220 '') icfg.varDirPaths);
221 }
222 ) cfg.apps;
223 };
224}