From f298be9ef44657fdd267f7c296b40d4c97c9c1fc Mon Sep 17 00:00:00 2001 From: Robin Gloster Date: Sun, 24 Jan 2016 15:50:54 +0000 Subject: [PATCH 01/23] nginx module: declarative config --- .../services/web-servers/nginx/default.nix | 113 +++++++++++++++++- .../web-servers/nginx/location-options.nix | 32 +++++ .../web-servers/nginx/vhost-options.nix | 96 +++++++++++++++ 3 files changed, 237 insertions(+), 4 deletions(-) create mode 100644 nixos/modules/services/web-servers/nginx/location-options.nix create mode 100644 nixos/modules/services/web-servers/nginx/vhost-options.nix diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index 27a33f33ff9..ab5657a9aa9 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -7,18 +7,107 @@ let nginx = cfg.package; configFile = pkgs.writeText "nginx.conf" '' user ${cfg.user} ${cfg.group}; + error_log stderr; daemon off; ${cfg.config} - ${optionalString (cfg.httpConfig != "") '' http { include ${cfg.package}/conf/mime.types; + include ${cfg.package}/conf/fastcgi.conf; + + # optimisation + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + + # use secure TLS defaults + ssl_protocols TLSv1.2; + ssl_session_cache shared:SSL:42m; + ssl_session_timeout 23m; + + ssl_ciphers EDH+aRSA+AES256:+AESGCM:ECDHE+aRSA+AES256; + ssl_ecdh_curve secp521r1; + ssl_prefer_server_ciphers on; + + ssl_stapling on; + ssl_stapling_verify on; + + gzip on; + gzip_disable "msie6"; + gzip_proxied any; + gzip_comp_level 9; + gzip_buffers 16 8k; + gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; + + # sane proxy settings/headers + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Accept-Encoding ""; + + proxy_redirect off; + client_max_body_size 10m; + client_body_buffer_size 128k; + proxy_connect_timeout 90; + proxy_send_timeout 90; + proxy_read_timeout 90; + proxy_buffers 32 4k; + proxy_buffer_size 8k; + proxy_http_version 1.0; + + server_tokens ${if cfg.serverTokens then "on" else "off"}; + ${vhosts} ${cfg.httpConfig} } - ''} ${cfg.appendConfig} ''; + + vhosts = concatStringsSep "\n" (mapAttrsToList (serverName: vhost: + let + ssl = vhost.enableSSL || vhost.forceSSL; + port = if vhost.port != null then vhost.port else (if ssl then 443 else 80); + listenString = toString port + optionalString ssl " ssl spdy"; + in '' + ${if vhost.forceSSL then '' + server { + listen 80; + listen [::]:80; + + server_name ${serverName} ${concatStringsSep " " vhost.serverAliases}; + return 301 https://$host${optionalString (port != 443) ":${port}"}$request_uri; + } + '' else ""} + + server { + listen ${listenString}; + listen [::]:${listenString}; + + server_name ${serverName} ${concatStringsSep " " vhost.serverAliases}; + ${optionalString (vhost.root != null) "root ${vhost.root};"} + ${optionalString (vhost.globalRedirect != null) '' + return 301 https://${vhost.globalRedirect}$request_uri; + ''} + ${optionalString ssl '' + ssl_certificate ${vhost.sslCertificate}; + ssl_certificate_key ${vhost.sslCertificateKey}; + ''} + + ${genLocations vhost.locations} + + ${vhost.extraConfig} + } + '' + ) cfg.virtualHosts); + genLocations = locations: concatStringsSep "\n" (mapAttrsToList (location: config: '' + location ${location} { + ${optionalString (config.proxyPass != null) "proxy_pass ${config.proxyPass};"} + ${optionalString (config.root != null) "root ${config.root};"} + } + '') locations); in { @@ -86,8 +175,24 @@ in description = "Group account under which nginx runs."; }; - }; + serverTokens = mkOption { + type = types.bool; + default = false; + description = "Show nginx version in headers and error pages"; + }; + virtualHosts = mkOption { + type = types.attrsOf (types.submodule (import ./vhost-options.nix { + inherit lib; + })); + default = { + localhost = {}; + }; + example = []; + description = '' + ''; + }; + }; }; config = mkIf cfg.enable { @@ -107,7 +212,7 @@ in serviceConfig = { ExecStart = "${nginx}/bin/nginx -c ${configFile} -p ${cfg.stateDir}"; ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; - Restart = "on-failure"; + Restart = "always"; RestartSec = "10s"; StartLimitInterval = "1min"; }; diff --git a/nixos/modules/services/web-servers/nginx/location-options.nix b/nixos/modules/services/web-servers/nginx/location-options.nix new file mode 100644 index 00000000000..6537e45a459 --- /dev/null +++ b/nixos/modules/services/web-servers/nginx/location-options.nix @@ -0,0 +1,32 @@ +# This file defines the options that can be used both for the Apache +# main server configuration, and for the virtual hosts. (The latter +# has additional options that affect the web server as a whole, like +# the user/group to run under.) + +{ lib }: + +with lib; + +{ + options = { + proxyPass = mkOption { + type = types.nullOr types.str; + default = null; + example = "http://www.example.org/"; + description = '' + Adds proxy_pass directive and sets default proxy headers Host, X-Real-Ip + and X-Forwarded-For. + ''; + }; + + root = mkOption { + type = types.nullOr types.path; + default = null; + example = /your/root/directory; + description = '' + Root directory for requests. + ''; + }; + }; +} + diff --git a/nixos/modules/services/web-servers/nginx/vhost-options.nix b/nixos/modules/services/web-servers/nginx/vhost-options.nix new file mode 100644 index 00000000000..2acb3743677 --- /dev/null +++ b/nixos/modules/services/web-servers/nginx/vhost-options.nix @@ -0,0 +1,96 @@ +# This file defines the options that can be used both for the Apache +# main server configuration, and for the virtual hosts. (The latter +# has additional options that affect the web server as a whole, like +# the user/group to run under.) + +{ lib }: + +with lib; +{ + options = { + serverAliases = mkOption { + type = types.listOf types.str; + default = []; + example = ["www.example.org" "example.org"]; + description = '' + Additional names of virtual hosts served by this virtual host configuration. + ''; + }; + + port = mkOption { + type = types.nullOr types.int; + default = null; + description = '' + Port for the server. 80 for http + and 443 for https (i.e. when enableSSL is set). + ''; + }; + + enableSSL = mkOption { + type = types.bool; + default = false; + description = "Whether to enable SSL (https) support."; + }; + + forceSSL = mkOption { + type = types.bool; + default = false; + description = "Whether to always redirect to https."; + }; + + sslCertificate = mkOption { + type = types.path; + example = "/var/host.cert"; + description = "Path to server SSL certificate."; + }; + + sslCertificateKey= mkOption { + type = types.path; + example = "/var/host.key"; + description = "Path to server SSL certificate key."; + }; + + root = mkOption { + type = types.nullOr types.path; + default = null; + example = "/data/webserver/docs"; + description = '' + The path of the web root directory. + ''; + }; + + extraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + These lines go to the end of the vhost verbatim. + ''; + }; + + globalRedirect = mkOption { + type = types.nullOr types.str; + default = null; + example = http://newserver.example.org/; + description = '' + If set, all requests for this host are redirected permanently to + the given URL. + ''; + }; + + basicAuth = mkOption { + type = types.attrsOf types.str; + default = {}; + description = "user = password"; + }; + + locations = mkOption { + type = types.attrsOf (types.submodule (import ./location-options.nix { + inherit lib; + })); + default = {}; + example = {}; + description = '' + ''; + }; + }; +} From 4676983990b1d35676eba19cee9e24a16e0f60d7 Mon Sep 17 00:00:00 2001 From: Tristan Helmich Date: Mon, 25 Jan 2016 19:36:21 +0100 Subject: [PATCH 02/23] nginx module: Add ACME support for ssl sites --- .../services/web-servers/nginx/default.nix | 27 ++++++++++++++----- .../web-servers/nginx/vhost-options.nix | 14 +++++++++- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index ab5657a9aa9..a84a3c9f2a2 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -4,7 +4,13 @@ with lib; let cfg = config.services.nginx; - nginx = cfg.package; + virtualHosts = mapAttrs (vhostName: vhostConfig: + vhostConfig // (optionalAttrs vhostConfig.enableACME { + sslCertificate = "/var/lib/acme/${vhostName}/fullchain.pem"; + sslCertificateKey = "/var/lib/acme/${vhostName}/key.pem"; + }) + ) cfg.virtualHosts; + configFile = pkgs.writeText "nginx.conf" '' user ${cfg.user} ${cfg.group}; error_log stderr; @@ -72,21 +78,23 @@ let port = if vhost.port != null then vhost.port else (if ssl then 443 else 80); listenString = toString port + optionalString ssl " ssl spdy"; in '' - ${if vhost.forceSSL then '' + ${optionalString vhost.forceSSL '' server { listen 80; listen [::]:80; server_name ${serverName} ${concatStringsSep " " vhost.serverAliases}; + ${optionalString vhost.enableACME "location /.well-known/acme-challenge { root ${vhost.acmeRoot}; }"} return 301 https://$host${optionalString (port != 443) ":${port}"}$request_uri; } - '' else ""} + ''} server { listen ${listenString}; listen [::]:${listenString}; server_name ${serverName} ${concatStringsSep " " vhost.serverAliases}; + ${optionalString vhost.enableACME "location /.well-known/acme-challenge { root ${vhost.acmeRoot}; }"} ${optionalString (vhost.root != null) "root ${vhost.root};"} ${optionalString (vhost.globalRedirect != null) '' return 301 https://${vhost.globalRedirect}$request_uri; @@ -101,7 +109,7 @@ let ${vhost.extraConfig} } '' - ) cfg.virtualHosts); + ) virtualHosts); genLocations = locations: concatStringsSep "\n" (mapAttrsToList (location: config: '' location ${location} { ${optionalString (config.proxyPass != null) "proxy_pass ${config.proxyPass};"} @@ -202,7 +210,6 @@ in description = "Nginx Web Server"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; - path = [ nginx ]; preStart = '' mkdir -p ${cfg.stateDir}/logs @@ -210,7 +217,7 @@ in chown -R ${cfg.user}:${cfg.group} ${cfg.stateDir} ''; serviceConfig = { - ExecStart = "${nginx}/bin/nginx -c ${configFile} -p ${cfg.stateDir}"; + ExecStart = "${cfg.package}/bin/nginx -c ${configFile} -p ${cfg.stateDir}"; ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; Restart = "always"; RestartSec = "10s"; @@ -218,6 +225,14 @@ in }; }; + security.acme.certs = mapAttrs (vhostName: vhostConfig: { + webroot = vhostConfig.acmeRoot; + extraDomains = genAttrs vhostConfig.serverAliases (alias: { + "${alias}" = null; + }); + }) virtualHosts; + + users.extraUsers = optionalAttrs (cfg.user == "nginx") (singleton { name = "nginx"; group = cfg.group; diff --git a/nixos/modules/services/web-servers/nginx/vhost-options.nix b/nixos/modules/services/web-servers/nginx/vhost-options.nix index 2acb3743677..5fa3b18c24f 100644 --- a/nixos/modules/services/web-servers/nginx/vhost-options.nix +++ b/nixos/modules/services/web-servers/nginx/vhost-options.nix @@ -26,6 +26,18 @@ with lib; ''; }; + enableACME = mkOption { + type = types.bool; + default = false; + description = "Whether to ask Let's Encrypt to sign a certificate for this vhost."; + }; + + acmeRoot = mkOption { + type = types.str; + default = "/var/lib/acme/acme-challenge"; + description = "Directory to store certificates and keys managed by the ACME service."; + }; + enableSSL = mkOption { type = types.bool; default = false; @@ -44,7 +56,7 @@ with lib; description = "Path to server SSL certificate."; }; - sslCertificateKey= mkOption { + sslCertificateKey = mkOption { type = types.path; example = "/var/host.key"; description = "Path to server SSL certificate key."; From 900b311a386b82ab66f209c1b9d4c292af08d6dc Mon Sep 17 00:00:00 2001 From: Tristan Helmich Date: Tue, 26 Jan 2016 14:29:30 +0100 Subject: [PATCH 03/23] nginx module: Fix ACME extraDomains, fix challenge url to not redirect to allow renewals --- nixos/modules/services/web-servers/nginx/default.nix | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index a84a3c9f2a2..fb3f554bbf2 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -85,7 +85,9 @@ let server_name ${serverName} ${concatStringsSep " " vhost.serverAliases}; ${optionalString vhost.enableACME "location /.well-known/acme-challenge { root ${vhost.acmeRoot}; }"} - return 301 https://$host${optionalString (port != 443) ":${port}"}$request_uri; + location / { + return 301 https://$host${optionalString (port != 443) ":${port}"}$request_uri; + } } ''} @@ -227,9 +229,7 @@ in security.acme.certs = mapAttrs (vhostName: vhostConfig: { webroot = vhostConfig.acmeRoot; - extraDomains = genAttrs vhostConfig.serverAliases (alias: { - "${alias}" = null; - }); + extraDomains = genAttrs vhostConfig.serverAliases (alias: null); }) virtualHosts; From 8bd1f401bbacf7e6537528d3f2dfd9e610e346c8 Mon Sep 17 00:00:00 2001 From: Tristan Helmich Date: Mon, 1 Feb 2016 14:08:45 +0100 Subject: [PATCH 04/23] nginx module: Add sslProtocols option --- nixos/modules/services/web-servers/nginx/default.nix | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index fb3f554bbf2..75ce9e26a30 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -30,7 +30,7 @@ let types_hash_max_size 2048; # use secure TLS defaults - ssl_protocols TLSv1.2; + ssl_protocols ${cfg.sslProtocols}; ssl_session_cache shared:SSL:42m; ssl_session_timeout 23m; @@ -191,6 +191,13 @@ in description = "Show nginx version in headers and error pages"; }; + sslProtocols = mkOption { + type = types.str; + default = "TLSv1.2"; + example = "TLSv1 TLSv1.1 TLSv1.2"; + description = "Allowed TLS protocol versions."; + }; + virtualHosts = mkOption { type = types.attrsOf (types.submodule (import ./vhost-options.nix { inherit lib; From 35d76a72aba69108a369478be6cb21914d5075a5 Mon Sep 17 00:00:00 2001 From: Tristan Helmich Date: Mon, 1 Feb 2016 14:09:13 +0100 Subject: [PATCH 05/23] nginx module: Add sslCiphers option --- nixos/modules/services/web-servers/nginx/default.nix | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index 75ce9e26a30..b74a35f1e9f 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -34,7 +34,7 @@ let ssl_session_cache shared:SSL:42m; ssl_session_timeout 23m; - ssl_ciphers EDH+aRSA+AES256:+AESGCM:ECDHE+aRSA+AES256; + ssl_ciphers ${cfg.sslCiphers}; ssl_ecdh_curve secp521r1; ssl_prefer_server_ciphers on; @@ -191,6 +191,12 @@ in description = "Show nginx version in headers and error pages"; }; + sslCiphers = mkOption { + type = types.str; + default = "EDH+CHACHA20:EDH+AES:EECDHE+CHACHA20:ECDHE+AES:+AES128:-DSS"; + description = "Ciphers to choose from when negotiating tls handshakes."; + }; + sslProtocols = mkOption { type = types.str; default = "TLSv1.2"; From c61157b7e6512036a7abc04a45df334162b3b111 Mon Sep 17 00:00:00 2001 From: Tristan Helmich Date: Mon, 1 Feb 2016 17:30:43 +0100 Subject: [PATCH 06/23] nginx module: Add dhParams option --- nixos/modules/services/web-servers/nginx/default.nix | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index b74a35f1e9f..e369505fbc3 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -37,6 +37,7 @@ let ssl_ciphers ${cfg.sslCiphers}; ssl_ecdh_curve secp521r1; ssl_prefer_server_ciphers on; + ${optionalString (cfg.sslDhparam != null) "ssl_dhparam ${cfg.sslDhparam};"} ssl_stapling on; ssl_stapling_verify on; @@ -204,6 +205,13 @@ in description = "Allowed TLS protocol versions."; }; + sslDhparam = mkOption { + type = types.nullOr types.path; + default = null; + example = literalExample "/path/to/dhparams.pem"; + description = "Path to DH parameters file."; + }; + virtualHosts = mkOption { type = types.attrsOf (types.submodule (import ./vhost-options.nix { inherit lib; From d5a097fdb609ec5ffb09bcab632e4b2a03ae05ca Mon Sep 17 00:00:00 2001 From: Franz Pletz Date: Mon, 8 Feb 2016 06:12:49 +0100 Subject: [PATCH 07/23] nginx module: Don't create acme certs if acme is not enabled --- nixos/modules/services/web-servers/nginx/default.nix | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index e369505fbc3..18fce9672dd 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -248,10 +248,14 @@ in }; }; - security.acme.certs = mapAttrs (vhostName: vhostConfig: { - webroot = vhostConfig.acmeRoot; - extraDomains = genAttrs vhostConfig.serverAliases (alias: null); - }) virtualHosts; + security.acme.certs = filterAttrs (n: v: v != {}) ( + mapAttrs (vhostName: vhostConfig: + optionalAttrs vhostConfig.enableACME { + webroot = vhostConfig.acmeRoot; + extraDomains = genAttrs vhostConfig.serverAliases (alias: null); + } + ) virtualHosts + ); users.extraUsers = optionalAttrs (cfg.user == "nginx") (singleton From 811f243ce6f1ce82cf93bc5b45e5879513a2a305 Mon Sep 17 00:00:00 2001 From: Franz Pletz Date: Wed, 10 Feb 2016 16:02:38 +0100 Subject: [PATCH 08/23] nginx module: Add extraConfig for locations --- nixos/modules/services/web-servers/nginx/default.nix | 1 + .../services/web-servers/nginx/location-options.nix | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index 18fce9672dd..62348d48f5d 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -117,6 +117,7 @@ let location ${location} { ${optionalString (config.proxyPass != null) "proxy_pass ${config.proxyPass};"} ${optionalString (config.root != null) "root ${config.root};"} + ${config.extraConfig} } '') locations); in diff --git a/nixos/modules/services/web-servers/nginx/location-options.nix b/nixos/modules/services/web-servers/nginx/location-options.nix index 6537e45a459..ce3462bed0a 100644 --- a/nixos/modules/services/web-servers/nginx/location-options.nix +++ b/nixos/modules/services/web-servers/nginx/location-options.nix @@ -27,6 +27,14 @@ with lib; Root directory for requests. ''; }; + + extraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + These lines go to the end of the location verbatim. + ''; + }; }; } From 4e5c7913e9db6906b031bb8310ba811f533854d3 Mon Sep 17 00:00:00 2001 From: Franz Pletz Date: Wed, 17 Feb 2016 04:01:50 +0100 Subject: [PATCH 09/23] nginx module: Add acmeFallbackHost vhost option --- .../modules/services/web-servers/nginx/default.nix | 13 +++++++++++-- .../services/web-servers/nginx/vhost-options.nix | 9 +++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index 62348d48f5d..e48e9b6cfd8 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -78,6 +78,15 @@ let ssl = vhost.enableSSL || vhost.forceSSL; port = if vhost.port != null then vhost.port else (if ssl then 443 else 80); listenString = toString port + optionalString ssl " ssl spdy"; + acmeLocation = optionalString vhost.enableACME '' + location /.well-known/acme-challenge { + try_files $uri @acme-fallback; + root ${vhost.acmeRoot}; + } + location @acme-fallback { + proxy_pass http://${vhost.acmeFallbackHost}; + } + ''; in '' ${optionalString vhost.forceSSL '' server { @@ -85,7 +94,7 @@ let listen [::]:80; server_name ${serverName} ${concatStringsSep " " vhost.serverAliases}; - ${optionalString vhost.enableACME "location /.well-known/acme-challenge { root ${vhost.acmeRoot}; }"} + ${acmeLocation} location / { return 301 https://$host${optionalString (port != 443) ":${port}"}$request_uri; } @@ -97,7 +106,7 @@ let listen [::]:${listenString}; server_name ${serverName} ${concatStringsSep " " vhost.serverAliases}; - ${optionalString vhost.enableACME "location /.well-known/acme-challenge { root ${vhost.acmeRoot}; }"} + ${acmeLocation} ${optionalString (vhost.root != null) "root ${vhost.root};"} ${optionalString (vhost.globalRedirect != null) '' return 301 https://${vhost.globalRedirect}$request_uri; diff --git a/nixos/modules/services/web-servers/nginx/vhost-options.nix b/nixos/modules/services/web-servers/nginx/vhost-options.nix index 5fa3b18c24f..61868d8890d 100644 --- a/nixos/modules/services/web-servers/nginx/vhost-options.nix +++ b/nixos/modules/services/web-servers/nginx/vhost-options.nix @@ -38,6 +38,15 @@ with lib; description = "Directory to store certificates and keys managed by the ACME service."; }; + acmeFallbackHost = mkOption { + type = types.str; + default = "0.0.0.0"; + description = '' + Host which to proxy requests to if acme challenge is not found. Useful + if you want multiple hosts to be able to verify the same domain name. + ''; + }; + enableSSL = mkOption { type = types.bool; default = false; From e18f8e8b6614499794ef704f0272bf986a906b78 Mon Sep 17 00:00:00 2001 From: Robin Gloster Date: Fri, 25 Mar 2016 00:58:45 +0000 Subject: [PATCH 10/23] nginx module: turn off basic auth on acme locations --- nixos/modules/services/web-servers/nginx/default.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index e48e9b6cfd8..b2bcb737a8f 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -82,8 +82,10 @@ let location /.well-known/acme-challenge { try_files $uri @acme-fallback; root ${vhost.acmeRoot}; + auth_basic off; } location @acme-fallback { + auth_basic off; proxy_pass http://${vhost.acmeFallbackHost}; } ''; From ff12ee35b702dca2ed3c3b6671ac232bc850e6d7 Mon Sep 17 00:00:00 2001 From: Robin Gloster Date: Fri, 25 Mar 2016 00:59:34 +0000 Subject: [PATCH 11/23] nginx module: redirect to same protocol --- nixos/modules/services/web-servers/nginx/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index b2bcb737a8f..37526255f8a 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -111,7 +111,7 @@ let ${acmeLocation} ${optionalString (vhost.root != null) "root ${vhost.root};"} ${optionalString (vhost.globalRedirect != null) '' - return 301 https://${vhost.globalRedirect}$request_uri; + return 301 http${optionalString ssl "s"}://${vhost.globalRedirect}$request_uri; ''} ${optionalString ssl '' ssl_certificate ${vhost.sslCertificate}; From 138945500ee71eaac71435a78f627f9c83d035f4 Mon Sep 17 00:00:00 2001 From: Robin Gloster Date: Fri, 25 Mar 2016 01:00:09 +0000 Subject: [PATCH 12/23] nginx module: implement basic auth --- .../services/web-servers/nginx/default.nix | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index 37526255f8a..d4c7cb08eef 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -118,19 +118,31 @@ let ssl_certificate_key ${vhost.sslCertificateKey}; ''} - ${genLocations vhost.locations} + ${optionalString (vhost.basicAuth != {}) (mkBasicAuth serverName vhost.basicAuth)} + + ${mkLocations vhost.locations} ${vhost.extraConfig} } '' ) virtualHosts); - genLocations = locations: concatStringsSep "\n" (mapAttrsToList (location: config: '' + mkLocations = locations: concatStringsSep "\n" (mapAttrsToList (location: config: '' location ${location} { ${optionalString (config.proxyPass != null) "proxy_pass ${config.proxyPass};"} ${optionalString (config.root != null) "root ${config.root};"} ${config.extraConfig} } '') locations); + mkBasicAuth = serverName: authDef: let + htpasswdFile = pkgs.writeText "${serverName}.htpasswd" ( + concatStringsSep "\n" (mapAttrsToList (user: password: '' + ${user}:{PLAIN}${password} + '') authDef) + ); + in '' + auth_basic secured; + auth_basic_user_file ${htpasswdFile}; + ''; in { From 3830a890ab42b35cd4da9991edef47b3c832cbdc Mon Sep 17 00:00:00 2001 From: Robin Gloster Date: Sun, 3 Apr 2016 10:58:34 +0000 Subject: [PATCH 13/23] nginx module: add option to make vhost default --- nixos/modules/services/web-servers/nginx/default.nix | 7 ++++--- .../modules/services/web-servers/nginx/vhost-options.nix | 8 ++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index d4c7cb08eef..e912434e6b0 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -77,7 +77,8 @@ let let ssl = vhost.enableSSL || vhost.forceSSL; port = if vhost.port != null then vhost.port else (if ssl then 443 else 80); - listenString = toString port + optionalString ssl " ssl spdy"; + listenString = toString port + optionalString ssl " ssl spdy" + + optionalString vhost.default " default"; acmeLocation = optionalString vhost.enableACME '' location /.well-known/acme-challenge { try_files $uri @acme-fallback; @@ -92,8 +93,8 @@ let in '' ${optionalString vhost.forceSSL '' server { - listen 80; - listen [::]:80; + listen 80 ${optionalString vhost.default "default"}; + listen [::]:80 ${optionalString vhost.default "default"}; server_name ${serverName} ${concatStringsSep " " vhost.serverAliases}; ${acmeLocation} diff --git a/nixos/modules/services/web-servers/nginx/vhost-options.nix b/nixos/modules/services/web-servers/nginx/vhost-options.nix index 61868d8890d..d684d7c1ff6 100644 --- a/nixos/modules/services/web-servers/nginx/vhost-options.nix +++ b/nixos/modules/services/web-servers/nginx/vhost-options.nix @@ -80,6 +80,14 @@ with lib; ''; }; + default = mkOption { + type = types.bool; + default = false; + description = '' + Makes this vhost the default. + ''; + }; + extraConfig = mkOption { type = types.lines; default = ""; From e982aeae6a2ab4f414b1a505852d69271cb779ae Mon Sep 17 00:00:00 2001 From: Franz Pletz Date: Thu, 7 Apr 2016 17:27:31 +0200 Subject: [PATCH 14/23] nginx module: Add default proxy headers for tomcat --- nixos/modules/services/web-servers/nginx/default.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index e912434e6b0..1338f6aec22 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -54,6 +54,8 @@ let proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Server $host; proxy_set_header Accept-Encoding ""; proxy_redirect off; From de8008a1b182ea2eb1740f8ca2aa2f7e3f37b5e1 Mon Sep 17 00:00:00 2001 From: Franz Pletz Date: Fri, 29 Apr 2016 09:17:30 +0200 Subject: [PATCH 15/23] nginx module: Enable http2 --- nixos/modules/services/web-servers/nginx/default.nix | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index 1338f6aec22..1978de6da6e 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -35,7 +35,7 @@ let ssl_session_timeout 23m; ssl_ciphers ${cfg.sslCiphers}; - ssl_ecdh_curve secp521r1; + ssl_ecdh_curve secp384r1; ssl_prefer_server_ciphers on; ${optionalString (cfg.sslDhparam != null) "ssl_dhparam ${cfg.sslDhparam};"} @@ -79,7 +79,7 @@ let let ssl = vhost.enableSSL || vhost.forceSSL; port = if vhost.port != null then vhost.port else (if ssl then 443 else 80); - listenString = toString port + optionalString ssl " ssl spdy" + listenString = toString port + optionalString ssl " ssl http2" + optionalString vhost.default " default"; acmeLocation = optionalString vhost.enableACME '' location /.well-known/acme-challenge { @@ -221,7 +221,7 @@ in sslCiphers = mkOption { type = types.str; - default = "EDH+CHACHA20:EDH+AES:EECDHE+CHACHA20:ECDHE+AES:+AES128:-DSS"; + default = "EECDH+aRSA+AESGCM:EDH+aRSA:EECDH+aRSA:+AES256:+AES128:+SHA1:!CAMELLIA:!SEED:!3DES:!DES:!RC4:!eNULL"; description = "Ciphers to choose from when negotiating tls handshakes."; }; From 5dd7cf964ac4f65b4d4ae35fcd7f553b7cbae1c0 Mon Sep 17 00:00:00 2001 From: Robin Gloster Date: Mon, 9 May 2016 14:46:44 +0000 Subject: [PATCH 16/23] nginx module: improve documentation --- .../services/web-servers/nginx/default.nix | 15 +++++++++--- .../web-servers/nginx/vhost-options.nix | 23 +++++++++++++++---- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index 1978de6da6e..b3889cb0294 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -235,7 +235,7 @@ in sslDhparam = mkOption { type = types.nullOr types.path; default = null; - example = literalExample "/path/to/dhparams.pem"; + example = "/path/to/dhparams.pem"; description = "Path to DH parameters file."; }; @@ -246,9 +246,18 @@ in default = { localhost = {}; }; - example = []; - description = '' + example = literalExample '' + { + "hydra.example.com" = { + forceSSL = true; + enableACME = true; + locations."/" = { + proxyPass = "http://localhost:3000"; + }; + }; + }; ''; + description = "Declarative vhost config"; }; }; }; diff --git a/nixos/modules/services/web-servers/nginx/vhost-options.nix b/nixos/modules/services/web-servers/nginx/vhost-options.nix index d684d7c1ff6..ee3f68bf805 100644 --- a/nixos/modules/services/web-servers/nginx/vhost-options.nix +++ b/nixos/modules/services/web-servers/nginx/vhost-options.nix @@ -21,7 +21,7 @@ with lib; type = types.nullOr types.int; default = null; description = '' - Port for the server. 80 for http + Port for the server. Defaults to 80 for http and 443 for https (i.e. when enableSSL is set). ''; }; @@ -109,7 +109,17 @@ with lib; basicAuth = mkOption { type = types.attrsOf types.str; default = {}; - description = "user = password"; + example = literalExample '' + { + user = "password"; + }; + ''; + description = '' + Basic Auth protection for a vhost. + + WARNING: This is implemented to store the password in plain text in the + nix store. + ''; }; locations = mkOption { @@ -117,9 +127,14 @@ with lib; inherit lib; })); default = {}; - example = {}; - description = '' + example = literalExample '' + { + "/" = { + proxyPass = "http://localhost:3000"; + }; + }; ''; + description = "Declarative location config"; }; }; } From 186a8400ed80f08d977d8c2d94644d4027b11f45 Mon Sep 17 00:00:00 2001 From: Robin Gloster Date: Mon, 25 Jul 2016 15:10:36 +0000 Subject: [PATCH 17/23] nginx module: make httpConfig backward compatible --- nixos/modules/services/web-servers/nginx/default.nix | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index b3889cb0294..6b6ad0d9b98 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -70,8 +70,14 @@ let server_tokens ${if cfg.serverTokens then "on" else "off"}; ${vhosts} + } + ${optionalString (cfg.httpConfig != "") '' + http { + include ${cfg.package}/conf/mime.types; + include ${cfg.package}/conf/fastcgi.conf; ${cfg.httpConfig} } + ''} ${cfg.appendConfig} ''; From a294ad01b38d9108e02d18aa9788143c15d1e151 Mon Sep 17 00:00:00 2001 From: Robin Gloster Date: Mon, 25 Jul 2016 16:07:53 +0000 Subject: [PATCH 18/23] nginx module: make recommended settings optional --- .../services/web-servers/nginx/default.nix | 110 +++++++++++------- 1 file changed, 70 insertions(+), 40 deletions(-) diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index 6b6ad0d9b98..c8486d3bfcd 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -16,61 +16,65 @@ let error_log stderr; daemon off; - ${cfg.config} - http { include ${cfg.package}/conf/mime.types; include ${cfg.package}/conf/fastcgi.conf; - # optimisation - sendfile on; - tcp_nopush on; - tcp_nodelay on; - keepalive_timeout 65; - types_hash_max_size 2048; + ${optionalString (cfg.recommendedOptimisation) '' + # optimisation + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + ''} - # use secure TLS defaults ssl_protocols ${cfg.sslProtocols}; - ssl_session_cache shared:SSL:42m; - ssl_session_timeout 23m; - ssl_ciphers ${cfg.sslCiphers}; - ssl_ecdh_curve secp384r1; - ssl_prefer_server_ciphers on; ${optionalString (cfg.sslDhparam != null) "ssl_dhparam ${cfg.sslDhparam};"} - ssl_stapling on; - ssl_stapling_verify on; + ${optionalString (cfg.recommendedTlsSettings) '' + ssl_session_cache shared:SSL:42m; + ssl_session_timeout 23m; + ssl_ecdh_curve secp384r1; + ssl_prefer_server_ciphers on; + ssl_stapling on; + ssl_stapling_verify on; + ''} - gzip on; - gzip_disable "msie6"; - gzip_proxied any; - gzip_comp_level 9; - gzip_buffers 16 8k; - gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; + ${optionalString (cfg.recommendedGzipSettings) '' + gzip on; + gzip_disable "msie6"; + gzip_proxied any; + gzip_comp_level 9; + gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; + ''} - # sane proxy settings/headers - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Forwarded-Host $host; - proxy_set_header X-Forwarded-Server $host; - proxy_set_header Accept-Encoding ""; + ${optionalString (cfg.recommendedProxySettings) '' + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Server $host; + proxy_set_header Accept-Encoding ""; + + proxy_redirect off; + proxy_connect_timeout 90; + proxy_send_timeout 90; + proxy_read_timeout 90; + proxy_http_version 1.0; + ''} - proxy_redirect off; client_max_body_size 10m; - client_body_buffer_size 128k; - proxy_connect_timeout 90; - proxy_send_timeout 90; - proxy_read_timeout 90; - proxy_buffers 32 4k; - proxy_buffer_size 8k; - proxy_http_version 1.0; server_tokens ${if cfg.serverTokens then "on" else "off"}; ${vhosts} } + + ${cfg.config} + + # Keep this seperate to allow overriding previous settings ${optionalString (cfg.httpConfig != "") '' http { include ${cfg.package}/conf/mime.types; @@ -157,11 +161,37 @@ in { options = { services.nginx = { - enable = mkOption { + enable = mkEnableOption "Nginx Web Server"; + + recommendedTlsSettings = mkOption { default = false; type = types.bool; description = " - Enable the nginx Web Server. + Enable recommended TLS settings. + "; + }; + + recommendedOptimisation = mkOption { + default = false; + type = types.bool; + description = " + Enable recommended optimisation settings. + "; + }; + + recommendedGzipSettings = mkOption { + default = false; + type = types.bool; + description = " + Enable recommended gzip settings. + "; + }; + + recommendedProxySettings = mkOption { + default = false; + type = types.bool; + description = " + Enable recommended proxy settings. "; }; From 91680de317b0a134c5a6b6bad441013aa6ed233a Mon Sep 17 00:00:00 2001 From: Robin Gloster Date: Tue, 26 Jul 2016 14:09:05 +0000 Subject: [PATCH 19/23] nginx module: add statusPage option --- .../services/web-servers/nginx/default.nix | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index c8486d3bfcd..1e5a8b9bc35 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -69,7 +69,23 @@ let client_max_body_size 10m; server_tokens ${if cfg.serverTokens then "on" else "off"}; + ${vhosts} + + ${optionalString cfg.statusPage '' + server { + listen 80; + listen [::]:80; + + server_name localhost; + + location /nginx_status { + stub_status on; + allow 127.0.0.1; + deny all; + } + } + ''} } ${cfg.config} @@ -163,6 +179,14 @@ in services.nginx = { enable = mkEnableOption "Nginx Web Server"; + statusPage = mkOption { + default = false; + type = types.bool; + description = " + Enable status page reachable from localhost on http://127.0.0.1/nginx_status. + "; + }; + recommendedTlsSettings = mkOption { default = false; type = types.bool; From 8c61b3af0398b1ec93d2abb2b80fa97099155b1c Mon Sep 17 00:00:00 2001 From: Tristan Helmich Date: Tue, 26 Jul 2016 18:11:16 +0200 Subject: [PATCH 20/23] nginx: fixed duplicate http declaration --- nixos/modules/services/web-servers/nginx/default.nix | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index 1e5a8b9bc35..d6b9836498d 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -16,6 +16,8 @@ let error_log stderr; daemon off; + ${cfg.config} + http { include ${cfg.package}/conf/mime.types; include ${cfg.package}/conf/fastcgi.conf; @@ -86,18 +88,10 @@ let } } ''} - } - ${cfg.config} - - # Keep this seperate to allow overriding previous settings - ${optionalString (cfg.httpConfig != "") '' - http { - include ${cfg.package}/conf/mime.types; - include ${cfg.package}/conf/fastcgi.conf; ${cfg.httpConfig} } - ''} + ${cfg.appendConfig} ''; From 511410789be5ef0baa441b1a684b3dff63d33704 Mon Sep 17 00:00:00 2001 From: Robin Gloster Date: Wed, 27 Jul 2016 13:47:31 +0000 Subject: [PATCH 21/23] nginx module: make client_max_body_size configurable --- nixos/modules/services/web-servers/nginx/default.nix | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index d6b9836498d..62737a28935 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -68,7 +68,7 @@ let proxy_http_version 1.0; ''} - client_max_body_size 10m; + client_max_body_size ${cfg.clientMaxBodySize}; server_tokens ${if cfg.serverTokens then "on" else "off"}; @@ -270,7 +270,13 @@ in serverTokens = mkOption { type = types.bool; default = false; - description = "Show nginx version in headers and error pages"; + description = "Show nginx version in headers and error pages."; + }; + + clientMaxBodySize = mkOption { + type = types.string; + default = "10m"; + description = "Set nginx global client_max_body_size."; }; sslCiphers = mkOption { From 3ccfca7d6b6a642bbe7075d09e4ffc0a89743038 Mon Sep 17 00:00:00 2001 From: Robin Gloster Date: Wed, 27 Jul 2016 13:48:13 +0000 Subject: [PATCH 22/23] nginx module: httpConfig backward compatibility Revert httpConfig its old behaviour and make it mutually exclusive to the new structured configuration. Adds appendHttpConfig to have the ability to write custom config in the generated http block. --- .../services/web-servers/nginx/default.nix | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index 62737a28935..ba3618cc101 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -18,6 +18,7 @@ let ${cfg.config} + ${optionalString (cfg.httpConfig == "") '' http { include ${cfg.package}/conf/mime.types; include ${cfg.package}/conf/fastcgi.conf; @@ -89,8 +90,15 @@ let } ''} + ${cfg.appendHttpConfig} + }''} + + ${optionalString (cfg.httpConfig != "") '' + http { + include ${cfg.package}/conf/mime.types; + include ${cfg.package}/conf/fastcgi.conf; ${cfg.httpConfig} - } + }''} ${cfg.appendConfig} ''; @@ -245,7 +253,22 @@ in httpConfig = mkOption { type = types.lines; default = ""; - description = "Configuration lines to be appended inside of the http {} block."; + description = " + Configuration lines to be set inside the http block. + This is mutually exclusive with the structured configuration + via virtualHosts and the recommendedXyzSettings configuration + options. See appendHttpConfig for appending to the generated http block. + "; + }; + + appendHttpConfig = mkOption { + type = types.lines; + default = ""; + description = " + Configuration lines to be appended to the generated http block. + This is mutually exclusive with using httpConfig for specifying the whole + http block verbatim. + "; }; stateDir = mkOption { @@ -353,7 +376,6 @@ in ) virtualHosts ); - users.extraUsers = optionalAttrs (cfg.user == "nginx") (singleton { name = "nginx"; group = cfg.group; From a193fecf0ef3fb2d048981217d6de7a051212e44 Mon Sep 17 00:00:00 2001 From: Robin Gloster Date: Wed, 27 Jul 2016 13:49:46 +0000 Subject: [PATCH 23/23] nginx module: improve statusPage generated code Adds ::1 as allowed host and turns of access_log for the status page. --- nixos/modules/services/web-servers/nginx/default.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index ba3618cc101..8385d8e6026 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -84,7 +84,9 @@ let location /nginx_status { stub_status on; + access_log off; allow 127.0.0.1; + allow ::1; deny all; } }