|
52 | 52 |
|
53 | 53 | # Attrset with the ACME certificate names split by whether or not they depend |
54 | 54 | # on H2O serving challenges. |
55 | | - certNames = |
| 55 | + acmeCertNames = |
56 | 56 | let |
57 | 57 | partition = |
58 | 58 | acc: vhostSettings: |
|
67 | 67 | else |
68 | 68 | acc; |
69 | 69 |
|
70 | | - certNames' = lib.lists.foldl partition { |
| 70 | + certNames = lib.lists.foldl partition { |
71 | 71 | dependent = [ ]; |
72 | 72 | independent = [ ]; |
73 | 73 | } acmeEnabledHostsConfigs; |
74 | 74 | in |
75 | | - certNames' |
| 75 | + certNames |
76 | 76 | // { |
77 | | - all = certNames'.dependent ++ certNames'.independent; |
| 77 | + all = certNames.dependent ++ certNames.independent; |
78 | 78 | }; |
79 | 79 |
|
80 | 80 | mozTLSRecs = |
|
115 | 115 |
|
116 | 116 | names = getNames name value; |
117 | 117 |
|
118 | | - acmeSettings = lib.optionalAttrs (builtins.elem names.cert certNames.dependent) ( |
| 118 | + acmeSettings = lib.optionalAttrs (builtins.elem names.cert acmeCertNames.dependent) ( |
119 | 119 | let |
120 | 120 | acmePort = 80; |
121 | 121 | acmeChallengePath = "/.well-known/acme-challenge"; |
@@ -165,25 +165,34 @@ let |
165 | 165 |
|
166 | 166 | hasTLSRecommendations = tlsRecommendations != null && mozTLSRecs != null; |
167 | 167 |
|
168 | | - # NOTE: Let’s Encrypt has sunset OCSP stapling. Mozilla’s |
169 | | - # ssl-config-generator is at present still recommending this setting, but |
170 | | - # this module will skip setting a stapling value as Let’s Encrypt + |
171 | | - # ACME is the most likely use case. |
172 | | - # |
173 | | - # See: https://github.com/mozilla/ssl-config-generator/issues/323 |
174 | | - tlsRecAttrs = lib.optionalAttrs hasTLSRecommendations ( |
175 | | - let |
176 | | - recs = mozTLSRecs.${tlsRecommendations}; |
177 | | - in |
178 | | - { |
179 | | - min-version = builtins.head recs.tls_versions; |
180 | | - cipher-preference = "server"; |
181 | | - "cipher-suite-tls1.3" = recs.ciphersuites; |
182 | | - } |
183 | | - // lib.optionalAttrs (recs.ciphers.openssl != [ ]) { |
184 | | - cipher-suite = lib.concatStringsSep ":" recs.ciphers.openssl; |
| 168 | + # ATTENTION: Let’s Encrypt has sunset OCSP stapling. |
| 169 | + tlsRecAttrs = |
| 170 | + # If using ACME, this module will disable H2O’s default OCSP |
| 171 | + # stapling. |
| 172 | + # |
| 173 | + # See: https://letsencrypt.org/2024/12/05/ending-ocsp/ |
| 174 | + lib.optionalAttrs (builtins.elem names.cert acmeCertNames.all) { |
| 175 | + ocsp-update-interval = 0; |
185 | 176 | } |
186 | | - ); |
| 177 | + # Mozilla’s ssl-config-generator is at present still |
| 178 | + # recommending this setting as well, but this module will |
| 179 | + # skip setting a stapling value as Let’s Encrypt + ACME is |
| 180 | + # the most likely use case. |
| 181 | + # |
| 182 | + # See: https://github.com/mozilla/ssl-config-generator/issues/323 |
| 183 | + // lib.optionalAttrs hasTLSRecommendations ( |
| 184 | + let |
| 185 | + recs = mozTLSRecs.${tlsRecommendations}; |
| 186 | + in |
| 187 | + { |
| 188 | + min-version = builtins.head recs.tls_versions; |
| 189 | + cipher-preference = "server"; |
| 190 | + "cipher-suite-tls1.3" = recs.ciphersuites; |
| 191 | + } |
| 192 | + // lib.optionalAttrs (recs.ciphers.openssl != [ ]) { |
| 193 | + cipher-suite = lib.concatStringsSep ":" recs.ciphers.openssl; |
| 194 | + } |
| 195 | + ); |
187 | 196 |
|
188 | 197 | headerRecAttrs = |
189 | 198 | lib.optionalAttrs |
|
220 | 229 | let |
221 | 230 | identity = |
222 | 231 | value.tls.identity |
223 | | - ++ lib.optional (builtins.elem names.cert certNames.all) { |
| 232 | + ++ lib.optional (builtins.elem names.cert acmeCertNames.all) { |
224 | 233 | key-file = "${certs.${names.cert}.directory}/key.pem"; |
225 | 234 | certificate-file = "${certs.${names.cert}.directory}/fullchain.pem"; |
226 | 235 | }; |
|
402 | 411 | groups = config.users.groups; |
403 | 412 | services = [ |
404 | 413 | config.systemd.services.h2o |
405 | | - ] ++ lib.optional (certNames.all != [ ]) config.systemd.services.h2o-config-reload; |
| 414 | + ] ++ lib.optional (acmeCertNames.all != [ ]) config.systemd.services.h2o-config-reload; |
406 | 415 | } |
407 | | - ) certNames.all; |
| 416 | + ) acmeCertNames.all; |
408 | 417 |
|
409 | 418 | users = { |
410 | 419 | users.${cfg.user} = |
|
420 | 429 | systemd.services.h2o = { |
421 | 430 | description = "H2O HTTP server"; |
422 | 431 | wantedBy = [ "multi-user.target" ]; |
423 | | - wants = lib.concatLists (map (certName: [ "acme-finished-${certName}.target" ]) certNames.all); |
| 432 | + wants = lib.concatLists (map (certName: [ "acme-finished-${certName}.target" ]) acmeCertNames.all); |
424 | 433 | # Since H2O will be hosting the challenges, H2O must be started |
425 | | - before = builtins.map (certName: "acme-${certName}.service") certNames.dependent; |
| 434 | + before = builtins.map (certName: "acme-${certName}.service") acmeCertNames.dependent; |
426 | 435 | after = |
427 | 436 | [ "network.target" ] |
428 | | - ++ builtins.map (certName: "acme-selfsigned-${certName}.service") certNames.all |
429 | | - ++ builtins.map (certName: "acme-${certName}.service") certNames.independent; # avoid loading self-signed key w/ real cert, or vice-versa |
| 437 | + ++ builtins.map (certName: "acme-selfsigned-${certName}.service") acmeCertNames.all |
| 438 | + ++ builtins.map (certName: "acme-${certName}.service") acmeCertNames.independent; # avoid loading self-signed key w/ real cert, or vice-versa |
430 | 439 |
|
431 | 440 | serviceConfig = { |
432 | 441 | ExecStart = "${h2oExe} --mode 'master'"; |
|
479 | 488 | # of certs end-to-end. |
480 | 489 | systemd.services.h2o-config-reload = |
481 | 490 | let |
482 | | - tlsTargets = map (certName: "acme-${certName}.target") certNames.all; |
483 | | - tlsServices = map (certName: "acme-${certName}.service") certNames.all; |
| 491 | + tlsTargets = map (certName: "acme-${certName}.target") acmeCertNames.all; |
| 492 | + tlsServices = map (certName: "acme-${certName}.service") acmeCertNames.all; |
484 | 493 | in |
485 | | - mkIf (certNames.all != [ ]) { |
| 494 | + mkIf (acmeCertNames.all != [ ]) { |
486 | 495 | wantedBy = tlsServices ++ [ "multi-user.target" ]; |
487 | 496 | before = tlsTargets; |
488 | 497 | after = tlsServices; |
489 | 498 | unitConfig = { |
490 | | - ConditionPathExists = map (certName: "${certs.${certName}.directory}/fullchain.pem") certNames.all; |
| 499 | + ConditionPathExists = map ( |
| 500 | + certName: "${certs.${certName}.directory}/fullchain.pem" |
| 501 | + ) acmeCertNames.all; |
491 | 502 | # Disable rate limiting for this since it may be triggered quickly |
492 | 503 | # a bunch of times if a lot of certificates are renewed in quick |
493 | 504 | # succession. The reload itself is cheap, so even doing a lot of them |
|
0 commit comments