aboutsummaryrefslogtreecommitdiff
path: root/nixpkgs/nixos/modules/services/web-servers
diff options
context:
space:
mode:
Diffstat (limited to 'nixpkgs/nixos/modules/services/web-servers')
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/apache-httpd/default.nix109
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/caddy.nix66
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/jboss/builder.sh12
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/meguca.nix174
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/molly-brown.nix117
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/nginx/default.nix105
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/phpfpm/default.nix1
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/shellinabox.nix2
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/unit/default.nix5
9 files changed, 321 insertions, 270 deletions
diff --git a/nixpkgs/nixos/modules/services/web-servers/apache-httpd/default.nix b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/default.nix
index 8abee7130d7..6dd1c85132c 100644
--- a/nixpkgs/nixos/modules/services/web-servers/apache-httpd/default.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/default.nix
@@ -6,10 +6,18 @@ let
cfg = config.services.httpd;
+ certs = config.security.acme.certs;
+
runtimeDir = "/run/httpd";
pkg = cfg.package.out;
+ apachectl = pkgs.runCommand "apachectl" { meta.priority = -1; } ''
+ mkdir -p $out/bin
+ cp ${pkg}/bin/apachectl $out/bin/apachectl
+ sed -i $out/bin/apachectl -e 's|$HTTPD -t|$HTTPD -t -f ${httpdConf}|'
+ '';
+
httpdConf = cfg.configFile;
php = cfg.phpPackage.override { apacheHttpd = pkg; };
@@ -20,6 +28,13 @@ let
vhosts = attrValues cfg.virtualHosts;
+ # certName is used later on to determine systemd service names.
+ acmeEnabledVhosts = map (hostOpts: hostOpts // {
+ certName = if hostOpts.useACMEHost != null then hostOpts.useACMEHost else hostOpts.hostName;
+ }) (filter (hostOpts: hostOpts.enableACME || hostOpts.useACMEHost != null) vhosts);
+
+ dependentCertNames = unique (map (hostOpts: hostOpts.certName) acmeEnabledVhosts);
+
mkListenInfo = hostOpts:
if hostOpts.listen != [] then hostOpts.listen
else (
@@ -119,13 +134,13 @@ let
useACME = hostOpts.enableACME || hostOpts.useACMEHost != null;
sslCertDir =
- if hostOpts.enableACME then config.security.acme.certs.${hostOpts.hostName}.directory
- else if hostOpts.useACMEHost != null then config.security.acme.certs.${hostOpts.useACMEHost}.directory
+ if hostOpts.enableACME then certs.${hostOpts.hostName}.directory
+ else if hostOpts.useACMEHost != null then certs.${hostOpts.useACMEHost}.directory
else abort "This case should never happen.";
- sslServerCert = if useACME then "${sslCertDir}/full.pem" else hostOpts.sslServerCert;
+ sslServerCert = if useACME then "${sslCertDir}/fullchain.pem" else hostOpts.sslServerCert;
sslServerKey = if useACME then "${sslCertDir}/key.pem" else hostOpts.sslServerKey;
- sslServerChain = if useACME then "${sslCertDir}/fullchain.pem" else hostOpts.sslServerChain;
+ sslServerChain = if useACME then "${sslCertDir}/chain.pem" else hostOpts.sslServerChain;
acmeChallenge = optionalString useACME ''
Alias /.well-known/acme-challenge/ "${hostOpts.acmeRoot}/.well-known/acme-challenge/"
@@ -341,7 +356,6 @@ let
cat ${php.phpIni} > $out
echo "$options" >> $out
'';
-
in
@@ -641,19 +655,41 @@ in
wwwrun.gid = config.ids.gids.wwwrun;
};
- security.acme.certs = mapAttrs (name: hostOpts: {
- user = cfg.user;
- group = mkDefault cfg.group;
- email = if hostOpts.adminAddr != null then hostOpts.adminAddr else cfg.adminAddr;
- webroot = hostOpts.acmeRoot;
- extraDomains = genAttrs hostOpts.serverAliases (alias: null);
- postRun = "systemctl reload httpd.service";
- }) (filterAttrs (name: hostOpts: hostOpts.enableACME) cfg.virtualHosts);
-
- environment.systemPackages = [ pkg ];
+ security.acme.certs = let
+ acmePairs = map (hostOpts: nameValuePair hostOpts.hostName {
+ group = mkDefault cfg.group;
+ webroot = hostOpts.acmeRoot;
+ extraDomainNames = hostOpts.serverAliases;
+ # Use the vhost-specific email address if provided, otherwise let
+ # security.acme.email or security.acme.certs.<cert>.email be used.
+ email = mkOverride 2000 (if hostOpts.adminAddr != null then hostOpts.adminAddr else cfg.adminAddr);
+ # Filter for enableACME-only vhosts. Don't want to create dud certs
+ }) (filter (hostOpts: hostOpts.useACMEHost == null) acmeEnabledVhosts);
+ in listToAttrs acmePairs;
+
+ environment.systemPackages = [
+ apachectl
+ pkg
+ ];
- # required for "apachectl configtest"
- environment.etc."httpd/httpd.conf".source = httpdConf;
+ services.logrotate = optionalAttrs (cfg.logFormat != "none") {
+ enable = mkDefault true;
+ paths.httpd = {
+ path = "${cfg.logDir}/*.log";
+ user = cfg.user;
+ group = cfg.group;
+ frequency = "daily";
+ keep = 28;
+ extraConfig = ''
+ sharedscripts
+ compress
+ delaycompress
+ postrotate
+ systemctl reload httpd.service > /dev/null 2>/dev/null || true
+ endscript
+ '';
+ };
+ };
services.httpd.phpOptions =
''
@@ -699,15 +735,12 @@ in
"Z '${cfg.logDir}' - ${svc.User} ${svc.Group}"
];
- systemd.services.httpd =
- let
- vhostsACME = filter (hostOpts: hostOpts.enableACME) vhosts;
- in
- { description = "Apache HTTPD";
-
+ systemd.services.httpd = {
+ description = "Apache HTTPD";
wantedBy = [ "multi-user.target" ];
- wants = concatLists (map (hostOpts: [ "acme-${hostOpts.hostName}.service" "acme-selfsigned-${hostOpts.hostName}.service" ]) vhostsACME);
- after = [ "network.target" "fs.target" ] ++ map (hostOpts: "acme-selfsigned-${hostOpts.hostName}.service") vhostsACME;
+ wants = concatLists (map (certName: [ "acme-finished-${certName}.target" ]) dependentCertNames);
+ after = [ "network.target" ] ++ map (certName: "acme-selfsigned-${certName}.service") dependentCertNames;
+ before = map (certName: "acme-${certName}.service") dependentCertNames;
path = [ pkg pkgs.coreutils pkgs.gnugrep ];
@@ -741,5 +774,31 @@ in
};
};
+ # postRun hooks on cert renew can't be used to restart Apache since renewal
+ # runs as the unprivileged acme user. sslTargets are added to wantedBy + before
+ # which allows the acme-finished-$cert.target to signify the successful updating
+ # of certs end-to-end.
+ systemd.services.httpd-config-reload = let
+ sslServices = map (certName: "acme-${certName}.service") dependentCertNames;
+ sslTargets = map (certName: "acme-finished-${certName}.target") dependentCertNames;
+ in mkIf (sslServices != []) {
+ wantedBy = sslServices ++ [ "multi-user.target" ];
+ # Before the finished targets, after the renew services.
+ # This service might be needed for HTTP-01 challenges, but we only want to confirm
+ # certs are updated _after_ config has been reloaded.
+ before = sslTargets;
+ after = sslServices;
+ # Block reloading if not all certs exist yet.
+ # Happens when config changes add new vhosts/certs.
+ unitConfig.ConditionPathExists = map (certName: certs.${certName}.directory + "/fullchain.pem") dependentCertNames;
+ serviceConfig = {
+ Type = "oneshot";
+ TimeoutSec = 60;
+ ExecCondition = "/run/current-system/systemd/bin/systemctl -q is-active httpd.service";
+ ExecStartPre = "${pkg}/bin/httpd -f ${httpdConf} -t";
+ ExecStart = "/run/current-system/systemd/bin/systemctl reload httpd.service";
+ };
+ };
+
};
}
diff --git a/nixpkgs/nixos/modules/services/web-servers/caddy.nix b/nixpkgs/nixos/modules/services/web-servers/caddy.nix
index 0e6e10a5f47..dda26fe491a 100644
--- a/nixpkgs/nixos/modules/services/web-servers/caddy.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/caddy.nix
@@ -5,6 +5,26 @@ with lib;
let
cfg = config.services.caddy;
configFile = pkgs.writeText "Caddyfile" cfg.config;
+
+ # v2-specific options
+ isCaddy2 = versionAtLeast cfg.package.version "2.0";
+ tlsConfig = {
+ apps.tls.automation.policies = [{
+ issuer = {
+ inherit (cfg) ca email;
+ module = "acme";
+ };
+ }];
+ };
+
+ adaptedConfig = pkgs.runCommand "caddy-config-adapted.json" { } ''
+ ${cfg.package}/bin/caddy adapt \
+ --config ${configFile} --adapter ${cfg.adapter} > $out
+ '';
+ tlsJSON = pkgs.writeText "tls.json" (builtins.toJSON tlsConfig);
+ configJSON = pkgs.runCommand "caddy-config.json" { } ''
+ ${pkgs.jq}/bin/jq -s '.[0] * .[1]' ${adaptedConfig} ${tlsJSON} > $out
+ '';
in {
options.services.caddy = {
enable = mkEnableOption "Caddy web server";
@@ -13,15 +33,26 @@ in {
default = "";
example = ''
example.com {
- gzip
- minify
- log syslog
-
- root /srv/http
+ encode gzip
+ log
+ root /srv/http
}
'';
type = types.lines;
- description = "Verbatim Caddyfile to use";
+ description = ''
+ Verbatim Caddyfile to use.
+ Caddy v2 supports multiple config formats via adapters (see <option>services.caddy.adapter</option>).
+ '';
+ };
+
+ adapter = mkOption {
+ default = "caddyfile";
+ example = "nginx";
+ type = types.str;
+ description = ''
+ Name of the config adapter to use. Not applicable to Caddy v1.
+ See https://caddyserver.com/docs/config-adapters for the full list.
+ '';
};
ca = mkOption {
@@ -50,33 +81,46 @@ in {
The data directory, for storing certificates. Before 17.09, this
would create a .caddy directory. With 17.09 the contents of the
.caddy directory are in the specified data directory instead.
+
+ Caddy v2 replaced CADDYPATH with XDG directories.
+ See https://caddyserver.com/docs/conventions#file-locations.
'';
};
package = mkOption {
default = pkgs.caddy;
defaultText = "pkgs.caddy";
+ example = "pkgs.caddy1";
type = types.package;
- description = "Caddy package to use.";
+ description = ''
+ Caddy package to use.
+ To use Caddy v1 (obsolete), set this to <literal>pkgs.caddy1</literal>.
+ '';
};
};
config = mkIf cfg.enable {
systemd.services.caddy = {
description = "Caddy web server";
- # upstream unit: https://github.com/caddyserver/caddy/blob/master/dist/init/linux-systemd/caddy.service
+ # upstream unit: https://github.com/caddyserver/dist/blob/master/init/caddy.service
after = [ "network-online.target" ];
wants = [ "network-online.target" ]; # systemd-networkd-wait-online.service
wantedBy = [ "multi-user.target" ];
- environment = mkIf (versionAtLeast config.system.stateVersion "17.09")
+ environment = mkIf (versionAtLeast config.system.stateVersion "17.09" && !isCaddy2)
{ CADDYPATH = cfg.dataDir; };
serviceConfig = {
- ExecStart = ''
+ ExecStart = if isCaddy2 then ''
+ ${cfg.package}/bin/caddy run --config ${configJSON}
+ '' else ''
${cfg.package}/bin/caddy -log stdout -log-timestamps=false \
-root=/var/tmp -conf=${configFile} \
-ca=${cfg.ca} -email=${cfg.email} ${optionalString cfg.agree "-agree"}
'';
- ExecReload = "${pkgs.coreutils}/bin/kill -USR1 $MAINPID";
+ ExecReload =
+ if isCaddy2 then
+ "${cfg.package}/bin/caddy reload --config ${configJSON}"
+ else
+ "${pkgs.coreutils}/bin/kill -USR1 $MAINPID";
Type = "simple";
User = "caddy";
Group = "caddy";
diff --git a/nixpkgs/nixos/modules/services/web-servers/jboss/builder.sh b/nixpkgs/nixos/modules/services/web-servers/jboss/builder.sh
index 2eb89a90f67..0e5af324c13 100644
--- a/nixpkgs/nixos/modules/services/web-servers/jboss/builder.sh
+++ b/nixpkgs/nixos/modules/services/web-servers/jboss/builder.sh
@@ -28,11 +28,11 @@ stop()
if test "\$1" = start
then
trap stop 15
-
+
start
elif test "\$1" = stop
then
- stop
+ stop
elif test "\$1" = init
then
echo "Are you sure you want to create a new server instance (old server instance will be lost!)?"
@@ -42,21 +42,21 @@ then
then
exit 1
fi
-
+
rm -rf $serverDir
mkdir -p $serverDir
cd $serverDir
cp -av $jboss/server/default .
sed -i -e "s|deploy/|$deployDir|" default/conf/jboss-service.xml
-
+
if ! test "$useJK" = ""
then
sed -i -e 's|<attribute name="UseJK">false</attribute>|<attribute name="UseJK">true</attribute>|' default/deploy/jboss-web.deployer/META-INF/jboss-service.xml
sed -i -e 's|<Engine name="jboss.web" defaultHost="localhost">|<Engine name="jboss.web" defaultHost="localhost" jvmRoute="node1">|' default/deploy/jboss-web.deployer/server.xml
fi
-
+
# Make files accessible for the server user
-
+
chown -R $user $serverDir
for i in \`find $serverDir -type d\`
do
diff --git a/nixpkgs/nixos/modules/services/web-servers/meguca.nix b/nixpkgs/nixos/modules/services/web-servers/meguca.nix
deleted file mode 100644
index 5a00070dc94..00000000000
--- a/nixpkgs/nixos/modules/services/web-servers/meguca.nix
+++ /dev/null
@@ -1,174 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-let
- cfg = config.services.meguca;
- postgres = config.services.postgresql;
-in with lib; {
- options.services.meguca = {
- enable = mkEnableOption "meguca";
-
- dataDir = mkOption {
- type = types.path;
- default = "/var/lib/meguca";
- example = "/home/okina/meguca";
- description = "Location where meguca stores it's database and links.";
- };
-
- password = mkOption {
- type = types.str;
- default = "meguca";
- example = "dumbpass";
- description = "Password for the meguca database.";
- };
-
- passwordFile = mkOption {
- type = types.path;
- default = "/run/keys/meguca-password-file";
- example = "/home/okina/meguca/keys/pass";
- description = "Password file for the meguca database.";
- };
-
- reverseProxy = mkOption {
- type = types.nullOr types.str;
- default = null;
- example = "192.168.1.5";
- description = "Reverse proxy IP.";
- };
-
- sslCertificate = mkOption {
- type = types.nullOr types.str;
- default = null;
- example = "/home/okina/meguca/ssl.cert";
- description = "Path to the SSL certificate.";
- };
-
- listenAddress = mkOption {
- type = types.nullOr types.str;
- default = null;
- example = "127.0.0.1:8000";
- description = "Listen on a specific IP address and port.";
- };
-
- cacheSize = mkOption {
- type = types.nullOr types.int;
- default = null;
- example = 256;
- description = "Cache size in MB.";
- };
-
- postgresArgs = mkOption {
- type = types.str;
- example = "user=meguca password=dumbpass dbname=meguca sslmode=disable";
- description = "Postgresql connection arguments.";
- };
-
- postgresArgsFile = mkOption {
- type = types.path;
- default = "/run/keys/meguca-postgres-args";
- example = "/home/okina/meguca/keys/postgres";
- description = "Postgresql connection arguments file.";
- };
-
- compressTraffic = mkOption {
- type = types.bool;
- default = false;
- description = "Compress all traffic with gzip.";
- };
-
- assumeReverseProxy = mkOption {
- type = types.bool;
- default = false;
- description = "Assume the server is behind a reverse proxy, when resolving client IPs.";
- };
-
- httpsOnly = mkOption {
- type = types.bool;
- default = false;
- description = "Serve and listen only through HTTPS.";
- };
-
- videoPaths = mkOption {
- type = types.listOf types.path;
- default = [];
- example = [ "/home/okina/Videos/tehe_pero.webm" ];
- description = "Videos that will be symlinked into www/videos.";
- };
- };
-
- config = mkIf cfg.enable {
- security.sudo.enable = cfg.enable;
- services.postgresql.enable = cfg.enable;
- services.postgresql.package = pkgs.postgresql_11;
- services.meguca.passwordFile = mkDefault (pkgs.writeText "meguca-password-file" cfg.password);
- services.meguca.postgresArgsFile = mkDefault (pkgs.writeText "meguca-postgres-args" cfg.postgresArgs);
- services.meguca.postgresArgs = mkDefault "user=meguca password=${cfg.password} dbname=meguca sslmode=disable";
-
- systemd.services.meguca = {
- description = "meguca";
- after = [ "network.target" "postgresql.service" ];
- wantedBy = [ "multi-user.target" ];
-
- preStart = ''
- # Ensure folder exists or create it and links and permissions are correct
- mkdir -p ${escapeShellArg cfg.dataDir}/www
- rm -rf ${escapeShellArg cfg.dataDir}/www/videos
- ln -sf ${pkgs.meguca}/share/meguca/www/* ${escapeShellArg cfg.dataDir}/www
- unlink ${escapeShellArg cfg.dataDir}/www/videos
- mkdir -p ${escapeShellArg cfg.dataDir}/www/videos
-
- for vid in ${escapeShellArg cfg.videoPaths}; do
- ln -sf $vid ${escapeShellArg cfg.dataDir}/www/videos
- done
-
- chmod 750 ${escapeShellArg cfg.dataDir}
- chown -R meguca:meguca ${escapeShellArg cfg.dataDir}
-
- # Ensure the database is correct or create it
- ${pkgs.sudo}/bin/sudo -u ${postgres.superUser} ${postgres.package}/bin/createuser \
- -SDR meguca || true
- ${pkgs.sudo}/bin/sudo -u ${postgres.superUser} ${postgres.package}/bin/createdb \
- -T template0 -E UTF8 -O meguca meguca || true
- ${pkgs.sudo}/bin/sudo -u meguca ${postgres.package}/bin/psql \
- -c "ALTER ROLE meguca WITH PASSWORD '$(cat ${escapeShellArg cfg.passwordFile})';" || true
- '';
-
- script = ''
- cd ${escapeShellArg cfg.dataDir}
-
- ${pkgs.meguca}/bin/meguca -d "$(cat ${escapeShellArg cfg.postgresArgsFile})"''
- + optionalString (cfg.reverseProxy != null) " -R ${cfg.reverseProxy}"
- + optionalString (cfg.sslCertificate != null) " -S ${cfg.sslCertificate}"
- + optionalString (cfg.listenAddress != null) " -a ${cfg.listenAddress}"
- + optionalString (cfg.cacheSize != null) " -c ${toString cfg.cacheSize}"
- + optionalString (cfg.compressTraffic) " -g"
- + optionalString (cfg.assumeReverseProxy) " -r"
- + optionalString (cfg.httpsOnly) " -s" + " start";
-
- serviceConfig = {
- PermissionsStartOnly = true;
- Type = "forking";
- User = "meguca";
- Group = "meguca";
- ExecStop = "${pkgs.meguca}/bin/meguca stop";
- };
- };
-
- users = {
- groups.meguca.gid = config.ids.gids.meguca;
-
- users.meguca = {
- description = "meguca server service user";
- home = cfg.dataDir;
- createHome = true;
- group = "meguca";
- uid = config.ids.uids.meguca;
- };
- };
- };
-
- imports = [
- (mkRenamedOptionModule [ "services" "meguca" "baseDir" ] [ "services" "meguca" "dataDir" ])
- ];
-
- meta.maintainers = with maintainers; [ chiiruno ];
-}
diff --git a/nixpkgs/nixos/modules/services/web-servers/molly-brown.nix b/nixpkgs/nixos/modules/services/web-servers/molly-brown.nix
new file mode 100644
index 00000000000..e9052a184b2
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/web-servers/molly-brown.nix
@@ -0,0 +1,117 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ cfg = config.services.molly-brown;
+
+ settingsType = with types;
+ attrsOf (oneOf [
+ int
+ str
+ (listOf str)
+ (attrsOf (oneOf [ int str (listOf str) (attrsOf str) ]))
+ ]) // {
+ description = "primitive expression convertable to TOML";
+ };
+
+ configFile = pkgs.runCommand "molly-brown.toml" {
+ buildInputs = [ pkgs.remarshal ];
+ preferLocalBuild = true;
+ passAsFile = [ "settings" ];
+ settings = builtins.toJSON cfg.settings;
+ } "remarshal -if json -of toml < $settingsPath > $out";
+in {
+
+ options.services.molly-brown = {
+
+ enable = mkEnableOption "Molly-Brown Gemini server";
+
+ port = mkOption {
+ default = 1965;
+ type = types.port;
+ description = ''
+ TCP port for molly-brown to bind to.
+ '';
+ };
+
+ hostName = mkOption {
+ type = types.str;
+ example = literalExample "config.networking.hostName";
+ default = config.networking.hostName;
+ description = ''
+ The hostname to respond to requests for. Requests for URLs with
+ other hosts will result in a status 53 (PROXY REQUEST REFUSED)
+ response.
+ '';
+ };
+
+ certPath = mkOption {
+ type = types.path;
+ example = "/var/lib/acme/example.com/cert.pem";
+ description = ''
+ Path to TLS certificate. An ACME certificate and key may be
+ shared with an HTTP server, but only if molly-brown has
+ permissions allowing it to read such keys.
+
+ As an example:
+ <programlisting>
+ security.acme.certs."example.com".allowKeysForGroup = true;
+ systemd.services.molly-brown.serviceConfig.SupplementaryGroups =
+ [ config.security.acme.certs."example.com".group ];
+ </programlisting>
+ '';
+ };
+
+ keyPath = mkOption {
+ type = types.path;
+ example = "/var/lib/acme/example.com/key.pem";
+ description = "Path to TLS key. See <option>CertPath</option>.";
+ };
+
+ docBase = mkOption {
+ type = types.path;
+ example = "/var/lib/molly-brown";
+ description = "Base directory for Gemini content.";
+ };
+
+ settings = mkOption {
+ type = settingsType;
+ default = { };
+ description = ''
+ molly-brown configuration. Refer to
+ <link xlink:href="https://tildegit.org/solderpunk/molly-brown/src/branch/master/example.conf"/>
+ for details on supported values.
+ '';
+ };
+
+ };
+
+ config = mkIf cfg.enable {
+
+ services.molly-brown.settings = let logDir = "/var/log/molly-brown";
+ in {
+ Port = cfg.port;
+ Hostname = cfg.hostName;
+ CertPath = cfg.certPath;
+ KeyPath = cfg.keyPath;
+ DocBase = cfg.docBase;
+ AccessLog = "${logDir}/access.log";
+ ErrorLog = "${logDir}/error.log";
+ };
+
+ systemd.services.molly-brown = {
+ description = "Molly Brown gemini server";
+ after = [ "network.target" ];
+ wantedBy = [ "multi-user.target" ];
+ serviceConfig = {
+ DynamicUser = true;
+ LogsDirectory = "molly-brown";
+ ExecStart = "${pkgs.molly-brown}/bin/molly-brown -c ${configFile}";
+ Restart = "always";
+ };
+ };
+
+ };
+
+}
diff --git a/nixpkgs/nixos/modules/services/web-servers/nginx/default.nix b/nixpkgs/nixos/modules/services/web-servers/nginx/default.nix
index 8a015bb3556..39bcb14e5af 100644
--- a/nixpkgs/nixos/modules/services/web-servers/nginx/default.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/nginx/default.nix
@@ -6,23 +6,23 @@ let
cfg = config.services.nginx;
certs = config.security.acme.certs;
vhostsConfigs = mapAttrsToList (vhostName: vhostConfig: vhostConfig) virtualHosts;
- acmeEnabledVhosts = filter (vhostConfig: vhostConfig.enableACME && vhostConfig.useACMEHost == null) vhostsConfigs;
+ acmeEnabledVhosts = filter (vhostConfig: vhostConfig.enableACME || vhostConfig.useACMEHost != null) vhostsConfigs;
+ dependentCertNames = unique (map (hostOpts: hostOpts.certName) acmeEnabledVhosts);
virtualHosts = mapAttrs (vhostName: vhostConfig:
let
serverName = if vhostConfig.serverName != null
then vhostConfig.serverName
else vhostName;
+ certName = if vhostConfig.useACMEHost != null
+ then vhostConfig.useACMEHost
+ else serverName;
in
vhostConfig // {
- inherit serverName;
- } // (optionalAttrs vhostConfig.enableACME {
- sslCertificate = "${certs.${serverName}.directory}/fullchain.pem";
- sslCertificateKey = "${certs.${serverName}.directory}/key.pem";
- sslTrustedCertificate = "${certs.${serverName}.directory}/full.pem";
- }) // (optionalAttrs (vhostConfig.useACMEHost != null) {
- sslCertificate = "${certs.${vhostConfig.useACMEHost}.directory}/fullchain.pem";
- sslCertificateKey = "${certs.${vhostConfig.useACMEHost}.directory}/key.pem";
- sslTrustedCertificate = "${certs.${vhostConfig.useACMEHost}.directory}/fullchain.pem";
+ inherit serverName certName;
+ } // (optionalAttrs (vhostConfig.enableACME || vhostConfig.useACMEHost != null) {
+ sslCertificate = "${certs.${certName}.directory}/fullchain.pem";
+ sslCertificateKey = "${certs.${certName}.directory}/key.pem";
+ sslTrustedCertificate = "${certs.${certName}.directory}/chain.pem";
})
) cfg.virtualHosts;
enableIPv6 = config.networking.enableIPv6;
@@ -463,14 +463,6 @@ in
'';
};
- enableSandbox = mkOption {
- default = false;
- type = types.bool;
- description = ''
- Starting Nginx web server with additional sandbox/hardening options.
- '';
- };
-
user = mkOption {
type = types.str;
default = "nginx";
@@ -691,8 +683,12 @@ in
systemd.services.nginx = {
description = "Nginx Web Server";
wantedBy = [ "multi-user.target" ];
- wants = concatLists (map (vhostConfig: ["acme-${vhostConfig.serverName}.service" "acme-selfsigned-${vhostConfig.serverName}.service"]) acmeEnabledVhosts);
- after = [ "network.target" ] ++ map (vhostConfig: "acme-selfsigned-${vhostConfig.serverName}.service") acmeEnabledVhosts;
+ wants = concatLists (map (certName: [ "acme-finished-${certName}.target" ]) dependentCertNames);
+ after = [ "network.target" ] ++ map (certName: "acme-selfsigned-${certName}.service") dependentCertNames;
+ # Nginx needs to be started in order to be able to request certificates
+ # (it's hosting the acme challenge after all)
+ # This fixes https://github.com/NixOS/nixpkgs/issues/81842
+ before = map (certName: "acme-${certName}.service") dependentCertNames;
stopIfChanged = false;
preStart = ''
${cfg.preStart}
@@ -700,7 +696,10 @@ in
'';
serviceConfig = {
ExecStart = execCommand;
- ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+ ExecReload = [
+ "${execCommand} -t"
+ "${pkgs.coreutils}/bin/kill -HUP $MAINPID"
+ ];
Restart = "always";
RestartSec = "10s";
StartLimitInterval = "1min";
@@ -721,7 +720,6 @@ in
CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" "CAP_SYS_RESOURCE" ];
# Security
NoNewPrivileges = true;
- } // optionalAttrs cfg.enableSandbox {
# Sandboxing
ProtectSystem = "strict";
ProtectHome = mkDefault true;
@@ -746,38 +744,41 @@ in
source = configFile;
};
- systemd.services.nginx-config-reload = mkIf cfg.enableReload {
- wants = [ "nginx.service" ];
- wantedBy = [ "multi-user.target" ];
- restartTriggers = [ configFile ];
- # commented, because can cause extra delays during activate for this config:
- # services.nginx.virtualHosts."_".locations."/".proxyPass = "http://blabla:3000";
- # stopIfChanged = false;
- serviceConfig.Type = "oneshot";
- serviceConfig.TimeoutSec = 60;
- script = ''
- if /run/current-system/systemd/bin/systemctl -q is-active nginx.service ; then
- ${execCommand} -t && \
- /run/current-system/systemd/bin/systemctl reload nginx.service
- fi
- '';
- serviceConfig.RemainAfterExit = true;
+ # postRun hooks on cert renew can't be used to restart Nginx since renewal
+ # runs as the unprivileged acme user. sslTargets are added to wantedBy + before
+ # which allows the acme-finished-$cert.target to signify the successful updating
+ # of certs end-to-end.
+ systemd.services.nginx-config-reload = let
+ sslServices = map (certName: "acme-${certName}.service") dependentCertNames;
+ sslTargets = map (certName: "acme-finished-${certName}.target") dependentCertNames;
+ in mkIf (cfg.enableReload || sslServices != []) {
+ wants = optionals (cfg.enableReload) [ "nginx.service" ];
+ wantedBy = sslServices ++ [ "multi-user.target" ];
+ # Before the finished targets, after the renew services.
+ # This service might be needed for HTTP-01 challenges, but we only want to confirm
+ # certs are updated _after_ config has been reloaded.
+ before = sslTargets;
+ after = sslServices;
+ restartTriggers = optionals (cfg.enableReload) [ configFile ];
+ # Block reloading if not all certs exist yet.
+ # Happens when config changes add new vhosts/certs.
+ unitConfig.ConditionPathExists = optionals (sslServices != []) (map (certName: certs.${certName}.directory + "/fullchain.pem") dependentCertNames);
+ serviceConfig = {
+ Type = "oneshot";
+ TimeoutSec = 60;
+ ExecCondition = "/run/current-system/systemd/bin/systemctl -q is-active nginx.service";
+ ExecStart = "/run/current-system/systemd/bin/systemctl reload nginx.service";
+ };
};
- security.acme.certs = filterAttrs (n: v: v != {}) (
- let
- acmePairs = map (vhostConfig: { name = vhostConfig.serverName; value = {
- user = cfg.user;
- group = lib.mkDefault cfg.group;
- webroot = vhostConfig.acmeRoot;
- extraDomains = genAttrs vhostConfig.serverAliases (alias: null);
- postRun = ''
- /run/current-system/systemd/bin/systemctl reload nginx
- '';
- }; }) acmeEnabledVhosts;
- in
- listToAttrs acmePairs
- );
+ security.acme.certs = let
+ acmePairs = map (vhostConfig: nameValuePair vhostConfig.serverName {
+ group = mkDefault cfg.group;
+ webroot = vhostConfig.acmeRoot;
+ extraDomainNames = vhostConfig.serverAliases;
+ # Filter for enableACME-only vhosts. Don't want to create dud certs
+ }) (filter (vhostConfig: vhostConfig.useACMEHost == null) acmeEnabledVhosts);
+ in listToAttrs acmePairs;
users.users = optionalAttrs (cfg.user == "nginx") {
nginx = {
diff --git a/nixpkgs/nixos/modules/services/web-servers/phpfpm/default.nix b/nixpkgs/nixos/modules/services/web-servers/phpfpm/default.nix
index d090885a8ca..759eebf768d 100644
--- a/nixpkgs/nixos/modules/services/web-servers/phpfpm/default.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/phpfpm/default.nix
@@ -277,6 +277,7 @@ in {
ExecReload = "${pkgs.coreutils}/bin/kill -USR2 $MAINPID";
RuntimeDirectory = "phpfpm";
RuntimeDirectoryPreserve = true; # Relevant when multiple processes are running
+ Restart = "always";
};
}
) cfg.pools;
diff --git a/nixpkgs/nixos/modules/services/web-servers/shellinabox.nix b/nixpkgs/nixos/modules/services/web-servers/shellinabox.nix
index 58a02ac59c3..c7c51f873eb 100644
--- a/nixpkgs/nixos/modules/services/web-servers/shellinabox.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/shellinabox.nix
@@ -51,7 +51,7 @@ in
Whether or not to enable SSL (https) support.
'';
};
-
+
certDirectory = mkOption {
type = types.nullOr types.path;
default = null;
diff --git a/nixpkgs/nixos/modules/services/web-servers/unit/default.nix b/nixpkgs/nixos/modules/services/web-servers/unit/default.nix
index 989866144e1..894271d1e55 100644
--- a/nixpkgs/nixos/modules/services/web-servers/unit/default.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/unit/default.nix
@@ -102,7 +102,7 @@ in {
PIDFile = "/run/unit/unit.pid";
ExecStart = ''
${cfg.package}/bin/unitd --control 'unix:/run/unit/control.unit.sock' --pid '/run/unit/unit.pid' \
- --log '${cfg.logDir}/unit.log' --state '${cfg.stateDir}' \
+ --log '${cfg.logDir}/unit.log' --state '${cfg.stateDir}' --tmp '/tmp' \
--user ${cfg.user} --group ${cfg.group}
'';
ExecStop = ''
@@ -120,9 +120,12 @@ in {
ProtectHome = true;
PrivateTmp = true;
PrivateDevices = true;
+ PrivateUsers = false;
ProtectHostname = true;
+ ProtectClock = true;
ProtectKernelTunables = true;
ProtectKernelModules = true;
+ ProtectKernelLogs = true;
ProtectControlGroups = true;
RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ];
LockPersonality = true;