Merge pull request #27426 from rnhmjoj/nginx

nginx: make enabling SSL port-specific
This commit is contained in:
Wout Mertens 2017-08-07 16:46:28 +02:00 committed by GitHub
commit 339330b322
2 changed files with 91 additions and 26 deletions

View File

@ -130,15 +130,31 @@ let
vhosts = concatStringsSep "\n" (mapAttrsToList (vhostName: vhost: vhosts = concatStringsSep "\n" (mapAttrsToList (vhostName: vhost:
let let
ssl = vhost.enableSSL || vhost.forceSSL; ssl = with vhost; addSSL || onlySSL || enableSSL;
defaultPort = if ssl then 443 else 80;
listenString = { addr, port, ... }: defaultListen = with vhost;
"listen ${addr}:${toString (if port != null then port else defaultPort)} " if listen != [] then listen
else if onlySSL || enableSSL then
singleton { addr = "0.0.0.0"; port = 443; ssl = true; }
++ optional enableIPv6 { addr = "[::]"; port = 443; ssl = true; }
else singleton { addr = "0.0.0.0"; port = 80; ssl = false; }
++ optional enableIPv6 { addr = "[::]"; port = 80; ssl = false; }
++ optional addSSL { addr = "0.0.0.0"; port = 443; ssl = true; }
++ optional (enableIPv6 && addSSL) { addr = "[::]"; port = 443; ssl = true; };
hostListen =
if !vhost.forceSSL
then defaultListen
else filter (x: x.ssl) defaultListen;
listenString = { addr, port, ssl, ... }:
"listen ${addr}:${toString port} "
+ optionalString ssl "ssl http2 " + optionalString ssl "ssl http2 "
+ optionalString vhost.default "default_server" + optionalString vhost.default "default_server "
+ ";"; + ";";
redirectListen = filter (x: !x.ssl) defaultListen;
redirectListenString = { addr, ... }: redirectListenString = { addr, ... }:
"listen ${addr}:80 ${optionalString vhost.default "default_server"};"; "listen ${addr}:80 ${optionalString vhost.default "default_server"};";
@ -159,7 +175,7 @@ let
in '' in ''
${optionalString vhost.forceSSL '' ${optionalString vhost.forceSSL ''
server { server {
${concatMapStringsSep "\n" redirectListenString vhost.listen} ${concatMapStringsSep "\n" redirectListenString redirectListen}
server_name ${vhost.serverName} ${concatStringsSep " " vhost.serverAliases}; server_name ${vhost.serverName} ${concatStringsSep " " vhost.serverAliases};
${optionalString vhost.enableACME acmeLocation} ${optionalString vhost.enableACME acmeLocation}
@ -170,7 +186,7 @@ let
''} ''}
server { server {
${concatMapStringsSep "\n" listenString vhost.listen} ${concatMapStringsSep "\n" listenString hostListen}
server_name ${vhost.serverName} ${concatStringsSep " " vhost.serverAliases}; server_name ${vhost.serverName} ${concatStringsSep " " vhost.serverAliases};
${optionalString vhost.enableACME acmeLocation} ${optionalString vhost.enableACME acmeLocation}
${optionalString (vhost.root != null) "root ${vhost.root};"} ${optionalString (vhost.root != null) "root ${vhost.root};"}
@ -425,6 +441,7 @@ in
example = literalExample '' example = literalExample ''
{ {
"hydra.example.com" = { "hydra.example.com" = {
addSSL = true;
forceSSL = true; forceSSL = true;
enableACME = true; enableACME = true;
locations."/" = { locations."/" = {
@ -441,11 +458,40 @@ in
config = mkIf cfg.enable { config = mkIf cfg.enable {
# TODO: test user supplied config file pases syntax test # TODO: test user supplied config file pases syntax test
assertions = let hostOrAliasIsNull = l: l.root == null || l.alias == null; in [ warnings =
let
deprecatedSSL = name: config: optional config.enableSSL
''
config.services.nginx.virtualHosts.<name>.enableSSL is deprecated,
use config.services.nginx.virtualHosts.<name>.onlySSL instead.
'';
in flatten (mapAttrsToList deprecatedSSL virtualHosts);
assertions =
let
hostOrAliasIsNull = l: l.root == null || l.alias == null;
in [
{ {
assertion = all (host: all hostOrAliasIsNull (attrValues host.locations)) (attrValues virtualHosts); assertion = all (host: all hostOrAliasIsNull (attrValues host.locations)) (attrValues virtualHosts);
message = "Only one of nginx root or alias can be specified on a location."; message = "Only one of nginx root or alias can be specified on a location.";
} }
{
assertion = all (conf: with conf; !(addSSL && (onlySSL || enableSSL))) (attrValues virtualHosts);
message = ''
Options services.nginx.service.virtualHosts.<name>.addSSL and
services.nginx.virtualHosts.<name>.onlySSL are mutually esclusive
'';
}
{
assertion = all (conf: with conf; forceSSL -> addSSL) (attrValues virtualHosts);
message = ''
Option services.nginx.virtualHosts.<name>.forceSSL requires
services.nginx.virtualHosts.<name>.addSSL set to true.
'';
}
]; ];
systemd.services.nginx = { systemd.services.nginx = {

View File

@ -27,25 +27,21 @@ with lib;
}; };
listen = mkOption { listen = mkOption {
type = with types; listOf (submodule { type = with types; listOf (submodule { options = {
options = {
addr = mkOption { type = str; description = "IP address."; }; addr = mkOption { type = str; description = "IP address."; };
port = mkOption { type = nullOr int; description = "Port number."; }; port = mkOption { type = int; description = "Port number."; default = 80; };
}; ssl = mkOption { type = bool; description = "Enable SSL."; default = false; };
}); }; });
default = default = [];
[ { addr = "0.0.0.0"; port = null; } ]
++ optional config.networking.enableIPv6
{ addr = "[::]"; port = null; };
example = [ example = [
{ addr = "195.154.1.1"; port = 443; } { addr = "195.154.1.1"; port = 443; ssl = true;}
{ addr = "192.168.1.2"; port = 443; } { addr = "192.154.1.1"; port = 80; }
]; ];
description = '' description = ''
Listen addresses and ports for this virtual host. Listen addresses and ports for this virtual host.
IPv6 addresses must be enclosed in square brackets. IPv6 addresses must be enclosed in square brackets.
Setting the port to <literal>null</literal> defaults Note: this option overrides <literal>addSSL</literal>
to 80 for http and 443 for https (i.e. when enableSSL is set). and <literal>onlySSL</literal>.
''; '';
}; };
@ -70,16 +66,39 @@ with lib;
''; '';
}; };
enableSSL = mkOption { addSSL = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = "Whether to enable SSL (https) support."; description = ''
Whether to enable HTTPS in addition to plain HTTP. This will set defaults for
<literal>listen</literal> to listen on all interfaces on the respective default
ports (80, 443).
'';
};
onlySSL = mkOption {
type = types.bool;
default = false;
description = ''
Whether to enable HTTPS and reject plain HTTP connections. This will set
defaults for <literal>listen</literal> to listen on all interfaces on port 443.
'';
};
enableSSL = mkOption {
type = types.bool;
visible = false;
default = false;
}; };
forceSSL = mkOption { forceSSL = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = "Whether to always redirect to https."; description = ''
Whether to add a separate nginx server block that permanently redirects (301)
all plain HTTP traffic to HTTPS. This option needs <literal>addSSL</literal>
to be set to true.
'';
}; };
sslCertificate = mkOption { sslCertificate = mkOption {