Merge pull request #33900 from jtojnar/nginx-acme

nixos/nginx: allow using existing ACME certificate
This commit is contained in:
Jan Tojnar 2018-01-29 01:38:45 +01:00 committed by GitHub
commit 0f21306ca3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 30 additions and 5 deletions

View file

@ -15,6 +15,9 @@ let
} // (optionalAttrs vhostConfig.enableACME { } // (optionalAttrs vhostConfig.enableACME {
sslCertificate = "/var/lib/acme/${serverName}/fullchain.pem"; sslCertificate = "/var/lib/acme/${serverName}/fullchain.pem";
sslCertificateKey = "/var/lib/acme/${serverName}/key.pem"; sslCertificateKey = "/var/lib/acme/${serverName}/key.pem";
}) // (optionalAttrs (vhostConfig.useACMEHost != null) {
sslCertificate = "/var/lib/acme/${vhostConfig.useACMEHost}/fullchain.pem";
sslCertificateKey = "/var/lib/acme/${vhostConfig.useACMEHost}/key.pem";
}) })
) cfg.virtualHosts; ) cfg.virtualHosts;
enableIPv6 = config.networking.enableIPv6; enableIPv6 = config.networking.enableIPv6;
@ -174,7 +177,7 @@ let
redirectListen = filter (x: !x.ssl) defaultListen; redirectListen = filter (x: !x.ssl) defaultListen;
acmeLocation = '' acmeLocation = optionalString (vhost.enableACME || vhost.useACMEHost != null) ''
location /.well-known/acme-challenge { location /.well-known/acme-challenge {
${optionalString (vhost.acmeFallbackHost != null) "try_files $uri @acme-fallback;"} ${optionalString (vhost.acmeFallbackHost != null) "try_files $uri @acme-fallback;"}
root ${vhost.acmeRoot}; root ${vhost.acmeRoot};
@ -194,7 +197,7 @@ let
${concatMapStringsSep "\n" listenString redirectListen} ${concatMapStringsSep "\n" listenString redirectListen}
server_name ${vhost.serverName} ${concatStringsSep " " vhost.serverAliases}; server_name ${vhost.serverName} ${concatStringsSep " " vhost.serverAliases};
${optionalString vhost.enableACME acmeLocation} ${acmeLocation}
location / { location / {
return 301 https://$host$request_uri; return 301 https://$host$request_uri;
} }
@ -204,7 +207,7 @@ let
server { server {
${concatMapStringsSep "\n" listenString hostListen} ${concatMapStringsSep "\n" listenString hostListen}
server_name ${vhost.serverName} ${concatStringsSep " " vhost.serverAliases}; server_name ${vhost.serverName} ${concatStringsSep " " vhost.serverAliases};
${optionalString vhost.enableACME acmeLocation} ${acmeLocation}
${optionalString (vhost.root != null) "root ${vhost.root};"} ${optionalString (vhost.root != null) "root ${vhost.root};"}
${optionalString (vhost.globalRedirect != null) '' ${optionalString (vhost.globalRedirect != null) ''
return 301 http${optionalString hasSSL "s"}://${vhost.globalRedirect}$request_uri; return 301 http${optionalString hasSSL "s"}://${vhost.globalRedirect}$request_uri;
@ -555,6 +558,14 @@ in
are mutually exclusive. are mutually exclusive.
''; '';
} }
{
assertion = all (conf: !(conf.enableACME && conf.useACMEHost != null)) (attrValues virtualHosts);
message = ''
Options services.nginx.service.virtualHosts.<name>.enableACME and
services.nginx.virtualHosts.<name>.useACMEHost are mutually exclusive.
'';
}
]; ];
systemd.services.nginx = { systemd.services.nginx = {
@ -580,7 +591,7 @@ in
security.acme.certs = filterAttrs (n: v: v != {}) ( security.acme.certs = filterAttrs (n: v: v != {}) (
let let
vhostsConfigs = mapAttrsToList (vhostName: vhostConfig: vhostConfig) virtualHosts; vhostsConfigs = mapAttrsToList (vhostName: vhostConfig: vhostConfig) virtualHosts;
acmeEnabledVhosts = filter (vhostConfig: vhostConfig.enableACME) vhostsConfigs; acmeEnabledVhosts = filter (vhostConfig: vhostConfig.enableACME && vhostConfig.useACMEHost == null) vhostsConfigs;
acmePairs = map (vhostConfig: { name = vhostConfig.serverName; value = { acmePairs = map (vhostConfig: { name = vhostConfig.serverName; value = {
user = cfg.user; user = cfg.user;
group = lib.mkDefault cfg.group; group = lib.mkDefault cfg.group;

View file

@ -48,7 +48,21 @@ with lib;
enableACME = mkOption { enableACME = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = "Whether to ask Let's Encrypt to sign a certificate for this vhost."; description = ''
Whether to ask Let's Encrypt to sign a certificate for this vhost.
Alternately, you can use an existing certificate through <option>useACMEHost</option>.
'';
};
useACMEHost = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
A host of an existing Let's Encrypt certificate to use.
This is useful if you have many subdomains and want to avoid hitting the
<link xlink:href="https://letsencrypt.org/docs/rate-limits/">rate limit</link>.
Alternately, you can generate a certificate through <option>enableACME</option>.
'';
}; };
acmeRoot = mkOption { acmeRoot = mkOption {