aboutsummaryrefslogtreecommitdiff
path: root/nixpkgs/nixos/modules/services
diff options
context:
space:
mode:
Diffstat (limited to 'nixpkgs/nixos/modules/services')
-rw-r--r--nixpkgs/nixos/modules/services/audio/alsa.nix6
-rw-r--r--nixpkgs/nixos/modules/services/audio/mopidy.nix4
-rw-r--r--nixpkgs/nixos/modules/services/backup/restic.nix56
-rw-r--r--nixpkgs/nixos/modules/services/backup/sanoid.nix213
-rw-r--r--nixpkgs/nixos/modules/services/backup/syncoid.nix168
-rw-r--r--nixpkgs/nixos/modules/services/computing/foldingathome/client.nix81
-rw-r--r--nixpkgs/nixos/modules/services/computing/slurm/slurm.nix1
-rw-r--r--nixpkgs/nixos/modules/services/continuous-integration/buildkite-agents.nix (renamed from nixpkgs/nixos/modules/services/continuous-integration/buildkite-agent.nix)81
-rw-r--r--nixpkgs/nixos/modules/services/databases/mysql.nix103
-rw-r--r--nixpkgs/nixos/modules/services/databases/postgresql.nix35
-rw-r--r--nixpkgs/nixos/modules/services/databases/redis.nix47
-rw-r--r--nixpkgs/nixos/modules/services/desktops/malcontent.nix32
-rw-r--r--nixpkgs/nixos/modules/services/development/jupyter/default.nix6
-rw-r--r--nixpkgs/nixos/modules/services/hardware/fwupd.nix5
-rw-r--r--nixpkgs/nixos/modules/services/hardware/irqbalance.nix14
-rw-r--r--nixpkgs/nixos/modules/services/hardware/tlp.nix142
-rw-r--r--nixpkgs/nixos/modules/services/mail/dovecot.nix234
-rw-r--r--nixpkgs/nixos/modules/services/mail/mailman.nix8
-rw-r--r--nixpkgs/nixos/modules/services/mail/sympa.nix596
-rw-r--r--nixpkgs/nixos/modules/services/misc/ankisyncd.nix79
-rw-r--r--nixpkgs/nixos/modules/services/misc/autorandr.nix2
-rw-r--r--nixpkgs/nixos/modules/services/misc/disnix.nix5
-rw-r--r--nixpkgs/nixos/modules/services/misc/folding-at-home.nix67
-rw-r--r--nixpkgs/nixos/modules/services/misc/home-assistant.nix15
-rw-r--r--nixpkgs/nixos/modules/services/misc/matrix-synapse.nix46
-rw-r--r--nixpkgs/nixos/modules/services/misc/matrix-synapse.xml224
-rw-r--r--nixpkgs/nixos/modules/services/misc/parsoid.nix25
-rw-r--r--nixpkgs/nixos/modules/services/misc/sssd.nix6
-rw-r--r--nixpkgs/nixos/modules/services/misc/zoneminder.nix4
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/cadvisor.nix1
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/heapster.nix2
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/nagios.nix2
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/default.nix27
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.nix17
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/blackbox.nix2
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/collectd.nix2
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/dnsmasq.nix2
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/dovecot.nix2
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/json.nix2
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/mail.nix9
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/mikrotik.nix66
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/minio.nix4
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/nextcloud.nix2
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/nginx.nix13
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/postfix.nix6
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/snmp.nix16
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/unifi.nix4
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/varnish.nix4
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/wireguard.nix2
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/prometheus/xmpp-alerts.nix47
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/statsd.nix2
-rw-r--r--nixpkgs/nixos/modules/services/networking/cjdns.nix52
-rw-r--r--nixpkgs/nixos/modules/services/networking/dhcpcd.nix4
-rw-r--r--nixpkgs/nixos/modules/services/networking/dnscrypt-proxy.nix328
-rw-r--r--nixpkgs/nixos/modules/services/networking/dnscrypt-proxy.xml66
-rw-r--r--nixpkgs/nixos/modules/services/networking/dnscrypt-proxy2.nix61
-rw-r--r--nixpkgs/nixos/modules/services/networking/firewall.nix10
-rw-r--r--nixpkgs/nixos/modules/services/networking/freeradius.nix18
-rw-r--r--nixpkgs/nixos/modules/services/networking/git-daemon.nix4
-rw-r--r--nixpkgs/nixos/modules/services/networking/haproxy.nix26
-rw-r--r--nixpkgs/nixos/modules/services/networking/i2pd.nix22
-rw-r--r--nixpkgs/nixos/modules/services/networking/iodine.nix163
-rw-r--r--nixpkgs/nixos/modules/services/networking/iwd.nix7
-rw-r--r--nixpkgs/nixos/modules/services/networking/knot.nix40
-rw-r--r--nixpkgs/nixos/modules/services/networking/kresd.nix152
-rw-r--r--nixpkgs/nixos/modules/services/networking/minidlna.nix17
-rw-r--r--nixpkgs/nixos/modules/services/networking/nat.nix2
-rw-r--r--nixpkgs/nixos/modules/services/networking/nix-store-gcs-proxy.nix75
-rw-r--r--nixpkgs/nixos/modules/services/networking/nsd.nix4
-rw-r--r--nixpkgs/nixos/modules/services/networking/ntp/ntpd.nix13
-rw-r--r--nixpkgs/nixos/modules/services/networking/pppd.nix4
-rw-r--r--nixpkgs/nixos/modules/services/networking/shorewall.nix9
-rw-r--r--nixpkgs/nixos/modules/services/networking/shorewall6.nix9
-rw-r--r--nixpkgs/nixos/modules/services/networking/smartdns.nix61
-rw-r--r--nixpkgs/nixos/modules/services/networking/ssh/sshd.nix26
-rw-r--r--nixpkgs/nixos/modules/services/networking/sslh.nix9
-rw-r--r--nixpkgs/nixos/modules/services/networking/stubby.nix3
-rw-r--r--nixpkgs/nixos/modules/services/networking/supybot.nix111
-rw-r--r--nixpkgs/nixos/modules/services/networking/tailscale.nix46
-rw-r--r--nixpkgs/nixos/modules/services/networking/vsftpd.nix2
-rw-r--r--nixpkgs/nixos/modules/services/networking/wireguard.nix6
-rw-r--r--nixpkgs/nixos/modules/services/networking/zerotierone.nix11
-rw-r--r--nixpkgs/nixos/modules/services/torrent/transmission.nix3
-rw-r--r--nixpkgs/nixos/modules/services/wayland/cage.nix99
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/codimd.nix2
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/grocy.nix172
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/grocy.xml77
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/jirafeau.nix169
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/limesurvey.nix2
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/mattermost.nix16
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/mediawiki.nix2
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/moodle.nix2
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/nextcloud.nix4
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/wordpress.nix2
-rw-r--r--nixpkgs/nixos/modules/services/web-apps/zabbix.nix2
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/apache-httpd/default.nix210
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/apache-httpd/vhost-options.nix (renamed from nixpkgs/nixos/modules/services/web-servers/apache-httpd/per-server-options.nix)9
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/caddy.nix18
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/nginx/default.nix20
-rw-r--r--nixpkgs/nixos/modules/services/web-servers/uwsgi.nix2
-rw-r--r--nixpkgs/nixos/modules/services/x11/desktop-managers/mate.nix1
-rw-r--r--nixpkgs/nixos/modules/services/x11/desktop-managers/pantheon.nix5
-rw-r--r--nixpkgs/nixos/modules/services/x11/desktop-managers/pantheon.xml130
-rw-r--r--nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix178
-rw-r--r--nixpkgs/nixos/modules/services/x11/desktop-managers/xfce.nix11
-rw-r--r--nixpkgs/nixos/modules/services/x11/display-managers/default.nix7
-rw-r--r--nixpkgs/nixos/modules/services/x11/display-managers/gdm.nix5
-rw-r--r--nixpkgs/nixos/modules/services/x11/display-managers/lightdm-greeters/tiny.nix92
-rw-r--r--nixpkgs/nixos/modules/services/x11/display-managers/lightdm.nix1
-rw-r--r--nixpkgs/nixos/modules/services/x11/unclutter.nix2
-rw-r--r--nixpkgs/nixos/modules/services/x11/urxvtd.nix6
-rw-r--r--nixpkgs/nixos/modules/services/x11/xserver.nix76
112 files changed, 3941 insertions, 1284 deletions
diff --git a/nixpkgs/nixos/modules/services/audio/alsa.nix b/nixpkgs/nixos/modules/services/audio/alsa.nix
index 990398e6546..3fe76a16540 100644
--- a/nixpkgs/nixos/modules/services/audio/alsa.nix
+++ b/nixpkgs/nixos/modules/services/audio/alsa.nix
@@ -91,11 +91,7 @@ in
environment.systemPackages = [ alsaUtils ];
environment.etc = mkIf (!pulseaudioEnabled && config.sound.extraConfig != "")
- [
- { source = pkgs.writeText "asound.conf" config.sound.extraConfig;
- target = "asound.conf";
- }
- ];
+ { "asound.conf".text = config.sound.extraConfig; };
# ALSA provides a udev rule for restoring volume settings.
services.udev.packages = [ alsaUtils ];
diff --git a/nixpkgs/nixos/modules/services/audio/mopidy.nix b/nixpkgs/nixos/modules/services/audio/mopidy.nix
index a534b692f17..d30c227db42 100644
--- a/nixpkgs/nixos/modules/services/audio/mopidy.nix
+++ b/nixpkgs/nixos/modules/services/audio/mopidy.nix
@@ -13,11 +13,11 @@ let
mopidyEnv = buildEnv {
name = "mopidy-with-extensions-${mopidy.version}";
paths = closePropagation cfg.extensionPackages;
- pathsToLink = [ "/${python.sitePackages}" ];
+ pathsToLink = [ "/${python3.sitePackages}" ];
buildInputs = [ makeWrapper ];
postBuild = ''
makeWrapper ${mopidy}/bin/mopidy $out/bin/mopidy \
- --prefix PYTHONPATH : $out/${python.sitePackages}
+ --prefix PYTHONPATH : $out/${python3.sitePackages}
'';
};
in {
diff --git a/nixpkgs/nixos/modules/services/backup/restic.nix b/nixpkgs/nixos/modules/services/backup/restic.nix
index 7e8e91e4b9c..2388f1d6ca1 100644
--- a/nixpkgs/nixos/modules/services/backup/restic.nix
+++ b/nixpkgs/nixos/modules/services/backup/restic.nix
@@ -103,6 +103,34 @@ in
Create the repository if it doesn't exist.
'';
};
+
+ pruneOpts = mkOption {
+ type = types.listOf types.str;
+ default = [];
+ description = ''
+ A list of options (--keep-* et al.) for 'restic forget
+ --prune', to automatically prune old snapshots. The
+ 'forget' command is run *after* the 'backup' command, so
+ keep that in mind when constructing the --keep-* options.
+ '';
+ example = [
+ "--keep-daily 7"
+ "--keep-weekly 5"
+ "--keep-monthly 12"
+ "--keep-yearly 75"
+ ];
+ };
+
+ dynamicFilesFrom = mkOption {
+ type = with types; nullOr str;
+ default = null;
+ description = ''
+ A script that produces a list of files to back up. The
+ results of this command are given to the '--files-from'
+ option.
+ '';
+ example = "find /home/matt/git -type d -name .git";
+ };
};
}));
default = {};
@@ -134,25 +162,41 @@ in
let
extraOptions = concatMapStrings (arg: " -o ${arg}") backup.extraOptions;
resticCmd = "${pkgs.restic}/bin/restic${extraOptions}";
+ filesFromTmpFile = "/run/restic-backups-${name}/includes";
+ backupPaths = if (backup.dynamicFilesFrom == null)
+ then concatStringsSep " " backup.paths
+ else "--files-from ${filesFromTmpFile}";
+ pruneCmd = optionals (builtins.length backup.pruneOpts > 0) [
+ ( resticCmd + " forget --prune " + (concatStringsSep " " backup.pruneOpts) )
+ ( resticCmd + " check" )
+ ];
in nameValuePair "restic-backups-${name}" ({
environment = {
RESTIC_PASSWORD_FILE = backup.passwordFile;
RESTIC_REPOSITORY = backup.repository;
};
- path = with pkgs; [
- openssh
- ];
+ path = [ pkgs.openssh ];
restartIfChanged = false;
serviceConfig = {
Type = "oneshot";
- ExecStart = "${resticCmd} backup ${concatStringsSep " " backup.extraBackupArgs} ${concatStringsSep " " backup.paths}";
+ ExecStart = [ "${resticCmd} backup ${concatStringsSep " " backup.extraBackupArgs} ${backupPaths}" ] ++ pruneCmd;
User = backup.user;
+ RuntimeDirectory = "restic-backups-${name}";
} // optionalAttrs (backup.s3CredentialsFile != null) {
EnvironmentFile = backup.s3CredentialsFile;
};
- } // optionalAttrs backup.initialize {
+ } // optionalAttrs (backup.initialize || backup.dynamicFilesFrom != null) {
preStart = ''
- ${resticCmd} snapshots || ${resticCmd} init
+ ${optionalString (backup.initialize) ''
+ ${resticCmd} snapshots || ${resticCmd} init
+ ''}
+ ${optionalString (backup.dynamicFilesFrom != null) ''
+ ${pkgs.writeScript "dynamicFilesFromScript" backup.dynamicFilesFrom} > ${filesFromTmpFile}
+ ''}
+ '';
+ } // optionalAttrs (backup.dynamicFilesFrom != null) {
+ postStart = ''
+ rm ${filesFromTmpFile}
'';
})
) config.services.restic.backups;
diff --git a/nixpkgs/nixos/modules/services/backup/sanoid.nix b/nixpkgs/nixos/modules/services/backup/sanoid.nix
new file mode 100644
index 00000000000..0472fb4ba1e
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/backup/sanoid.nix
@@ -0,0 +1,213 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ cfg = config.services.sanoid;
+
+ datasetSettingsType = with types;
+ (attrsOf (nullOr (oneOf [ str int bool (listOf str) ]))) // {
+ description = "dataset/template options";
+ };
+
+ # Default values from https://github.com/jimsalterjrs/sanoid/blob/master/sanoid.defaults.conf
+
+ commonOptions = {
+ hourly = mkOption {
+ description = "Number of hourly snapshots.";
+ type = types.ints.unsigned;
+ default = 48;
+ };
+
+ daily = mkOption {
+ description = "Number of daily snapshots.";
+ type = types.ints.unsigned;
+ default = 90;
+ };
+
+ monthly = mkOption {
+ description = "Number of monthly snapshots.";
+ type = types.ints.unsigned;
+ default = 6;
+ };
+
+ yearly = mkOption {
+ description = "Number of yearly snapshots.";
+ type = types.ints.unsigned;
+ default = 0;
+ };
+
+ autoprune = mkOption {
+ description = "Whether to automatically prune old snapshots.";
+ type = types.bool;
+ default = true;
+ };
+
+ autosnap = mkOption {
+ description = "Whether to automatically take snapshots.";
+ type = types.bool;
+ default = true;
+ };
+
+ settings = mkOption {
+ description = ''
+ Free-form settings for this template/dataset. See
+ <link xlink:href="https://github.com/jimsalterjrs/sanoid/blob/master/sanoid.defaults.conf"/>
+ for allowed values.
+ '';
+ type = datasetSettingsType;
+ };
+ };
+
+ commonConfig = config: {
+ settings = {
+ hourly = mkDefault config.hourly;
+ daily = mkDefault config.daily;
+ monthly = mkDefault config.monthly;
+ yearly = mkDefault config.yearly;
+ autoprune = mkDefault config.autoprune;
+ autosnap = mkDefault config.autosnap;
+ };
+ };
+
+ datasetOptions = {
+ useTemplate = mkOption {
+ description = "Names of the templates to use for this dataset.";
+ type = (types.listOf (types.enum (attrNames cfg.templates))) // {
+ description = "list of template names";
+ };
+ default = [];
+ };
+
+ recursive = mkOption {
+ description = "Whether to recursively snapshot dataset children.";
+ type = types.bool;
+ default = false;
+ };
+
+ processChildrenOnly = mkOption {
+ description = "Whether to only snapshot child datasets if recursing.";
+ type = types.bool;
+ default = false;
+ };
+ };
+
+ datasetConfig = config: {
+ settings = {
+ use_template = mkDefault config.useTemplate;
+ recursive = mkDefault config.recursive;
+ process_children_only = mkDefault config.processChildrenOnly;
+ };
+ };
+
+ # Extract pool names from configured datasets
+ pools = unique (map (d: head (builtins.match "([^/]+).*" d)) (attrNames cfg.datasets));
+
+ configFile = let
+ mkValueString = v:
+ if builtins.isList v then concatStringsSep "," v
+ else generators.mkValueStringDefault {} v;
+
+ mkKeyValue = k: v: if v == null then ""
+ else generators.mkKeyValueDefault { inherit mkValueString; } "=" k v;
+ in generators.toINI { inherit mkKeyValue; } cfg.settings;
+
+ configDir = pkgs.writeTextDir "sanoid.conf" configFile;
+
+in {
+
+ # Interface
+
+ options.services.sanoid = {
+ enable = mkEnableOption "Sanoid ZFS snapshotting service";
+
+ interval = mkOption {
+ type = types.str;
+ default = "hourly";
+ example = "daily";
+ description = ''
+ Run sanoid at this interval. The default is to run hourly.
+
+ The format is described in
+ <citerefentry><refentrytitle>systemd.time</refentrytitle>
+ <manvolnum>7</manvolnum></citerefentry>.
+ '';
+ };
+
+ datasets = mkOption {
+ type = types.attrsOf (types.submodule ({ config, ... }: {
+ options = commonOptions // datasetOptions;
+ config = mkMerge [ (commonConfig config) (datasetConfig config) ];
+ }));
+ default = {};
+ description = "Datasets to snapshot.";
+ };
+
+ templates = mkOption {
+ type = types.attrsOf (types.submodule ({ config, ... }: {
+ options = commonOptions;
+ config = commonConfig config;
+ }));
+ default = {};
+ description = "Templates for datasets.";
+ };
+
+ settings = mkOption {
+ type = types.attrsOf datasetSettingsType;
+ description = ''
+ Free-form settings written directly to the config file. See
+ <link xlink:href="https://github.com/jimsalterjrs/sanoid/blob/master/sanoid.defaults.conf"/>
+ for allowed values.
+ '';
+ };
+
+ extraArgs = mkOption {
+ type = types.listOf types.str;
+ default = [];
+ example = [ "--verbose" "--readonly" "--debug" ];
+ description = ''
+ Extra arguments to pass to sanoid. See
+ <link xlink:href="https://github.com/jimsalterjrs/sanoid/#sanoid-command-line-options"/>
+ for allowed options.
+ '';
+ };
+ };
+
+ # Implementation
+
+ config = mkIf cfg.enable {
+ services.sanoid.settings = mkMerge [
+ (mapAttrs' (d: v: nameValuePair ("template_" + d) v.settings) cfg.templates)
+ (mapAttrs (d: v: v.settings) cfg.datasets)
+ ];
+
+ systemd.services.sanoid = {
+ description = "Sanoid snapshot service";
+ serviceConfig = {
+ ExecStartPre = map (pool: lib.escapeShellArgs [
+ "+/run/booted-system/sw/bin/zfs" "allow"
+ "sanoid" "snapshot,mount,destroy" pool
+ ]) pools;
+ ExecStart = lib.escapeShellArgs ([
+ "${pkgs.sanoid}/bin/sanoid"
+ "--cron"
+ "--configdir" configDir
+ ] ++ cfg.extraArgs);
+ ExecStopPost = map (pool: lib.escapeShellArgs [
+ "+/run/booted-system/sw/bin/zfs" "unallow" "sanoid" pool
+ ]) pools;
+ User = "sanoid";
+ Group = "sanoid";
+ DynamicUser = true;
+ RuntimeDirectory = "sanoid";
+ CacheDirectory = "sanoid";
+ };
+ # Prevents missing snapshots during DST changes
+ environment.TZ = "UTC";
+ after = [ "zfs.target" ];
+ startAt = cfg.interval;
+ };
+ };
+
+ meta.maintainers = with maintainers; [ lopsided98 ];
+ }
diff --git a/nixpkgs/nixos/modules/services/backup/syncoid.nix b/nixpkgs/nixos/modules/services/backup/syncoid.nix
new file mode 100644
index 00000000000..53787a0182a
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/backup/syncoid.nix
@@ -0,0 +1,168 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ cfg = config.services.syncoid;
+in {
+
+ # Interface
+
+ options.services.syncoid = {
+ enable = mkEnableOption "Syncoid ZFS synchronization service";
+
+ interval = mkOption {
+ type = types.str;
+ default = "hourly";
+ example = "*-*-* *:15:00";
+ description = ''
+ Run syncoid at this interval. The default is to run hourly.
+
+ The format is described in
+ <citerefentry><refentrytitle>systemd.time</refentrytitle>
+ <manvolnum>7</manvolnum></citerefentry>.
+ '';
+ };
+
+ user = mkOption {
+ type = types.str;
+ default = "root";
+ example = "backup";
+ description = ''
+ The user for the service. Sudo or ZFS privilege delegation must be
+ configured to use a user other than root.
+ '';
+ };
+
+ sshKey = mkOption {
+ type = types.nullOr types.path;
+ # Prevent key from being copied to store
+ apply = mapNullable toString;
+ default = null;
+ description = ''
+ SSH private key file to use to login to the remote system. Can be
+ overridden in individual commands.
+ '';
+ };
+
+ commonArgs = mkOption {
+ type = types.listOf types.str;
+ default = [];
+ example = [ "--no-sync-snap" ];
+ description = ''
+ Arguments to add to every syncoid command, unless disabled for that
+ command. See
+ <link xlink:href="https://github.com/jimsalterjrs/sanoid/#syncoid-command-line-options"/>
+ for available options.
+ '';
+ };
+
+ commands = mkOption {
+ type = types.attrsOf (types.submodule ({ name, ... }: {
+ options = {
+ source = mkOption {
+ type = types.str;
+ example = "pool/dataset";
+ description = ''
+ Source ZFS dataset. Can be either local or remote. Defaults to
+ the attribute name.
+ '';
+ };
+
+ target = mkOption {
+ type = types.str;
+ example = "user@server:pool/dataset";
+ description = ''
+ Target ZFS dataset. Can be either local
+ (<replaceable>pool/dataset</replaceable>) or remote
+ (<replaceable>user@server:pool/dataset</replaceable>).
+ '';
+ };
+
+ recursive = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Whether to also transfer child datasets.
+ '';
+ };
+
+ sshKey = mkOption {
+ type = types.nullOr types.path;
+ # Prevent key from being copied to store
+ apply = mapNullable toString;
+ description = ''
+ SSH private key file to use to login to the remote system.
+ Defaults to <option>services.syncoid.sshKey</option> option.
+ '';
+ };
+
+ sendOptions = mkOption {
+ type = types.separatedString " ";
+ default = "";
+ example = "Lc e";
+ description = ''
+ Advanced options to pass to zfs send. Options are specified
+ without their leading dashes and separated by spaces.
+ '';
+ };
+
+ recvOptions = mkOption {
+ type = types.separatedString " ";
+ default = "";
+ example = "ux recordsize o compression=lz4";
+ description = ''
+ Advanced options to pass to zfs recv. Options are specified
+ without their leading dashes and separated by spaces.
+ '';
+ };
+
+ useCommonArgs = mkOption {
+ type = types.bool;
+ default = true;
+ description = ''
+ Whether to add the configured common arguments to this command.
+ '';
+ };
+
+ extraArgs = mkOption {
+ type = types.listOf types.str;
+ default = [];
+ example = [ "--sshport 2222" ];
+ description = "Extra syncoid arguments for this command.";
+ };
+ };
+ config = {
+ source = mkDefault name;
+ sshKey = mkDefault cfg.sshKey;
+ };
+ }));
+ default = {};
+ example."pool/test".target = "root@target:pool/test";
+ description = "Syncoid commands to run.";
+ };
+ };
+
+ # Implementation
+
+ config = mkIf cfg.enable {
+ systemd.services.syncoid = {
+ description = "Syncoid ZFS synchronization service";
+ script = concatMapStringsSep "\n" (c: lib.escapeShellArgs
+ ([ "${pkgs.sanoid}/bin/syncoid" ]
+ ++ (optionals c.useCommonArgs cfg.commonArgs)
+ ++ (optional c.recursive "-r")
+ ++ (optionals (c.sshKey != null) [ "--sshkey" c.sshKey ])
+ ++ c.extraArgs
+ ++ [ "--sendoptions" c.sendOptions
+ "--recvoptions" c.recvOptions
+ c.source c.target
+ ])) (attrValues cfg.commands);
+ after = [ "zfs.target" ];
+ serviceConfig.User = cfg.user;
+ startAt = cfg.interval;
+ };
+ };
+
+ meta.maintainers = with maintainers; [ lopsided98 ];
+ }
diff --git a/nixpkgs/nixos/modules/services/computing/foldingathome/client.nix b/nixpkgs/nixos/modules/services/computing/foldingathome/client.nix
new file mode 100644
index 00000000000..9f99af48c48
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/computing/foldingathome/client.nix
@@ -0,0 +1,81 @@
+{ config, lib, pkgs, ... }:
+with lib;
+let
+ cfg = config.services.foldingathome;
+
+ args =
+ ["--team" "${toString cfg.team}"]
+ ++ lib.optionals (cfg.user != null) ["--user" cfg.user]
+ ++ cfg.extraArgs
+ ;
+in
+{
+ imports = [
+ (mkRenamedOptionModule [ "services" "foldingAtHome" ] [ "services" "foldingathome" ])
+ (mkRenamedOptionModule [ "services" "foldingathome" "nickname" ] [ "services" "foldingathome" "user" ])
+ (mkRemovedOptionModule [ "services" "foldingathome" "config" ] ''
+ Use <literal>services.foldingathome.extraArgs instead<literal>
+ '')
+ ];
+ options.services.foldingathome = {
+ enable = mkEnableOption "Enable the Folding@home client";
+
+ package = mkOption {
+ type = types.package;
+ default = pkgs.fahclient;
+ defaultText = "pkgs.fahclient";
+ description = ''
+ Which Folding@home client to use.
+ '';
+ };
+
+ user = mkOption {
+ type = types.nullOr types.str;
+ default = null;
+ description = ''
+ The user associated with the reported computation results. This will
+ be used in the ranking statistics.
+ '';
+ };
+
+ team = mkOption {
+ type = types.int;
+ default = 236565;
+ description = ''
+ The team ID associated with the reported computation results. This
+ will be used in the ranking statistics.
+
+ By default, use the NixOS folding@home team ID is being used.
+ '';
+ };
+
+ extraArgs = mkOption {
+ type = types.listOf types.str;
+ default = [];
+ description = ''
+ Extra startup options for the FAHClient. Run
+ <literal>FAHClient --help</literal> to find all the available options.
+ '';
+ };
+ };
+
+ config = mkIf cfg.enable {
+ systemd.services.foldingathome = {
+ description = "Folding@home client";
+ after = [ "network.target" ];
+ wantedBy = [ "multi-user.target" ];
+ script = ''
+ exec ${cfg.package}/bin/FAHClient ${lib.escapeShellArgs args}
+ '';
+ serviceConfig = {
+ DynamicUser = true;
+ StateDirectory = "foldingathome";
+ WorkingDirectory = "%S/foldingathome";
+ };
+ };
+ };
+
+ meta = {
+ maintainers = with lib.maintainers; [ zimbatm ];
+ };
+}
diff --git a/nixpkgs/nixos/modules/services/computing/slurm/slurm.nix b/nixpkgs/nixos/modules/services/computing/slurm/slurm.nix
index c70d999ca96..050872e933f 100644
--- a/nixpkgs/nixos/modules/services/computing/slurm/slurm.nix
+++ b/nixpkgs/nixos/modules/services/computing/slurm/slurm.nix
@@ -355,6 +355,7 @@ in
ExecStart = "${wrappedSlurm}/bin/slurmd";
PIDFile = "/run/slurmd.pid";
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+ LimitMEMLOCK = "infinity";
};
preStart = ''
diff --git a/nixpkgs/nixos/modules/services/continuous-integration/buildkite-agent.nix b/nixpkgs/nixos/modules/services/continuous-integration/buildkite-agents.nix
index 58bce654941..c17d89c387a 100644
--- a/nixpkgs/nixos/modules/services/continuous-integration/buildkite-agent.nix
+++ b/nixpkgs/nixos/modules/services/continuous-integration/buildkite-agents.nix
@@ -3,7 +3,7 @@
with lib;
let
- cfg = config.services.buildkite-agent;
+ cfg = config.services.buildkite-agents;
mkHookOption = { name, description, example ? null }: {
inherit name;
@@ -15,7 +15,7 @@ let
};
mkHookOptions = hooks: listToAttrs (map mkHookOption hooks);
- hooksDir = let
+ hooksDir = cfg: let
mkHookEntry = name: value: ''
cat > $out/${name} <<'EOF'
#! ${pkgs.runtimeShell}
@@ -29,12 +29,13 @@ let
${concatStringsSep "\n" (mapAttrsToList mkHookEntry (filterAttrs (n: v: v != null) cfg.hooks))}
'';
-in
-
-{
- options = {
- services.buildkite-agent = {
- enable = mkEnableOption "buildkite-agent";
+ buildkiteOptions = { name ? "", config, ... }: {
+ options = {
+ enable = mkOption {
+ default = true;
+ type = types.bool;
+ description = "Whether to enable this buildkite agent";
+ };
package = mkOption {
default = pkgs.buildkite-agent;
@@ -44,7 +45,7 @@ in
};
dataDir = mkOption {
- default = "/var/lib/buildkite-agent";
+ default = "/var/lib/buildkite-agent-${name}";
description = "The workdir for the agent";
type = types.str;
};
@@ -68,9 +69,9 @@ in
name = mkOption {
type = types.str;
- default = "%hostname-%n";
+ default = "%hostname-${name}-%n";
description = ''
- The name of the agent.
+ The name of the agent as seen in the buildkite dashboard.
'';
};
@@ -166,11 +167,11 @@ in
hooksPath = mkOption {
type = types.path;
- default = hooksDir;
- defaultText = "generated from services.buildkite-agent.hooks";
+ default = hooksDir config;
+ defaultText = "generated from services.buildkite-agents.<name>.hooks";
description = ''
Path to the directory storing the hooks.
- Consider using <option>services.buildkite-agent.hooks.&lt;name&gt;</option>
+ Consider using <option>services.buildkite-agents.&lt;name&gt;.hooks.&lt;name&gt;</option>
instead.
'';
};
@@ -184,24 +185,38 @@ in
};
};
};
+ enabledAgents = lib.filterAttrs (n: v: v.enable) cfg;
+ mapAgents = function: lib.mkMerge (lib.mapAttrsToList function enabledAgents);
+in
+{
+ options.services.buildkite-agents = mkOption {
+ type = types.attrsOf (types.submodule buildkiteOptions);
+ default = {};
+ description = ''
+ Attribute set of buildkite agents.
+ The attribute key is combined with the hostname and a unique integer to
+ create the final agent name. This can be overridden by setting the `name`
+ attribute.
+ '';
+ };
- config = mkIf config.services.buildkite-agent.enable {
- users.users.buildkite-agent = {
- name = "buildkite-agent";
+ config.users.users = mapAgents (name: cfg: {
+ "buildkite-agent-${name}" = {
+ name = "buildkite-agent-${name}";
home = cfg.dataDir;
createHome = true;
description = "Buildkite agent user";
extraGroups = [ "keys" ];
isSystemUser = true;
};
+ });
- environment.systemPackages = [ cfg.package ];
-
- systemd.services.buildkite-agent =
+ config.systemd.services = mapAgents (name: cfg: {
+ "buildkite-agent-${name}" =
{ description = "Buildkite Agent";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
- path = cfg.runtimePackages ++ [ pkgs.coreutils ];
+ path = cfg.runtimePackages ++ [ cfg.package pkgs.coreutils ];
environment = config.networking.proxy.envVars // {
HOME = cfg.dataDir;
NIX_REMOTE = "daemon";
@@ -230,8 +245,8 @@ in
'';
serviceConfig =
- { ExecStart = "${cfg.package}/bin/buildkite-agent start --config /var/lib/buildkite-agent/buildkite-agent.cfg";
- User = "buildkite-agent";
+ { ExecStart = "${cfg.package}/bin/buildkite-agent start --config ${cfg.dataDir}/buildkite-agent.cfg";
+ User = "buildkite-agent-${name}";
RestartSec = 5;
Restart = "on-failure";
TimeoutSec = 10;
@@ -240,22 +255,18 @@ in
KillMode = "mixed";
};
};
+ });
- assertions = [
- { assertion = cfg.hooksPath == hooksDir || all (v: v == null) (attrValues cfg.hooks);
+ config.assertions = mapAgents (name: cfg: [
+ { assertion = cfg.hooksPath == (hooksDir cfg) || all (v: v == null) (attrValues cfg.hooks);
message = ''
- Options `services.buildkite-agent.hooksPath' and
- `services.buildkite-agent.hooks.<name>' are mutually exclusive.
+ Options `services.buildkite-agents.${name}.hooksPath' and
+ `services.buildkite-agents.${name}.hooks.<name>' are mutually exclusive.
'';
}
- ];
- };
+ ]);
+
imports = [
- (mkRenamedOptionModule [ "services" "buildkite-agent" "token" ] [ "services" "buildkite-agent" "tokenPath" ])
- (mkRenamedOptionModule [ "services" "buildkite-agent" "openssh" "privateKey" ] [ "services" "buildkite-agent" "privateSshKeyPath" ])
- (mkRenamedOptionModule [ "services" "buildkite-agent" "openssh" "privateKeyPath" ] [ "services" "buildkite-agent" "privateSshKeyPath" ])
- (mkRemovedOptionModule [ "services" "buildkite-agent" "openssh" "publicKey" ] "SSH public keys aren't necessary to clone private repos.")
- (mkRemovedOptionModule [ "services" "buildkite-agent" "openssh" "publicKeyPath" ] "SSH public keys aren't necessary to clone private repos.")
- (mkRenamedOptionModule [ "services" "buildkite-agent" "meta-data"] [ "services" "buildkite-agent" "tags" ])
+ (mkRemovedOptionModule [ "services" "buildkite-agent"] "services.buildkite-agent has been upgraded from version 2 to version 3 and moved to an attribute set at services.buildkite-agents. Please consult the 20.03 release notes for more information.")
];
}
diff --git a/nixpkgs/nixos/modules/services/databases/mysql.nix b/nixpkgs/nixos/modules/services/databases/mysql.nix
index 8d520b82fb5..248bf0ebc91 100644
--- a/nixpkgs/nixos/modules/services/databases/mysql.nix
+++ b/nixpkgs/nixos/modules/services/databases/mysql.nix
@@ -21,6 +21,11 @@ let
installOptions =
"${mysqldOptions} ${lib.optionalString isMysqlAtLeast57 "--insecure"}";
+ settingsFile = pkgs.writeText "my.cnf" (
+ generators.toINI { listsAsDuplicateKeys = true; } cfg.settings +
+ optionalString (cfg.extraOptions != null) "[mysqld]\n${cfg.extraOptions}"
+ );
+
in
{
@@ -76,9 +81,64 @@ in
description = "Location where MySQL stores its table files";
};
+ configFile = mkOption {
+ type = types.path;
+ default = settingsFile;
+ defaultText = "settingsFile";
+ description = ''
+ Override the configuration file used by MySQL. By default,
+ NixOS generates one automatically from <option>services.mysql.settings</option>.
+ '';
+ example = literalExample ''
+ pkgs.writeText "my.cnf" '''
+ [mysqld]
+ datadir = /var/lib/mysql
+ bind-address = 127.0.0.1
+ port = 3336
+ plugin-load-add = auth_socket.so
+
+ !includedir /etc/mysql/conf.d/
+ ''';
+ '';
+ };
+
+ settings = mkOption {
+ type = with types; attrsOf (attrsOf (oneOf [ bool int str (listOf str) ]));
+ default = {};
+ description = ''
+ MySQL configuration. Refer to
+ <link xlink:href="https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html"/>,
+ <link xlink:href="https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html"/>,
+ and <link xlink:href="https://mariadb.com/kb/en/server-system-variables/"/>
+ for details on supported values.
+
+ <note>
+ <para>
+ MySQL configuration options such as <literal>--quick</literal> should be treated as
+ boolean options and provided values such as <literal>true</literal>, <literal>false</literal>,
+ <literal>1</literal>, or <literal>0</literal>. See the provided example below.
+ </para>
+ </note>
+ '';
+ example = literalExample ''
+ {
+ mysqld = {
+ key_buffer_size = "6G";
+ table_cache = 1600;
+ log-error = "/var/log/mysql_err.log";
+ plugin-load-add = [ "server_audit" "ed25519=auth_ed25519" ];
+ };
+ mysqldump = {
+ quick = true;
+ max_allowed_packet = "16M";
+ };
+ }
+ '';
+ };
+
extraOptions = mkOption {
- type = types.lines;
- default = "";
+ type = with types; nullOr lines;
+ default = null;
example = ''
key_buffer_size = 6G
table_cache = 1600
@@ -252,10 +312,27 @@ in
config = mkIf config.services.mysql.enable {
+ warnings = optional (cfg.extraOptions != null) "services.mysql.`extraOptions` is deprecated, please use services.mysql.`settings`.";
+
services.mysql.dataDir =
mkDefault (if versionAtLeast config.system.stateVersion "17.09" then "/var/lib/mysql"
else "/var/mysql");
+ services.mysql.settings.mysqld = mkMerge [
+ {
+ datadir = cfg.dataDir;
+ bind-address = mkIf (cfg.bind != null) cfg.bind;
+ port = cfg.port;
+ plugin-load-add = optional (cfg.ensureUsers != []) "auth_socket.so";
+ }
+ (mkIf (cfg.replication.role == "master" || cfg.replication.role == "slave") {
+ log-bin = "mysql-bin-${toString cfg.replication.serverId}";
+ log-bin-index = "mysql-bin-${toString cfg.replication.serverId}.index";
+ relay-log = "mysql-relay-bin";
+ server-id = cfg.replication.serverId;
+ })
+ ];
+
users.users.mysql = {
description = "MySQL server user";
group = "mysql";
@@ -266,25 +343,7 @@ in
environment.systemPackages = [mysql];
- environment.etc."my.cnf".text =
- ''
- [mysqld]
- port = ${toString cfg.port}
- datadir = ${cfg.dataDir}
- ${optionalString (cfg.bind != null) "bind-address = ${cfg.bind}" }
- ${optionalString (cfg.replication.role == "master" || cfg.replication.role == "slave")
- ''
- log-bin=mysql-bin-${toString cfg.replication.serverId}
- log-bin-index=mysql-bin-${toString cfg.replication.serverId}.index
- relay-log=mysql-relay-bin
- server-id = ${toString cfg.replication.serverId}
- ''}
- ${optionalString (cfg.ensureUsers != [])
- ''
- plugin-load-add = auth_socket.so
- ''}
- ${cfg.extraOptions}
- '';
+ environment.etc."my.cnf".source = cfg.configFile;
systemd.tmpfiles.rules = [
"d '${cfg.dataDir}' 0700 ${cfg.user} mysql -"
@@ -297,7 +356,7 @@ in
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
- restartTriggers = [ config.environment.etc."my.cnf".source ];
+ restartTriggers = [ cfg.configFile ];
unitConfig.RequiresMountsFor = "${cfg.dataDir}";
diff --git a/nixpkgs/nixos/modules/services/databases/postgresql.nix b/nixpkgs/nixos/modules/services/databases/postgresql.nix
index c8fdd89d0d8..0b79a996dc7 100644
--- a/nixpkgs/nixos/modules/services/databases/postgresql.nix
+++ b/nixpkgs/nixos/modules/services/databases/postgresql.nix
@@ -20,7 +20,9 @@ let
listen_addresses = '${if cfg.enableTCPIP then "*" else "localhost"}'
port = ${toString cfg.port}
${cfg.extraConfig}
- '';
+ '';
+
+ groupAccessAvailable = versionAtLeast postgresql.version "11.0";
in
@@ -88,6 +90,16 @@ in
'';
};
+ initdbArgs = mkOption {
+ type = with types; listOf str;
+ default = [];
+ example = [ "--data-checksums" "--allow-group-access" ];
+ description = ''
+ Additional arguments passed to <literal>initdb</literal> during data dir
+ initialisation.
+ '';
+ };
+
initialScript = mkOption {
type = types.nullOr types.path;
default = null;
@@ -220,7 +232,7 @@ in
###### implementation
- config = mkIf config.services.postgresql.enable {
+ config = mkIf cfg.enable {
services.postgresql.package =
# Note: when changing the default, make it conditional on
@@ -232,13 +244,14 @@ in
else throw "postgresql_9_4 was removed, please upgrade your postgresql version.");
services.postgresql.dataDir =
- mkDefault (if versionAtLeast config.system.stateVersion "17.09" then "/var/lib/postgresql/${config.services.postgresql.package.psqlSchema}"
- else "/var/db/postgresql");
+ mkDefault (if versionAtLeast config.system.stateVersion "17.09"
+ then "/var/lib/postgresql/${cfg.package.psqlSchema}"
+ else "/var/db/postgresql");
services.postgresql.authentication = mkAfter
''
# Generated file; do not edit!
- local all all ident
+ local all all peer
host all all 127.0.0.1/32 md5
host all all ::1/128 md5
'';
@@ -284,7 +297,7 @@ in
''
# Initialise the database.
if ! test -e ${cfg.dataDir}/PG_VERSION; then
- initdb -U ${cfg.superUser}
+ initdb -U ${cfg.superUser} ${concatStringsSep " " cfg.initdbArgs}
# See postStart!
touch "${cfg.dataDir}/.first_startup"
fi
@@ -293,8 +306,12 @@ in
ln -sfn "${pkgs.writeText "recovery.conf" cfg.recoveryConfig}" \
"${cfg.dataDir}/recovery.conf"
''}
+ ${optionalString (!groupAccessAvailable) ''
+ # postgresql pre 11.0 doesn't start if state directory mode is group accessible
+ chmod 0700 "${cfg.dataDir}"
+ ''}
- exec postgres
+ exec postgres
'';
serviceConfig =
@@ -303,7 +320,7 @@ in
Group = "postgres";
PermissionsStartOnly = true;
RuntimeDirectory = "postgresql";
- Type = if lib.versionAtLeast cfg.package.version "9.6"
+ Type = if versionAtLeast cfg.package.version "9.6"
then "notify"
else "simple";
@@ -352,5 +369,5 @@ in
};
meta.doc = ./postgresql.xml;
- meta.maintainers = with lib.maintainers; [ thoughtpolice ];
+ meta.maintainers = with lib.maintainers; [ thoughtpolice danbst ];
}
diff --git a/nixpkgs/nixos/modules/services/databases/redis.nix b/nixpkgs/nixos/modules/services/databases/redis.nix
index 70895fa53e4..5c817422aae 100644
--- a/nixpkgs/nixos/modules/services/databases/redis.nix
+++ b/nixpkgs/nixos/modules/services/databases/redis.nix
@@ -150,10 +150,20 @@ in
requirePass = mkOption {
type = with types; nullOr str;
default = null;
- description = "Password for database (STORED PLAIN TEXT, WORLD-READABLE IN NIX STORE)";
+ description = ''
+ Password for database (STORED PLAIN TEXT, WORLD-READABLE IN NIX STORE).
+ Use requirePassFile to store it outside of the nix store in a dedicated file.
+ '';
example = "letmein!";
};
+ requirePassFile = mkOption {
+ type = with types; nullOr path;
+ default = null;
+ description = "File with password for the database.";
+ example = "/run/keys/redis-password";
+ };
+
appendOnly = mkOption {
type = types.bool;
default = false;
@@ -192,6 +202,10 @@ in
###### implementation
config = mkIf config.services.redis.enable {
+ assertions = [{
+ assertion = cfg.requirePass != null -> cfg.requirePassFile == null;
+ message = "You can only set one services.redis.requirePass or services.redis.requirePassFile";
+ }];
boot.kernel.sysctl = (mkMerge [
{ "vm.nr_hugepages" = "0"; }
( mkIf cfg.vmOverCommit { "vm.overcommit_memory" = "1"; } )
@@ -208,21 +222,26 @@ in
environment.systemPackages = [ cfg.package ];
- systemd.services.redis =
- { description = "Redis Server";
+ systemd.services.redis = {
+ description = "Redis Server";
- wantedBy = [ "multi-user.target" ];
- after = [ "network.target" ];
+ wantedBy = [ "multi-user.target" ];
+ after = [ "network.target" ];
- serviceConfig = {
- ExecStart = "${cfg.package}/bin/redis-server ${redisConfig}";
- RuntimeDirectory = "redis";
- StateDirectory = "redis";
- Type = "notify";
- User = "redis";
- };
- };
+ preStart = ''
+ install -m 600 ${redisConfig} /run/redis/redis.conf
+ '' + optionalString (cfg.requirePassFile != null) ''
+ password=$(cat ${escapeShellArg cfg.requirePassFile})
+ echo "requirePass $password" >> /run/redis/redis.conf
+ '';
+ serviceConfig = {
+ ExecStart = "${cfg.package}/bin/redis-server /run/redis/redis.conf";
+ RuntimeDirectory = "redis";
+ StateDirectory = "redis";
+ Type = "notify";
+ User = "redis";
+ };
+ };
};
-
}
diff --git a/nixpkgs/nixos/modules/services/desktops/malcontent.nix b/nixpkgs/nixos/modules/services/desktops/malcontent.nix
new file mode 100644
index 00000000000..416464cbe08
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/desktops/malcontent.nix
@@ -0,0 +1,32 @@
+# Malcontent daemon.
+
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+
+ ###### interface
+
+ options = {
+
+ services.malcontent = {
+
+ enable = mkEnableOption "Malcontent";
+
+ };
+
+ };
+
+
+ ###### implementation
+
+ config = mkIf config.services.malcontent.enable {
+
+ environment.systemPackages = [ pkgs.malcontent ];
+
+ services.dbus.packages = [ pkgs.malcontent ];
+
+ };
+
+}
diff --git a/nixpkgs/nixos/modules/services/development/jupyter/default.nix b/nixpkgs/nixos/modules/services/development/jupyter/default.nix
index f20860af6e1..e598b018645 100644
--- a/nixpkgs/nixos/modules/services/development/jupyter/default.nix
+++ b/nixpkgs/nixos/modules/services/development/jupyter/default.nix
@@ -118,15 +118,15 @@ in {
in {
displayName = "Python 3 for machine learning";
argv = [
- "$ {env.interpreter}"
+ "''${env.interpreter}"
"-m"
"ipykernel_launcher"
"-f"
"{connection_file}"
];
language = "python";
- logo32 = "$ {env.sitePackages}/ipykernel/resources/logo-32x32.png";
- logo64 = "$ {env.sitePackages}/ipykernel/resources/logo-64x64.png";
+ logo32 = "''${env.sitePackages}/ipykernel/resources/logo-32x32.png";
+ logo64 = "''${env.sitePackages}/ipykernel/resources/logo-64x64.png";
};
}
'';
diff --git a/nixpkgs/nixos/modules/services/hardware/fwupd.nix b/nixpkgs/nixos/modules/services/hardware/fwupd.nix
index 51877970a8b..e586af25c2b 100644
--- a/nixpkgs/nixos/modules/services/hardware/fwupd.nix
+++ b/nixpkgs/nixos/modules/services/hardware/fwupd.nix
@@ -53,7 +53,7 @@ in {
blacklistPlugins = mkOption {
type = types.listOf types.str;
- default = [ "test" ];
+ default = [];
example = [ "udev" ];
description = ''
Allow blacklisting specific plugins
@@ -91,6 +91,9 @@ in {
###### implementation
config = mkIf cfg.enable {
+ # Disable test related plug-ins implicitly so that users do not have to care about them.
+ services.fwupd.blacklistPlugins = cfg.package.defaultBlacklistedPlugins;
+
environment.systemPackages = [ cfg.package ];
environment.etc = {
diff --git a/nixpkgs/nixos/modules/services/hardware/irqbalance.nix b/nixpkgs/nixos/modules/services/hardware/irqbalance.nix
index b139154432c..c79e0eb83ec 100644
--- a/nixpkgs/nixos/modules/services/hardware/irqbalance.nix
+++ b/nixpkgs/nixos/modules/services/hardware/irqbalance.nix
@@ -13,18 +13,12 @@ in
config = mkIf cfg.enable {
- systemd.services = {
- irqbalance = {
- description = "irqbalance daemon";
- path = [ pkgs.irqbalance ];
- serviceConfig =
- { ExecStart = "${pkgs.irqbalance}/bin/irqbalance --foreground"; };
- wantedBy = [ "multi-user.target" ];
- };
- };
-
environment.systemPackages = [ pkgs.irqbalance ];
+ systemd.services.irqbalance.wantedBy = ["multi-user.target"];
+
+ systemd.packages = [ pkgs.irqbalance ];
+
};
}
diff --git a/nixpkgs/nixos/modules/services/hardware/tlp.nix b/nixpkgs/nixos/modules/services/hardware/tlp.nix
index 955a6067799..3962d7b1598 100644
--- a/nixpkgs/nixos/modules/services/hardware/tlp.nix
+++ b/nixpkgs/nixos/modules/services/hardware/tlp.nix
@@ -1,39 +1,26 @@
{ config, lib, pkgs, ... }:
-
with lib;
-
let
-
-cfg = config.services.tlp;
-
-enableRDW = config.networking.networkmanager.enable;
-
-tlp = pkgs.tlp.override {
- inherit enableRDW;
-};
-
-# XXX: We can't use writeTextFile + readFile here because it triggers
-# TLP build to get the .drv (even on --dry-run).
-confFile = pkgs.runCommand "tlp"
- { config = cfg.extraConfig;
- passAsFile = [ "config" ];
- preferLocalBuild = true;
- }
- ''
- cat ${tlp}/etc/default/tlp > $out
- cat $configPath >> $out
- '';
-
+ cfg = config.services.tlp;
+ enableRDW = config.networking.networkmanager.enable;
+ tlp = pkgs.tlp.override { inherit enableRDW; };
+ # TODO: Use this for having proper parameters in the future
+ mkTlpConfig = tlpConfig: generators.toKeyValue {
+ mkKeyValue = generators.mkKeyValueDefault {
+ mkValueString = val:
+ if isInt val then toString val
+ else if isString val then val
+ else if true == val then "1"
+ else if false == val then "0"
+ else if isList val then "\"" + (concatStringsSep " " val) + "\""
+ else err "invalid value provided to mkTlpConfig:" (toString val);
+ } "=";
+ } tlpConfig;
in
-
{
-
###### interface
-
options = {
-
services.tlp = {
-
enable = mkOption {
type = types.bool;
default = false;
@@ -45,77 +32,64 @@ in
default = "";
description = "Additional configuration variables for TLP";
};
-
};
-
};
-
###### implementation
-
config = mkIf cfg.enable {
+ boot.kernelModules = [ "msr" ];
- powerManagement.scsiLinkPolicy = null;
- powerManagement.cpuFreqGovernor = null;
- powerManagement.cpufreq.max = null;
- powerManagement.cpufreq.min = null;
+ environment.etc = {
+ "tlp.conf".text = cfg.extraConfig;
+ } // optionalAttrs enableRDW {
+ "NetworkManager/dispatcher.d/99tlp-rdw-nm".source =
+ "${tlp}/etc/NetworkManager/dispatcher.d/99tlp-rdw-nm";
+ };
- systemd.sockets.systemd-rfkill.enable = false;
+ environment.systemPackages = [ tlp ];
- systemd.services = {
- "systemd-rfkill@".enable = false;
- systemd-rfkill.enable = false;
+ # FIXME: When the config is parametrized we need to move these into a
+ # conditional on the relevant options being enabled.
+ powerManagement = {
+ scsiLinkPolicy = null;
+ cpuFreqGovernor = null;
+ cpufreq.max = null;
+ cpufreq.min = null;
+ };
- tlp = {
- description = "TLP system startup/shutdown";
+ services.udev.packages = [ tlp ];
- after = [ "multi-user.target" ];
+ systemd = {
+ packages = [ tlp ];
+ # XXX: These must always be disabled/masked according to [1].
+ #
+ # [1]: https://github.com/linrunner/TLP/blob/a9ada09e0821f275ce5f93dc80a4d81a7ff62ae4/tlp-stat.in#L319
+ sockets.systemd-rfkill.enable = false;
+ services.systemd-rfkill.enable = false;
+
+ services.tlp = {
+ # XXX: The service should reload whenever the configuration changes,
+ # otherwise newly set power options remain inactive until reboot (or
+ # manual unit restart.)
+ restartTriggers = [ config.environment.etc."tlp.conf".source ];
+ # XXX: When using systemd.packages (which we do above) the [Install]
+ # section of systemd units does not work (citation needed) so we manually
+ # enforce it here.
wantedBy = [ "multi-user.target" ];
- before = [ "shutdown.target" ];
- restartTriggers = [ confFile ];
-
- serviceConfig = {
- Type = "oneshot";
- RemainAfterExit = true;
- ExecStart = "${tlp}/bin/tlp init start";
- ExecStop = "${tlp}/bin/tlp init stop";
- };
};
- tlp-sleep = {
- description = "TLP suspend/resume";
-
- wantedBy = [ "sleep.target" ];
+ services.tlp-sleep = {
+ # XXX: When using systemd.packages (which we do above) the [Install]
+ # section of systemd units does not work (citation needed) so we manually
+ # enforce it here.
before = [ "sleep.target" ];
-
- unitConfig = {
- StopWhenUnneeded = true;
- };
-
- serviceConfig = {
- Type = "oneshot";
- RemainAfterExit = true;
- ExecStart = "${tlp}/bin/tlp suspend";
- ExecStop = "${tlp}/bin/tlp resume";
- };
+ wantedBy = [ "sleep.target" ];
+ # XXX: `tlp suspend` requires /var/lib/tlp to exist in order to save
+ # some stuff in there. There is no way, that I know of, to do this in
+ # the package itself, so we do it here instead making sure the unit
+ # won't fail due to the save dir not existing.
+ serviceConfig.StateDirectory = "tlp";
};
};
-
- services.udev.packages = [ tlp ];
-
- environment.etc =
- {
- "default/tlp".source = confFile;
- } // optionalAttrs enableRDW {
- "NetworkManager/dispatcher.d/99tlp-rdw-nm" = {
- source = "${tlp}/etc/NetworkManager/dispatcher.d/99tlp-rdw-nm";
- };
- };
-
- environment.systemPackages = [ tlp ];
-
- boot.kernelModules = [ "msr" ];
-
};
-
}
diff --git a/nixpkgs/nixos/modules/services/mail/dovecot.nix b/nixpkgs/nixos/modules/services/mail/dovecot.nix
index b5ed2c594f7..230a2ae3f82 100644
--- a/nixpkgs/nixos/modules/services/mail/dovecot.nix
+++ b/nixpkgs/nixos/modules/services/mail/dovecot.nix
@@ -14,18 +14,34 @@ let
base_dir = ${baseDir}
protocols = ${concatStringsSep " " cfg.protocols}
sendmail_path = /run/wrappers/bin/sendmail
+ # defining mail_plugins must be done before the first protocol {} filter because of https://doc.dovecot.org/configuration_manual/config_file/config_file_syntax/#variable-expansion
+ mail_plugins = $mail_plugins ${concatStringsSep " " cfg.mailPlugins.globally.enable}
''
- (if cfg.sslServerCert == null then ''
- ssl = no
- disable_plaintext_auth = no
- '' else ''
- ssl_cert = <${cfg.sslServerCert}
- ssl_key = <${cfg.sslServerKey}
- ${optionalString (cfg.sslCACert != null) ("ssl_ca = <" + cfg.sslCACert)}
- ssl_dh = <${config.security.dhparams.params.dovecot2.path}
- disable_plaintext_auth = yes
- '')
+ (
+ concatStringsSep "\n" (
+ mapAttrsToList (
+ protocol: plugins: ''
+ protocol ${protocol} {
+ mail_plugins = $mail_plugins ${concatStringsSep " " plugins.enable}
+ }
+ ''
+ ) cfg.mailPlugins.perProtocol
+ )
+ )
+
+ (
+ if cfg.sslServerCert == null then ''
+ ssl = no
+ disable_plaintext_auth = no
+ '' else ''
+ ssl_cert = <${cfg.sslServerCert}
+ ssl_key = <${cfg.sslServerKey}
+ ${optionalString (cfg.sslCACert != null) ("ssl_ca = <" + cfg.sslCACert)}
+ ssl_dh = <${config.security.dhparams.params.dovecot2.path}
+ disable_plaintext_auth = yes
+ ''
+ )
''
default_internal_user = ${cfg.user}
@@ -45,55 +61,58 @@ let
}
''
- (optionalString cfg.enablePAM ''
- userdb {
- driver = passwd
- }
-
- passdb {
- driver = pam
- args = ${optionalString cfg.showPAMFailure "failure_show_msg=yes"} dovecot2
- }
- '')
+ (
+ optionalString cfg.enablePAM ''
+ userdb {
+ driver = passwd
+ }
- (optionalString (cfg.sieveScripts != {}) ''
- plugin {
- ${concatStringsSep "\n" (mapAttrsToList (to: from: "sieve_${to} = ${stateDir}/sieve/${to}") cfg.sieveScripts)}
- }
- '')
+ passdb {
+ driver = pam
+ args = ${optionalString cfg.showPAMFailure "failure_show_msg=yes"} dovecot2
+ }
+ ''
+ )
- (optionalString (cfg.mailboxes != []) ''
- protocol imap {
- namespace inbox {
- inbox=yes
- ${concatStringsSep "\n" (map mailboxConfig cfg.mailboxes)}
+ (
+ optionalString (cfg.sieveScripts != {}) ''
+ plugin {
+ ${concatStringsSep "\n" (mapAttrsToList (to: from: "sieve_${to} = ${stateDir}/sieve/${to}") cfg.sieveScripts)}
}
- }
- '')
-
- (optionalString cfg.enableQuota ''
- mail_plugins = $mail_plugins quota
- service quota-status {
- executable = ${dovecotPkg}/libexec/dovecot/quota-status -p postfix
- inet_listener {
- port = ${cfg.quotaPort}
+ ''
+ )
+
+ (
+ optionalString (cfg.mailboxes != []) ''
+ protocol imap {
+ namespace inbox {
+ inbox=yes
+ ${concatStringsSep "\n" (map mailboxConfig cfg.mailboxes)}
+ }
+ }
+ ''
+ )
+
+ (
+ optionalString cfg.enableQuota ''
+ service quota-status {
+ executable = ${dovecotPkg}/libexec/dovecot/quota-status -p postfix
+ inet_listener {
+ port = ${cfg.quotaPort}
+ }
+ client_limit = 1
}
- client_limit = 1
- }
-
- protocol imap {
- mail_plugins = $mail_plugins imap_quota
- }
- plugin {
- quota_rule = *:storage=${cfg.quotaGlobalPerUser}
- quota = maildir:User quota # per virtual mail user quota # BUG/FIXME broken, we couldn't get this working
- quota_status_success = DUNNO
- quota_status_nouser = DUNNO
- quota_status_overquota = "552 5.2.2 Mailbox is full"
- quota_grace = 10%%
- }
- '')
+ plugin {
+ quota_rule = *:storage=${cfg.quotaGlobalPerUser}
+ quota = maildir:User quota # per virtual mail user quota # BUG/FIXME broken, we couldn't get this working
+ quota_status_success = DUNNO
+ quota_status_nouser = DUNNO
+ quota_status_overquota = "552 5.2.2 Mailbox is full"
+ quota_grace = 10%%
+ }
+ ''
+ )
cfg.extraConfig
];
@@ -107,7 +126,7 @@ let
mailbox "${mailbox.name}" {
auto = ${toString mailbox.auto}
'' + optionalString (mailbox.specialUse != null) ''
- special_use = \${toString mailbox.specialUse}
+ special_use = \${toString mailbox.specialUse}
'' + "}";
mailboxes = { ... }: {
@@ -160,7 +179,7 @@ in
protocols = mkOption {
type = types.listOf types.str;
- default = [ ];
+ default = [];
description = "Additional listeners to start when Dovecot is enabled.";
};
@@ -183,6 +202,43 @@ in
description = "Additional entries to put verbatim into Dovecot's config file.";
};
+ mailPlugins =
+ let
+ plugins = hint: types.submodule {
+ options = {
+ enable = mkOption {
+ type = types.listOf types.str;
+ default = [];
+ description = "mail plugins to enable as a list of strings to append to the ${hint} <literal>$mail_plugins</literal> configuration variable";
+ };
+ };
+ };
+ in
+ mkOption {
+ type = with types; submodule {
+ options = {
+ globally = mkOption {
+ description = "Additional entries to add to the mail_plugins variable for all protocols";
+ type = plugins "top-level";
+ example = { enable = [ "virtual" ]; };
+ default = { enable = []; };
+ };
+ perProtocol = mkOption {
+ description = "Additional entries to add to the mail_plugins variable, per protocol";
+ type = attrsOf (plugins "corresponding per-protocol");
+ default = {};
+ example = { imap = [ "imap_acl" ]; };
+ };
+ };
+ };
+ description = "Additional entries to add to the mail_plugins variable, globally and per protocol";
+ example = {
+ globally.enable = [ "acl" ];
+ perProtocol.imap.enable = [ "imap_acl" ];
+ };
+ default = { globally.enable = []; perProtocol = {}; };
+ };
+
configFile = mkOption {
type = types.nullOr types.path;
default = null;
@@ -305,27 +361,33 @@ in
enable = true;
params.dovecot2 = {};
};
- services.dovecot2.protocols =
- optional cfg.enableImap "imap"
- ++ optional cfg.enablePop3 "pop3"
- ++ optional cfg.enableLmtp "lmtp";
+ services.dovecot2.protocols =
+ optional cfg.enableImap "imap"
+ ++ optional cfg.enablePop3 "pop3"
+ ++ optional cfg.enableLmtp "lmtp";
+
+ services.dovecot2.mailPlugins = mkIf cfg.enableQuota {
+ globally.enable = [ "quota" ];
+ perProtocol.imap.enable = [ "imap_quota" ];
+ };
users.users = {
dovenull =
- { uid = config.ids.uids.dovenull2;
+ {
+ uid = config.ids.uids.dovenull2;
description = "Dovecot user for untrusted logins";
group = "dovenull";
};
} // optionalAttrs (cfg.user == "dovecot2") {
dovecot2 =
- { uid = config.ids.uids.dovecot2;
- description = "Dovecot user";
- group = cfg.group;
- };
+ {
+ uid = config.ids.uids.dovecot2;
+ description = "Dovecot user";
+ group = cfg.group;
+ };
} // optionalAttrs (cfg.createMailUser && cfg.mailUser != null) {
${cfg.mailUser} =
- { description = "Virtual Mail User"; } //
- optionalAttrs (cfg.mailGroup != null)
+ { description = "Virtual Mail User"; } // optionalAttrs (cfg.mailGroup != null)
{ group = cfg.mailGroup; };
};
@@ -334,7 +396,7 @@ in
} // optionalAttrs (cfg.group == "dovecot2") {
dovecot2.gid = config.ids.gids.dovecot2;
} // optionalAttrs (cfg.createMailUser && cfg.mailGroup != null) {
- ${cfg.mailGroup} = { };
+ ${cfg.mailGroup} = {};
};
environment.etc."dovecot/modules".source = modulesDir;
@@ -363,15 +425,19 @@ in
rm -rf ${stateDir}/sieve
'' + optionalString (cfg.sieveScripts != {}) ''
mkdir -p ${stateDir}/sieve
- ${concatStringsSep "\n" (mapAttrsToList (to: from: ''
- if [ -d '${from}' ]; then
- mkdir '${stateDir}/sieve/${to}'
- cp -p "${from}/"*.sieve '${stateDir}/sieve/${to}'
- else
- cp -p '${from}' '${stateDir}/sieve/${to}'
- fi
- ${pkgs.dovecot_pigeonhole}/bin/sievec '${stateDir}/sieve/${to}'
- '') cfg.sieveScripts)}
+ ${concatStringsSep "\n" (
+ mapAttrsToList (
+ to: from: ''
+ if [ -d '${from}' ]; then
+ mkdir '${stateDir}/sieve/${to}'
+ cp -p "${from}/"*.sieve '${stateDir}/sieve/${to}'
+ else
+ cp -p '${from}' '${stateDir}/sieve/${to}'
+ fi
+ ${pkgs.dovecot_pigeonhole}/bin/sievec '${stateDir}/sieve/${to}'
+ ''
+ ) cfg.sieveScripts
+ )}
chown -R '${cfg.mailUser}:${cfg.mailGroup}' '${stateDir}/sieve'
'';
};
@@ -379,17 +445,21 @@ in
environment.systemPackages = [ dovecotPkg ];
assertions = [
- { assertion = intersectLists cfg.protocols [ "pop3" "imap" ] != [];
+ {
+ assertion = intersectLists cfg.protocols [ "pop3" "imap" ] != [];
message = "dovecot needs at least one of the IMAP or POP3 listeners enabled";
}
- { assertion = (cfg.sslServerCert == null) == (cfg.sslServerKey == null)
- && (cfg.sslCACert != null -> !(cfg.sslServerCert == null || cfg.sslServerKey == null));
+ {
+ assertion = (cfg.sslServerCert == null) == (cfg.sslServerKey == null)
+ && (cfg.sslCACert != null -> !(cfg.sslServerCert == null || cfg.sslServerKey == null));
message = "dovecot needs both sslServerCert and sslServerKey defined for working crypto";
}
- { assertion = cfg.showPAMFailure -> cfg.enablePAM;
+ {
+ assertion = cfg.showPAMFailure -> cfg.enablePAM;
message = "dovecot is configured with showPAMFailure while enablePAM is disabled";
}
- { assertion = cfg.sieveScripts != {} -> (cfg.mailUser != null && cfg.mailGroup != null);
+ {
+ assertion = cfg.sieveScripts != {} -> (cfg.mailUser != null && cfg.mailGroup != null);
message = "dovecot requires mailUser and mailGroup to be set when sieveScripts is set";
}
];
diff --git a/nixpkgs/nixos/modules/services/mail/mailman.nix b/nixpkgs/nixos/modules/services/mail/mailman.nix
index 43dc185cdd7..f5e78b18293 100644
--- a/nixpkgs/nixos/modules/services/mail/mailman.nix
+++ b/nixpkgs/nixos/modules/services/mail/mailman.nix
@@ -265,6 +265,11 @@ in {
'';
serviceConfig = {
Type = "oneshot";
+ # RemainAfterExit makes restartIfChanged work for this service, so
+ # downstream services will get updated automatically when things like
+ # services.mailman.hyperkitty.baseUrl change. Otherwise users have to
+ # restart things manually, which is confusing.
+ RemainAfterExit = "yes";
};
};
@@ -282,6 +287,9 @@ in {
serviceConfig = {
User = cfg.webUser;
Type = "oneshot";
+ # Similar to mailman-settings.service, this makes restartTriggers work
+ # properly for this service.
+ RemainAfterExit = "yes";
WorkingDirectory = "/var/lib/mailman-web";
};
};
diff --git a/nixpkgs/nixos/modules/services/mail/sympa.nix b/nixpkgs/nixos/modules/services/mail/sympa.nix
new file mode 100644
index 00000000000..c3ae9d4255b
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/mail/sympa.nix
@@ -0,0 +1,596 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ cfg = config.services.sympa;
+ dataDir = "/var/lib/sympa";
+ user = "sympa";
+ group = "sympa";
+ pkg = pkgs.sympa;
+ fqdns = attrNames cfg.domains;
+ usingNginx = cfg.web.enable && cfg.web.server == "nginx";
+ mysqlLocal = cfg.database.createLocally && cfg.database.type == "MySQL";
+ pgsqlLocal = cfg.database.createLocally && cfg.database.type == "PostgreSQL";
+
+ sympaSubServices = [
+ "sympa-archive.service"
+ "sympa-bounce.service"
+ "sympa-bulk.service"
+ "sympa-task.service"
+ ];
+
+ # common for all services including wwsympa
+ commonServiceConfig = {
+ StateDirectory = "sympa";
+ ProtectHome = true;
+ ProtectSystem = "full";
+ ProtectKernelTunables = true;
+ ProtectKernelModules = true;
+ ProtectControlGroups = true;
+ };
+
+ # wwsympa has its own service config
+ sympaServiceConfig = srv: {
+ Type = "simple";
+ Restart = "always";
+ ExecStart = "${pkg}/bin/${srv}.pl --foreground";
+ PIDFile = "/run/sympa/${srv}.pid";
+ User = user;
+ Group = group;
+
+ # avoid duplicating log messageges in journal
+ StandardError = "null";
+ } // commonServiceConfig;
+
+ configVal = value:
+ if isBool value then
+ if value then "on" else "off"
+ else toString value;
+ configGenerator = c: concatStrings (flip mapAttrsToList c (key: val: "${key}\t${configVal val}\n"));
+
+ mainConfig = pkgs.writeText "sympa.conf" (configGenerator cfg.settings);
+ robotConfig = fqdn: domain: pkgs.writeText "${fqdn}-robot.conf" (configGenerator domain.settings);
+
+ transport = pkgs.writeText "transport.sympa" (concatStringsSep "\n" (flip map fqdns (domain: ''
+ ${domain} error:User unknown in recipient table
+ sympa@${domain} sympa:sympa@${domain}
+ listmaster@${domain} sympa:listmaster@${domain}
+ bounce@${domain} sympabounce:sympa@${domain}
+ abuse-feedback-report@${domain} sympabounce:sympa@${domain}
+ '')));
+
+ virtual = pkgs.writeText "virtual.sympa" (concatStringsSep "\n" (flip map fqdns (domain: ''
+ sympa-request@${domain} postmaster@localhost
+ sympa-owner@${domain} postmaster@localhost
+ '')));
+
+ listAliases = pkgs.writeText "list_aliases.tt2" ''
+ #--- [% list.name %]@[% list.domain %]: list transport map created at [% date %]
+ [% list.name %]@[% list.domain %] sympa:[% list.name %]@[% list.domain %]
+ [% list.name %]-request@[% list.domain %] sympa:[% list.name %]-request@[% list.domain %]
+ [% list.name %]-editor@[% list.domain %] sympa:[% list.name %]-editor@[% list.domain %]
+ #[% list.name %]-subscribe@[% list.domain %] sympa:[% list.name %]-subscribe@[%list.domain %]
+ [% list.name %]-unsubscribe@[% list.domain %] sympa:[% list.name %]-unsubscribe@[% list.domain %]
+ [% list.name %][% return_path_suffix %]@[% list.domain %] sympabounce:[% list.name %]@[% list.domain %]
+ '';
+
+ enabledFiles = filterAttrs (n: v: v.enable) cfg.settingsFile;
+in
+{
+
+ ###### interface
+ options.services.sympa = with types; {
+
+ enable = mkEnableOption "Sympa mailing list manager";
+
+ lang = mkOption {
+ type = str;
+ default = "en_US";
+ example = "cs";
+ description = ''
+ Default Sympa language.
+ See <link xlink:href='https://github.com/sympa-community/sympa/tree/sympa-6.2/po/sympa' />
+ for available options.
+ '';
+ };
+
+ listMasters = mkOption {
+ type = listOf str;
+ example = [ "postmaster@sympa.example.org" ];
+ description = ''
+ The list of the email addresses of the listmasters
+ (users authorized to perform global server commands).
+ '';
+ };
+
+ mainDomain = mkOption {
+ type = nullOr str;
+ default = null;
+ example = "lists.example.org";
+ description = ''
+ Main domain to be used in <filename>sympa.conf</filename>.
+ If <literal>null</literal>, one of the <option>services.sympa.domains</option> is chosen for you.
+ '';
+ };
+
+ domains = mkOption {
+ type = attrsOf (submodule ({ name, config, ... }: {
+ options = {
+ webHost = mkOption {
+ type = nullOr str;
+ default = null;
+ example = "archive.example.org";
+ description = ''
+ Domain part of the web interface URL (no web interface for this domain if <literal>null</literal>).
+ DNS record of type A (or AAAA or CNAME) has to exist with this value.
+ '';
+ };
+ webLocation = mkOption {
+ type = str;
+ default = "/";
+ example = "/sympa";
+ description = "URL path part of the web interface.";
+ };
+ settings = mkOption {
+ type = attrsOf (oneOf [ str int bool ]);
+ default = {};
+ example = {
+ default_max_list_members = 3;
+ };
+ description = ''
+ The <filename>robot.conf</filename> configuration file as key value set.
+ See <link xlink:href='https://sympa-community.github.io/gpldoc/man/sympa.conf.5.html' />
+ for list of configuration parameters.
+ '';
+ };
+ };
+
+ config.settings = mkIf (cfg.web.enable && config.webHost != null) {
+ wwsympa_url = mkDefault "https://${config.webHost}${strings.removeSuffix "/" config.webLocation}";
+ };
+ }));
+
+ description = ''
+ Email domains handled by this instance. There have
+ to be MX records for keys of this attribute set.
+ '';
+ example = literalExample ''
+ {
+ "lists.example.org" = {
+ webHost = "lists.example.org";
+ webLocation = "/";
+ };
+ "sympa.example.com" = {
+ webHost = "example.com";
+ webLocation = "/sympa";
+ };
+ }
+ '';
+ };
+
+ database = {
+ type = mkOption {
+ type = enum [ "SQLite" "PostgreSQL" "MySQL" ];
+ default = "SQLite";
+ example = "MySQL";
+ description = "Database engine to use.";
+ };
+
+ host = mkOption {
+ type = nullOr str;
+ default = null;
+ description = ''
+ Database host address.
+
+ For MySQL, use <literal>localhost</literal> to connect using Unix domain socket.
+
+ For PostgreSQL, use path to directory (e.g. <filename>/run/postgresql</filename>)
+ to connect using Unix domain socket located in this directory.
+
+ Use <literal>null</literal> to fall back on Sympa default, or when using
+ <option>services.sympa.database.createLocally</option>.
+ '';
+ };
+
+ port = mkOption {
+ type = nullOr port;
+ default = null;
+ description = "Database port. Use <literal>null</literal> for default port.";
+ };
+
+ name = mkOption {
+ type = str;
+ default = if cfg.database.type == "SQLite" then "${dataDir}/sympa.sqlite" else "sympa";
+ defaultText = ''if database.type == "SQLite" then "${dataDir}/sympa.sqlite" else "sympa"'';
+ description = ''
+ Database name. When using SQLite this must be an absolute
+ path to the database file.
+ '';
+ };
+
+ user = mkOption {
+ type = nullOr str;
+ default = user;
+ description = "Database user. The system user name is used as a default.";
+ };
+
+ passwordFile = mkOption {
+ type = nullOr path;
+ default = null;
+ example = "/run/keys/sympa-dbpassword";
+ description = ''
+ A file containing the password for <option>services.sympa.database.user</option>.
+ '';
+ };
+
+ createLocally = mkOption {
+ type = bool;
+ default = true;
+ description = "Whether to create a local database automatically.";
+ };
+ };
+
+ web = {
+ enable = mkOption {
+ type = bool;
+ default = true;
+ description = "Whether to enable Sympa web interface.";
+ };
+
+ server = mkOption {
+ type = enum [ "nginx" "none" ];
+ default = "nginx";
+ description = ''
+ The webserver used for the Sympa web interface. Set it to `none` if you want to configure it yourself.
+ Further nginx configuration can be done by adapting
+ <option>services.nginx.virtualHosts.<replaceable>name</replaceable></option>.
+ '';
+ };
+
+ https = mkOption {
+ type = bool;
+ default = true;
+ description = ''
+ Whether to use HTTPS. When nginx integration is enabled, this option forces SSL and enables ACME.
+ Please note that Sympa web interface always uses https links even when this option is disabled.
+ '';
+ };
+
+ fcgiProcs = mkOption {
+ type = ints.positive;
+ default = 2;
+ description = "Number of FastCGI processes to fork.";
+ };
+ };
+
+ mta = {
+ type = mkOption {
+ type = enum [ "postfix" "none" ];
+ default = "postfix";
+ description = ''
+ Mail transfer agent (MTA) integration. Use <literal>none</literal> if you want to configure it yourself.
+
+ The <literal>postfix</literal> integration sets up local Postfix instance that will pass incoming
+ messages from configured domains to Sympa. You still need to configure at least outgoing message
+ handling using e.g. <option>services.postfix.relayHost</option>.
+ '';
+ };
+ };
+
+ settings = mkOption {
+ type = attrsOf (oneOf [ str int bool ]);
+ default = {};
+ example = literalExample ''
+ {
+ default_home = "lists";
+ viewlogs_page_size = 50;
+ }
+ '';
+ description = ''
+ The <filename>sympa.conf</filename> configuration file as key value set.
+ See <link xlink:href='https://sympa-community.github.io/gpldoc/man/sympa.conf.5.html' />
+ for list of configuration parameters.
+ '';
+ };
+
+ settingsFile = mkOption {
+ type = attrsOf (submodule ({ name, config, ... }: {
+ options = {
+ enable = mkOption {
+ type = bool;
+ default = true;
+ description = "Whether this file should be generated. This option allows specific files to be disabled.";
+ };
+ text = mkOption {
+ default = null;
+ type = nullOr lines;
+ description = "Text of the file.";
+ };
+ source = mkOption {
+ type = path;
+ description = "Path of the source file.";
+ };
+ };
+
+ config.source = mkIf (config.text != null) (mkDefault (pkgs.writeText "sympa-${baseNameOf name}" config.text));
+ }));
+ default = {};
+ example = literalExample ''
+ {
+ "list_data/lists.example.org/help" = {
+ text = "subject This list provides help to users";
+ };
+ }
+ '';
+ description = "Set of files to be linked in <filename>${dataDir}</filename>.";
+ };
+ };
+
+ ###### implementation
+
+ config = mkIf cfg.enable {
+
+ services.sympa.settings = (mapAttrs (_: v: mkDefault v) {
+ domain = if cfg.mainDomain != null then cfg.mainDomain else head fqdns;
+ listmaster = concatStringsSep "," cfg.listMasters;
+ lang = cfg.lang;
+
+ home = "${dataDir}/list_data";
+ arc_path = "${dataDir}/arc";
+ bounce_path = "${dataDir}/bounce";
+
+ sendmail = "${pkgs.system-sendmail}/bin/sendmail";
+
+ db_type = cfg.database.type;
+ db_name = cfg.database.name;
+ }
+ // (optionalAttrs (cfg.database.host != null) {
+ db_host = cfg.database.host;
+ })
+ // (optionalAttrs mysqlLocal {
+ db_host = "localhost"; # use unix domain socket
+ })
+ // (optionalAttrs pgsqlLocal {
+ db_host = "/run/postgresql"; # use unix domain socket
+ })
+ // (optionalAttrs (cfg.database.port != null) {
+ db_port = cfg.database.port;
+ })
+ // (optionalAttrs (cfg.database.user != null) {
+ db_user = cfg.database.user;
+ })
+ // (optionalAttrs (cfg.mta.type == "postfix") {
+ sendmail_aliases = "${dataDir}/sympa_transport";
+ aliases_program = "${pkgs.postfix}/bin/postmap";
+ aliases_db_type = "hash";
+ })
+ // (optionalAttrs cfg.web.enable {
+ static_content_path = "${dataDir}/static_content";
+ css_path = "${dataDir}/static_content/css";
+ pictures_path = "${dataDir}/static_content/pictures";
+ mhonarc = "${pkgs.perlPackages.MHonArc}/bin/mhonarc";
+ }));
+
+ services.sympa.settingsFile = {
+ "virtual.sympa" = mkDefault { source = virtual; };
+ "transport.sympa" = mkDefault { source = transport; };
+ "etc/list_aliases.tt2" = mkDefault { source = listAliases; };
+ }
+ // (flip mapAttrs' cfg.domains (fqdn: domain:
+ nameValuePair "etc/${fqdn}/robot.conf" (mkDefault { source = robotConfig fqdn domain; })));
+
+ environment = {
+ systemPackages = [ pkg ];
+ };
+
+ users.users.${user} = {
+ description = "Sympa mailing list manager user";
+ group = group;
+ home = dataDir;
+ createHome = false;
+ isSystemUser = true;
+ };
+
+ users.groups.${group} = {};
+
+ assertions = [
+ { assertion = cfg.database.createLocally -> cfg.database.user == user;
+ message = "services.sympa.database.user must be set to ${user} if services.sympa.database.createLocally is set to true";
+ }
+ { assertion = cfg.database.createLocally -> cfg.database.passwordFile == null;
+ message = "a password cannot be specified if services.sympa.database.createLocally is set to true";
+ }
+ ];
+
+ systemd.tmpfiles.rules = [
+ "d ${dataDir} 0711 ${user} ${group} - -"
+ "d ${dataDir}/etc 0700 ${user} ${group} - -"
+ "d ${dataDir}/spool 0700 ${user} ${group} - -"
+ "d ${dataDir}/list_data 0700 ${user} ${group} - -"
+ "d ${dataDir}/arc 0700 ${user} ${group} - -"
+ "d ${dataDir}/bounce 0700 ${user} ${group} - -"
+ "f ${dataDir}/sympa_transport 0600 ${user} ${group} - -"
+
+ # force-copy static_content so it's up to date with package
+ # set permissions for wwsympa which needs write access (...)
+ "R ${dataDir}/static_content - - - - -"
+ "C ${dataDir}/static_content 0711 ${user} ${group} - ${pkg}/static_content"
+ "e ${dataDir}/static_content/* 0711 ${user} ${group} - -"
+
+ "d /run/sympa 0755 ${user} ${group} - -"
+ ]
+ ++ (flip concatMap fqdns (fqdn: [
+ "d ${dataDir}/etc/${fqdn} 0700 ${user} ${group} - -"
+ "d ${dataDir}/list_data/${fqdn} 0700 ${user} ${group} - -"
+ ]))
+ #++ (flip mapAttrsToList enabledFiles (k: v:
+ # "L+ ${dataDir}/${k} - - - - ${v.source}"
+ #))
+ ++ (concatLists (flip mapAttrsToList enabledFiles (k: v: [
+ # sympa doesn't handle symlinks well (e.g. fails to create locks)
+ # force-copy instead
+ "R ${dataDir}/${k} - - - - -"
+ "C ${dataDir}/${k} 0700 ${user} ${group} - ${v.source}"
+ ])));
+
+ systemd.services.sympa = {
+ description = "Sympa mailing list manager";
+
+ wantedBy = [ "multi-user.target" ];
+ after = [ "network-online.target" ];
+ wants = sympaSubServices;
+ before = sympaSubServices;
+ serviceConfig = sympaServiceConfig "sympa_msg";
+
+ preStart = ''
+ umask 0077
+
+ cp -f ${mainConfig} ${dataDir}/etc/sympa.conf
+ ${optionalString (cfg.database.passwordFile != null) ''
+ chmod u+w ${dataDir}/etc/sympa.conf
+ echo -n "db_passwd " >> ${dataDir}/etc/sympa.conf
+ cat ${cfg.database.passwordFile} >> ${dataDir}/etc/sympa.conf
+ ''}
+
+ ${optionalString (cfg.mta.type == "postfix") ''
+ ${pkgs.postfix}/bin/postmap hash:${dataDir}/virtual.sympa
+ ${pkgs.postfix}/bin/postmap hash:${dataDir}/transport.sympa
+ ''}
+ ${pkg}/bin/sympa_newaliases.pl
+ ${pkg}/bin/sympa.pl --health_check
+ '';
+ };
+ systemd.services.sympa-archive = {
+ description = "Sympa mailing list manager (archiving)";
+ bindsTo = [ "sympa.service" ];
+ serviceConfig = sympaServiceConfig "archived";
+ };
+ systemd.services.sympa-bounce = {
+ description = "Sympa mailing list manager (bounce processing)";
+ bindsTo = [ "sympa.service" ];
+ serviceConfig = sympaServiceConfig "bounced";
+ };
+ systemd.services.sympa-bulk = {
+ description = "Sympa mailing list manager (message distribution)";
+ bindsTo = [ "sympa.service" ];
+ serviceConfig = sympaServiceConfig "bulk";
+ };
+ systemd.services.sympa-task = {
+ description = "Sympa mailing list manager (task management)";
+ bindsTo = [ "sympa.service" ];
+ serviceConfig = sympaServiceConfig "task_manager";
+ };
+
+ systemd.services.wwsympa = mkIf usingNginx {
+ wantedBy = [ "multi-user.target" ];
+ after = [ "sympa.service" ];
+ serviceConfig = {
+ Type = "forking";
+ PIDFile = "/run/sympa/wwsympa.pid";
+ Restart = "always";
+ ExecStart = ''${pkgs.spawn_fcgi}/bin/spawn-fcgi \
+ -u ${user} \
+ -g ${group} \
+ -U nginx \
+ -M 0600 \
+ -F ${toString cfg.web.fcgiProcs} \
+ -P /run/sympa/wwsympa.pid \
+ -s /run/sympa/wwsympa.socket \
+ -- ${pkg}/bin/wwsympa.fcgi
+ '';
+
+ } // commonServiceConfig;
+ };
+
+ services.nginx.enable = mkIf usingNginx true;
+ services.nginx.virtualHosts = mkIf usingNginx (let
+ vHosts = unique (remove null (mapAttrsToList (_k: v: v.webHost) cfg.domains));
+ hostLocations = host: map (v: v.webLocation) (filter (v: v.webHost == host) (attrValues cfg.domains));
+ httpsOpts = optionalAttrs cfg.web.https { forceSSL = mkDefault true; enableACME = mkDefault true; };
+ in
+ genAttrs vHosts (host: {
+ locations = genAttrs (hostLocations host) (loc: {
+ extraConfig = ''
+ include ${config.services.nginx.package}/conf/fastcgi_params;
+
+ fastcgi_pass unix:/run/sympa/wwsympa.socket;
+ fastcgi_split_path_info ^(${loc})(.*)$;
+
+ fastcgi_param PATH_INFO $fastcgi_path_info;
+ fastcgi_param SCRIPT_FILENAME ${pkg}/bin/wwsympa.fcgi;
+ '';
+ }) // {
+ "/static-sympa/".alias = "${dataDir}/static_content/";
+ };
+ } // httpsOpts));
+
+ services.postfix = mkIf (cfg.mta.type == "postfix") {
+ enable = true;
+ recipientDelimiter = "+";
+ config = {
+ virtual_alias_maps = [ "hash:${dataDir}/virtual.sympa" ];
+ virtual_mailbox_maps = [
+ "hash:${dataDir}/transport.sympa"
+ "hash:${dataDir}/sympa_transport"
+ "hash:${dataDir}/virtual.sympa"
+ ];
+ virtual_mailbox_domains = [ "hash:${dataDir}/transport.sympa" ];
+ transport_maps = [
+ "hash:${dataDir}/transport.sympa"
+ "hash:${dataDir}/sympa_transport"
+ ];
+ };
+ masterConfig = {
+ "sympa" = {
+ type = "unix";
+ privileged = true;
+ chroot = false;
+ command = "pipe";
+ args = [
+ "flags=hqRu"
+ "user=${user}"
+ "argv=${pkg}/bin/queue"
+ "\${nexthop}"
+ ];
+ };
+ "sympabounce" = {
+ type = "unix";
+ privileged = true;
+ chroot = false;
+ command = "pipe";
+ args = [
+ "flags=hqRu"
+ "user=${user}"
+ "argv=${pkg}/bin/bouncequeue"
+ "\${nexthop}"
+ ];
+ };
+ };
+ };
+
+ services.mysql = optionalAttrs mysqlLocal {
+ enable = true;
+ package = mkDefault pkgs.mariadb;
+ ensureDatabases = [ cfg.database.name ];
+ ensureUsers = [
+ { name = cfg.database.user;
+ ensurePermissions = { "${cfg.database.name}.*" = "ALL PRIVILEGES"; };
+ }
+ ];
+ };
+
+ services.postgresql = optionalAttrs pgsqlLocal {
+ enable = true;
+ ensureDatabases = [ cfg.database.name ];
+ ensureUsers = [
+ { name = cfg.database.user;
+ ensurePermissions = { "DATABASE ${cfg.database.name}" = "ALL PRIVILEGES"; };
+ }
+ ];
+ };
+
+ };
+
+ meta.maintainers = with maintainers; [ mmilata sorki ];
+}
diff --git a/nixpkgs/nixos/modules/services/misc/ankisyncd.nix b/nixpkgs/nixos/modules/services/misc/ankisyncd.nix
new file mode 100644
index 00000000000..5fc19649d3d
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/misc/ankisyncd.nix
@@ -0,0 +1,79 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ cfg = config.services.ankisyncd;
+
+ name = "ankisyncd";
+
+ stateDir = "/var/lib/${name}";
+
+ authDbPath = "${stateDir}/auth.db";
+
+ sessionDbPath = "${stateDir}/session.db";
+
+ configFile = pkgs.writeText "ankisyncd.conf" (lib.generators.toINI {} {
+ sync_app = {
+ host = cfg.host;
+ port = cfg.port;
+ data_root = stateDir;
+ auth_db_path = authDbPath;
+ session_db_path = sessionDbPath;
+
+ base_url = "/sync/";
+ base_media_url = "/msync/";
+ };
+ });
+in
+ {
+ options.services.ankisyncd = {
+ enable = mkEnableOption "ankisyncd";
+
+ package = mkOption {
+ type = types.package;
+ default = pkgs.ankisyncd;
+ defaultText = literalExample "pkgs.ankisyncd";
+ description = "The package to use for the ankisyncd command.";
+ };
+
+ host = mkOption {
+ type = types.str;
+ default = "localhost";
+ description = "ankisyncd host";
+ };
+
+ port = mkOption {
+ type = types.int;
+ default = 27701;
+ description = "ankisyncd port";
+ };
+
+ openFirewall = mkOption {
+ default = false;
+ type = types.bool;
+ description = "Whether to open the firewall for the specified port.";
+ };
+ };
+
+ config = mkIf cfg.enable {
+ networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ];
+
+ environment.etc."ankisyncd/ankisyncd.conf".source = configFile;
+
+ systemd.services.ankisyncd = {
+ description = "ankisyncd - Anki sync server";
+ after = [ "network.target" ];
+ wantedBy = [ "multi-user.target" ];
+ path = [ cfg.package ];
+
+ serviceConfig = {
+ Type = "simple";
+ DynamicUser = true;
+ StateDirectory = name;
+ ExecStart = "${cfg.package}/bin/ankisyncd";
+ Restart = "always";
+ };
+ };
+ };
+ }
diff --git a/nixpkgs/nixos/modules/services/misc/autorandr.nix b/nixpkgs/nixos/modules/services/misc/autorandr.nix
index 4708e16e2a6..cf7fb5f78d3 100644
--- a/nixpkgs/nixos/modules/services/misc/autorandr.nix
+++ b/nixpkgs/nixos/modules/services/misc/autorandr.nix
@@ -48,5 +48,5 @@ in {
};
- meta.maintainers = with maintainers; [ gnidorah ma27 ];
+ meta.maintainers = with maintainers; [ gnidorah ];
}
diff --git a/nixpkgs/nixos/modules/services/misc/disnix.nix b/nixpkgs/nixos/modules/services/misc/disnix.nix
index c21cb2afc3c..b7b6eb7cd66 100644
--- a/nixpkgs/nixos/modules/services/misc/disnix.nix
+++ b/nixpkgs/nixos/modules/services/misc/disnix.nix
@@ -61,10 +61,7 @@ in
++ optional cfg.useWebServiceInterface "${pkgs.dbus_java}/share/java/dbus.jar";
services.tomcat.webapps = optional cfg.useWebServiceInterface pkgs.DisnixWebService;
- users.groups = singleton
- { name = "disnix";
- gid = config.ids.gids.disnix;
- };
+ users.groups.disnix.gid = config.ids.gids.disnix;
systemd.services = {
disnix = mkIf cfg.enableMultiUser {
diff --git a/nixpkgs/nixos/modules/services/misc/folding-at-home.nix b/nixpkgs/nixos/modules/services/misc/folding-at-home.nix
deleted file mode 100644
index fd2ea3948f6..00000000000
--- a/nixpkgs/nixos/modules/services/misc/folding-at-home.nix
+++ /dev/null
@@ -1,67 +0,0 @@
-{ config, lib, pkgs, ... }:
-with lib;
-let
- stateDir = "/var/lib/foldingathome";
- cfg = config.services.foldingAtHome;
- fahUser = "foldingathome";
-in {
-
- ###### interface
-
- options = {
-
- services.foldingAtHome = {
-
- enable = mkOption {
- default = false;
- description = ''
- Whether to enable the Folding@Home to use idle CPU time.
- '';
- };
-
- nickname = mkOption {
- default = "Anonymous";
- description = ''
- A unique handle for statistics.
- '';
- };
-
- config = mkOption {
- default = "";
- description = ''
- Extra configuration. Contents will be added verbatim to the
- configuration file.
- '';
- };
-
- };
-
- };
-
- ###### implementation
-
- config = mkIf cfg.enable {
-
- users.users.${fahUser} =
- { uid = config.ids.uids.foldingathome;
- description = "Folding@Home user";
- home = stateDir;
- };
-
- systemd.services.foldingathome = {
- after = [ "network.target" ];
- wantedBy = [ "multi-user.target" ];
- preStart = ''
- mkdir -m 0755 -p ${stateDir}
- chown ${fahUser} ${stateDir}
- cp -f ${pkgs.writeText "client.cfg" cfg.config} ${stateDir}/client.cfg
- '';
- script = "${pkgs.su}/bin/su -s ${pkgs.runtimeShell} ${fahUser} -c 'cd ${stateDir}; ${pkgs.foldingathome}/bin/fah6'";
- };
-
- services.foldingAtHome.config = ''
- [settings]
- username=${cfg.nickname}
- '';
- };
-}
diff --git a/nixpkgs/nixos/modules/services/misc/home-assistant.nix b/nixpkgs/nixos/modules/services/misc/home-assistant.nix
index d63f38e93b8..86033d02bf3 100644
--- a/nixpkgs/nixos/modules/services/misc/home-assistant.nix
+++ b/nixpkgs/nixos/modules/services/misc/home-assistant.nix
@@ -96,7 +96,20 @@ in {
config = mkOption {
default = null;
- type = with types; nullOr attrs;
+ # Migrate to new option types later: https://github.com/NixOS/nixpkgs/pull/75584
+ type = with lib.types; let
+ valueType = nullOr (oneOf [
+ bool
+ int
+ float
+ str
+ (lazyAttrsOf valueType)
+ (listOf valueType)
+ ]) // {
+ description = "Yaml value";
+ emptyValue.value = {};
+ };
+ in valueType;
example = literalExample ''
{
homeassistant = {
diff --git a/nixpkgs/nixos/modules/services/misc/matrix-synapse.nix b/nixpkgs/nixos/modules/services/misc/matrix-synapse.nix
index 750f4a292fb..d02fa13bb99 100644
--- a/nixpkgs/nixos/modules/services/misc/matrix-synapse.nix
+++ b/nixpkgs/nixos/modules/services/misc/matrix-synapse.nix
@@ -111,6 +111,9 @@ app_service_config_files: ${builtins.toJSON cfg.app_service_config_files}
${cfg.extraConfig}
'';
+
+ hasLocalPostgresDB = let args = cfg.database_args; in
+ usePostgresql && (!(args ? host) || (elem args.host [ "localhost" "127.0.0.1" "::1" ]));
in {
options = {
services.matrix-synapse = {
@@ -354,13 +357,6 @@ in {
The database engine name. Can be sqlite or psycopg2.
'';
};
- create_local_database = mkOption {
- type = types.bool;
- default = true;
- description = ''
- Whether to create a local database automatically.
- '';
- };
database_name = mkOption {
type = types.str;
default = "matrix-synapse";
@@ -657,6 +653,25 @@ in {
};
config = mkIf cfg.enable {
+ assertions = [
+ { assertion = hasLocalPostgresDB -> config.services.postgresql.enable;
+ message = ''
+ Cannot deploy matrix-synapse with a configuration for a local postgresql database
+ and a missing postgresql service. Since 20.03 it's mandatory to manually configure the
+ database (please read the thread in https://github.com/NixOS/nixpkgs/pull/80447 for
+ further reference).
+
+ If you
+ - try to deploy a fresh synapse, you need to configure the database yourself. An example
+ for this can be found in <nixpkgs/nixos/tests/matrix-synapse.nix>
+ - update your existing matrix-synapse instance, you simply need to add `services.postgresql.enable = true`
+ to your configuration.
+
+ For further information about this update, please read the release-notes of 20.03 carefully.
+ '';
+ }
+ ];
+
users.users.matrix-synapse = {
group = "matrix-synapse";
home = cfg.dataDir;
@@ -669,18 +684,9 @@ in {
gid = config.ids.gids.matrix-synapse;
};
- services.postgresql = mkIf (usePostgresql && cfg.create_local_database) {
- enable = mkDefault true;
- ensureDatabases = [ cfg.database_name ];
- ensureUsers = [{
- name = cfg.database_user;
- ensurePermissions = { "DATABASE \"${cfg.database_name}\"" = "ALL PRIVILEGES"; };
- }];
- };
-
systemd.services.matrix-synapse = {
description = "Synapse Matrix homeserver";
- after = [ "network.target" ] ++ lib.optional config.services.postgresql.enable "postgresql.service" ;
+ after = [ "network.target" ] ++ optional hasLocalPostgresDB "postgresql.service";
wantedBy = [ "multi-user.target" ];
preStart = ''
${cfg.package}/bin/homeserver \
@@ -709,6 +715,12 @@ in {
The `trusted_third_party_id_servers` option as been removed in `matrix-synapse` v1.4.0
as the behavior is now obsolete.
'')
+ (mkRemovedOptionModule [ "services" "matrix-synapse" "create_local_database" ] ''
+ Database configuration must be done manually. An exemplary setup is demonstrated in
+ <nixpkgs/nixos/tests/matrix-synapse.nix>
+ '')
];
+ meta.doc = ./matrix-synapse.xml;
+
}
diff --git a/nixpkgs/nixos/modules/services/misc/matrix-synapse.xml b/nixpkgs/nixos/modules/services/misc/matrix-synapse.xml
new file mode 100644
index 00000000000..053a3b2a563
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/misc/matrix-synapse.xml
@@ -0,0 +1,224 @@
+<chapter xmlns="http://docbook.org/ns/docbook"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ version="5.0"
+ xml:id="module-services-matrix">
+ <title>Matrix</title>
+ <para>
+ <link xlink:href="https://matrix.org/">Matrix</link> is an open standard for
+ interoperable, decentralised, real-time communication over IP. It can be used
+ to power Instant Messaging, VoIP/WebRTC signalling, Internet of Things
+ communication - or anywhere you need a standard HTTP API for publishing and
+ subscribing to data whilst tracking the conversation history.
+ </para>
+ <para>
+ This chapter will show you how to set up your own, self-hosted Matrix
+ homeserver using the Synapse reference homeserver, and how to serve your own
+ copy of the Riot web client. See the
+ <link xlink:href="https://matrix.org/docs/projects/try-matrix-now.html">Try
+ Matrix Now!</link> overview page for links to Riot Apps for Android and iOS,
+ desktop clients, as well as bridges to other networks and other projects
+ around Matrix.
+ </para>
+ <section xml:id="module-services-matrix-synapse">
+ <title>Synapse Homeserver</title>
+
+ <para>
+ <link xlink:href="https://github.com/matrix-org/synapse">Synapse</link> is
+ the reference homeserver implementation of Matrix from the core development
+ team at matrix.org. The following configuration example will set up a
+ synapse server for the <literal>example.org</literal> domain, served from
+ the host <literal>myhostname.example.org</literal>. For more information,
+ please refer to the
+ <link xlink:href="https://github.com/matrix-org/synapse#synapse-installation">
+ installation instructions of Synapse </link>.
+<programlisting>
+let
+ fqdn =
+ let
+ join = hostName: domain: hostName + optionalString (domain != null) ".${domain}";
+ in join config.networking.hostName config.networking.domain;
+in {
+ networking = {
+ <link linkend="opt-networking.hostName">hostName</link> = "myhostname";
+ <link linkend="opt-networking.domain">domain</link> = "example.org";
+ };
+ <link linkend="opt-networking.firewall.allowedTCPPorts">networking.firewall.allowedTCPPorts</link> = [ 80 443 ];
+
+ <link linkend="opt-services.postgresql.enable">services.postgresql.enable</link> = true;
+ <link linkend="opt-services.postgresql.initialScript">services.postgresql.initialScript</link> = ''
+ CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD 'synapse';
+ CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse"
+ TEMPLATE template0
+ LC_COLLATE = "C"
+ LC_CTYPE = "C";
+ '';
+
+ services.nginx = {
+ <link linkend="opt-services.nginx.enable">enable</link> = true;
+ # only recommendedProxySettings and recommendedGzipSettings are strictly required,
+ # but the rest make sense as well
+ <link linkend="opt-services.nginx.recommendedTlsSettings">recommendedTlsSettings</link> = true;
+ <link linkend="opt-services.nginx.recommendedOptimisation">recommendedOptimisation</link> = true;
+ <link linkend="opt-services.nginx.recommendedGzipSettings">recommendedGzipSettings</link> = true;
+ <link linkend="opt-services.nginx.recommendedProxySettings">recommendedProxySettings</link> = true;
+
+ <link linkend="opt-services.nginx.virtualHosts">virtualHosts</link> = {
+ # This host section can be placed on a different host than the rest,
+ # i.e. to delegate from the host being accessible as ${config.networking.domain}
+ # to another host actually running the Matrix homeserver.
+ "${config.networking.domain}" = {
+ <link linkend="opt-services.nginx.virtualHosts._name_.locations._name_.extraConfig">locations."= /.well-known/matrix/server".extraConfig</link> =
+ let
+ # use 443 instead of the default 8448 port to unite
+ # the client-server and server-server port for simplicity
+ server = { "m.server" = "${fqdn}:443"; };
+ in ''
+ add_header Content-Type application/json;
+ return 200 '${builtins.toJSON server}';
+ '';
+ <link linkend="opt-services.nginx.virtualHosts._name_.locations._name_.extraConfig">locations."= /.well-known/matrix/client".extraConfig</link> =
+ let
+ client = {
+ "m.homeserver" = { "base_url" = "https://${fqdn}"; };
+ "m.identity_server" = { "base_url" = "https://vector.im"; };
+ };
+ # ACAO required to allow riot-web on any URL to request this json file
+ in ''
+ add_header Content-Type application/json;
+ add_header Access-Control-Allow-Origin *;
+ return 200 '${builtins.toJSON client}';
+ '';
+ };
+
+ # Reverse proxy for Matrix client-server and server-server communication
+ ${fqdn} = {
+ <link linkend="opt-services.nginx.virtualHosts._name_.enableACME">enableACME</link> = true;
+ <link linkend="opt-services.nginx.virtualHosts._name_.forceSSL">forceSSL</link> = true;
+
+ # Or do a redirect instead of the 404, or whatever is appropriate for you.
+ # But do not put a Matrix Web client here! See the Riot Web section below.
+ <link linkend="opt-services.nginx.virtualHosts._name_.locations._name_.extraConfig">locations."/".extraConfig</link> = ''
+ return 404;
+ '';
+
+ # forward all Matrix API calls to the synapse Matrix homeserver
+ locations."/_matrix" = {
+ <link linkend="opt-services.nginx.virtualHosts._name_.locations._name_.proxyPass">proxyPass</link> = "http://[::1]:8008"; # without a trailing /
+ };
+ };
+ };
+ };
+ services.matrix-synapse = {
+ <link linkend="opt-services.matrix-synapse.enable">enable</link> = true;
+ <link linkend="opt-services.matrix-synapse.server_name">server_name</link> = config.networking.domain;
+ <link linkend="opt-services.matrix-synapse.listeners">listeners</link> = [
+ {
+ <link linkend="opt-services.matrix-synapse.listeners._.port">port</link> = 8008;
+ <link linkend="opt-services.matrix-synapse.listeners._.bind_address">bind_address</link> = "::1";
+ <link linkend="opt-services.matrix-synapse.listeners._.type">type</link> = "http";
+ <link linkend="opt-services.matrix-synapse.listeners._.tls">tls</link> = false;
+ <link linkend="opt-services.matrix-synapse.listeners._.x_forwarded">x_forwarded</link> = true;
+ <link linkend="opt-services.matrix-synapse.listeners._.resources">resources</link> = [
+ {
+ <link linkend="opt-services.matrix-synapse.listeners._.resources._.names">names</link> = [ "client" "federation" ];
+ <link linkend="opt-services.matrix-synapse.listeners._.resources._.compress">compress</link> = false;
+ }
+ ];
+ }
+ ];
+ };
+};
+</programlisting>
+ </para>
+
+ <para>
+ If the <code>A</code> and <code>AAAA</code> DNS records on
+ <literal>example.org</literal> do not point on the same host as the records
+ for <code>myhostname.example.org</code>, you can easily move the
+ <code>/.well-known</code> virtualHost section of the code to the host that
+ is serving <literal>example.org</literal>, while the rest stays on
+ <literal>myhostname.example.org</literal> with no other changes required.
+ This pattern also allows to seamlessly move the homeserver from
+ <literal>myhostname.example.org</literal> to
+ <literal>myotherhost.example.org</literal> by only changing the
+ <code>/.well-known</code> redirection target.
+ </para>
+
+ <para>
+ If you want to run a server with public registration by anybody, you can
+ then enable <literal><link linkend="opt-services.matrix-synapse.enable_registration">services.matrix-synapse.enable_registration</link> =
+ true;</literal>. Otherwise, or you can generate a registration secret with
+ <command>pwgen -s 64 1</command> and set it with
+ <option><link linkend="opt-services.matrix-synapse.registration_shared_secret">services.matrix-synapse.registration_shared_secret</link></option>. To
+ create a new user or admin, run the following after you have set the secret
+ and have rebuilt NixOS:
+<screen>
+<prompt>$ </prompt>nix run nixpkgs.matrix-synapse
+<prompt>$ </prompt>register_new_matrix_user -k <replaceable>your-registration-shared-secret</replaceable> http://localhost:8008
+<prompt>New user localpart: </prompt><replaceable>your-username</replaceable>
+<prompt>Password:</prompt>
+<prompt>Confirm password:</prompt>
+<prompt>Make admin [no]:</prompt>
+Success!
+</screen>
+ In the example, this would create a user with the Matrix Identifier
+ <literal>@your-username:example.org</literal>. Note that the registration
+ secret ends up in the nix store and therefore is world-readable by any user
+ on your machine, so it makes sense to only temporarily activate the
+ <link linkend="opt-services.matrix-synapse.registration_shared_secret">registration_shared_secret</link>
+ option until a better solution for NixOS is in place.
+ </para>
+ </section>
+ <section xml:id="module-services-matrix-riot-web">
+ <title>Riot Web Client</title>
+
+ <para>
+ <link xlink:href="https://github.com/vector-im/riot-web/">Riot Web</link> is
+ the reference web client for Matrix and developed by the core team at
+ matrix.org. The following snippet can be optionally added to the code before
+ to complete the synapse installation with a web client served at
+ <code>https://riot.myhostname.example.org</code> and
+ <code>https://riot.example.org</code>. Alternatively, you can use the hosted
+ copy at <link xlink:href="https://riot.im/app">https://riot.im/app</link>,
+ or use other web clients or native client applications. Due to the
+ <literal>/.well-known</literal> urls set up done above, many clients should
+ fill in the required connection details automatically when you enter your
+ Matrix Identifier. See
+ <link xlink:href="https://matrix.org/docs/projects/try-matrix-now.html">Try
+ Matrix Now!</link> for a list of existing clients and their supported
+ featureset.
+<programlisting>
+{
+ services.nginx.virtualHosts."riot.${fqdn}" = {
+ <link linkend="opt-services.nginx.virtualHosts._name_.enableACME">enableACME</link> = true;
+ <link linkend="opt-services.nginx.virtualHosts._name_.forceSSL">forceSSL</link> = true;
+ <link linkend="opt-services.nginx.virtualHosts._name_.serverAliases">serverAliases</link> = [
+ "riot.${config.networking.domain}"
+ ];
+
+ <link linkend="opt-services.nginx.virtualHosts._name_.root">root</link> = pkgs.riot-web.override {
+ conf = {
+ default_server_config."m.homeserver" = {
+ "base_url" = "${config.networking.domain}";
+ "server_name" = "${fqdn}";
+ };
+ };
+ };
+ };
+}
+</programlisting>
+ </para>
+
+ <para>
+ Note that the Riot developers do not recommend running Riot and your Matrix
+ homeserver on the same fully-qualified domain name for security reasons. In
+ the example, this means that you should not reuse the
+ <literal>myhostname.example.org</literal> virtualHost to also serve Riot,
+ but instead serve it on a different subdomain, like
+ <literal>riot.example.org</literal> in the example. See the
+ <link xlink:href="https://github.com/vector-im/riot-web#important-security-note">Riot
+ Important Security Notes</link> for more information on this subject.
+ </para>
+ </section>
+</chapter>
diff --git a/nixpkgs/nixos/modules/services/misc/parsoid.nix b/nixpkgs/nixos/modules/services/misc/parsoid.nix
index 61626e78f8b..09b7f977bfb 100644
--- a/nixpkgs/nixos/modules/services/misc/parsoid.nix
+++ b/nixpkgs/nixos/modules/services/misc/parsoid.nix
@@ -6,7 +6,7 @@ let
cfg = config.services.parsoid;
- parsoid = pkgs.nodePackages."parsoid-git://github.com/abbradar/parsoid#stable";
+ parsoid = pkgs.nodePackages.parsoid;
confTree = {
worker_heartbeat_timeout = 300000;
@@ -98,8 +98,29 @@ in
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
serviceConfig = {
- User = "nobody";
ExecStart = "${parsoid}/lib/node_modules/parsoid/bin/server.js -c ${confFile} -n ${toString cfg.workers}";
+
+ DynamicUser = true;
+ User = "parsoid";
+ Group = "parsoid";
+
+ CapabilityBoundingSet = "";
+ NoNewPrivileges = true;
+ ProtectSystem = "strict";
+ ProtectHome = true;
+ PrivateTmp = true;
+ PrivateDevices = true;
+ ProtectHostname = true;
+ ProtectKernelTunables = true;
+ ProtectKernelModules = true;
+ ProtectControlGroups = true;
+ RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
+ RestrictNamespaces = true;
+ LockPersonality = true;
+ #MemoryDenyWriteExecute = true;
+ RestrictRealtime = true;
+ RestrictSUIDSGID = true;
+ RemoveIPC = true;
};
};
diff --git a/nixpkgs/nixos/modules/services/misc/sssd.nix b/nixpkgs/nixos/modules/services/misc/sssd.nix
index 6b64045dde8..36008d25741 100644
--- a/nixpkgs/nixos/modules/services/misc/sssd.nix
+++ b/nixpkgs/nixos/modules/services/misc/sssd.nix
@@ -88,9 +88,7 @@ in {
exec ${pkgs.sssd}/bin/sss_ssh_authorizedkeys "$@"
'';
};
- services.openssh.extraConfig = ''
- AuthorizedKeysCommand /etc/ssh/authorized_keys_command
- AuthorizedKeysCommandUser nobody
- '';
+ services.openssh.authorizedKeysCommand = "/etc/ssh/authorized_keys_command";
+ services.openssh.authorizedKeysCommandUser = "nobody";
})];
}
diff --git a/nixpkgs/nixos/modules/services/misc/zoneminder.nix b/nixpkgs/nixos/modules/services/misc/zoneminder.nix
index d7f7324580c..d5b3537068d 100644
--- a/nixpkgs/nixos/modules/services/misc/zoneminder.nix
+++ b/nixpkgs/nixos/modules/services/misc/zoneminder.nix
@@ -77,6 +77,8 @@ in {
`config.services.zoneminder.database.createLocally` to true. Otherwise,
when set to `false` (the default), you will have to create the database
and database user as well as populate the database yourself.
+ Additionally, you will need to run `zmupdate.pl` yourself when
+ upgrading to a newer version.
'';
webserver = mkOption {
@@ -330,6 +332,8 @@ in {
${config.services.mysql.package}/bin/mysql < ${pkg}/share/zoneminder/db/zm_create.sql
touch "/var/lib/${dirName}/db-created"
fi
+
+ ${zoneminder}/bin/zmupdate.pl -nointeractive
'';
serviceConfig = {
User = user;
diff --git a/nixpkgs/nixos/modules/services/monitoring/cadvisor.nix b/nixpkgs/nixos/modules/services/monitoring/cadvisor.nix
index 695a8c42e85..655a6934a26 100644
--- a/nixpkgs/nixos/modules/services/monitoring/cadvisor.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/cadvisor.nix
@@ -135,7 +135,6 @@ in {
serviceConfig.TimeoutStartSec=300;
};
- virtualisation.docker.enable = mkDefault true;
})
];
}
diff --git a/nixpkgs/nixos/modules/services/monitoring/heapster.nix b/nixpkgs/nixos/modules/services/monitoring/heapster.nix
index 585632943fd..0a9dfa12eaa 100644
--- a/nixpkgs/nixos/modules/services/monitoring/heapster.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/heapster.nix
@@ -49,7 +49,7 @@ in {
};
};
- users.users.heapsterrs = {
+ users.users.heapster = {
uid = config.ids.uids.heapster;
description = "Heapster user";
};
diff --git a/nixpkgs/nixos/modules/services/monitoring/nagios.nix b/nixpkgs/nixos/modules/services/monitoring/nagios.nix
index 3ca79dddaf5..9ac6869068f 100644
--- a/nixpkgs/nixos/modules/services/monitoring/nagios.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/nagios.nix
@@ -154,7 +154,7 @@ in
};
virtualHost = mkOption {
- type = types.submodule (import ../web-servers/apache-httpd/per-server-options.nix);
+ type = types.submodule (import ../web-servers/apache-httpd/vhost-options.nix);
example = literalExample ''
{ hostName = "example.org";
adminAddr = "webmaster@example.org";
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/default.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/default.nix
index b67f697ca0d..6b1a4be44d1 100644
--- a/nixpkgs/nixos/modules/services/monitoring/prometheus/default.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/default.nix
@@ -9,12 +9,13 @@ let
# a wrapper that verifies that the configuration is valid
promtoolCheck = what: name: file:
- pkgs.runCommand
- "${name}-${replaceStrings [" "] [""] what}-checked"
- { buildInputs = [ cfg.package ]; } ''
- ln -s ${file} $out
- promtool ${what} $out
- '';
+ if cfg.checkConfig then
+ pkgs.runCommand
+ "${name}-${replaceStrings [" "] [""] what}-checked"
+ { buildInputs = [ cfg.package ]; } ''
+ ln -s ${file} $out
+ promtool ${what} $out
+ '' else file;
# Pretty-print JSON to a file
writePrettyJSON = name: x:
@@ -601,6 +602,20 @@ in {
if Prometheus is served via a reverse proxy).
'';
};
+
+ checkConfig = mkOption {
+ type = types.bool;
+ default = true;
+ description = ''
+ Check configuration with <literal>promtool
+ check</literal>. The call to <literal>promtool</literal> is
+ subject to sandboxing by Nix. When credentials are stored in
+ external files (<literal>password_file</literal>,
+ <literal>bearer_token_file</literal>, etc), they will not be
+ visible to <literal>promtool</literal> and it will report
+ errors, despite a correct configuration.
+ '';
+ };
};
config = mkIf cfg.enable {
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.nix
index 36ebffa4463..f9ad1457fc8 100644
--- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.nix
@@ -29,6 +29,7 @@ let
"fritzbox"
"json"
"mail"
+ "mikrotik"
"minio"
"nextcloud"
"nginx"
@@ -197,13 +198,25 @@ in
config = mkMerge ([{
assertions = [ {
- assertion = (cfg.snmp.configurationPath == null) != (cfg.snmp.configuration == null);
+ assertion = cfg.snmp.enable -> (
+ (cfg.snmp.configurationPath == null) != (cfg.snmp.configuration == null)
+ );
message = ''
Please ensure you have either `services.prometheus.exporters.snmp.configuration'
or `services.prometheus.exporters.snmp.configurationPath' set!
'';
} {
- assertion = (cfg.mail.configFile == null) != (cfg.mail.configuration == {});
+ assertion = cfg.mikrotik.enable -> (
+ (cfg.mikrotik.configFile == null) != (cfg.mikrotik.configuration == null)
+ );
+ message = ''
+ Please specify either `services.prometheus.exporters.mikrotik.configuration'
+ or `services.prometheus.exporters.mikrotik.configFile'.
+ '';
+ } {
+ assertion = cfg.mail.enable -> (
+ (cfg.mail.configFile == null) != (cfg.mail.configuration == null)
+ );
message = ''
Please specify either 'services.prometheus.exporters.mail.configuration'
or 'services.prometheus.exporters.mail.configFile'.
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/blackbox.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/blackbox.nix
index 8a90afa9984..fe8d905da3f 100644
--- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/blackbox.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/blackbox.nix
@@ -61,7 +61,7 @@ in {
ExecStart = ''
${pkgs.prometheus-blackbox-exporter}/bin/blackbox_exporter \
--web.listen-address ${cfg.listenAddress}:${toString cfg.port} \
- --config.file ${adjustedConfigFile} \
+ --config.file ${escapeShellArg adjustedConfigFile} \
${concatStringsSep " \\\n " cfg.extraFlags}
'';
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/collectd.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/collectd.nix
index 1cc34641809..97210463027 100644
--- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/collectd.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/collectd.nix
@@ -66,7 +66,7 @@ in
serviceConfig = {
ExecStart = ''
${pkgs.prometheus-collectd-exporter}/bin/collectd_exporter \
- -log.format ${cfg.logFormat} \
+ -log.format ${escapeShellArg cfg.logFormat} \
-log.level ${cfg.logLevel} \
-web.listen-address ${cfg.listenAddress}:${toString cfg.port} \
${collectSettingsArgs} \
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/dnsmasq.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/dnsmasq.nix
index e9fa26cb1f5..68afba21d64 100644
--- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/dnsmasq.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/dnsmasq.nix
@@ -30,7 +30,7 @@ in
${pkgs.prometheus-dnsmasq-exporter}/bin/dnsmasq_exporter \
--listen ${cfg.listenAddress}:${toString cfg.port} \
--dnsmasq ${cfg.dnsmasqListenAddress} \
- --leases_path ${cfg.leasesPath} \
+ --leases_path ${escapeShellArg cfg.leasesPath} \
${concatStringsSep " \\\n " cfg.extraFlags}
'';
};
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/dovecot.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/dovecot.nix
index a01074758ff..aba3533e439 100644
--- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/dovecot.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/dovecot.nix
@@ -64,7 +64,7 @@ in
${pkgs.prometheus-dovecot-exporter}/bin/dovecot_exporter \
--web.listen-address ${cfg.listenAddress}:${toString cfg.port} \
--web.telemetry-path ${cfg.telemetryPath} \
- --dovecot.socket-path ${cfg.socketPath} \
+ --dovecot.socket-path ${escapeShellArg cfg.socketPath} \
--dovecot.scopes ${concatStringsSep "," cfg.scopes} \
${concatStringsSep " \\\n " cfg.extraFlags}
'';
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/json.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/json.nix
index 82a55bafc98..bd0026b55f7 100644
--- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/json.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/json.nix
@@ -27,7 +27,7 @@ in
ExecStart = ''
${pkgs.prometheus-json-exporter}/bin/prometheus-json-exporter \
--port ${toString cfg.port} \
- ${cfg.url} ${cfg.configFile} \
+ ${cfg.url} ${escapeShellArg cfg.configFile} \
${concatStringsSep " \\\n " cfg.extraFlags}
'';
};
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/mail.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/mail.nix
index 7d8c6fb6140..18c5c4dd162 100644
--- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/mail.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/mail.nix
@@ -90,7 +90,7 @@ let
Timeout until mails are considered "didn't make it".
'';
};
- disableFileDelition = mkOption {
+ disableFileDeletion = mkOption {
type = types.bool;
default = false;
description = ''
@@ -127,8 +127,8 @@ in
'';
};
configuration = mkOption {
- type = types.submodule exporterOptions;
- default = {};
+ type = types.nullOr (types.submodule exporterOptions);
+ default = null;
description = ''
Specify the mailexporter configuration file to use.
'';
@@ -147,8 +147,9 @@ in
ExecStart = ''
${pkgs.prometheus-mail-exporter}/bin/mailexporter \
--web.listen-address ${cfg.listenAddress}:${toString cfg.port} \
+ --web.telemetry-path ${cfg.telemetryPath} \
--config.file ${
- if cfg.configuration != {} then configurationFile else cfg.configFile
+ if cfg.configuration != null then configurationFile else (escapeShellArg cfg.configFile)
} \
${concatStringsSep " \\\n " cfg.extraFlags}
'';
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/mikrotik.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/mikrotik.nix
new file mode 100644
index 00000000000..62c2cc56847
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/mikrotik.nix
@@ -0,0 +1,66 @@
+{ config, lib, pkgs, options }:
+
+with lib;
+
+let
+ cfg = config.services.prometheus.exporters.mikrotik;
+in
+{
+ port = 9436;
+ extraOpts = {
+ configFile = mkOption {
+ type = types.nullOr types.path;
+ default = null;
+ description = ''
+ Path to a mikrotik exporter configuration file. Mutually exclusive with
+ <option>configuration</option> option.
+ '';
+ example = literalExample "./mikrotik.yml";
+ };
+
+ configuration = mkOption {
+ type = types.nullOr types.attrs;
+ default = null;
+ description = ''
+ Mikrotik exporter configuration as nix attribute set. Mutually exclusive with
+ <option>configFile</option> option.
+
+ See <link xlink:href="https://github.com/nshttpd/mikrotik-exporter/blob/master/README.md"/>
+ for the description of the configuration file format.
+ '';
+ example = literalExample ''
+ {
+ devices = [
+ {
+ name = "my_router";
+ address = "10.10.0.1";
+ user = "prometheus";
+ password = "changeme";
+ }
+ ];
+ features = {
+ bgp = true;
+ dhcp = true;
+ routes = true;
+ optics = true;
+ };
+ }
+ '';
+ };
+ };
+ serviceOpts = let
+ configFile = if cfg.configFile != null
+ then cfg.configFile
+ else "${pkgs.writeText "mikrotik-exporter.yml" (builtins.toJSON cfg.configuration)}";
+ in {
+ serviceConfig = {
+ # -port is misleading name, it actually accepts address too
+ ExecStart = ''
+ ${pkgs.prometheus-mikrotik-exporter}/bin/mikrotik-exporter \
+ -config-file=${escapeShellArg configFile} \
+ -port=${cfg.listenAddress}:${toString cfg.port} \
+ ${concatStringsSep " \\\n " cfg.extraFlags}
+ '';
+ };
+ };
+}
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/minio.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/minio.nix
index ab3e3d7d5d5..d6dd62f871b 100644
--- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/minio.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/minio.nix
@@ -54,8 +54,8 @@ in
${pkgs.prometheus-minio-exporter}/bin/minio-exporter \
-web.listen-address ${cfg.listenAddress}:${toString cfg.port} \
-minio.server ${cfg.minioAddress} \
- -minio.access-key ${cfg.minioAccessKey} \
- -minio.access-secret ${cfg.minioAccessSecret} \
+ -minio.access-key ${escapeShellArg cfg.minioAccessKey} \
+ -minio.access-secret ${escapeShellArg cfg.minioAccessSecret} \
${optionalString cfg.minioBucketStats "-minio.bucket-stats"} \
${concatStringsSep " \\\n " cfg.extraFlags}
'';
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/nextcloud.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/nextcloud.nix
index 5f9a52053f7..aee6bd5e66c 100644
--- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/nextcloud.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/nextcloud.nix
@@ -50,7 +50,7 @@ in
-u ${cfg.username} \
-t ${cfg.timeout} \
-l ${cfg.url} \
- -p @${cfg.passwordFile} \
+ -p ${escapeShellArg "@${cfg.passwordFile}"} \
${concatStringsSep " \\\n " cfg.extraFlags}
'';
};
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/nginx.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/nginx.nix
index ba852fea433..56cddfc55b7 100644
--- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/nginx.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/nginx.nix
@@ -30,7 +30,17 @@ in
Whether to perform certificate verification for https.
'';
};
-
+ constLabels = mkOption {
+ type = types.listOf types.str;
+ default = [];
+ example = [
+ "label1=value1"
+ "label2=value2"
+ ];
+ description = ''
+ A list of constant labels that will be used in every metric.
+ '';
+ };
};
serviceOpts = {
serviceConfig = {
@@ -40,6 +50,7 @@ in
--nginx.ssl-verify ${toString cfg.sslVerify} \
--web.listen-address ${cfg.listenAddress}:${toString cfg.port} \
--web.telemetry-path ${cfg.telemetryPath} \
+ --prometheus.const-labels ${concatStringsSep "," cfg.constLabels} \
${concatStringsSep " \\\n " cfg.extraFlags}
'';
};
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/postfix.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/postfix.nix
index d50564717ea..3b6ef1631f8 100644
--- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/postfix.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/postfix.nix
@@ -67,15 +67,15 @@ in
${pkgs.prometheus-postfix-exporter}/bin/postfix_exporter \
--web.listen-address ${cfg.listenAddress}:${toString cfg.port} \
--web.telemetry-path ${cfg.telemetryPath} \
- --postfix.showq_path ${cfg.showqPath} \
+ --postfix.showq_path ${escapeShellArg cfg.showqPath} \
${concatStringsSep " \\\n " (cfg.extraFlags
++ optional cfg.systemd.enable "--systemd.enable"
++ optional cfg.systemd.enable (if cfg.systemd.slice != null
then "--systemd.slice ${cfg.systemd.slice}"
else "--systemd.unit ${cfg.systemd.unit}")
++ optional (cfg.systemd.enable && (cfg.systemd.journalPath != null))
- "--systemd.journal_path ${cfg.systemd.journalPath}"
- ++ optional (!cfg.systemd.enable) "--postfix.logfile_path ${cfg.logfilePath}")}
+ "--systemd.journal_path ${escapeShellArg cfg.systemd.journalPath}"
+ ++ optional (!cfg.systemd.enable) "--postfix.logfile_path ${escapeShellArg cfg.logfilePath}")}
'';
};
};
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/snmp.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/snmp.nix
index fe7ae8a8ac9..045e48a3d0f 100644
--- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/snmp.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/snmp.nix
@@ -19,7 +19,7 @@ in
configuration = mkOption {
type = types.nullOr types.attrs;
- default = {};
+ default = null;
description = ''
Snmp exporter configuration as nix attribute set. Mutually exclusive with 'configurationPath' option.
'';
@@ -36,15 +36,15 @@ in
};
logFormat = mkOption {
- type = types.str;
- default = "logger:stderr";
+ type = types.enum ["logfmt" "json"];
+ default = "logfmt";
description = ''
- Set the log target and format.
+ Output format of log messages.
'';
};
logLevel = mkOption {
- type = types.enum ["debug" "info" "warn" "error" "fatal"];
+ type = types.enum ["debug" "info" "warn" "error"];
default = "info";
description = ''
Only log messages with the given severity or above.
@@ -54,13 +54,13 @@ in
serviceOpts = let
configFile = if cfg.configurationPath != null
then cfg.configurationPath
- else "${pkgs.writeText "snmp-eporter-conf.yml" (builtins.toJSON cfg.configuration)}";
+ else "${pkgs.writeText "snmp-exporter-conf.yml" (builtins.toJSON cfg.configuration)}";
in {
serviceConfig = {
ExecStart = ''
${pkgs.prometheus-snmp-exporter.bin}/bin/snmp_exporter \
- --config.file=${configFile} \
- --log.format=${cfg.logFormat} \
+ --config.file=${escapeShellArg configFile} \
+ --log.format=${escapeShellArg cfg.logFormat} \
--log.level=${cfg.logLevel} \
--web.listen-address=${cfg.listenAddress}:${toString cfg.port} \
${concatStringsSep " \\\n " cfg.extraFlags}
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/unifi.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/unifi.nix
index 9aa0f1b85aa..8d0e8764001 100644
--- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/unifi.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/unifi.nix
@@ -55,8 +55,8 @@ in
${pkgs.prometheus-unifi-exporter}/bin/unifi_exporter \
-telemetry.addr ${cfg.listenAddress}:${toString cfg.port} \
-unifi.addr ${cfg.unifiAddress} \
- -unifi.username ${cfg.unifiUsername} \
- -unifi.password ${cfg.unifiPassword} \
+ -unifi.username ${escapeShellArg cfg.unifiUsername} \
+ -unifi.password ${escapeShellArg cfg.unifiPassword} \
-unifi.timeout ${cfg.unifiTimeout} \
${optionalString cfg.unifiInsecure "-unifi.insecure" } \
${concatStringsSep " \\\n " cfg.extraFlags}
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/varnish.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/varnish.nix
index 12153fa021e..5b5a6e18fcd 100644
--- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/varnish.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/varnish.nix
@@ -74,10 +74,10 @@ in
${pkgs.prometheus-varnish-exporter}/bin/prometheus_varnish_exporter \
--web.listen-address ${cfg.listenAddress}:${toString cfg.port} \
--web.telemetry-path ${cfg.telemetryPath} \
- --varnishstat-path ${cfg.varnishStatPath} \
+ --varnishstat-path ${escapeShellArg cfg.varnishStatPath} \
${concatStringsSep " \\\n " (cfg.extraFlags
++ optional (cfg.healthPath != null) "--web.health-path ${cfg.healthPath}"
- ++ optional (cfg.instance != null) "-n ${cfg.instance}"
+ ++ optional (cfg.instance != null) "-n ${escapeShellArg cfg.instance}"
++ optional cfg.noExit "--no-exit"
++ optional cfg.withGoMetrics "--with-go-metrics"
++ optional cfg.verbose "--verbose"
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/wireguard.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/wireguard.nix
index 374f83a2939..04421fc2d25 100644
--- a/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/wireguard.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/wireguard.nix
@@ -59,7 +59,7 @@ in {
${optionalString cfg.verbose "-v"} \
${optionalString cfg.singleSubnetPerField "-s"} \
${optionalString cfg.withRemoteIp "-r"} \
- ${optionalString (cfg.wireguardConfig != null) "-n ${cfg.wireguardConfig}"}
+ ${optionalString (cfg.wireguardConfig != null) "-n ${escapeShellArg cfg.wireguardConfig}"}
'';
};
};
diff --git a/nixpkgs/nixos/modules/services/monitoring/prometheus/xmpp-alerts.nix b/nixpkgs/nixos/modules/services/monitoring/prometheus/xmpp-alerts.nix
new file mode 100644
index 00000000000..44b15cb2034
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/monitoring/prometheus/xmpp-alerts.nix
@@ -0,0 +1,47 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ cfg = config.services.prometheus.xmpp-alerts;
+
+ configFile = pkgs.writeText "prometheus-xmpp-alerts.yml" (builtins.toJSON cfg.configuration);
+
+in
+
+{
+ options.services.prometheus.xmpp-alerts = {
+
+ enable = mkEnableOption "XMPP Web hook service for Alertmanager";
+
+ configuration = mkOption {
+ type = types.attrs;
+ description = "Configuration as attribute set which will be converted to YAML";
+ };
+
+ };
+
+ config = mkIf cfg.enable {
+ systemd.services.prometheus-xmpp-alerts = {
+ wantedBy = [ "multi-user.target" ];
+ after = [ "network-online.target" ];
+ wants = [ "network-online.target" ];
+ serviceConfig = {
+ ExecStart = "${pkgs.prometheus-xmpp-alerts}/bin/prometheus-xmpp-alerts --config ${configFile}";
+ Restart = "on-failure";
+ DynamicUser = true;
+ PrivateTmp = true;
+ PrivateDevices = true;
+ ProtectHome = true;
+ ProtectSystem = "strict";
+ ProtectKernelTunables = true;
+ ProtectKernelModules = true;
+ ProtectControlGroups = true;
+ NoNewPrivileges = true;
+ SystemCallArchitectures = "native";
+ RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
+ SystemCallFilter = [ "@system-service" ];
+ };
+ };
+ };
+}
diff --git a/nixpkgs/nixos/modules/services/monitoring/statsd.nix b/nixpkgs/nixos/modules/services/monitoring/statsd.nix
index 17836e95a6f..30b2916a992 100644
--- a/nixpkgs/nixos/modules/services/monitoring/statsd.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/statsd.nix
@@ -125,7 +125,7 @@ in
message = "Only builtin backends (graphite, console, repeater) or backends enumerated in `pkgs.nodePackages` are allowed!";
}) cfg.backends;
- users.use.statsdrs = {
+ users.users.statsd = {
uid = config.ids.uids.statsd;
description = "Statsd daemon user";
};
diff --git a/nixpkgs/nixos/modules/services/networking/cjdns.nix b/nixpkgs/nixos/modules/services/networking/cjdns.nix
index 3fb85b16cbe..5f8ac96b229 100644
--- a/nixpkgs/nixos/modules/services/networking/cjdns.nix
+++ b/nixpkgs/nixos/modules/services/networking/cjdns.nix
@@ -29,17 +29,13 @@ let
};
# Additional /etc/hosts entries for peers with an associated hostname
- cjdnsExtraHosts = import (pkgs.runCommand "cjdns-hosts" {}
- # Generate a builder that produces an output usable as a Nix string value
- ''
- exec >$out
- echo \'\'
- ${concatStringsSep "\n" (mapAttrsToList (k: v:
- optionalString (v.hostname != "")
- "echo $(${pkgs.cjdns}/bin/publictoip6 ${v.publicKey}) ${v.hostname}")
- (cfg.ETHInterface.connectTo // cfg.UDPInterface.connectTo))}
- echo \'\'
- '');
+ cjdnsExtraHosts = pkgs.runCommandNoCC "cjdns-hosts" {} ''
+ exec >$out
+ ${concatStringsSep "\n" (mapAttrsToList (k: v:
+ optionalString (v.hostname != "")
+ "echo $(${pkgs.cjdns}/bin/publictoip6 ${v.publicKey}) ${v.hostname}")
+ (cfg.ETHInterface.connectTo // cfg.UDPInterface.connectTo))}
+ '';
parseModules = x:
x // { connectTo = mapAttrs (name: value: { inherit (value) password publicKey; }) x.connectTo; };
@@ -144,13 +140,15 @@ in
connectTo = mkOption {
type = types.attrsOf ( types.submodule ( connectToSubmodule ) );
default = { };
- example = {
- "192.168.1.1:27313" = {
- hostname = "homer.hype";
- password = "5kG15EfpdcKNX3f2GSQ0H1HC7yIfxoCoImnO5FHM";
- publicKey = "371zpkgs8ss387tmr81q04mp0hg1skb51hw34vk1cq644mjqhup0.k";
- };
- };
+ example = literalExample ''
+ {
+ "192.168.1.1:27313" = {
+ hostname = "homer.hype";
+ password = "5kG15EfpdcKNX3f2GSQ0H1HC7yIfxoCoImnO5FHM";
+ publicKey = "371zpkgs8ss387tmr81q04mp0hg1skb51hw34vk1cq644mjqhup0.k";
+ };
+ }
+ '';
description = ''
Credentials for making UDP tunnels.
'';
@@ -189,13 +187,15 @@ in
connectTo = mkOption {
type = types.attrsOf ( types.submodule ( connectToSubmodule ) );
default = { };
- example = {
- "01:02:03:04:05:06" = {
- hostname = "homer.hype";
- password = "5kG15EfpdcKNX3f2GSQ0H1HC7yIfxoCoImnO5FHM";
- publicKey = "371zpkgs8ss387tmr81q04mp0hg1skb51hw34vk1cq644mjqhup0.k";
- };
- };
+ example = literalExample ''
+ {
+ "01:02:03:04:05:06" = {
+ hostname = "homer.hype";
+ password = "5kG15EfpdcKNX3f2GSQ0H1HC7yIfxoCoImnO5FHM";
+ publicKey = "371zpkgs8ss387tmr81q04mp0hg1skb51hw34vk1cq644mjqhup0.k";
+ };
+ }
+ '';
description = ''
Credentials for connecting look similar to UDP credientials
except they begin with the mac address.
@@ -278,7 +278,7 @@ in
};
};
- networking.extraHosts = mkIf cfg.addExtraHosts cjdnsExtraHosts;
+ networking.hostFiles = mkIf cfg.addExtraHosts [ cjdnsExtraHosts ];
assertions = [
{ assertion = ( cfg.ETHInterface.bind != "" || cfg.UDPInterface.bind != "" || cfg.confFile != null );
diff --git a/nixpkgs/nixos/modules/services/networking/dhcpcd.nix b/nixpkgs/nixos/modules/services/networking/dhcpcd.nix
index 6972c833cc5..c0619211c2f 100644
--- a/nixpkgs/nixos/modules/services/networking/dhcpcd.nix
+++ b/nixpkgs/nixos/modules/services/networking/dhcpcd.nix
@@ -19,7 +19,7 @@ let
map (i: i.name) (filter (i: if i.useDHCP != null then !i.useDHCP else i.ipv4.addresses != [ ]) interfaces)
++ mapAttrsToList (i: _: i) config.networking.sits
++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.bridges))
- ++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.vswitches))
+ ++ flatten (concatMap (i: attrNames (filterAttrs (_: config: config.type != "internal") i.interfaces)) (attrValues config.networking.vswitches))
++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.bonds))
++ config.networking.dhcpcd.denyInterfaces;
@@ -190,6 +190,8 @@ in
before = [ "network-online.target" ];
after = [ "systemd-udev-settle.service" ];
+ restartTriggers = [ exitHook ];
+
# Stopping dhcpcd during a reconfiguration is undesirable
# because it brings down the network interfaces configured by
# dhcpcd. So do a "systemctl restart" instead.
diff --git a/nixpkgs/nixos/modules/services/networking/dnscrypt-proxy.nix b/nixpkgs/nixos/modules/services/networking/dnscrypt-proxy.nix
deleted file mode 100644
index 8edcf925dbf..00000000000
--- a/nixpkgs/nixos/modules/services/networking/dnscrypt-proxy.nix
+++ /dev/null
@@ -1,328 +0,0 @@
-{ config, lib, pkgs, ... }:
-with lib;
-
-let
- cfg = config.services.dnscrypt-proxy;
-
- stateDirectory = "/var/lib/dnscrypt-proxy";
-
- # The minisign public key used to sign the upstream resolver list.
- # This is somewhat more flexible than preloading the key as an
- # embedded string.
- upstreamResolverListPubKey = pkgs.fetchurl {
- url = https://raw.githubusercontent.com/dyne/dnscrypt-proxy/master/minisign.pub;
- sha256 = "18lnp8qr6ghfc2sd46nn1rhcpr324fqlvgsp4zaigw396cd7vnnh";
- };
-
- # Internal flag indicating whether the upstream resolver list is used.
- useUpstreamResolverList = cfg.customResolver == null;
-
- # The final local address.
- localAddress = "${cfg.localAddress}:${toString cfg.localPort}";
-
- # The final resolvers list path.
- resolverList = "${stateDirectory}/dnscrypt-resolvers.csv";
-
- # Build daemon command line
-
- resolverArgs =
- if (cfg.customResolver == null)
- then
- [ "-L ${resolverList}"
- "-R ${cfg.resolverName}"
- ]
- else with cfg.customResolver;
- [ "-N ${name}"
- "-k ${key}"
- "-r ${address}:${toString port}"
- ];
-
- daemonArgs =
- [ "-a ${localAddress}" ]
- ++ resolverArgs
- ++ cfg.extraArgs;
-in
-
-{
- meta = {
- maintainers = with maintainers; [ joachifm ];
- doc = ./dnscrypt-proxy.xml;
- };
-
- options = {
- # Before adding another option, consider whether it could
- # equally well be passed via extraArgs.
-
- services.dnscrypt-proxy = {
- enable = mkOption {
- default = false;
- type = types.bool;
- description = "Whether to enable the DNSCrypt client proxy";
- };
-
- localAddress = mkOption {
- default = "127.0.0.1";
- type = types.str;
- description = ''
- Listen for DNS queries to relay on this address. The only reason to
- change this from its default value is to proxy queries on behalf
- of other machines (typically on the local network).
- '';
- };
-
- localPort = mkOption {
- default = 53;
- type = types.int;
- description = ''
- Listen for DNS queries to relay on this port. The default value
- assumes that the DNSCrypt proxy should relay DNS queries directly.
- When running as a forwarder for another DNS client, set this option
- to a different value; otherwise leave the default.
- '';
- };
-
- resolverName = mkOption {
- default = "random";
- example = "dnscrypt.eu-nl";
- type = types.nullOr types.str;
- description = ''
- The name of the DNSCrypt resolver to use, taken from
- <filename>${resolverList}</filename>. The default is to
- pick a random non-logging resolver that supports DNSSEC.
- '';
- };
-
- customResolver = mkOption {
- default = null;
- description = ''
- Use an unlisted resolver (e.g., a private DNSCrypt provider). For
- advanced users only. If specified, this option takes precedence.
- '';
- type = types.nullOr (types.submodule ({ ... }: { options = {
- address = mkOption {
- type = types.str;
- description = "IP address";
- example = "208.67.220.220";
- };
-
- port = mkOption {
- type = types.int;
- description = "Port";
- default = 443;
- };
-
- name = mkOption {
- type = types.str;
- description = "Fully qualified domain name";
- example = "2.dnscrypt-cert.example.com";
- };
-
- key = mkOption {
- type = types.str;
- description = "Public key";
- example = "B735:1140:206F:225D:3E2B:D822:D7FD:691E:A1C3:3CC8:D666:8D0C:BE04:BFAB:CA43:FB79";
- };
- }; }));
- };
-
- extraArgs = mkOption {
- default = [];
- type = types.listOf types.str;
- description = ''
- Additional command-line arguments passed verbatim to the daemon.
- See <citerefentry><refentrytitle>dnscrypt-proxy</refentrytitle>
- <manvolnum>8</manvolnum></citerefentry> for details.
- '';
- example = [ "-X libdcplugin_example_cache.so,--min-ttl=60" ];
- };
- };
- };
-
- config = mkIf cfg.enable (mkMerge [{
- assertions = [
- { assertion = (cfg.customResolver != null) || (cfg.resolverName != null);
- message = "please configure upstream DNSCrypt resolver";
- }
- ];
-
- # make man 8 dnscrypt-proxy work
- environment.systemPackages = [ pkgs.dnscrypt-proxy ];
-
- users.users.dnscrypt-proxy = {
- description = "dnscrypt-proxy daemon user";
- isSystemUser = true;
- group = "dnscrypt-proxy";
- };
- users.groups.dnscrypt-proxy = {};
-
- systemd.sockets.dnscrypt-proxy = {
- description = "dnscrypt-proxy listening socket";
- documentation = [ "man:dnscrypt-proxy(8)" ];
-
- wantedBy = [ "sockets.target" ];
-
- socketConfig = {
- ListenStream = localAddress;
- ListenDatagram = localAddress;
- };
- };
-
- systemd.services.dnscrypt-proxy = {
- description = "dnscrypt-proxy daemon";
- documentation = [ "man:dnscrypt-proxy(8)" ];
-
- before = [ "nss-lookup.target" ];
- after = [ "network.target" ];
- requires = [ "dnscrypt-proxy.socket "];
-
- serviceConfig = {
- NonBlocking = "true";
- ExecStart = "${pkgs.dnscrypt-proxy}/bin/dnscrypt-proxy ${toString daemonArgs}";
- ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
-
- User = "dnscrypt-proxy";
-
- PrivateTmp = true;
- PrivateDevices = true;
- ProtectHome = true;
- };
- };
- }
-
- (mkIf config.security.apparmor.enable {
- systemd.services.dnscrypt-proxy.after = [ "apparmor.service" ];
-
- security.apparmor.profiles = singleton (pkgs.writeText "apparmor-dnscrypt-proxy" ''
- ${pkgs.dnscrypt-proxy}/bin/dnscrypt-proxy {
- /dev/null rw,
- /dev/random r,
- /dev/urandom r,
-
- /etc/passwd r,
- /etc/group r,
- ${config.environment.etc."nsswitch.conf".source} r,
-
- ${getLib pkgs.glibc}/lib/*.so mr,
- ${pkgs.tzdata}/share/zoneinfo/** r,
-
- network inet stream,
- network inet6 stream,
- network inet dgram,
- network inet6 dgram,
-
- ${getLib pkgs.dnscrypt-proxy}/lib/dnscrypt-proxy/libdcplugin*.so mr,
-
- ${getLib pkgs.gcc.cc}/lib/libssp.so.* mr,
- ${getLib pkgs.libsodium}/lib/libsodium.so.* mr,
- ${getLib pkgs.systemd}/lib/libsystemd.so.* mr,
- ${getLib pkgs.utillinuxMinimal.out}/lib/libmount.so.* mr,
- ${getLib pkgs.utillinuxMinimal.out}/lib/libblkid.so.* mr,
- ${getLib pkgs.utillinuxMinimal.out}/lib/libuuid.so.* mr,
- ${getLib pkgs.xz}/lib/liblzma.so.* mr,
- ${getLib pkgs.libgcrypt}/lib/libgcrypt.so.* mr,
- ${getLib pkgs.libgpgerror}/lib/libgpg-error.so.* mr,
- ${getLib pkgs.libcap}/lib/libcap.so.* mr,
- ${getLib pkgs.lz4}/lib/liblz4.so.* mr,
- ${getLib pkgs.attr}/lib/libattr.so.* mr, # */
-
- ${resolverList} r,
-
- /run/systemd/notify rw,
- }
- '');
- })
-
- (mkIf useUpstreamResolverList {
- systemd.services.init-dnscrypt-proxy-statedir = {
- description = "Initialize dnscrypt-proxy state directory";
-
- wantedBy = [ "dnscrypt-proxy.service" ];
- before = [ "dnscrypt-proxy.service" ];
-
- script = ''
- mkdir -pv ${stateDirectory}
- chown -c dnscrypt-proxy:dnscrypt-proxy ${stateDirectory}
- cp -uv \
- ${pkgs.dnscrypt-proxy}/share/dnscrypt-proxy/dnscrypt-resolvers.csv \
- ${stateDirectory}
- '';
-
- serviceConfig = {
- Type = "oneshot";
- RemainAfterExit = true;
- };
- };
-
- systemd.services.update-dnscrypt-resolvers = {
- description = "Update list of DNSCrypt resolvers";
-
- requires = [ "init-dnscrypt-proxy-statedir.service" ];
- after = [ "init-dnscrypt-proxy-statedir.service" ];
-
- path = with pkgs; [ curl diffutils dnscrypt-proxy minisign ];
- script = ''
- cd ${stateDirectory}
- domain=raw.githubusercontent.com
- get="curl -fSs --resolve $domain:443:$(hostip -r 8.8.8.8 $domain | head -1)"
- $get -o dnscrypt-resolvers.csv.tmp \
- https://$domain/dyne/dnscrypt-proxy/master/dnscrypt-resolvers.csv
- $get -o dnscrypt-resolvers.csv.minisig.tmp \
- https://$domain/dyne/dnscrypt-proxy/master/dnscrypt-resolvers.csv.minisig
- mv dnscrypt-resolvers.csv.minisig{.tmp,}
- if ! minisign -q -V -p ${upstreamResolverListPubKey} \
- -m dnscrypt-resolvers.csv.tmp -x dnscrypt-resolvers.csv.minisig ; then
- echo "failed to verify resolver list!" >&2
- exit 1
- fi
- [[ -f dnscrypt-resolvers.csv ]] && mv dnscrypt-resolvers.csv{,.old}
- mv dnscrypt-resolvers.csv{.tmp,}
- if cmp dnscrypt-resolvers.csv{,.old} ; then
- echo "no change"
- else
- echo "resolver list updated"
- fi
- '';
-
- serviceConfig = {
- PrivateTmp = true;
- PrivateDevices = true;
- ProtectHome = true;
- ProtectSystem = "strict";
- ReadWritePaths = "${dirOf stateDirectory} ${stateDirectory}";
- SystemCallFilter = "~@mount";
- };
- };
-
- systemd.timers.update-dnscrypt-resolvers = {
- wantedBy = [ "timers.target" ];
- timerConfig = {
- OnBootSec = "5min";
- OnUnitActiveSec = "6h";
- };
- };
- })
- ]);
-
- imports = [
- (mkRenamedOptionModule [ "services" "dnscrypt-proxy" "port" ] [ "services" "dnscrypt-proxy" "localPort" ])
-
- (mkChangedOptionModule
- [ "services" "dnscrypt-proxy" "tcpOnly" ]
- [ "services" "dnscrypt-proxy" "extraArgs" ]
- (config:
- let val = getAttrFromPath [ "services" "dnscrypt-proxy" "tcpOnly" ] config; in
- optional val "-T"))
-
- (mkChangedOptionModule
- [ "services" "dnscrypt-proxy" "ephemeralKeys" ]
- [ "services" "dnscrypt-proxy" "extraArgs" ]
- (config:
- let val = getAttrFromPath [ "services" "dnscrypt-proxy" "ephemeralKeys" ] config; in
- optional val "-E"))
-
- (mkRemovedOptionModule [ "services" "dnscrypt-proxy" "resolverList" ] ''
- The current resolver listing from upstream is always used
- unless a custom resolver is specified.
- '')
- ];
-}
diff --git a/nixpkgs/nixos/modules/services/networking/dnscrypt-proxy.xml b/nixpkgs/nixos/modules/services/networking/dnscrypt-proxy.xml
deleted file mode 100644
index afc7880392a..00000000000
--- a/nixpkgs/nixos/modules/services/networking/dnscrypt-proxy.xml
+++ /dev/null
@@ -1,66 +0,0 @@
-<chapter xmlns="http://docbook.org/ns/docbook"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- xmlns:xi="http://www.w3.org/2001/XInclude"
- version="5.0"
- xml:id="sec-dnscrypt-proxy">
- <title>DNSCrypt client proxy</title>
- <para>
- The DNSCrypt client proxy relays DNS queries to a DNSCrypt enabled upstream
- resolver. The traffic between the client and the upstream resolver is
- encrypted and authenticated, mitigating the risk of MITM attacks, DNS
- poisoning attacks, and third-party snooping (assuming the upstream is
- trustworthy).
- </para>
- <sect1 xml:id="sec-dnscrypt-proxy-configuration">
- <title>Basic configuration</title>
-
- <para>
- To enable the client proxy, set
-<programlisting>
-<xref linkend="opt-services.dnscrypt-proxy.enable"/> = true;
-</programlisting>
- </para>
-
- <para>
- Enabling the client proxy does not alter the system nameserver; to relay
- local queries, prepend <literal>127.0.0.1</literal> to
- <option>networking.nameservers</option>.
- </para>
- </sect1>
- <sect1 xml:id="sec-dnscrypt-proxy-forwarder">
- <title>As a forwarder for another DNS client</title>
-
- <para>
- To run the DNSCrypt proxy client as a forwarder for another DNS client,
- change the default proxy listening port to a non-standard value and point
- the other client to it:
-<programlisting>
-<xref linkend="opt-services.dnscrypt-proxy.localPort"/> = 43;
-</programlisting>
- </para>
-
- <sect2 xml:id="sec-dnscrypt-proxy-forwarder-dsnmasq">
- <title>dnsmasq</title>
- <para>
-<programlisting>
-{
- <xref linkend="opt-services.dnsmasq.enable"/> = true;
- <xref linkend="opt-services.dnsmasq.servers"/> = [ "127.0.0.1#43" ];
-}
-</programlisting>
- </para>
- </sect2>
-
- <sect2 xml:id="sec-dnscrypt-proxy-forwarder-unbound">
- <title>unbound</title>
- <para>
-<programlisting>
-{
- <xref linkend="opt-services.unbound.enable"/> = true;
- <xref linkend="opt-services.unbound.forwardAddresses"/> = [ "127.0.0.1@43" ];
-}
-</programlisting>
- </para>
- </sect2>
- </sect1>
-</chapter>
diff --git a/nixpkgs/nixos/modules/services/networking/dnscrypt-proxy2.nix b/nixpkgs/nixos/modules/services/networking/dnscrypt-proxy2.nix
new file mode 100644
index 00000000000..e48eb729103
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/networking/dnscrypt-proxy2.nix
@@ -0,0 +1,61 @@
+{ config, lib, pkgs, ... }: with lib;
+
+let
+ cfg = config.services.dnscrypt-proxy2;
+in
+
+{
+ options.services.dnscrypt-proxy2 = {
+ enable = mkEnableOption "dnscrypt-proxy2";
+
+ settings = mkOption {
+ description = ''
+ Attrset that is converted and passed as TOML config file.
+ For available params, see: <link xlink:href="https://github.com/DNSCrypt/dnscrypt-proxy/blob/master/dnscrypt-proxy/example-dnscrypt-proxy.toml"/>
+ '';
+ example = literalExample ''
+ {
+ sources.public-resolvers = {
+ urls = [ "https://download.dnscrypt.info/resolvers-list/v2/public-resolvers.md" ];
+ cache_file = "public-resolvers.md";
+ minisign_key = "RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3";
+ refresh_delay = 72;
+ };
+ }
+ '';
+ type = types.attrs;
+ default = {};
+ };
+
+ configFile = mkOption {
+ description = ''
+ Path to TOML config file. See: <link xlink:href="https://github.com/DNSCrypt/dnscrypt-proxy/blob/master/dnscrypt-proxy/example-dnscrypt-proxy.toml"/>
+ If this option is set, it will override any configuration done in options.services.dnscrypt-proxy2.settings.
+ '';
+ example = "/etc/dnscrypt-proxy/dnscrypt-proxy.toml";
+ type = types.path;
+ default = pkgs.runCommand "dnscrypt-proxy.toml" {
+ json = builtins.toJSON cfg.settings;
+ passAsFile = [ "json" ];
+ } ''
+ ${pkgs.remarshal}/bin/json2toml < $jsonPath > $out
+ '';
+ defaultText = literalExample "TOML file generated from services.dnscrypt-proxy2.settings";
+ };
+ };
+
+ config = mkIf cfg.enable {
+
+ networking.nameservers = lib.mkDefault [ "127.0.0.1" ];
+
+ systemd.services.dnscrypt-proxy2 = {
+ after = [ "network.target" ];
+ wantedBy = [ "multi-user.target" ];
+ serviceConfig = {
+ AmbientCapabilities = "CAP_NET_BIND_SERVICE";
+ DynamicUser = true;
+ ExecStart = "${pkgs.dnscrypt-proxy2}/bin/dnscrypt-proxy -config ${cfg.configFile}";
+ };
+ };
+ };
+}
diff --git a/nixpkgs/nixos/modules/services/networking/firewall.nix b/nixpkgs/nixos/modules/services/networking/firewall.nix
index 15aaf741067..cdc3a172ea7 100644
--- a/nixpkgs/nixos/modules/services/networking/firewall.nix
+++ b/nixpkgs/nixos/modules/services/networking/firewall.nix
@@ -546,9 +546,13 @@ in
options nf_conntrack nf_conntrack_helper=1
'';
- assertions = [ { assertion = (cfg.checkReversePath != false) || kernelHasRPFilter;
- message = "This kernel does not support rpfilter"; }
- ];
+ assertions = [
+ # This is approximately "checkReversePath -> kernelHasRPFilter",
+ # but the checkReversePath option can include non-boolean
+ # values.
+ { assertion = cfg.checkReversePath == false || kernelHasRPFilter;
+ message = "This kernel does not support rpfilter"; }
+ ];
systemd.services.firewall = {
description = "Firewall";
diff --git a/nixpkgs/nixos/modules/services/networking/freeradius.nix b/nixpkgs/nixos/modules/services/networking/freeradius.nix
index e192b70c129..f3fdd576b65 100644
--- a/nixpkgs/nixos/modules/services/networking/freeradius.nix
+++ b/nixpkgs/nixos/modules/services/networking/freeradius.nix
@@ -10,14 +10,15 @@ let
{
description = "FreeRadius server";
wantedBy = ["multi-user.target"];
- after = ["network-online.target"];
- wants = ["network-online.target"];
+ after = ["network.target"];
+ wants = ["network.target"];
preStart = ''
${pkgs.freeradius}/bin/radiusd -C -d ${cfg.configDir} -l stdout
'';
serviceConfig = {
- ExecStart = "${pkgs.freeradius}/bin/radiusd -f -d ${cfg.configDir} -l stdout -xx";
+ ExecStart = "${pkgs.freeradius}/bin/radiusd -f -d ${cfg.configDir} -l stdout" +
+ optionalString cfg.debug " -xx";
ExecReload = [
"${pkgs.freeradius}/bin/radiusd -C -d ${cfg.configDir} -l stdout"
"${pkgs.coreutils}/bin/kill -HUP $MAINPID"
@@ -41,6 +42,16 @@ let
'';
};
+ debug = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Whether to enable debug logging for freeradius (-xx
+ option). This should not be left on, since it includes
+ sensitive data such as passwords in the logs.
+ '';
+ };
+
};
in
@@ -66,6 +77,7 @@ in
};
systemd.services.freeradius = freeradiusService cfg;
+ warnings = optional cfg.debug "Freeradius debug logging is enabled. This will log passwords in plaintext to the journal!";
};
diff --git a/nixpkgs/nixos/modules/services/networking/git-daemon.nix b/nixpkgs/nixos/modules/services/networking/git-daemon.nix
index 6f2e149433f..52c895215fb 100644
--- a/nixpkgs/nixos/modules/services/networking/git-daemon.nix
+++ b/nixpkgs/nixos/modules/services/networking/git-daemon.nix
@@ -104,14 +104,14 @@ in
config = mkIf cfg.enable {
- users.users = optionalAttrs (cfg.user != "git") {
+ users.users = optionalAttrs (cfg.user == "git") {
git = {
uid = config.ids.uids.git;
description = "Git daemon user";
};
};
- users.groups = optionalAttrs (cfg.group != "git") {
+ users.groups = optionalAttrs (cfg.group == "git") {
git.gid = config.ids.gids.git;
};
diff --git a/nixpkgs/nixos/modules/services/networking/haproxy.nix b/nixpkgs/nixos/modules/services/networking/haproxy.nix
index aff71e5e97d..4678829986c 100644
--- a/nixpkgs/nixos/modules/services/networking/haproxy.nix
+++ b/nixpkgs/nixos/modules/services/networking/haproxy.nix
@@ -26,6 +26,18 @@ with lib;
'';
};
+ user = mkOption {
+ type = types.str;
+ default = "haproxy";
+ description = "User account under which haproxy runs.";
+ };
+
+ group = mkOption {
+ type = types.str;
+ default = "haproxy";
+ description = "Group account under which haproxy runs.";
+ };
+
config = mkOption {
type = types.nullOr types.lines;
default = null;
@@ -49,7 +61,8 @@ with lib;
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
- DynamicUser = true;
+ User = cfg.user;
+ Group = cfg.group;
Type = "notify";
# when running the config test, don't be quiet so we can see what goes wrong
ExecStartPre = "${pkgs.haproxy}/sbin/haproxy -c -f ${haproxyCfg}";
@@ -60,5 +73,16 @@ with lib;
AmbientCapabilities = "CAP_NET_BIND_SERVICE";
};
};
+
+ users.users = optionalAttrs (cfg.user == "haproxy") {
+ haproxy = {
+ group = cfg.group;
+ isSystemUser = true;
+ };
+ };
+
+ users.groups = optionalAttrs (cfg.group == "haproxy") {
+ haproxy = {};
+ };
};
}
diff --git a/nixpkgs/nixos/modules/services/networking/i2pd.nix b/nixpkgs/nixos/modules/services/networking/i2pd.nix
index 326d34f6ca9..93a21fd4c97 100644
--- a/nixpkgs/nixos/modules/services/networking/i2pd.nix
+++ b/nixpkgs/nixos/modules/services/networking/i2pd.nix
@@ -158,10 +158,10 @@ let
(sec "addressbook")
(strOpt "defaulturl" cfg.addressbook.defaulturl)
] ++ (optionalEmptyList "subscriptions" cfg.addressbook.subscriptions)
- ++ (flip mapAttrs
- (collect (name: proto: proto ? port && proto ? address && proto ? name) cfg.proto)
+ ++ (flip map
+ (collect (proto: proto ? port && proto ? address) cfg.proto)
(proto: let protoOpts = [
- (sec name)
+ (sec proto.name)
(boolOpt "enabled" proto.enable)
(strOpt "address" proto.address)
(intOpt "port" proto.port)
@@ -181,10 +181,10 @@ let
tunnelConf = let opts = [
notice
- (flip mapAttrs
- (collect (name: tun: tun ? port && tun ? destination) cfg.outTunnels)
+ (flip map
+ (collect (tun: tun ? port && tun ? destination) cfg.outTunnels)
(tun: let outTunOpts = [
- (sec name)
+ (sec tun.name)
"type = client"
(intOpt "port" tun.port)
(strOpt "destination" tun.destination)
@@ -204,10 +204,10 @@ let
++ (if tun ? crypto.tagsToSend then
optionalNullInt "crypto.tagstosend" tun.crypto.tagsToSend else []);
in concatStringsSep "\n" outTunOpts))
- (flip mapAttrs
- (collect (name: tun: tun ? port && tun ? address) cfg.inTunnels)
+ (flip map
+ (collect (tun: tun ? port && tun ? address) cfg.inTunnels)
(tun: let inTunOpts = [
- (sec name)
+ (sec tun.name)
"type = server"
(intOpt "port" tun.port)
(strOpt "host" tun.address)
@@ -606,7 +606,7 @@ in
outTunnels = mkOption {
default = {};
- type = with types; loaOf (submodule (
+ type = with types; attrsOf (submodule (
{ name, ... }: {
options = {
destinationPort = mkOption {
@@ -627,7 +627,7 @@ in
inTunnels = mkOption {
default = {};
- type = with types; loaOf (submodule (
+ type = with types; attrsOf (submodule (
{ name, ... }: {
options = {
inPort = mkOption {
diff --git a/nixpkgs/nixos/modules/services/networking/iodine.nix b/nixpkgs/nixos/modules/services/networking/iodine.nix
index f9ca26c2796..46051d7044b 100644
--- a/nixpkgs/nixos/modules/services/networking/iodine.nix
+++ b/nixpkgs/nixos/modules/services/networking/iodine.nix
@@ -9,6 +9,8 @@ let
iodinedUser = "iodined";
+ /* is this path made unreadable by ProtectHome = true ? */
+ isProtected = x: hasPrefix "/root" x || hasPrefix "/home" x;
in
{
imports = [
@@ -35,45 +37,48 @@ in
corresponding attribute name.
'';
example = literalExample ''
- {
- foo = {
- server = "tunnel.mdomain.com";
- relay = "8.8.8.8";
- extraConfig = "-v";
+ {
+ foo = {
+ server = "tunnel.mdomain.com";
+ relay = "8.8.8.8";
+ extraConfig = "-v";
+ }
}
- }
'';
- type = types.attrsOf (types.submodule (
- {
- options = {
- server = mkOption {
- type = types.str;
- default = "";
- description = "Domain or Subdomain of server running iodined";
- example = "tunnel.mydomain.com";
- };
-
- relay = mkOption {
- type = types.str;
- default = "";
- description = "DNS server to use as a intermediate relay to the iodined server";
- example = "8.8.8.8";
- };
-
- extraConfig = mkOption {
- type = types.str;
- default = "";
- description = "Additional command line parameters";
- example = "-l 192.168.1.10 -p 23";
- };
-
- passwordFile = mkOption {
- type = types.str;
- default = "";
- description = "File that contains password";
- };
- };
- }));
+ type = types.attrsOf (
+ types.submodule (
+ {
+ options = {
+ server = mkOption {
+ type = types.str;
+ default = "";
+ description = "Hostname of server running iodined";
+ example = "tunnel.mydomain.com";
+ };
+
+ relay = mkOption {
+ type = types.str;
+ default = "";
+ description = "DNS server to use as an intermediate relay to the iodined server";
+ example = "8.8.8.8";
+ };
+
+ extraConfig = mkOption {
+ type = types.str;
+ default = "";
+ description = "Additional command line parameters";
+ example = "-l 192.168.1.10 -p 23";
+ };
+
+ passwordFile = mkOption {
+ type = types.str;
+ default = "";
+ description = "Path to a file containing the password.";
+ };
+ };
+ }
+ )
+ );
};
server = {
@@ -121,31 +126,67 @@ in
boot.kernelModules = [ "tun" ];
systemd.services =
- let
- createIodineClientService = name: cfg:
- {
- description = "iodine client - ${name}";
- after = [ "network.target" ];
- wantedBy = [ "multi-user.target" ];
- script = "exec ${pkgs.iodine}/bin/iodine -f -u ${iodinedUser} ${cfg.extraConfig} ${optionalString (cfg.passwordFile != "") "< \"${cfg.passwordFile}\""} ${cfg.relay} ${cfg.server}";
- serviceConfig = {
- RestartSec = "30s";
- Restart = "always";
+ let
+ createIodineClientService = name: cfg:
+ {
+ description = "iodine client - ${name}";
+ after = [ "network.target" ];
+ wantedBy = [ "multi-user.target" ];
+ script = "exec ${pkgs.iodine}/bin/iodine -f -u ${iodinedUser} ${cfg.extraConfig} ${optionalString (cfg.passwordFile != "") "< \"${builtins.toString cfg.passwordFile}\""} ${cfg.relay} ${cfg.server}";
+ serviceConfig = {
+ RestartSec = "30s";
+ Restart = "always";
+
+ # hardening :
+ # Filesystem access
+ ProtectSystem = "strict";
+ ProtectHome = if isProtected cfg.passwordFile then "read-only" else "true" ;
+ PrivateTmp = true;
+ ReadWritePaths = "/dev/net/tun";
+ PrivateDevices = false;
+ ProtectKernelTunables = true;
+ ProtectKernelModules = true;
+ ProtectControlGroups = true;
+ # Caps
+ NoNewPrivileges = true;
+ # Misc.
+ LockPersonality = true;
+ RestrictRealtime = true;
+ PrivateMounts = true;
+ MemoryDenyWriteExecute = true;
+ };
+ };
+ in
+ listToAttrs (
+ mapAttrsToList
+ (name: value: nameValuePair "iodine-${name}" (createIodineClientService name value))
+ cfg.clients
+ ) // {
+ iodined = mkIf (cfg.server.enable) {
+ description = "iodine, ip over dns server daemon";
+ after = [ "network.target" ];
+ wantedBy = [ "multi-user.target" ];
+ script = "exec ${pkgs.iodine}/bin/iodined -f -u ${iodinedUser} ${cfg.server.extraConfig} ${optionalString (cfg.server.passwordFile != "") "< \"${builtins.toString cfg.server.passwordFile}\""} ${cfg.server.ip} ${cfg.server.domain}";
+ serviceConfig = {
+ # Filesystem access
+ ProtectSystem = "strict";
+ ProtectHome = if isProtected cfg.server.passwordFile then "read-only" else "true" ;
+ PrivateTmp = true;
+ ReadWritePaths = "/dev/net/tun";
+ PrivateDevices = false;
+ ProtectKernelTunables = true;
+ ProtectKernelModules = true;
+ ProtectControlGroups = true;
+ # Caps
+ NoNewPrivileges = true;
+ # Misc.
+ LockPersonality = true;
+ RestrictRealtime = true;
+ PrivateMounts = true;
+ MemoryDenyWriteExecute = true;
+ };
+ };
};
- };
- in
- listToAttrs (
- mapAttrsToList
- (name: value: nameValuePair "iodine-${name}" (createIodineClientService name value))
- cfg.clients
- ) // {
- iodined = mkIf (cfg.server.enable) {
- description = "iodine, ip over dns server daemon";
- after = [ "network.target" ];
- wantedBy = [ "multi-user.target" ];
- script = "exec ${pkgs.iodine}/bin/iodined -f -u ${iodinedUser} ${cfg.server.extraConfig} ${optionalString (cfg.server.passwordFile != "") "< \"${cfg.server.passwordFile}\""} ${cfg.server.ip} ${cfg.server.domain}";
- };
- };
users.users.${iodinedUser} = {
uid = config.ids.uids.iodined;
diff --git a/nixpkgs/nixos/modules/services/networking/iwd.nix b/nixpkgs/nixos/modules/services/networking/iwd.nix
index 839fa48d9a4..6be67a8b96f 100644
--- a/nixpkgs/nixos/modules/services/networking/iwd.nix
+++ b/nixpkgs/nixos/modules/services/networking/iwd.nix
@@ -23,12 +23,7 @@ in {
systemd.packages = [ pkgs.iwd ];
systemd.services.iwd.wantedBy = [ "multi-user.target" ];
-
- systemd.tmpfiles.rules = [
- "d /var/lib/iwd 0700 root root -"
- "d /var/lib/ead 0700 root root -"
- ];
};
- meta.maintainers = with lib.maintainers; [ mic92 ];
+ meta.maintainers = with lib.maintainers; [ mic92 dtzWill ];
}
diff --git a/nixpkgs/nixos/modules/services/networking/knot.nix b/nixpkgs/nixos/modules/services/networking/knot.nix
index 47364ecb846..12ff89fe849 100644
--- a/nixpkgs/nixos/modules/services/networking/knot.nix
+++ b/nixpkgs/nixos/modules/services/networking/knot.nix
@@ -5,14 +5,16 @@ with lib;
let
cfg = config.services.knot;
- configFile = pkgs.writeText "knot.conf" cfg.extraConfig;
- socketFile = "/run/knot/knot.sock";
+ configFile = pkgs.writeTextFile {
+ name = "knot.conf";
+ text = (concatMapStringsSep "\n" (file: "include: ${file}") cfg.keyFiles) + "\n" +
+ cfg.extraConfig;
+ checkPhase = lib.optionalString (cfg.keyFiles == []) ''
+ ${cfg.package}/bin/knotc --config=$out conf-check
+ '';
+ };
- knotConfCheck = file: pkgs.runCommand "knot-config-checked"
- { buildInputs = [ cfg.package ]; } ''
- ln -s ${configFile} $out
- knotc --config=${configFile} conf-check
- '';
+ socketFile = "/run/knot/knot.sock";
knot-cli-wrappers = pkgs.stdenv.mkDerivation {
name = "knot-cli-wrappers";
@@ -45,6 +47,19 @@ in {
'';
};
+ keyFiles = mkOption {
+ type = types.listOf types.path;
+ default = [];
+ description = ''
+ A list of files containing additional configuration
+ to be included using the include directive. This option
+ allows to include configuration like TSIG keys without
+ exposing them to the nix store readable to any process.
+ Note that using this option will also disable configuration
+ checks at build time.
+ '';
+ };
+
extraConfig = mkOption {
type = types.lines;
default = "";
@@ -65,6 +80,13 @@ in {
};
config = mkIf config.services.knot.enable {
+ users.users.knot = {
+ isSystemUser = true;
+ group = "knot";
+ description = "Knot daemon user";
+ };
+
+ users.groups.knot.gid = null;
systemd.services.knot = {
unitConfig.Documentation = "man:knotd(8) man:knot.conf(5) man:knotc(8) https://www.knot-dns.cz/docs/${cfg.package.version}/html/";
description = cfg.package.meta.description;
@@ -74,12 +96,12 @@ in {
serviceConfig = {
Type = "notify";
- ExecStart = "${cfg.package}/bin/knotd --config=${knotConfCheck configFile} --socket=${socketFile} ${concatStringsSep " " cfg.extraArgs}";
+ ExecStart = "${cfg.package}/bin/knotd --config=${configFile} --socket=${socketFile} ${concatStringsSep " " cfg.extraArgs}";
ExecReload = "${knot-cli-wrappers}/bin/knotc reload";
CapabilityBoundingSet = "CAP_NET_BIND_SERVICE CAP_SETPCAP";
AmbientCapabilities = "CAP_NET_BIND_SERVICE CAP_SETPCAP";
NoNewPrivileges = true;
- DynamicUser = "yes";
+ User = "knot";
RuntimeDirectory = "knot";
StateDirectory = "knot";
StateDirectoryMode = "0700";
diff --git a/nixpkgs/nixos/modules/services/networking/kresd.nix b/nixpkgs/nixos/modules/services/networking/kresd.nix
index bb941e93e15..c5a84eebd46 100644
--- a/nixpkgs/nixos/modules/services/networking/kresd.nix
+++ b/nixpkgs/nixos/modules/services/networking/kresd.nix
@@ -3,16 +3,38 @@
with lib;
let
-
cfg = config.services.kresd;
- configFile = pkgs.writeText "kresd.conf" ''
- ${optionalString (cfg.listenDoH != []) "modules.load('http')"}
- ${cfg.extraConfig};
- '';
- package = pkgs.knot-resolver.override {
- extraFeatures = cfg.listenDoH != [];
- };
+ # Convert systemd-style address specification to kresd config line(s).
+ # On Nix level we don't attempt to precisely validate the address specifications.
+ mkListen = kind: addr: let
+ al_v4 = builtins.match "([0-9.]\+):([0-9]\+)" addr;
+ al_v6 = builtins.match "\\[(.\+)]:([0-9]\+)" addr;
+ al_portOnly = builtins.match "()([0-9]\+)" addr;
+ al = findFirst (a: a != null)
+ (throw "services.kresd.*: incorrect address specification '${addr}'")
+ [ al_v4 al_v6 al_portOnly ];
+ port = last al;
+ addrSpec = if al_portOnly == null then "'${head al}'" else "{'::', '127.0.0.1'}";
+ in # freebind is set for compatibility with earlier kresd services;
+ # it could be configurable, for example.
+ ''
+ net.listen(${addrSpec}, ${port}, { kind = '${kind}', freebind = true })
+ '';
+
+ configFile = pkgs.writeText "kresd.conf" (
+ optionalString (cfg.listenDoH != []) ''
+ modules.load('http')
+ ''
+ + concatMapStrings (mkListen "dns") cfg.listenPlain
+ + concatMapStrings (mkListen "tls") cfg.listenTLS
+ + concatMapStrings (mkListen "doh") cfg.listenDoH
+ + cfg.extraConfig
+ );
+
+ package = if cfg.listenDoH == []
+ then pkgs.knot-resolver # never force `extraFeatures = false`
+ else pkgs.knot-resolver.override { extraFeatures = true; };
in {
meta.maintainers = [ maintainers.vcunat /* upstream developer */ ];
@@ -25,6 +47,7 @@ in {
value
)
)
+ (mkRemovedOptionModule [ "services" "kresd" "cacheDir" ] "Please use (bind-)mounting instead.")
];
###### interface
@@ -35,8 +58,8 @@ in {
description = ''
Whether to enable knot-resolver domain name server.
DNSSEC validation is turned on by default.
- You can run <literal>sudo nc -U /run/kresd/control</literal>
- and give commands interactively to kresd.
+ You can run <literal>sudo nc -U /run/knot-resolver/control/1</literal>
+ and give commands interactively to kresd@1.service.
'';
};
extraConfig = mkOption {
@@ -46,16 +69,10 @@ in {
Extra lines to be added verbatim to the generated configuration file.
'';
};
- cacheDir = mkOption {
- type = types.path;
- default = "/var/cache/kresd";
- description = ''
- Directory for caches. They are intended to survive reboots.
- '';
- };
listenPlain = mkOption {
type = with types; listOf str;
default = [ "[::1]:53" "127.0.0.1:53" ];
+ example = [ "53" ];
description = ''
What addresses and ports the server should listen on.
For detailed syntax see ListenStream in man systemd.socket.
@@ -75,91 +92,54 @@ in {
default = [];
example = [ "198.51.100.1:443" "[2001:db8::1]:443" "443" ];
description = ''
- Addresses and ports on which kresd should provide DNS over HTTPS (see RFC 7858).
+ Addresses and ports on which kresd should provide DNS over HTTPS (see RFC 8484).
For detailed syntax see ListenStream in man systemd.socket.
'';
};
+ instances = mkOption {
+ type = types.ints.unsigned;
+ default = 1;
+ description = ''
+ The number of instances to start. They will be called kresd@{1,2,...}.service.
+ Knot Resolver uses no threads, so this is the way to scale.
+ You can dynamically start/stop them at will, so this is just system default.
+ '';
+ };
# TODO: perhaps options for more common stuff like cache size or forwarding
};
###### implementation
config = mkIf cfg.enable {
- environment.etc."kresd.conf".source = configFile; # not required
+ environment.etc."knot-resolver/kresd.conf".source = configFile; # not required
- users.users.kresd =
- { uid = config.ids.uids.kresd;
- group = "kresd";
+ users.users.knot-resolver =
+ { isSystemUser = true;
+ group = "knot-resolver";
description = "Knot-resolver daemon user";
};
- users.groups.kresd.gid = config.ids.gids.kresd;
-
- systemd.sockets.kresd = rec {
- wantedBy = [ "sockets.target" ];
- before = wantedBy;
- listenStreams = cfg.listenPlain;
- socketConfig = {
- ListenDatagram = listenStreams;
- FreeBind = true;
- FileDescriptorName = "dns";
- };
- };
+ users.groups.knot-resolver.gid = null;
- systemd.sockets.kresd-tls = mkIf (cfg.listenTLS != []) rec {
- wantedBy = [ "sockets.target" ];
- before = wantedBy;
- partOf = [ "kresd.socket" ];
- listenStreams = cfg.listenTLS;
- socketConfig = {
- FileDescriptorName = "tls";
- FreeBind = true;
- Service = "kresd.service";
- };
- };
+ systemd.packages = [ package ]; # the units are patched inside the package a bit
- systemd.sockets.kresd-doh = mkIf (cfg.listenDoH != []) rec {
- wantedBy = [ "sockets.target" ];
- before = wantedBy;
- partOf = [ "kresd.socket" ];
- listenStreams = cfg.listenDoH;
- socketConfig = {
- FileDescriptorName = "doh";
- FreeBind = true;
- Service = "kresd.service";
- };
+ systemd.targets.kresd = { # configure units started by default
+ wantedBy = [ "multi-user.target" ];
+ wants = [ "kres-cache-gc.service" ]
+ ++ map (i: "kresd@${toString i}.service") (range 1 cfg.instances);
};
-
- systemd.sockets.kresd-control = rec {
- wantedBy = [ "sockets.target" ];
- before = wantedBy;
- partOf = [ "kresd.socket" ];
- listenStreams = [ "/run/kresd/control" ];
- socketConfig = {
- FileDescriptorName = "control";
- Service = "kresd.service";
- SocketMode = "0660"; # only root user/group may connect and control kresd
- };
+ systemd.services."kresd@".serviceConfig = {
+ ExecStart = "${package}/bin/kresd --noninteractive "
+ + "-c ${package}/lib/knot-resolver/distro-preconfig.lua -c ${configFile}";
+ # Ensure correct ownership in case UID or GID changes.
+ CacheDirectory = "knot-resolver";
+ CacheDirectoryMode = "0750";
};
- systemd.tmpfiles.rules = [ "d '${cfg.cacheDir}' 0770 kresd kresd - -" ];
+ environment.etc."tmpfiles.d/knot-resolver.conf".source =
+ "${package}/lib/tmpfiles.d/knot-resolver.conf";
- systemd.services.kresd = {
- description = "Knot-resolver daemon";
-
- serviceConfig = {
- User = "kresd";
- Type = "notify";
- WorkingDirectory = cfg.cacheDir;
- Restart = "on-failure";
- Sockets = [ "kresd.socket" "kresd-control.socket" ]
- ++ optional (cfg.listenTLS != []) "kresd-tls.socket";
- };
-
- # Trust anchor goes from dns-root-data by default.
- script = ''
- exec '${package}/bin/kresd' --config '${configFile}' --forks=1
- '';
-
- requires = [ "kresd.socket" ];
- };
+ # Try cleaning up the previously default location of cache file.
+ # Note that /var/cache/* should always be safe to remove.
+ # TODO: remove later, probably between 20.09 and 21.03
+ systemd.tmpfiles.rules = [ "R /var/cache/kresd" ];
};
}
diff --git a/nixpkgs/nixos/modules/services/networking/minidlna.nix b/nixpkgs/nixos/modules/services/networking/minidlna.nix
index 3ddea3c9757..c580ba47dad 100644
--- a/nixpkgs/nixos/modules/services/networking/minidlna.nix
+++ b/nixpkgs/nixos/modules/services/networking/minidlna.nix
@@ -95,6 +95,22 @@ in
'';
};
+ services.minidlna.announceInterval = mkOption {
+ type = types.int;
+ default = 895;
+ description =
+ ''
+ The interval between announces (in seconds).
+
+ By default miniDLNA will announce its presence on the network
+ approximately every 15 minutes.
+
+ Many people prefer shorter announce intervals (e.g. 60 seconds)
+ on their home networks, especially when DLNA clients are
+ started on demand.
+ '';
+ };
+
services.minidlna.config = mkOption {
type = types.lines;
description =
@@ -144,6 +160,7 @@ in
${concatMapStrings (dir: ''
media_dir=${dir}
'') cfg.mediaDirs}
+ notify_interval=${toString cfg.announceInterval}
${cfg.extraConfig}
'';
diff --git a/nixpkgs/nixos/modules/services/networking/nat.nix b/nixpkgs/nixos/modules/services/networking/nat.nix
index 9c658af30f7..21ae9eb8b6d 100644
--- a/nixpkgs/nixos/modules/services/networking/nat.nix
+++ b/nixpkgs/nixos/modules/services/networking/nat.nix
@@ -65,7 +65,7 @@ let
let
m = builtins.match "([0-9.]+):([0-9-]+)" fwd.destination;
destinationIP = if (m == null) then throw "bad ip:ports `${fwd.destination}'" else elemAt m 0;
- destinationPorts = if (m == null) then throw "bad ip:ports `${fwd.destination}'" else elemAt m 1;
+ destinationPorts = if (m == null) then throw "bad ip:ports `${fwd.destination}'" else builtins.replaceStrings ["-"] [":"] (elemAt m 1);
in ''
# Allow connections to ${loopbackip}:${toString fwd.sourcePort} from the host itself
iptables -w -t nat -A nixos-nat-out \
diff --git a/nixpkgs/nixos/modules/services/networking/nix-store-gcs-proxy.nix b/nixpkgs/nixos/modules/services/networking/nix-store-gcs-proxy.nix
new file mode 100644
index 00000000000..3f2ce5bca4d
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/networking/nix-store-gcs-proxy.nix
@@ -0,0 +1,75 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ opts = { name, config, ... }: {
+ options = {
+ enable = mkOption {
+ default = true;
+ type = types.bool;
+ example = true;
+ description = "Whether to enable proxy for this bucket";
+ };
+ bucketName = mkOption {
+ type = types.str;
+ default = name;
+ example = "my-bucket-name";
+ description = "Name of Google storage bucket";
+ };
+ address = mkOption {
+ type = types.str;
+ example = "localhost:3000";
+ description = "The address of the proxy.";
+ };
+ };
+ };
+ enabledProxies = lib.filterAttrs (n: v: v.enable) config.services.nix-store-gcs-proxy;
+ mapProxies = function: lib.mkMerge (lib.mapAttrsToList function enabledProxies);
+in
+{
+ options.services.nix-store-gcs-proxy = mkOption {
+ type = types.attrsOf (types.submodule opts);
+ default = {};
+ description = ''
+ An attribute set describing an HTTP to GCS proxy that allows us to use GCS
+ bucket via HTTP protocol.
+ '';
+ };
+
+ config.systemd.services = mapProxies (name: cfg: {
+ "nix-store-gcs-proxy-${name}" = {
+ description = "A HTTP nix store that proxies requests to Google Storage";
+ wantedBy = ["multi-user.target"];
+
+ serviceConfig = {
+ RestartSec = 5;
+ StartLimitInterval = 10;
+ ExecStart = ''
+ ${pkgs.nix-store-gcs-proxy}/bin/nix-store-gcs-proxy \
+ --bucket-name ${cfg.bucketName} \
+ --addr ${cfg.address}
+ '';
+
+ DynamicUser = true;
+
+ ProtectSystem = "strict";
+ ProtectHome = true;
+ PrivateTmp = true;
+ PrivateDevices = true;
+ PrivateMounts = true;
+ PrivateUsers = true;
+
+ ProtectKernelTunables = true;
+ ProtectKernelModules = true;
+ ProtectControlGroups = true;
+
+ NoNewPrivileges = true;
+ LockPersonality = true;
+ RestrictRealtime = true;
+ };
+ };
+ });
+
+ meta.maintainers = [ maintainers.mrkkrp ];
+}
diff --git a/nixpkgs/nixos/modules/services/networking/nsd.nix b/nixpkgs/nixos/modules/services/networking/nsd.nix
index 344396638a6..429580e5c6c 100644
--- a/nixpkgs/nixos/modules/services/networking/nsd.nix
+++ b/nixpkgs/nixos/modules/services/networking/nsd.nix
@@ -244,7 +244,7 @@ let
};
data = mkOption {
- type = types.str;
+ type = types.lines;
default = "";
example = "";
description = ''
@@ -484,7 +484,7 @@ in
};
extraConfig = mkOption {
- type = types.str;
+ type = types.lines;
default = "";
description = ''
Extra nsd config.
diff --git a/nixpkgs/nixos/modules/services/networking/ntp/ntpd.nix b/nixpkgs/nixos/modules/services/networking/ntp/ntpd.nix
index b5403cb747d..54ff054d84c 100644
--- a/nixpkgs/nixos/modules/services/networking/ntp/ntpd.nix
+++ b/nixpkgs/nixos/modules/services/networking/ntp/ntpd.nix
@@ -23,6 +23,8 @@ let
restrict -6 ::1
${toString (map (server: "server " + server + " iburst\n") cfg.servers)}
+
+ ${cfg.extraConfig}
'';
ntpFlags = "-c ${configFile} -u ${ntpUser}:nogroup ${toString cfg.extraFlags}";
@@ -81,6 +83,17 @@ in
'';
};
+ extraConfig = mkOption {
+ type = types.lines;
+ default = "";
+ example = ''
+ fudge 127.127.1.0 stratum 10
+ '';
+ description = ''
+ Additional text appended to <filename>ntp.conf</filename>.
+ '';
+ };
+
extraFlags = mkOption {
type = types.listOf types.str;
description = "Extra flags passed to the ntpd command.";
diff --git a/nixpkgs/nixos/modules/services/networking/pppd.nix b/nixpkgs/nixos/modules/services/networking/pppd.nix
index b31bfa64235..c1cbdb46176 100644
--- a/nixpkgs/nixos/modules/services/networking/pppd.nix
+++ b/nixpkgs/nixos/modules/services/networking/pppd.nix
@@ -130,7 +130,7 @@ in
systemdConfigs = listToAttrs (map mkSystemd enabledConfigs);
in mkIf cfg.enable {
- environment.etc = mkMerge etcFiles;
- systemd.services = mkMerge systemdConfigs;
+ environment.etc = etcFiles;
+ systemd.services = systemdConfigs;
};
}
diff --git a/nixpkgs/nixos/modules/services/networking/shorewall.nix b/nixpkgs/nixos/modules/services/networking/shorewall.nix
index 0f94d414fcf..16383be2530 100644
--- a/nixpkgs/nixos/modules/services/networking/shorewall.nix
+++ b/nixpkgs/nixos/modules/services/networking/shorewall.nix
@@ -26,7 +26,7 @@ in {
description = "The shorewall package to use.";
};
configs = lib.mkOption {
- type = types.attrsOf types.str;
+ type = types.attrsOf types.lines;
default = {};
description = ''
This option defines the Shorewall configs.
@@ -63,12 +63,7 @@ in {
'';
};
environment = {
- etc = lib.mapAttrsToList
- (name: file:
- { source = file;
- target = "shorewall/${name}";
- })
- cfg.configs;
+ etc = lib.mapAttrs' (name: conf: lib.nameValuePair "shorewall/${name}" {source=conf;}) cfg.configs;
systemPackages = [ cfg.package ];
};
};
diff --git a/nixpkgs/nixos/modules/services/networking/shorewall6.nix b/nixpkgs/nixos/modules/services/networking/shorewall6.nix
index 9c22a037c0b..e081aedc6c3 100644
--- a/nixpkgs/nixos/modules/services/networking/shorewall6.nix
+++ b/nixpkgs/nixos/modules/services/networking/shorewall6.nix
@@ -26,7 +26,7 @@ in {
description = "The shorewall package to use.";
};
configs = lib.mkOption {
- type = types.attrsOf types.str;
+ type = types.attrsOf types.lines;
default = {};
description = ''
This option defines the Shorewall configs.
@@ -63,12 +63,7 @@ in {
'';
};
environment = {
- etc = lib.mapAttrsToList
- (name: file:
- { source = file;
- target = "shorewall6/${name}";
- })
- cfg.configs;
+ etc = lib.mapAttrs' (name: conf: lib.nameValuePair "shorewall6/${name}" {source=conf;}) cfg.configs;
systemPackages = [ cfg.package ];
};
};
diff --git a/nixpkgs/nixos/modules/services/networking/smartdns.nix b/nixpkgs/nixos/modules/services/networking/smartdns.nix
new file mode 100644
index 00000000000..f1888af7041
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/networking/smartdns.nix
@@ -0,0 +1,61 @@
+{ lib, pkgs, config, ... }:
+
+with lib;
+
+let
+ inherit (lib.types) attrsOf coercedTo listOf oneOf str int bool;
+ cfg = config.services.smartdns;
+
+ confFile = pkgs.writeText "smartdns.conf" (with generators;
+ toKeyValue {
+ mkKeyValue = mkKeyValueDefault {
+ mkValueString = v:
+ if isBool v then
+ if v then "yes" else "no"
+ else
+ mkValueStringDefault { } v;
+ } " ";
+ listsAsDuplicateKeys =
+ true; # Allowing duplications because we need to deal with multiple entries with the same key.
+ } cfg.settings);
+in {
+ options.services.smartdns = {
+ enable = mkEnableOption "SmartDNS DNS server";
+
+ bindPort = mkOption {
+ type = types.port;
+ default = 53;
+ description = "DNS listening port number.";
+ };
+
+ settings = mkOption {
+ type =
+ let atom = oneOf [ str int bool ];
+ in attrsOf (coercedTo atom toList (listOf atom));
+ example = literalExample ''
+ {
+ bind = ":5353 -no-rule -group example";
+ cache-size = 4096;
+ server-tls = [ "8.8.8.8:853" "1.1.1.1:853" ];
+ server-https = "https://cloudflare-dns.com/dns-query -exclude-default-group";
+ prefetch-domain = true;
+ speed-check-mode = "ping,tcp:80";
+ };
+ '';
+ description = ''
+ A set that will be generated into configuration file, see the <link xlink:href="https://github.com/pymumu/smartdns/blob/master/ReadMe_en.md#configuration-parameter">SmartDNS README</link> for details of configuration parameters.
+ You could override the options here like <option>services.smartdns.bindPort</option> by writing <literal>settings.bind = ":5353 -no-rule -group example";</literal>.
+ '';
+ };
+ };
+
+ config = lib.mkIf cfg.enable {
+ services.smartdns.settings.bind = mkDefault ":${toString cfg.bindPort}";
+
+ systemd.packages = [ pkgs.smartdns ];
+ systemd.services.smartdns.wantedBy = [ "multi-user.target" ];
+ environment.etc."smartdns/smartdns.conf".source = confFile;
+ environment.etc."default/smartdns".source =
+ "${pkgs.smartdns}/etc/default/smartdns";
+ };
+}
diff --git a/nixpkgs/nixos/modules/services/networking/ssh/sshd.nix b/nixpkgs/nixos/modules/services/networking/ssh/sshd.nix
index b0e2e303cbc..464e9ed38c4 100644
--- a/nixpkgs/nixos/modules/services/networking/ssh/sshd.nix
+++ b/nixpkgs/nixos/modules/services/networking/ssh/sshd.nix
@@ -17,7 +17,7 @@ let
${cfg.extraConfig}
EOL
- ssh-keygen -f mock-hostkey -N ""
+ ssh-keygen -q -f mock-hostkey -N ""
sshd -t -f $out -h mock-hostkey
'';
@@ -238,6 +238,26 @@ in
description = "Files from which authorized keys are read.";
};
+ authorizedKeysCommand = mkOption {
+ type = types.str;
+ default = "none";
+ description = ''
+ Specifies a program to be used to look up the user's public
+ keys. The program must be owned by root, not writable by group
+ or others and specified by an absolute path.
+ '';
+ };
+
+ authorizedKeysCommandUser = mkOption {
+ type = types.str;
+ default = "nobody";
+ description = ''
+ Specifies the user under whose account the AuthorizedKeysCommand
+ is run. It is recommended to use a dedicated user that has no
+ other role on the host than running authorized keys commands.
+ '';
+ };
+
kexAlgorithms = mkOption {
type = types.listOf types.str;
default = [
@@ -485,6 +505,10 @@ in
PrintMotd no # handled by pam_motd
AuthorizedKeysFile ${toString cfg.authorizedKeysFiles}
+ ${optionalString (cfg.authorizedKeysCommand != "none") ''
+ AuthorizedKeysCommand ${cfg.authorizedKeysCommand}
+ AuthorizedKeysCommandUser ${cfg.authorizedKeysCommandUser}
+ ''}
${flip concatMapStrings cfg.hostKeys (k: ''
HostKey ${k.path}
diff --git a/nixpkgs/nixos/modules/services/networking/sslh.nix b/nixpkgs/nixos/modules/services/networking/sslh.nix
index 0222e8ce8b5..c4fa370a5fe 100644
--- a/nixpkgs/nixos/modules/services/networking/sslh.nix
+++ b/nixpkgs/nixos/modules/services/networking/sslh.nix
@@ -77,19 +77,14 @@ in
config = mkMerge [
(mkIf cfg.enable {
- users.users.${user} = {
- description = "sslh daemon user";
- isSystemUser = true;
- };
-
systemd.services.sslh = {
description = "Applicative Protocol Multiplexer (e.g. share SSH and HTTPS on the same port)";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
- User = user;
- Group = "nogroup";
+ DynamicUser = true;
+ User = "sslh";
PermissionsStartOnly = true;
Restart = "always";
RestartSec = "1s";
diff --git a/nixpkgs/nixos/modules/services/networking/stubby.nix b/nixpkgs/nixos/modules/services/networking/stubby.nix
index b38bcd4cec0..c5e0f929a12 100644
--- a/nixpkgs/nixos/modules/services/networking/stubby.nix
+++ b/nixpkgs/nixos/modules/services/networking/stubby.nix
@@ -72,6 +72,7 @@ let
resolution_type: GETDNS_RESOLUTION_STUB
dns_transport_list:
${fallbacks}
+ appdata_dir: "/var/cache/stubby"
tls_authentication: ${cfg.authenticationMode}
tls_query_padding_blocksize: ${toString cfg.queryPaddingBlocksize}
edns_client_subnet_private: ${if cfg.subnetPrivate then "1" else "0"}
@@ -204,10 +205,12 @@ in
wantedBy = [ "multi-user.target" ];
serviceConfig = {
+ Type = "notify";
AmbientCapabilities = "CAP_NET_BIND_SERVICE";
CapabilityBoundingSet = "CAP_NET_BIND_SERVICE";
ExecStart = "${pkgs.stubby}/bin/stubby -C ${confFile} ${optionalString cfg.debugLogging "-l"}";
DynamicUser = true;
+ CacheDirectory = "stubby";
};
};
};
diff --git a/nixpkgs/nixos/modules/services/networking/supybot.nix b/nixpkgs/nixos/modules/services/networking/supybot.nix
index 92c84bd0e1e..dc9fb31ffd0 100644
--- a/nixpkgs/nixos/modules/services/networking/supybot.nix
+++ b/nixpkgs/nixos/modules/services/networking/supybot.nix
@@ -3,32 +3,35 @@
with lib;
let
-
cfg = config.services.supybot;
-
+ isStateDirHome = hasPrefix "/home/" cfg.stateDir;
+ isStateDirVar = cfg.stateDir == "/var/lib/supybot";
+ pyEnv = pkgs.python3.withPackages (p: [ p.limnoria ] ++ (cfg.extraPackages p));
in
-
{
-
options = {
services.supybot = {
enable = mkOption {
+ type = types.bool;
default = false;
- description = "Enable Supybot, an IRC bot";
+ description = "Enable Supybot, an IRC bot (also known as Limnoria).";
};
stateDir = mkOption {
- # Setting this to /var/lib/supybot caused useradd to fail
- default = "/home/supybot";
+ type = types.path;
+ default = if versionAtLeast config.system.stateVersion "20.09"
+ then "/var/lib/supybot"
+ else "/home/supybot";
+ defaultText = "/var/lib/supybot";
description = "The root directory, logs and plugins are stored here";
};
configFile = mkOption {
type = types.path;
description = ''
- Path to a supybot config file. This can be generated by
+ Path to initial supybot config file. This can be generated by
running supybot-wizard.
Note: all paths should include the full path to the stateDir
@@ -36,21 +39,54 @@ in
'';
};
+ plugins = mkOption {
+ type = types.attrsOf types.path;
+ default = {};
+ description = ''
+ Attribute set of additional plugins that will be symlinked to the
+ <filename>plugin</filename> subdirectory.
+
+ Please note that you still need to add the plugins to the config
+ file (or with <literal>!load</literal>) using their attribute name.
+ '';
+ example = literalExample ''
+ let
+ plugins = pkgs.fetchzip {
+ url = "https://github.com/ProgVal/Supybot-plugins/archive/57c2450c.zip";
+ sha256 = "077snf84ibnva3sbpzdfpfma6hcdw7dflwnhg6pw7mgnf0nd84qd";
+ };
+ in
+ {
+ Wikipedia = "''${plugins}/Wikipedia";
+ Decide = ./supy-decide;
+ }
+ '';
+ };
+
+ extraPackages = mkOption {
+ default = p: [];
+ description = ''
+ Extra Python packages available to supybot plugins. The
+ value must be a function which receives the attrset defined
+ in <varname>python3Packages</varname> as the sole argument.
+ '';
+ example = literalExample ''p: [ p.lxml p.requests ]'';
+ };
+
};
};
-
config = mkIf cfg.enable {
- environment.systemPackages = [ pkgs.pythonPackages.limnoria ];
+ environment.systemPackages = [ pkgs.python3Packages.limnoria ];
- users.users.supybotrs = {
+ users.users.supybot = {
uid = config.ids.uids.supybot;
group = "supybot";
description = "Supybot IRC bot user";
home = cfg.stateDir;
- createHome = true;
+ isSystemUser = true;
};
users.groups.supybot = {
@@ -59,19 +95,16 @@ in
systemd.services.supybot = {
description = "Supybot, an IRC bot";
+ documentation = [ "https://limnoria.readthedocs.io/" ];
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
- path = [ pkgs.pythonPackages.limnoria ];
preStart = ''
- cd ${cfg.stateDir}
- mkdir -p backup conf data plugins logs/plugins tmp web
- ln -sf ${cfg.configFile} supybot.cfg
# This needs to be created afresh every time
- rm -f supybot.cfg.bak
+ rm -f '${cfg.stateDir}/supybot.cfg.bak'
'';
serviceConfig = {
- ExecStart = "${pkgs.pythonPackages.limnoria}/bin/supybot ${cfg.stateDir}/supybot.cfg";
+ ExecStart = "${pyEnv}/bin/supybot ${cfg.stateDir}/supybot.cfg";
PIDFile = "/run/supybot.pid";
User = "supybot";
Group = "supybot";
@@ -79,8 +112,50 @@ in
Restart = "on-abort";
StartLimitInterval = "5m";
StartLimitBurst = "1";
+
+ NoNewPrivileges = true;
+ PrivateDevices = true;
+ PrivateMounts = true;
+ PrivateTmp = true;
+ ProtectControlGroups = true;
+ ProtectKernelModules = true;
+ ProtectKernelTunables = true;
+ RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
+ RestrictSUIDSGID = true;
+ SystemCallArchitectures = "native";
+ RestrictNamespaces = true;
+ RestrictRealtime = true;
+ LockPersonality = true;
+ MemoryDenyWriteExecute = true;
+ RemoveIPC = true;
+ ProtectHostname = true;
+ CapabilityBoundingSet = "";
+ ProtectSystem = "full";
+ }
+ // optionalAttrs isStateDirVar {
+ StateDirectory = "supybot";
+ ProtectSystem = "strict";
+ }
+ // optionalAttrs (!isStateDirHome) {
+ ProtectHome = true;
};
};
+ systemd.tmpfiles.rules = [
+ "d '${cfg.stateDir}' 0700 supybot supybot - -"
+ "d '${cfg.stateDir}/backup' 0750 supybot supybot - -"
+ "d '${cfg.stateDir}/conf' 0750 supybot supybot - -"
+ "d '${cfg.stateDir}/data' 0750 supybot supybot - -"
+ "d '${cfg.stateDir}/plugins' 0750 supybot supybot - -"
+ "d '${cfg.stateDir}/logs' 0750 supybot supybot - -"
+ "d '${cfg.stateDir}/logs/plugins' 0750 supybot supybot - -"
+ "d '${cfg.stateDir}/tmp' 0750 supybot supybot - -"
+ "d '${cfg.stateDir}/web' 0750 supybot supybot - -"
+ "L '${cfg.stateDir}/supybot.cfg' - - - - ${cfg.configFile}"
+ ]
+ ++ (flip mapAttrsToList cfg.plugins (name: dest:
+ "L+ '${cfg.stateDir}/plugins/${name}' - - - - ${dest}"
+ ));
+
};
}
diff --git a/nixpkgs/nixos/modules/services/networking/tailscale.nix b/nixpkgs/nixos/modules/services/networking/tailscale.nix
new file mode 100644
index 00000000000..513c42b4011
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/networking/tailscale.nix
@@ -0,0 +1,46 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let cfg = config.services.tailscale;
+in {
+ meta.maintainers = with maintainers; [ danderson mbaillie ];
+
+ options.services.tailscale = {
+ enable = mkEnableOption "Tailscale client daemon";
+
+ port = mkOption {
+ type = types.port;
+ default = 41641;
+ description = "The port to listen on for tunnel traffic (0=autoselect).";
+ };
+ };
+
+ config = mkIf cfg.enable {
+ systemd.services.tailscale = {
+ description = "Tailscale client daemon";
+
+ after = [ "network-pre.target" ];
+ wants = [ "network-pre.target" ];
+ wantedBy = [ "multi-user.target" ];
+
+ unitConfig = {
+ StartLimitIntervalSec = 0;
+ StartLimitBurst = 0;
+ };
+
+ serviceConfig = {
+ ExecStart =
+ "${pkgs.tailscale}/bin/tailscaled --port ${toString cfg.port}";
+
+ RuntimeDirectory = "tailscale";
+ RuntimeDirectoryMode = 755;
+
+ StateDirectory = "tailscale";
+ StateDirectoryMode = 700;
+
+ Restart = "on-failure";
+ };
+ };
+ };
+}
diff --git a/nixpkgs/nixos/modules/services/networking/vsftpd.nix b/nixpkgs/nixos/modules/services/networking/vsftpd.nix
index 47990dbb377..b3e20184423 100644
--- a/nixpkgs/nixos/modules/services/networking/vsftpd.nix
+++ b/nixpkgs/nixos/modules/services/networking/vsftpd.nix
@@ -133,8 +133,8 @@ let
${optionalString cfg.enableVirtualUsers ''
guest_enable=YES
guest_username=vsftpd
- pam_service_name=vsftpd
''}
+ pam_service_name=vsftpd
${cfg.extraConfig}
'';
diff --git a/nixpkgs/nixos/modules/services/networking/wireguard.nix b/nixpkgs/nixos/modules/services/networking/wireguard.nix
index 980961225c9..e8f83f6dd8b 100644
--- a/nixpkgs/nixos/modules/services/networking/wireguard.nix
+++ b/nixpkgs/nixos/modules/services/networking/wireguard.nix
@@ -151,7 +151,7 @@ let
publicKey = mkOption {
example = "xTIBA5rboUvnH4htodjb6e697QjLERt1NAB4mZqp8Dg=";
type = types.str;
- description = "The base64 public key the peer.";
+ description = "The base64 public key of the peer.";
};
presharedKey = mkOption {
@@ -428,14 +428,14 @@ in
++ (attrValues (
mapAttrs (name: value: {
assertion = value.generatePrivateKeyFile -> (value.privateKey == null);
- message = "networking.wireguard.interfaces.${name}.generatePrivateKey must not be set if networking.wireguard.interfaces.${name}.privateKey is set.";
+ message = "networking.wireguard.interfaces.${name}.generatePrivateKeyFile must not be set if networking.wireguard.interfaces.${name}.privateKey is set.";
}) cfg.interfaces))
++ map ({ interfaceName, peer, ... }: {
assertion = (peer.presharedKey == null) || (peer.presharedKeyFile == null);
message = "networking.wireguard.interfaces.${interfaceName} peer «${peer.publicKey}» has both presharedKey and presharedKeyFile set, but only one can be used.";
}) all_peers;
- boot.extraModulePackages = [ kernel.wireguard ];
+ boot.extraModulePackages = optional (versionOlder kernel.kernel.version "5.6") kernel.wireguard;
environment.systemPackages = [ pkgs.wireguard-tools ];
systemd.services =
diff --git a/nixpkgs/nixos/modules/services/networking/zerotierone.nix b/nixpkgs/nixos/modules/services/networking/zerotierone.nix
index 069e15a909b..cf39ed065a7 100644
--- a/nixpkgs/nixos/modules/services/networking/zerotierone.nix
+++ b/nixpkgs/nixos/modules/services/networking/zerotierone.nix
@@ -67,5 +67,16 @@ in
networking.firewall.allowedUDPPorts = [ cfg.port ];
environment.systemPackages = [ cfg.package ];
+
+ # Prevent systemd from potentially changing the MAC address
+ systemd.network.links."50-zerotier" = {
+ matchConfig = {
+ OriginalName = "zt*";
+ };
+ linkConfig = {
+ AutoNegotiation = false;
+ MACAddressPolicy = "none";
+ };
+ };
};
}
diff --git a/nixpkgs/nixos/modules/services/torrent/transmission.nix b/nixpkgs/nixos/modules/services/torrent/transmission.nix
index 5ba72e8d773..fd28b94f7be 100644
--- a/nixpkgs/nixos/modules/services/torrent/transmission.nix
+++ b/nixpkgs/nixos/modules/services/torrent/transmission.nix
@@ -23,7 +23,8 @@ let
for DIR in "${homeDir}" "${settingsDir}" "${fullSettings.download-dir}" "${fullSettings.incomplete-dir}"; do
mkdir -p "$DIR"
done
- chmod 700 "${homeDir}" "${settingsDir}"
+ chmod 755 "${homeDir}"
+ chmod 700 "${settingsDir}"
chmod ${downloadDirPermissions} "${fullSettings.download-dir}" "${fullSettings.incomplete-dir}"
cp -f ${settingsFile} ${settingsDir}/settings.json
'';
diff --git a/nixpkgs/nixos/modules/services/wayland/cage.nix b/nixpkgs/nixos/modules/services/wayland/cage.nix
new file mode 100644
index 00000000000..c59ca9983a6
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/wayland/cage.nix
@@ -0,0 +1,99 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+ cfg = config.services.cage;
+in {
+ options.services.cage.enable = mkEnableOption "cage kiosk service";
+
+ options.services.cage.user = mkOption {
+ type = types.str;
+ default = "demo";
+ description = ''
+ User to log-in as.
+ '';
+ };
+
+ options.services.cage.extraArguments = mkOption {
+ type = types.listOf types.str;
+ default = [];
+ defaultText = "[]";
+ description = "Additional command line arguments to pass to Cage.";
+ example = ["-d"];
+ };
+
+ options.services.cage.program = mkOption {
+ type = types.path;
+ default = "${pkgs.xterm}/bin/xterm";
+ description = ''
+ Program to run in cage.
+ '';
+ };
+
+ config = mkIf cfg.enable {
+
+ # The service is partially based off of the one provided in the
+ # cage wiki at
+ # https://github.com/Hjdskes/cage/wiki/Starting-Cage-on-boot-with-systemd.
+ systemd.services."cage-tty1" = {
+ enable = true;
+ after = [
+ "systemd-user-sessions.service"
+ "plymouth-start.service"
+ "plymouth-quit.service"
+ "systemd-logind.service"
+ "getty@tty1.service"
+ ];
+ before = [ "graphical.target" ];
+ wants = [ "dbus.socket" "systemd-logind.service" "plymouth-quit.service"];
+ wantedBy = [ "graphical.target" ];
+ conflicts = [ "getty@tty1.service" ];
+
+ restartIfChanged = false;
+ unitConfig.ConditionPathExists = "/dev/tty1";
+ serviceConfig = {
+ ExecStart = ''
+ ${pkgs.cage}/bin/cage \
+ ${escapeShellArgs cfg.extraArguments} \
+ -- ${cfg.program}
+ '';
+ User = cfg.user;
+
+ IgnoreSIGPIPE = "no";
+
+ # Log this user with utmp, letting it show up with commands 'w' and
+ # 'who'. This is needed since we replace (a)getty.
+ UtmpIdentifier = "%n";
+ UtmpMode = "user";
+ # A virtual terminal is needed.
+ TTYPath = "/dev/tty1";
+ TTYReset = "yes";
+ TTYVHangup = "yes";
+ TTYVTDisallocate = "yes";
+ # Fail to start if not controlling the virtual terminal.
+ StandardInput = "tty-fail";
+ StandardOutput = "syslog";
+ StandardError = "syslog";
+ # Set up a full (custom) user session for the user, required by Cage.
+ PAMName = "cage";
+ };
+ };
+
+ security.pam.services.cage.text = ''
+ auth required pam_unix.so nullok
+ account required pam_unix.so
+ session required pam_unix.so
+ session required ${pkgs.systemd}/lib/security/pam_systemd.so
+ '';
+
+ hardware.opengl.enable = mkDefault true;
+
+ systemd.targets.graphical.wants = [ "cage-tty1.service" ];
+
+ systemd.defaultUnit = "graphical.target";
+ };
+
+ meta.maintainers = with lib.maintainers; [ matthewbauer flokli ];
+
+}
diff --git a/nixpkgs/nixos/modules/services/web-apps/codimd.nix b/nixpkgs/nixos/modules/services/web-apps/codimd.nix
index 5f56f8ed5a0..751f81649dd 100644
--- a/nixpkgs/nixos/modules/services/web-apps/codimd.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/codimd.nix
@@ -156,7 +156,7 @@ in
};
useCDN = mkOption {
type = types.bool;
- default = true;
+ default = false;
description = ''
Whether to use CDN resources or not.
'';
diff --git a/nixpkgs/nixos/modules/services/web-apps/grocy.nix b/nixpkgs/nixos/modules/services/web-apps/grocy.nix
new file mode 100644
index 00000000000..568bdfd0c42
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/web-apps/grocy.nix
@@ -0,0 +1,172 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+ cfg = config.services.grocy;
+in {
+ options.services.grocy = {
+ enable = mkEnableOption "grocy";
+
+ hostName = mkOption {
+ type = types.str;
+ description = ''
+ FQDN for the grocy instance.
+ '';
+ };
+
+ nginx.enableSSL = mkOption {
+ type = types.bool;
+ default = true;
+ description = ''
+ Whether or not to enable SSL (with ACME and let's encrypt)
+ for the grocy vhost.
+ '';
+ };
+
+ phpfpm.settings = mkOption {
+ type = with types; attrsOf (oneOf [ int str bool ]);
+ default = {
+ "pm" = "dynamic";
+ "php_admin_value[error_log]" = "stderr";
+ "php_admin_flag[log_errors]" = true;
+ "listen.owner" = "nginx";
+ "catch_workers_output" = true;
+ "pm.max_children" = "32";
+ "pm.start_servers" = "2";
+ "pm.min_spare_servers" = "2";
+ "pm.max_spare_servers" = "4";
+ "pm.max_requests" = "500";
+ };
+
+ description = ''
+ Options for grocy's PHPFPM pool.
+ '';
+ };
+
+ dataDir = mkOption {
+ type = types.str;
+ default = "/var/lib/grocy";
+ description = ''
+ Home directory of the <literal>grocy</literal> user which contains
+ the application's state.
+ '';
+ };
+
+ settings = {
+ currency = mkOption {
+ type = types.str;
+ default = "USD";
+ example = "EUR";
+ description = ''
+ ISO 4217 code for the currency to display.
+ '';
+ };
+
+ culture = mkOption {
+ type = types.enum [ "de" "en" "da" "en_GB" "es" "fr" "hu" "it" "nl" "no" "pl" "pt_BR" "ru" "sk_SK" "sv_SE" "tr" ];
+ default = "en";
+ description = ''
+ Display language of the frontend.
+ '';
+ };
+
+ calendar = {
+ showWeekNumber = mkOption {
+ default = true;
+ type = types.bool;
+ description = ''
+ Show the number of the weeks in the calendar views.
+ '';
+ };
+ firstDayOfWeek = mkOption {
+ default = null;
+ type = types.nullOr (types.enum (range 0 6));
+ description = ''
+ Which day of the week (0=Sunday, 1=Monday etc.) should be the
+ first day.
+ '';
+ };
+ };
+ };
+ };
+
+ config = mkIf cfg.enable {
+ environment.etc."grocy/config.php".text = ''
+ <?php
+ Setting('CULTURE', '${cfg.settings.culture}');
+ Setting('CURRENCY', '${cfg.settings.currency}');
+ Setting('CALENDAR_FIRST_DAY_OF_WEEK', '${toString cfg.settings.calendar.firstDayOfWeek}');
+ Setting('CALENDAR_SHOW_WEEK_OF_YEAR', ${boolToString cfg.settings.calendar.showWeekNumber});
+ '';
+
+ users.users.grocy = {
+ isSystemUser = true;
+ createHome = true;
+ home = cfg.dataDir;
+ group = "nginx";
+ };
+
+ systemd.tmpfiles.rules = map (
+ dirName: "d '${cfg.dataDir}/${dirName}' - grocy nginx - -"
+ ) [ "viewcache" "plugins" "settingoverrides" "storage" ];
+
+ services.phpfpm.pools.grocy = {
+ user = "grocy";
+ group = "nginx";
+
+ # PHP 7.3 is the only version which is supported/tested by upstream:
+ # https://github.com/grocy/grocy/blob/v2.6.0/README.md#how-to-install
+ phpPackage = pkgs.php73;
+
+ inherit (cfg.phpfpm) settings;
+
+ phpEnv = {
+ GROCY_CONFIG_FILE = "/etc/grocy/config.php";
+ GROCY_DB_FILE = "${cfg.dataDir}/grocy.db";
+ GROCY_STORAGE_DIR = "${cfg.dataDir}/storage";
+ GROCY_PLUGIN_DIR = "${cfg.dataDir}/plugins";
+ GROCY_CACHE_DIR = "${cfg.dataDir}/viewcache";
+ };
+ };
+
+ services.nginx = {
+ enable = true;
+ virtualHosts."${cfg.hostName}" = mkMerge [
+ { root = "${pkgs.grocy}/public";
+ locations."/".extraConfig = ''
+ rewrite ^ /index.php;
+ '';
+ locations."~ \\.php$".extraConfig = ''
+ fastcgi_split_path_info ^(.+\.php)(/.+)$;
+ fastcgi_pass unix:${config.services.phpfpm.pools.grocy.socket};
+ include ${config.services.nginx.package}/conf/fastcgi.conf;
+ include ${config.services.nginx.package}/conf/fastcgi_params;
+ '';
+ locations."~ \\.(js|css|ttf|woff2?|png|jpe?g|svg)$".extraConfig = ''
+ add_header Cache-Control "public, max-age=15778463";
+ add_header X-Content-Type-Options nosniff;
+ add_header X-XSS-Protection "1; mode=block";
+ add_header X-Robots-Tag none;
+ add_header X-Download-Options noopen;
+ add_header X-Permitted-Cross-Domain-Policies none;
+ add_header Referrer-Policy no-referrer;
+ access_log off;
+ '';
+ extraConfig = ''
+ try_files $uri /index.php;
+ '';
+ }
+ (mkIf cfg.nginx.enableSSL {
+ enableACME = true;
+ forceSSL = true;
+ })
+ ];
+ };
+ };
+
+ meta = {
+ maintainers = with maintainers; [ ma27 ];
+ doc = ./grocy.xml;
+ };
+}
diff --git a/nixpkgs/nixos/modules/services/web-apps/grocy.xml b/nixpkgs/nixos/modules/services/web-apps/grocy.xml
new file mode 100644
index 00000000000..fdf6d00f4b1
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/web-apps/grocy.xml
@@ -0,0 +1,77 @@
+<chapter xmlns="http://docbook.org/ns/docbook"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ version="5.0"
+ xml:id="module-services-grocy">
+
+ <title>Grocy</title>
+ <para>
+ <link xlink:href="https://grocy.info/">Grocy</link> is a web-based self-hosted groceries
+ &amp; household management solution for your home.
+ </para>
+
+ <section xml:id="module-services-grocy-basic-usage">
+ <title>Basic usage</title>
+ <para>
+ A very basic configuration may look like this:
+<programlisting>{ pkgs, ... }:
+{
+ services.grocy = {
+ <link linkend="opt-services.grocy.enable">enable</link> = true;
+ <link linkend="opt-services.grocy.hostName">hostName</link> = "grocy.tld";
+ };
+}</programlisting>
+ This configures a simple vhost using <link linkend="opt-services.nginx.enable">nginx</link>
+ which listens to <literal>grocy.tld</literal> with fully configured ACME/LE (this can be
+ disabled by setting <link linkend="opt-services.grocy.nginx.enableSSL">services.grocy.nginx.enableSSL</link>
+ to <literal>false</literal>). After the initial setup the credentials <literal>admin:admin</literal>
+ can be used to login.
+ </para>
+ <para>
+ The application's state is persisted at <literal>/var/lib/grocy/grocy.db</literal> in a
+ <package>sqlite3</package> database. The migration is applied when requesting the <literal>/</literal>-route
+ of the application.
+ </para>
+ </section>
+
+ <section xml:id="module-services-grocy-settings">
+ <title>Settings</title>
+ <para>
+ The configuration for <literal>grocy</literal> is located at <literal>/etc/grocy/config.php</literal>.
+ By default, the following settings can be defined in the NixOS-configuration:
+<programlisting>{ pkgs, ... }:
+{
+ services.grocy.settings = {
+ # The default currency in the system for invoices etc.
+ # Please note that exchange rates aren't taken into account, this
+ # is just the setting for what's shown in the frontend.
+ <link linkend="opt-services.grocy.settings.currency">currency</link> = "EUR";
+
+ # The display language (and locale configuration) for grocy.
+ <link linkend="opt-services.grocy.settings.currency">culture</link> = "de";
+
+ calendar = {
+ # Whether or not to show the week-numbers
+ # in the calendar.
+ <link linkend="opt-services.grocy.settings.calendar.showWeekNumber">showWeekNumber</link> = true;
+
+ # Index of the first day to be shown in the calendar (0=Sunday, 1=Monday,
+ # 2=Tuesday and so on).
+ <link linkend="opt-services.grocy.settings.calendar.firstDayOfWeek">firstDayOfWeek</link> = 2;
+ };
+ };
+}</programlisting>
+ </para>
+ <para>
+ If you want to alter the configuration file on your own, you can do this manually with
+ an expression like this:
+<programlisting>{ lib, ... }:
+{
+ environment.etc."grocy/config.php".text = lib.mkAfter ''
+ // Arbitrary PHP code in grocy's configuration file
+ '';
+}</programlisting>
+ </para>
+ </section>
+
+</chapter>
diff --git a/nixpkgs/nixos/modules/services/web-apps/jirafeau.nix b/nixpkgs/nixos/modules/services/web-apps/jirafeau.nix
new file mode 100644
index 00000000000..4f181257ef7
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/web-apps/jirafeau.nix
@@ -0,0 +1,169 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+let
+ cfg = config.services.jirafeau;
+
+ group = config.services.nginx.group;
+ user = config.services.nginx.user;
+
+ withTrailingSlash = str: if hasSuffix "/" str then str else "${str}/";
+
+ localConfig = pkgs.writeText "config.local.php" ''
+ <?php
+ $cfg['admin_password'] = '${cfg.adminPasswordSha256}';
+ $cfg['web_root'] = 'http://${withTrailingSlash cfg.hostName}';
+ $cfg['var_root'] = '${withTrailingSlash cfg.dataDir}';
+ $cfg['maximal_upload_size'] = ${builtins.toString cfg.maxUploadSizeMegabytes};
+ $cfg['installation_done'] = true;
+
+ ${cfg.extraConfig}
+ '';
+in
+{
+ options.services.jirafeau = {
+ adminPasswordSha256 = mkOption {
+ type = types.str;
+ default = "";
+ description = ''
+ SHA-256 of the desired administration password. Leave blank/unset for no password.
+ '';
+ };
+
+ dataDir = mkOption {
+ type = types.path;
+ default = "/var/lib/jirafeau/data/";
+ description = "Location of Jirafeau storage directory.";
+ };
+
+ enable = mkEnableOption "Jirafeau file upload application.";
+
+ extraConfig = mkOption {
+ type = types.lines;
+ default = "";
+ example = ''
+ $cfg['style'] = 'courgette';
+ $cfg['organisation'] = 'ACME';
+ '';
+ description = let
+ documentationLink =
+ "https://gitlab.com/mojo42/Jirafeau/-/blob/${cfg.package.version}/lib/config.original.php";
+ in
+ ''
+ Jirefeau configuration. Refer to <link xlink:href="${documentationLink}"/> for supported
+ values.
+ '';
+ };
+
+ hostName = mkOption {
+ type = types.str;
+ default = "localhost";
+ description = "URL of instance. Must have trailing slash.";
+ };
+
+ maxUploadSizeMegabytes = mkOption {
+ type = types.int;
+ default = 0;
+ description = "Maximum upload size of accepted files.";
+ };
+
+ maxUploadTimeout = mkOption {
+ type = types.str;
+ default = "30m";
+ description = let
+ nginxCoreDocumentation = "http://nginx.org/en/docs/http/ngx_http_core_module.html";
+ in
+ ''
+ Timeout for reading client request bodies and headers. Refer to
+ <link xlink:href="${nginxCoreDocumentation}#client_body_timeout"/> and
+ <link xlink:href="${nginxCoreDocumentation}#client_header_timeout"/> for accepted values.
+ '';
+ };
+
+ nginxConfig = mkOption {
+ type = types.submodule
+ (import ../web-servers/nginx/vhost-options.nix { inherit config lib; });
+ default = {};
+ example = {
+ serverAliases = [ "wiki.\${config.networking.domain}" ];
+ };
+ description = "Extra configuration for the nginx virtual host of Jirafeau.";
+ };
+
+ package = mkOption {
+ type = types.package;
+ default = pkgs.jirafeau;
+ defaultText = "pkgs.jirafeau";
+ description = "Jirafeau package to use";
+ example = "pkgs.jirafeau";
+ };
+
+ poolConfig = mkOption {
+ type = with types; attrsOf (oneOf [ str int bool ]);
+ default = {
+ "pm" = "dynamic";
+ "pm.max_children" = 32;
+ "pm.start_servers" = 2;
+ "pm.min_spare_servers" = 2;
+ "pm.max_spare_servers" = 4;
+ "pm.max_requests" = 500;
+ };
+ description = ''
+ Options for Jirafeau PHP pool. See documentation on <literal>php-fpm.conf</literal> for
+ details on configuration directives.
+ '';
+ };
+ };
+
+
+ config = mkIf cfg.enable {
+ services = {
+ nginx = {
+ enable = true;
+ virtualHosts."${cfg.hostName}" = mkMerge [
+ cfg.nginxConfig
+ {
+ extraConfig = let
+ clientMaxBodySize =
+ if cfg.maxUploadSizeMegabytes == 0 then "0" else "${cfg.maxUploadSizeMegabytes}m";
+ in
+ ''
+ index index.php;
+ client_max_body_size ${clientMaxBodySize};
+ client_body_timeout ${cfg.maxUploadTimeout};
+ client_header_timeout ${cfg.maxUploadTimeout};
+ '';
+ locations = {
+ "~ \\.php$".extraConfig = ''
+ include ${pkgs.nginx}/conf/fastcgi_params;
+ fastcgi_split_path_info ^(.+\.php)(/.+)$;
+ fastcgi_index index.php;
+ fastcgi_pass unix:${config.services.phpfpm.pools.jirafeau.socket};
+ fastcgi_param PATH_INFO $fastcgi_path_info;
+ fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
+ '';
+ };
+ root = mkForce "${cfg.package}";
+ }
+ ];
+ };
+
+ phpfpm.pools.jirafeau = {
+ inherit group user;
+ phpEnv."JIRAFEAU_CONFIG" = "${localConfig}";
+ settings = {
+ "listen.mode" = "0660";
+ "listen.owner" = user;
+ "listen.group" = group;
+ } // cfg.poolConfig;
+ };
+ };
+
+ systemd.tmpfiles.rules = [
+ "d ${cfg.dataDir} 0750 ${user} ${group} - -"
+ "d ${cfg.dataDir}/files/ 0750 ${user} ${group} - -"
+ "d ${cfg.dataDir}/links/ 0750 ${user} ${group} - -"
+ "d ${cfg.dataDir}/async/ 0750 ${user} ${group} - -"
+ ];
+ };
+}
diff --git a/nixpkgs/nixos/modules/services/web-apps/limesurvey.nix b/nixpkgs/nixos/modules/services/web-apps/limesurvey.nix
index e00a47191c6..56265e80957 100644
--- a/nixpkgs/nixos/modules/services/web-apps/limesurvey.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/limesurvey.nix
@@ -100,7 +100,7 @@ in
};
virtualHost = mkOption {
- type = types.submodule (import ../web-servers/apache-httpd/per-server-options.nix);
+ type = types.submodule (import ../web-servers/apache-httpd/vhost-options.nix);
example = literalExample ''
{
hostName = "survey.example.org";
diff --git a/nixpkgs/nixos/modules/services/web-apps/mattermost.nix b/nixpkgs/nixos/modules/services/web-apps/mattermost.nix
index 41c52b9653b..853347bf86e 100644
--- a/nixpkgs/nixos/modules/services/web-apps/mattermost.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/mattermost.nix
@@ -6,14 +6,18 @@ let
cfg = config.services.mattermost;
- defaultConfig = builtins.fromJSON (readFile "${pkgs.mattermost}/config/config.json");
+ defaultConfig = builtins.fromJSON (builtins.replaceStrings [ "\\u0026" ] [ "&" ]
+ (readFile "${pkgs.mattermost}/config/config.json")
+ );
+
+ database = "postgres://${cfg.localDatabaseUser}:${cfg.localDatabasePassword}@localhost:5432/${cfg.localDatabaseName}?sslmode=disable&connect_timeout=10";
mattermostConf = foldl recursiveUpdate defaultConfig
[ { ServiceSettings.SiteURL = cfg.siteUrl;
ServiceSettings.ListenAddress = cfg.listenAddress;
TeamSettings.SiteName = cfg.siteName;
SqlSettings.DriverName = "postgres";
- SqlSettings.DataSource = "postgres://${cfg.localDatabaseUser}:${cfg.localDatabasePassword}@localhost:5432/${cfg.localDatabaseName}?sslmode=disable&connect_timeout=10";
+ SqlSettings.DataSource = database;
}
cfg.extraConfig
];
@@ -175,7 +179,9 @@ in
mkdir -p ${cfg.statePath}/{data,config,logs}
ln -sf ${pkgs.mattermost}/{bin,fonts,i18n,templates,client} ${cfg.statePath}
'' + lib.optionalString (!cfg.mutableConfig) ''
- ln -sf ${mattermostConfJSON} ${cfg.statePath}/config/config.json
+ rm -f ${cfg.statePath}/config/config.json
+ cp ${mattermostConfJSON} ${cfg.statePath}/config/config.json
+ ${pkgs.mattermost}/bin/mattermost config migrate ${cfg.statePath}/config/config.json ${database}
'' + lib.optionalString cfg.mutableConfig ''
if ! test -e "${cfg.statePath}/config/.initial-created"; then
rm -f ${cfg.statePath}/config/config.json
@@ -201,7 +207,8 @@ in
PermissionsStartOnly = true;
User = cfg.user;
Group = cfg.group;
- ExecStart = "${pkgs.mattermost}/bin/mattermost";
+ ExecStart = "${pkgs.mattermost}/bin/mattermost" +
+ (lib.optionalString (!cfg.mutableConfig) " -c ${database}");
WorkingDirectory = "${cfg.statePath}";
Restart = "always";
RestartSec = "10";
@@ -227,4 +234,3 @@ in
})
];
}
-
diff --git a/nixpkgs/nixos/modules/services/web-apps/mediawiki.nix b/nixpkgs/nixos/modules/services/web-apps/mediawiki.nix
index 8a109b39bb5..e9ed53857d8 100644
--- a/nixpkgs/nixos/modules/services/web-apps/mediawiki.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/mediawiki.nix
@@ -290,7 +290,7 @@ in
};
virtualHost = mkOption {
- type = types.submodule (import ../web-servers/apache-httpd/per-server-options.nix);
+ type = types.submodule (import ../web-servers/apache-httpd/vhost-options.nix);
example = literalExample ''
{
hostName = "mediawiki.example.org";
diff --git a/nixpkgs/nixos/modules/services/web-apps/moodle.nix b/nixpkgs/nixos/modules/services/web-apps/moodle.nix
index 595d070d940..1196780cf6e 100644
--- a/nixpkgs/nixos/modules/services/web-apps/moodle.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/moodle.nix
@@ -140,7 +140,7 @@ in
};
virtualHost = mkOption {
- type = types.submodule (import ../web-servers/apache-httpd/per-server-options.nix);
+ type = types.submodule (import ../web-servers/apache-httpd/vhost-options.nix);
example = literalExample ''
{
hostName = "moodle.example.org";
diff --git a/nixpkgs/nixos/modules/services/web-apps/nextcloud.nix b/nixpkgs/nixos/modules/services/web-apps/nextcloud.nix
index d79f2bb735f..912e05d6d40 100644
--- a/nixpkgs/nixos/modules/services/web-apps/nextcloud.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/nextcloud.nix
@@ -443,7 +443,7 @@ in {
pools.nextcloud = {
user = "nextcloud";
group = "nginx";
- phpOptions = phpOptionsExtensions + phpOptionsStr;
+ phpOptions = phpOptionsStr;
phpPackage = phpPackage;
phpEnv = {
NEXTCLOUD_CONFIG_DIR = "${cfg.home}/config";
@@ -533,6 +533,7 @@ in {
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
+ add_header X-Frame-Options sameorigin;
add_header Referrer-Policy no-referrer;
access_log off;
'';
@@ -547,6 +548,7 @@ in {
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
+ add_header X-Frame-Options sameorigin;
add_header Referrer-Policy no-referrer;
add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
error_page 403 /core/templates/403.php;
diff --git a/nixpkgs/nixos/modules/services/web-apps/wordpress.nix b/nixpkgs/nixos/modules/services/web-apps/wordpress.nix
index ad4f39fbf52..c48a4409737 100644
--- a/nixpkgs/nixos/modules/services/web-apps/wordpress.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/wordpress.nix
@@ -209,7 +209,7 @@ let
};
virtualHost = mkOption {
- type = types.submodule (import ../web-servers/apache-httpd/per-server-options.nix);
+ type = types.submodule (import ../web-servers/apache-httpd/vhost-options.nix);
example = literalExample ''
{
adminAddr = "webmaster@example.org";
diff --git a/nixpkgs/nixos/modules/services/web-apps/zabbix.nix b/nixpkgs/nixos/modules/services/web-apps/zabbix.nix
index ee8447810c6..00719512834 100644
--- a/nixpkgs/nixos/modules/services/web-apps/zabbix.nix
+++ b/nixpkgs/nixos/modules/services/web-apps/zabbix.nix
@@ -113,7 +113,7 @@ in
};
virtualHost = mkOption {
- type = types.submodule (import ../web-servers/apache-httpd/per-server-options.nix);
+ type = types.submodule (import ../web-servers/apache-httpd/vhost-options.nix);
example = literalExample ''
{
hostName = "zabbix.example.org";
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 9942c63acce..832c8b30ee9 100644
--- a/nixpkgs/nixos/modules/services/web-servers/apache-httpd/default.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/default.nix
@@ -4,21 +4,21 @@ with lib;
let
- mainCfg = config.services.httpd;
+ cfg = config.services.httpd;
runtimeDir = "/run/httpd";
- httpd = mainCfg.package.out;
+ pkg = cfg.package.out;
- httpdConf = mainCfg.configFile;
+ httpdConf = cfg.configFile;
- php = mainCfg.phpPackage.override { apacheHttpd = httpd.dev; /* otherwise it only gets .out */ };
+ php = cfg.phpPackage.override { apacheHttpd = pkg.dev; /* otherwise it only gets .out */ };
phpMajorVersion = lib.versions.major (lib.getVersion php);
- mod_perl = pkgs.apacheHttpdPackages.mod_perl.override { apacheHttpd = httpd; };
+ mod_perl = pkgs.apacheHttpdPackages.mod_perl.override { apacheHttpd = pkg; };
- vhosts = attrValues mainCfg.virtualHosts;
+ vhosts = attrValues cfg.virtualHosts;
mkListenInfo = hostOpts:
if hostOpts.listen != [] then hostOpts.listen
@@ -29,8 +29,8 @@ let
listenInfo = unique (concatMap mkListenInfo vhosts);
+ enableHttp2 = any (vhost: vhost.http2) vhosts;
enableSSL = any (listen: listen.ssl) listenInfo;
-
enableUserDir = any (vhost: vhost.enableUserDir) vhosts;
# NOTE: generally speaking order of modules is very important
@@ -41,23 +41,19 @@ let
"mime" "autoindex" "negotiation" "dir"
"alias" "rewrite"
"unixd" "slotmem_shm" "socache_shmcb"
- "mpm_${mainCfg.multiProcessingModule}"
+ "mpm_${cfg.multiProcessingModule}"
]
- ++ (if mainCfg.multiProcessingModule == "prefork" then [ "cgi" ] else [ "cgid" ])
+ ++ (if cfg.multiProcessingModule == "prefork" then [ "cgi" ] else [ "cgid" ])
+ ++ optional enableHttp2 "http2"
++ optional enableSSL "ssl"
++ optional enableUserDir "userdir"
- ++ optional mainCfg.enableMellon { name = "auth_mellon"; path = "${pkgs.apacheHttpdPackages.mod_auth_mellon}/modules/mod_auth_mellon.so"; }
- ++ optional mainCfg.enablePHP { name = "php${phpMajorVersion}"; path = "${php}/modules/libphp${phpMajorVersion}.so"; }
- ++ optional mainCfg.enablePerl { name = "perl"; path = "${mod_perl}/modules/mod_perl.so"; }
- ++ mainCfg.extraModules;
-
-
- allDenied = "Require all denied";
- allGranted = "Require all granted";
+ ++ optional cfg.enableMellon { name = "auth_mellon"; path = "${pkgs.apacheHttpdPackages.mod_auth_mellon}/modules/mod_auth_mellon.so"; }
+ ++ optional cfg.enablePHP { name = "php${phpMajorVersion}"; path = "${php}/modules/libphp${phpMajorVersion}.so"; }
+ ++ optional cfg.enablePerl { name = "perl"; path = "${mod_perl}/modules/mod_perl.so"; }
+ ++ cfg.extraModules;
-
- loggingConf = (if mainCfg.logFormat != "none" then ''
- ErrorLog ${mainCfg.logDir}/error.log
+ loggingConf = (if cfg.logFormat != "none" then ''
+ ErrorLog ${cfg.logDir}/error.log
LogLevel notice
@@ -66,7 +62,7 @@ let
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent
- CustomLog ${mainCfg.logDir}/access.log ${mainCfg.logFormat}
+ CustomLog ${cfg.logDir}/access.log ${cfg.logFormat}
'' else ''
ErrorLog /dev/null
'');
@@ -88,34 +84,36 @@ let
sslConf = ''
- SSLSessionCache shmcb:${runtimeDir}/ssl_scache(512000)
+ <IfModule mod_ssl.c>
+ SSLSessionCache shmcb:${runtimeDir}/ssl_scache(512000)
- Mutex posixsem
+ Mutex posixsem
- SSLRandomSeed startup builtin
- SSLRandomSeed connect builtin
+ SSLRandomSeed startup builtin
+ SSLRandomSeed connect builtin
- SSLProtocol ${mainCfg.sslProtocols}
- SSLCipherSuite ${mainCfg.sslCiphers}
- SSLHonorCipherOrder on
+ SSLProtocol ${cfg.sslProtocols}
+ SSLCipherSuite ${cfg.sslCiphers}
+ SSLHonorCipherOrder on
+ </IfModule>
'';
mimeConf = ''
- TypesConfig ${httpd}/conf/mime.types
+ TypesConfig ${pkg}/conf/mime.types
AddType application/x-x509-ca-cert .crt
AddType application/x-pkcs7-crl .crl
AddType application/x-httpd-php .php .phtml
<IfModule mod_mime_magic.c>
- MIMEMagicFile ${httpd}/conf/magic
+ MIMEMagicFile ${pkg}/conf/magic
</IfModule>
'';
mkVHostConf = hostOpts:
let
- adminAddr = if hostOpts.adminAddr != null then hostOpts.adminAddr else mainCfg.adminAddr;
+ adminAddr = if hostOpts.adminAddr != null then hostOpts.adminAddr else cfg.adminAddr;
listen = filter (listen: !listen.ssl) (mkListenInfo hostOpts);
listenSSL = filter (listen: listen.ssl) (mkListenInfo hostOpts);
@@ -167,6 +165,7 @@ let
SSLCertificateFile ${sslServerCert}
SSLCertificateKeyFile ${sslServerKey}
${optionalString (sslServerChain != null) "SSLCertificateChainFile ${sslServerChain}"}
+ ${optionalString hostOpts.http2 "Protocols h2 h2c http/1.1"}
${acmeChallenge}
${mkVHostCommonConf hostOpts}
</VirtualHost>
@@ -203,9 +202,9 @@ let
'') (sortProperties (mapAttrsToList (k: v: v // { location = k; }) locations)));
in
''
- ${optionalString mainCfg.logPerVirtualHost ''
- ErrorLog ${mainCfg.logDir}/error-${hostOpts.hostName}.log
- CustomLog ${mainCfg.logDir}/access-${hostOpts.hostName}.log ${hostOpts.logFormat}
+ ${optionalString cfg.logPerVirtualHost ''
+ ErrorLog ${cfg.logDir}/error-${hostOpts.hostName}.log
+ CustomLog ${cfg.logDir}/access-${hostOpts.hostName}.log ${hostOpts.logFormat}
''}
${optionalString (hostOpts.robotsEntries != "") ''
@@ -217,7 +216,7 @@ let
<Directory "${documentRoot}">
Options Indexes FollowSymLinks
AllowOverride None
- ${allGranted}
+ Require all granted
</Directory>
${optionalString hostOpts.enableUserDir ''
@@ -244,7 +243,7 @@ let
Alias ${elem.urlPath} ${elem.dir}/
<Directory ${elem.dir}>
Options +Indexes
- ${allGranted}
+ Require all granted
AllowOverride All
</Directory>
'';
@@ -259,20 +258,20 @@ let
confFile = pkgs.writeText "httpd.conf" ''
- ServerRoot ${httpd}
+ ServerRoot ${pkg}
ServerName ${config.networking.hostName}
DefaultRuntimeDir ${runtimeDir}/runtime
PidFile ${runtimeDir}/httpd.pid
- ${optionalString (mainCfg.multiProcessingModule != "prefork") ''
+ ${optionalString (cfg.multiProcessingModule != "prefork") ''
# mod_cgid requires this.
ScriptSock ${runtimeDir}/cgisock
''}
<IfModule prefork.c>
- MaxClients ${toString mainCfg.maxClients}
- MaxRequestsPerChild ${toString mainCfg.maxRequestsPerChild}
+ MaxClients ${toString cfg.maxClients}
+ MaxRequestsPerChild ${toString cfg.maxRequestsPerChild}
</IfModule>
${let
@@ -281,12 +280,12 @@ let
in concatStringsSep "\n" uniqueListen
}
- User ${mainCfg.user}
- Group ${mainCfg.group}
+ User ${cfg.user}
+ Group ${cfg.group}
${let
mkModule = module:
- if isString module then { name = module; path = "${httpd}/modules/mod_${module}.so"; }
+ if isString module then { name = module; path = "${pkg}/modules/mod_${module}.so"; }
else if isAttrs module then { inherit (module) name path; }
else throw "Expecting either a string or attribute set including a name and path.";
in
@@ -296,37 +295,37 @@ let
AddHandler type-map var
<Files ~ "^\.ht">
- ${allDenied}
+ Require all denied
</Files>
${mimeConf}
${loggingConf}
${browserHacks}
- Include ${httpd}/conf/extra/httpd-default.conf
- Include ${httpd}/conf/extra/httpd-autoindex.conf
- Include ${httpd}/conf/extra/httpd-multilang-errordoc.conf
- Include ${httpd}/conf/extra/httpd-languages.conf
+ Include ${pkg}/conf/extra/httpd-default.conf
+ Include ${pkg}/conf/extra/httpd-autoindex.conf
+ Include ${pkg}/conf/extra/httpd-multilang-errordoc.conf
+ Include ${pkg}/conf/extra/httpd-languages.conf
TraceEnable off
- ${if enableSSL then sslConf else ""}
+ ${sslConf}
# Fascist default - deny access to everything.
<Directory />
Options FollowSymLinks
AllowOverride None
- ${allDenied}
+ Require all denied
</Directory>
# But do allow access to files in the store so that we don't have
# to generate <Directory> clauses for every generated file that we
# want to serve.
<Directory /nix/store>
- ${allGranted}
+ Require all granted
</Directory>
- ${mainCfg.extraConfig}
+ ${cfg.extraConfig}
${concatMapStringsSep "\n" mkVHostConf vhosts}
'';
@@ -334,7 +333,7 @@ let
# Generate the PHP configuration file. Should probably be factored
# out into a separate module.
phpIni = pkgs.runCommand "php.ini"
- { options = mainCfg.phpOptions;
+ { options = cfg.phpOptions;
preferLocalBuild = true;
}
''
@@ -367,17 +366,13 @@ in
(mkRemovedOptionModule [ "services" "httpd" "sslServerKey" ] "Please define a virtual host using `services.httpd.virtualHosts`.")
];
- ###### interface
+ # interface
options = {
services.httpd = {
- enable = mkOption {
- type = types.bool;
- default = false;
- description = "Whether to enable the Apache HTTP Server.";
- };
+ enable = mkEnableOption "the Apache HTTP Server";
package = mkOption {
type = types.package;
@@ -404,7 +399,7 @@ in
default = "";
description = ''
Configuration lines appended to the generated Apache
- configuration file. Note that this mechanism may not work
+ configuration file. Note that this mechanism will not work
when <option>configFile</option> is overridden.
'';
};
@@ -419,7 +414,7 @@ in
]
'';
description = ''
- Additional Apache modules to be used. These can be
+ Additional Apache modules to be used. These can be
specified as a string in the case of modules distributed
with Apache, or as an attribute set specifying the
<varname>name</varname> and <varname>path</varname> of the
@@ -458,8 +453,7 @@ in
type = types.str;
default = "wwwrun";
description = ''
- User account under which httpd runs. The account is created
- automatically if it doesn't exist.
+ User account under which httpd runs.
'';
};
@@ -467,8 +461,7 @@ in
type = types.str;
default = "wwwrun";
description = ''
- Group under which httpd runs. The account is created
- automatically if it doesn't exist.
+ Group under which httpd runs.
'';
};
@@ -476,15 +469,15 @@ in
type = types.path;
default = "/var/log/httpd";
description = ''
- Directory for Apache's log files. It is created automatically.
+ Directory for Apache's log files. It is created automatically.
'';
};
virtualHosts = mkOption {
- type = with types; attrsOf (submodule (import ./per-server-options.nix));
+ type = with types; attrsOf (submodule (import ./vhost-options.nix));
default = {
localhost = {
- documentRoot = "${httpd}/htdocs";
+ documentRoot = "${pkg}/htdocs";
};
};
example = literalExample ''
@@ -540,17 +533,18 @@ in
''
date.timezone = "CET"
'';
- description =
- "Options appended to the PHP configuration file <filename>php.ini</filename>.";
+ description = ''
+ Options appended to the PHP configuration file <filename>php.ini</filename>.
+ '';
};
multiProcessingModule = mkOption {
- type = types.str;
+ type = types.enum [ "event" "prefork" "worker" ];
default = "prefork";
example = "worker";
description =
''
- Multi-processing module to be used by Apache. Available
+ Multi-processing module to be used by Apache. Available
modules are <literal>prefork</literal> (the default;
handles each request in a separate child process),
<literal>worker</literal> (hybrid approach that starts a
@@ -572,8 +566,9 @@ in
type = types.int;
default = 0;
example = 500;
- description =
- "Maximum number of httpd requests answered per httpd child (prefork), 0 means unlimited";
+ description = ''
+ Maximum number of httpd requests answered per httpd child (prefork), 0 means unlimited.
+ '';
};
sslCiphers = mkOption {
@@ -592,10 +587,9 @@ in
};
+ # implementation
- ###### implementation
-
- config = mkIf config.services.httpd.enable {
+ config = mkIf cfg.enable {
assertions = [
{
@@ -626,30 +620,30 @@ in
warnings =
mapAttrsToList (name: hostOpts: ''
Using config.services.httpd.virtualHosts."${name}".servedFiles is deprecated and will become unsupported in a future release. Your configuration will continue to work as is but please migrate your configuration to config.services.httpd.virtualHosts."${name}".locations before the 20.09 release of NixOS.
- '') (filterAttrs (name: hostOpts: hostOpts.servedFiles != []) mainCfg.virtualHosts);
+ '') (filterAttrs (name: hostOpts: hostOpts.servedFiles != []) cfg.virtualHosts);
- users.users = optionalAttrs (mainCfg.user == "wwwrun") {
+ users.users = optionalAttrs (cfg.user == "wwwrun") {
wwwrun = {
- group = mainCfg.group;
+ group = cfg.group;
description = "Apache httpd user";
uid = config.ids.uids.wwwrun;
};
};
- users.groups = optionalAttrs (mainCfg.group == "wwwrun") {
+ users.groups = optionalAttrs (cfg.group == "wwwrun") {
wwwrun.gid = config.ids.gids.wwwrun;
};
security.acme.certs = mapAttrs (name: hostOpts: {
- user = mainCfg.user;
- group = mkDefault mainCfg.group;
- email = if hostOpts.adminAddr != null then hostOpts.adminAddr else mainCfg.adminAddr;
+ 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) mainCfg.virtualHosts);
+ }) (filterAttrs (name: hostOpts: hostOpts.enableACME) cfg.virtualHosts);
- environment.systemPackages = [httpd];
+ environment.systemPackages = [ pkg ];
# required for "apachectl configtest"
environment.etc."httpd/httpd.conf".source = httpdConf;
@@ -689,6 +683,15 @@ in
"access_compat"
];
+ systemd.tmpfiles.rules =
+ let
+ svc = config.systemd.services.httpd.serviceConfig;
+ in
+ [
+ "d '${cfg.logDir}' 0700 ${svc.User} ${svc.Group}"
+ "Z '${cfg.logDir}' - ${svc.User} ${svc.Group}"
+ ];
+
systemd.services.httpd =
let
vhostsACME = filter (hostOpts: hostOpts.enableACME) vhosts;
@@ -700,35 +703,36 @@ in
after = [ "network.target" "fs.target" ] ++ map (hostOpts: "acme-selfsigned-${hostOpts.hostName}.service") vhostsACME;
path =
- [ httpd pkgs.coreutils pkgs.gnugrep ]
- ++ optional mainCfg.enablePHP pkgs.system-sendmail; # Needed for PHP's mail() function.
+ [ pkg pkgs.coreutils pkgs.gnugrep ]
+ ++ optional cfg.enablePHP pkgs.system-sendmail; # Needed for PHP's mail() function.
environment =
- optionalAttrs mainCfg.enablePHP { PHPRC = phpIni; }
- // optionalAttrs mainCfg.enableMellon { LD_LIBRARY_PATH = "${pkgs.xmlsec}/lib"; };
+ optionalAttrs cfg.enablePHP { PHPRC = phpIni; }
+ // optionalAttrs cfg.enableMellon { LD_LIBRARY_PATH = "${pkgs.xmlsec}/lib"; };
preStart =
''
- mkdir -m 0700 -p ${mainCfg.logDir}
-
# Get rid of old semaphores. These tend to accumulate across
# server restarts, eventually preventing it from restarting
# successfully.
- for i in $(${pkgs.utillinux}/bin/ipcs -s | grep ' ${mainCfg.user} ' | cut -f2 -d ' '); do
+ for i in $(${pkgs.utillinux}/bin/ipcs -s | grep ' ${cfg.user} ' | cut -f2 -d ' '); do
${pkgs.utillinux}/bin/ipcrm -s $i
done
'';
- serviceConfig.ExecStart = "@${httpd}/bin/httpd httpd -f ${httpdConf}";
- serviceConfig.ExecStop = "${httpd}/bin/httpd -f ${httpdConf} -k graceful-stop";
- serviceConfig.ExecReload = "${httpd}/bin/httpd -f ${httpdConf} -k graceful";
- serviceConfig.Group = mainCfg.group;
- serviceConfig.Type = "forking";
- serviceConfig.PIDFile = "${runtimeDir}/httpd.pid";
- serviceConfig.Restart = "always";
- serviceConfig.RestartSec = "5s";
- serviceConfig.RuntimeDirectory = "httpd httpd/runtime";
- serviceConfig.RuntimeDirectoryMode = "0750";
+ serviceConfig = {
+ ExecStart = "@${pkg}/bin/httpd httpd -f ${httpdConf}";
+ ExecStop = "${pkg}/bin/httpd -f ${httpdConf} -k graceful-stop";
+ ExecReload = "${pkg}/bin/httpd -f ${httpdConf} -k graceful";
+ User = "root";
+ Group = cfg.group;
+ Type = "forking";
+ PIDFile = "${runtimeDir}/httpd.pid";
+ Restart = "always";
+ RestartSec = "5s";
+ RuntimeDirectory = "httpd httpd/runtime";
+ RuntimeDirectoryMode = "0750";
+ };
};
};
diff --git a/nixpkgs/nixos/modules/services/web-servers/apache-httpd/per-server-options.nix b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/vhost-options.nix
index f34f8b4acdf..263980add8b 100644
--- a/nixpkgs/nixos/modules/services/web-servers/apache-httpd/per-server-options.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/apache-httpd/vhost-options.nix
@@ -135,6 +135,15 @@ in
description = "Path to server SSL chain file.";
};
+ http2 = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Whether to enable HTTP 2. HTTP/2 is supported in all multi-processing modules that come with httpd. <emphasis>However, if you use the prefork mpm, there will
+ be severe restrictions.</emphasis> Refer to <link xlink:href="https://httpd.apache.org/docs/2.4/howto/http2.html#mpm-config"/> for details.
+ '';
+ };
+
adminAddr = mkOption {
type = types.nullOr types.str;
default = null;
diff --git a/nixpkgs/nixos/modules/services/web-servers/caddy.nix b/nixpkgs/nixos/modules/services/web-servers/caddy.nix
index 132c50735d9..0e6e10a5f47 100644
--- a/nixpkgs/nixos/modules/services/web-servers/caddy.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/caddy.nix
@@ -64,32 +64,38 @@ in {
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
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")
{ CADDYPATH = cfg.dataDir; };
serviceConfig = {
ExecStart = ''
- ${cfg.package}/bin/caddy -root=/var/tmp -conf=${configFile} \
+ ${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 -HUP $MAINPID";
+ ExecReload = "${pkgs.coreutils}/bin/kill -USR1 $MAINPID";
Type = "simple";
User = "caddy";
Group = "caddy";
- Restart = "on-failure";
- StartLimitInterval = 86400;
- StartLimitBurst = 5;
+ Restart = "on-abnormal";
+ StartLimitIntervalSec = 14400;
+ StartLimitBurst = 10;
AmbientCapabilities = "cap_net_bind_service";
CapabilityBoundingSet = "cap_net_bind_service";
NoNewPrivileges = true;
- LimitNPROC = 64;
+ LimitNPROC = 512;
LimitNOFILE = 1048576;
PrivateTmp = true;
PrivateDevices = true;
ProtectHome = true;
ProtectSystem = "full";
ReadWriteDirectories = cfg.dataDir;
+ KillMode = "mixed";
+ KillSignal = "SIGQUIT";
+ TimeoutStopSec = "5s";
};
};
diff --git a/nixpkgs/nixos/modules/services/web-servers/nginx/default.nix b/nixpkgs/nixos/modules/services/web-servers/nginx/default.nix
index c8602e5975b..28b433104a1 100644
--- a/nixpkgs/nixos/modules/services/web-servers/nginx/default.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/nginx/default.nix
@@ -87,10 +87,17 @@ let
${optionalString (cfg.sslDhparam != null) "ssl_dhparam ${cfg.sslDhparam};"}
${optionalString (cfg.recommendedTlsSettings) ''
- ssl_session_cache shared:SSL:42m;
- ssl_session_timeout 23m;
- ssl_ecdh_curve secp384r1;
- ssl_prefer_server_ciphers on;
+ # Keep in sync with https://ssl-config.mozilla.org/#server=nginx&config=intermediate
+
+ ssl_session_timeout 1d;
+ ssl_session_cache shared:SSL:10m;
+ # Breaks forward secrecy: https://github.com/mozilla/server-side-tls/issues/135
+ ssl_session_tickets off;
+ # We don't enable insecure ciphers by default, so this allows
+ # clients to pick the most performant, per https://github.com/mozilla/server-side-tls/issues/260
+ ssl_prefer_server_ciphers off;
+
+ # OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
''}
@@ -487,8 +494,9 @@ in
sslCiphers = mkOption {
type = types.str;
- 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.";
+ # Keep in sync with https://ssl-config.mozilla.org/#server=nginx&config=intermediate
+ default = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";
+ description = "Ciphers to choose from when negotiating TLS handshakes.";
};
sslProtocols = mkOption {
diff --git a/nixpkgs/nixos/modules/services/web-servers/uwsgi.nix b/nixpkgs/nixos/modules/services/web-servers/uwsgi.nix
index 3481b5e6040..4b74c329e3d 100644
--- a/nixpkgs/nixos/modules/services/web-servers/uwsgi.nix
+++ b/nixpkgs/nixos/modules/services/web-servers/uwsgi.nix
@@ -32,7 +32,7 @@ let
inherit plugins;
} // removeAttrs c [ "type" "pythonPackages" ]
// optionalAttrs (python != null) {
- pythonpath = "${pythonEnv}/${python.sitePackages}";
+ pyhome = "${pythonEnv}";
env =
# Argh, uwsgi expects list of key-values there instead of a dictionary.
let env' = c.env or [];
diff --git a/nixpkgs/nixos/modules/services/x11/desktop-managers/mate.nix b/nixpkgs/nixos/modules/services/x11/desktop-managers/mate.nix
index 4a6f2ca727d..910a246d776 100644
--- a/nixpkgs/nixos/modules/services/x11/desktop-managers/mate.nix
+++ b/nixpkgs/nixos/modules/services/x11/desktop-managers/mate.nix
@@ -86,6 +86,7 @@ in
pkgs.shared-mime-info
pkgs.xdg-user-dirs # Update user dirs as described in https://freedesktop.org/wiki/Software/xdg-user-dirs/
pkgs.mate.mate-settings-daemon
+ pkgs.yelp # for 'Contents' in 'Help' menus
];
programs.dconf.enable = true;
diff --git a/nixpkgs/nixos/modules/services/x11/desktop-managers/pantheon.nix b/nixpkgs/nixos/modules/services/x11/desktop-managers/pantheon.nix
index b46a2d189ef..869c6694489 100644
--- a/nixpkgs/nixos/modules/services/x11/desktop-managers/pantheon.nix
+++ b/nixpkgs/nixos/modules/services/x11/desktop-managers/pantheon.nix
@@ -16,7 +16,10 @@ in
{
- meta.maintainers = pkgs.pantheon.maintainers;
+ meta = {
+ doc = ./pantheon.xml;
+ maintainers = pkgs.pantheon.maintainers;
+ };
options = {
diff --git a/nixpkgs/nixos/modules/services/x11/desktop-managers/pantheon.xml b/nixpkgs/nixos/modules/services/x11/desktop-managers/pantheon.xml
new file mode 100644
index 00000000000..4d92a7446c0
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/x11/desktop-managers/pantheon.xml
@@ -0,0 +1,130 @@
+<chapter xmlns="http://docbook.org/ns/docbook"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xml:id="chap-pantheon">
+ <title>Pantheon Destkop</title>
+ <para>
+ Pantheon is the desktop environment created for the elementary OS distribution. It is written from scratch in Vala, utilizing GNOME technologies with GTK 3 and Granite.
+ </para>
+ <section xml:id="sec-pantheon-enable">
+ <title>Enabling Pantheon</title>
+
+ <para>
+ All of Pantheon is working in NixOS and the applications should be available, aside from a few <link xlink:href="https://github.com/NixOS/nixpkgs/issues/58161">exceptions</link>. To enable Pantheon, set
+<programlisting>
+<xref linkend="opt-services.xserver.desktopManager.pantheon.enable"/> = true;
+</programlisting>
+ This automatically enables LightDM and Pantheon's LightDM greeter. If you'd like to disable this, set
+<programlisting>
+<xref linkend="opt-services.xserver.displayManager.lightdm.greeters.pantheon.enable"/> = false;
+<xref linkend="opt-services.xserver.displayManager.lightdm.enable"/> = false;
+</programlisting>
+ but please be aware using Pantheon without LightDM as a display manager will break screenlocking from the UI. The NixOS module for Pantheon installs all of Pantheon's default applications. If you'd like to not install Pantheon's apps, set
+<programlisting>
+<xref linkend="opt-services.pantheon.apps.enable"/> = false;
+</programlisting>
+ You can also use <xref linkend="opt-environment.pantheon.excludePackages"/> to remove any other app (like <package>geary</package>).
+ </para>
+ </section>
+ <section xml:id="sec-pantheon-wingpanel-switchboard">
+ <title>Wingpanel and Switchboard plugins</title>
+
+ <para>
+ Wingpanel and Switchboard work differently than they do in other distributions, as far as using plugins. You cannot install a plugin globally (like with <option>environment.systemPackages</option>) to start using it. You should instead be using the following options:
+ <itemizedlist>
+ <listitem>
+ <para>
+ <xref linkend="opt-services.xserver.desktopManager.pantheon.extraWingpanelIndicators"/>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <xref linkend="opt-services.xserver.desktopManager.pantheon.extraSwitchboardPlugs"/>
+ </para>
+ </listitem>
+ </itemizedlist>
+ to configure the programs with plugs or indicators.
+ </para>
+
+ <para>
+ The difference in NixOS is both these programs are patched to load plugins from a directory that is the value of an environment variable. All of which is controlled in Nix. If you need to configure the particular packages manually you can override the packages like:
+<programlisting>
+wingpanel-with-indicators.override {
+ indicators = [
+ pkgs.some-special-indicator
+ ];
+};
+
+switchboard-with-plugs.override {
+ plugs = [
+ pkgs.some-special-plug
+ ];
+};
+</programlisting>
+ please note that, like how the NixOS options describe these as extra plugins, this would only add to the default plugins included with the programs. If for some reason you'd like to configure which plugins to use exactly, both packages have an argument for this:
+<programlisting>
+wingpanel-with-indicators.override {
+ useDefaultIndicators = false;
+ indicators = specialListOfIndicators;
+};
+
+switchboard-with-plugs.override {
+ useDefaultPlugs = false;
+ plugs = specialListOfPlugs;
+};
+</programlisting>
+ this could be most useful for testing a particular plug-in in isolation.
+ </para>
+ </section>
+ <section xml:id="sec-pantheon-faq">
+ <title>FAQ</title>
+
+ <variablelist>
+ <varlistentry xml:id="sec-pantheon-faq-messed-up-theme">
+ <term>
+ I have switched from a different desktop and Pantheon’s theming looks messed up.
+ </term>
+ <listitem>
+ <para>
+ Open Switchboard and go to: <guilabel>Administration</guilabel> → <guilabel>About</guilabel> → <guilabel>Restore Default Settings</guilabel> → <guibutton>Restore Settings</guibutton>. This will reset any dconf settings to their Pantheon defaults. Note this could reset certain GNOME specific preferences if that desktop was used prior.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry xml:id="sec-pantheon-faq-slow-shutdown">
+ <term>
+ Using Pantheon sometimes makes my shutdown take a long time.
+ </term>
+ <listitem>
+ <para>
+ We have not yet determined what processes fight with systemd during shutdown, there are many reports. In elementary OS the default system timeout is lowered to lessen the impact of the issue. If you'd like to do this in NixOS, set
+<programlisting>
+ <xref linkend="opt-systemd.extraConfig"/> = ''
+ DefaultTimeoutStopSec=10s
+ DefaultTimeoutStartSec=10s
+'';
+</programlisting>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry xml:id="sec-pantheon-faq-gnome3-and-pantheon">
+ <term>
+ I cannot enable both GNOME 3 and Pantheon.
+ </term>
+ <listitem>
+ <para>
+ This is a known <link xlink:href="https://github.com/NixOS/nixpkgs/issues/64611">issue</link> and there is no known workaround.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry xml:id="sec-pantheon-faq-appcenter">
+ <term>
+ Does AppCenter work, or is it available?
+ </term>
+ <listitem>
+ <para>
+ AppCenter has been available since 20.03, but it is of little use. This is because there is no functioning PackageKit backend for Nix 2.0. In the near future you will be able to install Flatpak applications from AppCenter on NixOS. See this <link xlink:href="https://github.com/NixOS/nixpkgs/issues/70214">issue</link>.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </section>
+</chapter>
diff --git a/nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix b/nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix
index 2538858ac0f..60ef0159ff1 100644
--- a/nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix
+++ b/nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix
@@ -8,6 +8,137 @@ let
cfg = xcfg.desktopManager.plasma5;
inherit (pkgs) kdeApplications plasma5 libsForQt5 qt5;
+ inherit (pkgs) writeText;
+
+ pulseaudio = config.hardware.pulseaudio;
+ pactl = "${getBin pulseaudio.package}/bin/pactl";
+ startplasma-x11 = "${getBin plasma5.plasma-workspace}/bin/startplasma-x11";
+ sed = "${getBin pkgs.gnused}/bin/sed";
+
+ gtkrc2 = writeText "gtkrc-2.0" ''
+ # Default GTK+ 2 config for NixOS Plasma 5
+ include "/run/current-system/sw/share/themes/Breeze/gtk-2.0/gtkrc"
+ style "user-font"
+ {
+ font_name="Sans Serif Regular"
+ }
+ widget_class "*" style "user-font"
+ gtk-font-name="Sans Serif Regular 10"
+ gtk-theme-name="Breeze"
+ gtk-icon-theme-name="breeze"
+ gtk-fallback-icon-theme="hicolor"
+ gtk-cursor-theme-name="breeze_cursors"
+ gtk-toolbar-style=GTK_TOOLBAR_ICONS
+ gtk-menu-images=1
+ gtk-button-images=1
+ '';
+
+ gtk3_settings = writeText "settings.ini" ''
+ [Settings]
+ gtk-font-name=Sans Serif Regular 10
+ gtk-theme-name=Breeze
+ gtk-icon-theme-name=breeze
+ gtk-fallback-icon-theme=hicolor
+ gtk-cursor-theme-name=breeze_cursors
+ gtk-toolbar-style=GTK_TOOLBAR_ICONS
+ gtk-menu-images=1
+ gtk-button-images=1
+ '';
+
+ kcminputrc = writeText "kcminputrc" ''
+ [Mouse]
+ cursorTheme=breeze_cursors
+ cursorSize=0
+ '';
+
+ activationScript = ''
+ ${set_XDG_CONFIG_HOME}
+
+ # The KDE icon cache is supposed to update itself automatically, but it uses
+ # the timestamp on the icon theme directory as a trigger. This doesn't work
+ # on NixOS because the timestamp never changes. As a workaround, delete the
+ # icon cache at login and session activation.
+ # See also: http://lists-archives.org/kde-devel/26175-what-when-will-icon-cache-refresh.html
+ rm -fv $HOME/.cache/icon-cache.kcache
+
+ # xdg-desktop-settings generates this empty file but
+ # it makes kbuildsyscoca5 fail silently. To fix this
+ # remove that menu if it exists.
+ rm -fv ''${XDG_CONFIG_HOME}/menus/applications-merged/xdg-desktop-menu-dummy.menu
+
+ # Qt writes a weird ‘libraryPath’ line to
+ # ~/.config/Trolltech.conf that causes the KDE plugin
+ # paths of previous KDE invocations to be searched.
+ # Obviously using mismatching KDE libraries is potentially
+ # disastrous, so here we nuke references to the Nix store
+ # in Trolltech.conf. A better solution would be to stop
+ # Qt from doing this wackiness in the first place.
+ trolltech_conf="''${XDG_CONFIG_HOME}/Trolltech.conf"
+ if [ -e "$trolltech_conf" ]; then
+ ${sed} -i "$trolltech_conf" -e '/nix\\store\|nix\/store/ d'
+ fi
+
+ # Remove the kbuildsyscoca5 cache. It will be regenerated
+ # immediately after. This is necessary for kbuildsyscoca5 to
+ # recognize that software that has been removed.
+ rm -fv $HOME/.cache/ksycoca*
+
+ ${pkgs.libsForQt5.kservice}/bin/kbuildsycoca5
+ '';
+
+ set_XDG_CONFIG_HOME = ''
+ # Set the default XDG_CONFIG_HOME if it is unset.
+ # Per the XDG Base Directory Specification:
+ # https://specifications.freedesktop.org/basedir-spec/latest
+ # 1. Never export this variable! If it is unset, then child processes are
+ # expected to set the default themselves.
+ # 2. Contaminate / if $HOME is unset; do not check if $HOME is set.
+ XDG_CONFIG_HOME=''${XDG_CONFIG_HOME:-$HOME/.config}
+ '';
+
+ startplasma =
+ ''
+ ${set_XDG_CONFIG_HOME}
+ mkdir -p "''${XDG_CONFIG_HOME}"
+
+ ''
+ + optionalString pulseaudio.enable ''
+ # Load PulseAudio module for routing support.
+ # See also: http://colin.guthr.ie/2009/10/so-how-does-the-kde-pulseaudio-support-work-anyway/
+ ${pactl} load-module module-device-manager "do_routing=1"
+
+ ''
+ + ''
+ ${activationScript}
+
+ # Create default configurations if Plasma has never been started.
+ kdeglobals="''${XDG_CONFIG_HOME}/kdeglobals"
+ if ! [ -f "$kdeglobals" ]
+ then
+ kcminputrc="''${XDG_CONFIG_HOME}/kcminputrc"
+ if ! [ -f "$kcminputrc" ]
+ then
+ cat ${kcminputrc} >"$kcminputrc"
+ fi
+
+ gtkrc2="$HOME/.gtkrc-2.0"
+ if ! [ -f "$gtkrc2" ]
+ then
+ cat ${gtkrc2} >"$gtkrc2"
+ fi
+
+ gtk3_settings="''${XDG_CONFIG_HOME}/gtk-3.0/settings.ini"
+ if ! [ -f "$gtk3_settings" ]
+ then
+ mkdir -p "$(dirname "$gtk3_settings")"
+ cat ${gtk3_settings} >"$gtk3_settings"
+ fi
+ fi
+
+ ''
+ + ''
+ exec "${startplasma-x11}"
+ '';
in
@@ -41,27 +172,7 @@ in
services.xserver.desktopManager.session = singleton {
name = "plasma5";
bgSupport = true;
- start = ''
- # Load PulseAudio module for routing support.
- # See http://colin.guthr.ie/2009/10/so-how-does-the-kde-pulseaudio-support-work-anyway/
- ${optionalString config.hardware.pulseaudio.enable ''
- ${getBin config.hardware.pulseaudio.package}/bin/pactl load-module module-device-manager "do_routing=1"
- ''}
-
- if [ -f "$HOME/.config/kdeglobals" ]
- then
- # Remove extraneous font style names.
- # See also: https://phabricator.kde.org/D9070
- ${getBin pkgs.gnused}/bin/sed -i "$HOME/.config/kdeglobals" \
- -e '/^fixed=/ s/,Regular$//' \
- -e '/^font=/ s/,Regular$//' \
- -e '/^menuFont=/ s/,Regular$//' \
- -e '/^smallestReadableFont=/ s/,Regular$//' \
- -e '/^toolBarFont=/ s/,Regular$//'
- fi
-
- exec "${getBin plasma5.plasma-workspace}/bin/startkde"
- '';
+ start = startplasma;
};
security.wrappers = {
@@ -137,6 +248,7 @@ in
libkscreen
libksysguard
milou
+ plasma-browser-integration
plasma-integration
polkit-kde-agent
systemsettings
@@ -226,29 +338,7 @@ in
xdg.portal.extraPortals = [ pkgs.xdg-desktop-portal-kde ];
# Update the start menu for each user that is currently logged in
- system.userActivationScripts.plasmaSetup = ''
- # The KDE icon cache is supposed to update itself
- # automatically, but it uses the timestamp on the icon
- # theme directory as a trigger. Since in Nix the
- # timestamp is always the same, this doesn't work. So as
- # a workaround, nuke the icon cache on login. This isn't
- # perfect, since it may require logging out after
- # installing new applications to update the cache.
- # See http://lists-archives.org/kde-devel/26175-what-when-will-icon-cache-refresh.html
- rm -fv $HOME/.cache/icon-cache.kcache
-
- # xdg-desktop-settings generates this empty file but
- # it makes kbuildsyscoca5 fail silently. To fix this
- # remove that menu if it exists.
- rm -fv $HOME/.config/menus/applications-merged/xdg-desktop-menu-dummy.menu
-
- # Remove the kbuildsyscoca5 cache. It will be regenerated
- # immediately after. This is necessary for kbuildsyscoca5 to
- # recognize that software that has been removed.
- rm -fv $HOME/.cache/ksycoca*
-
- ${pkgs.libsForQt5.kservice}/bin/kbuildsycoca5
- '';
+ system.userActivationScripts.plasmaSetup = activationScript;
})
];
diff --git a/nixpkgs/nixos/modules/services/x11/desktop-managers/xfce.nix b/nixpkgs/nixos/modules/services/x11/desktop-managers/xfce.nix
index 21f59074f3a..a08b1947f65 100644
--- a/nixpkgs/nixos/modules/services/x11/desktop-managers/xfce.nix
+++ b/nixpkgs/nixos/modules/services/x11/desktop-managers/xfce.nix
@@ -127,9 +127,14 @@ in
"/share/gtksourceview-4.0"
];
- services.xserver.displayManager.sessionPackages = [
- pkgs.xfce.xfce4-session
- ];
+ services.xserver.desktopManager.session = [{
+ name = "xfce";
+ bgSupport = true;
+ start = ''
+ ${pkgs.runtimeShell} ${pkgs.xfce.xfce4-session.xinitrc} &
+ waitPID=$!
+ '';
+ }];
services.xserver.updateDbusEnvironment = true;
services.xserver.gdk-pixbuf.modulePackages = [ pkgs.librsvg ];
diff --git a/nixpkgs/nixos/modules/services/x11/display-managers/default.nix b/nixpkgs/nixos/modules/services/x11/display-managers/default.nix
index 1efd0739376..5d49ca94387 100644
--- a/nixpkgs/nixos/modules/services/x11/display-managers/default.nix
+++ b/nixpkgs/nixos/modules/services/x11/display-managers/default.nix
@@ -141,9 +141,11 @@ let
'';
dmDefault = cfg.desktopManager.default;
+ # fallback default for cases when only default wm is set
+ dmFallbackDefault = if dmDefault != null then dmDefault else "none";
wmDefault = cfg.windowManager.default;
- defaultSessionFromLegacyOptions = concatStringsSep "+" (filter (s: s != null) ([ dmDefault ] ++ optional (wmDefault != "none") wmDefault));
+ defaultSessionFromLegacyOptions = dmFallbackDefault + optionalString (wmDefault != null && wmDefault != "none") "+${wmDefault}";
in
@@ -358,7 +360,7 @@ in
{ c = wmDefault; t = "- services.xserver.windowManager.default"; }
]))}
Please use
- services.xserver.displayManager.defaultSession = "${concatStringsSep "+" (filter (s: s != null) [ dmDefault wmDefault ])}";
+ services.xserver.displayManager.defaultSession = "${defaultSessionFromLegacyOptions}";
instead.
''
];
@@ -425,6 +427,7 @@ in
TryExec=${script}
Exec=${script}
Name=${sessionName}
+ DesktopNames=${sessionName}
'';
} // {
providedSessions = [ sessionName ];
diff --git a/nixpkgs/nixos/modules/services/x11/display-managers/gdm.nix b/nixpkgs/nixos/modules/services/x11/display-managers/gdm.nix
index 325023f4121..e0ac47bb766 100644
--- a/nixpkgs/nixos/modules/services/x11/display-managers/gdm.nix
+++ b/nixpkgs/nixos/modules/services/x11/display-managers/gdm.nix
@@ -166,9 +166,10 @@ in
};
systemd.tmpfiles.rules = [
- "d /run/gdm/.config 0711 gdm gdm -"
+ "d /run/gdm/.config 0711 gdm gdm"
] ++ optionals config.hardware.pulseaudio.enable [
- "L+ /run/gdm/.config/pulse - - - - ${pulseConfig}"
+ "d /run/gdm/.config/pulse 0711 gdm gdm"
+ "L+ /run/gdm/.config/pulse/${pulseConfig.name} - - - - ${pulseConfig}"
] ++ optionals config.services.gnome3.gnome-initial-setup.enable [
# Create stamp file for gnome-initial-setup to prevent it starting in GDM.
"f /run/gdm/.config/gnome-initial-setup-done 0711 gdm gdm - yes"
diff --git a/nixpkgs/nixos/modules/services/x11/display-managers/lightdm-greeters/tiny.nix b/nixpkgs/nixos/modules/services/x11/display-managers/lightdm-greeters/tiny.nix
new file mode 100644
index 00000000000..a9ba8e6280d
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/x11/display-managers/lightdm-greeters/tiny.nix
@@ -0,0 +1,92 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+ dmcfg = config.services.xserver.displayManager;
+ ldmcfg = dmcfg.lightdm;
+ cfg = ldmcfg.greeters.tiny;
+
+in
+{
+ options = {
+
+ services.xserver.displayManager.lightdm.greeters.tiny = {
+
+ enable = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Whether to enable lightdm-tiny-greeter as the lightdm greeter.
+
+ Note that this greeter starts only the default X session.
+ You can configure the default X session using
+ <xref linkend="opt-services.xserver.displayManager.defaultSession"/>.
+ '';
+ };
+
+ label = {
+ user = mkOption {
+ type = types.str;
+ default = "Username";
+ description = ''
+ The string to represent the user_text label.
+ '';
+ };
+
+ pass = mkOption {
+ type = types.str;
+ default = "Password";
+ description = ''
+ The string to represent the pass_text label.
+ '';
+ };
+ };
+
+
+ extraConfig = mkOption {
+ type = types.lines;
+ default = "";
+ description = ''
+ Section to describe style and ui.
+ '';
+ };
+
+ };
+
+ };
+
+ config = mkIf (ldmcfg.enable && cfg.enable) {
+
+ services.xserver.displayManager.lightdm.greeters.gtk.enable = false;
+
+ nixpkgs.config.lightdm-tiny-greeter.conf =
+ let
+ configHeader = ''
+ #include <gtk/gtk.h>
+ static const char *user_text = "${cfg.label.user}";
+ static const char *pass_text = "${cfg.label.pass}";
+ static const char *session = "${dmcfg.defaultSession}";
+ '';
+ in
+ optionalString (cfg.extraConfig != "")
+ (configHeader + cfg.extraConfig);
+
+ services.xserver.displayManager.lightdm.greeter =
+ mkDefault {
+ package = pkgs.lightdm-tiny-greeter.xgreeters;
+ name = "lightdm-tiny-greeter";
+ };
+
+ assertions = [
+ {
+ assertion = dmcfg.defaultSession != null;
+ message = ''
+ Please set: services.xserver.displayManager.defaultSession
+ '';
+ }
+ ];
+
+ };
+}
diff --git a/nixpkgs/nixos/modules/services/x11/display-managers/lightdm.nix b/nixpkgs/nixos/modules/services/x11/display-managers/lightdm.nix
index f7face0adb7..cb7b5f95958 100644
--- a/nixpkgs/nixos/modules/services/x11/display-managers/lightdm.nix
+++ b/nixpkgs/nixos/modules/services/x11/display-managers/lightdm.nix
@@ -77,6 +77,7 @@ in
./lightdm-greeters/mini.nix
./lightdm-greeters/enso-os.nix
./lightdm-greeters/pantheon.nix
+ ./lightdm-greeters/tiny.nix
];
options = {
diff --git a/nixpkgs/nixos/modules/services/x11/unclutter.nix b/nixpkgs/nixos/modules/services/x11/unclutter.nix
index c0868604a68..56e30c79d1f 100644
--- a/nixpkgs/nixos/modules/services/x11/unclutter.nix
+++ b/nixpkgs/nixos/modules/services/x11/unclutter.nix
@@ -61,7 +61,7 @@ in {
serviceConfig.ExecStart = ''
${cfg.package}/bin/unclutter \
-idle ${toString cfg.timeout} \
- -jitter ${toString (cfg.threeshold - 1)} \
+ -jitter ${toString (cfg.threshold - 1)} \
${optionalString cfg.keystroke "-keystroke"} \
${concatMapStrings (x: " -"+x) cfg.extraOptions} \
-not ${concatStringsSep " " cfg.excluded} \
diff --git a/nixpkgs/nixos/modules/services/x11/urxvtd.nix b/nixpkgs/nixos/modules/services/x11/urxvtd.nix
index 9bfcfa9b065..867ac38a944 100644
--- a/nixpkgs/nixos/modules/services/x11/urxvtd.nix
+++ b/nixpkgs/nixos/modules/services/x11/urxvtd.nix
@@ -18,10 +18,10 @@ in {
};
package = mkOption {
- default = pkgs.rxvt_unicode-with-plugins;
- defaultText = "pkgs.rxvt_unicode-with-plugins";
+ default = pkgs.rxvt-unicode;
+ defaultText = "pkgs.rxvt-unicode";
description = ''
- Package to install. Usually pkgs.rxvt_unicode-with-plugins or pkgs.rxvt_unicode
+ Package to install. Usually pkgs.rxvt-unicode.
'';
type = types.package;
};
diff --git a/nixpkgs/nixos/modules/services/x11/xserver.nix b/nixpkgs/nixos/modules/services/x11/xserver.nix
index 7f0de96d208..74d702ea1c3 100644
--- a/nixpkgs/nixos/modules/services/x11/xserver.nix
+++ b/nixpkgs/nixos/modules/services/x11/xserver.nix
@@ -573,7 +573,7 @@ in
then { modules = [xorg.${"xf86video" + name}]; }
else null)
knownVideoDrivers;
- in optional (driver != null) ({ inherit name; modules = []; driverName = name; } // driver));
+ in optional (driver != null) ({ inherit name; modules = []; driverName = name; display = true; } // driver));
assertions = [
{ assertion = config.security.polkit.enable;
@@ -740,7 +740,7 @@ in
${cfg.serverLayoutSection}
# Reference the Screen sections for each driver. This will
# cause the X server to try each in turn.
- ${flip concatMapStrings cfg.drivers (d: ''
+ ${flip concatMapStrings (filter (d: d.display) cfg.drivers) (d: ''
Screen "Screen-${d.name}[0]"
'')}
EndSection
@@ -764,42 +764,44 @@ in
${driver.deviceSection or ""}
${xrandrDeviceSection}
EndSection
+ ${optionalString driver.display ''
+
+ Section "Screen"
+ Identifier "Screen-${driver.name}[0]"
+ Device "Device-${driver.name}[0]"
+ ${optionalString (cfg.monitorSection != "") ''
+ Monitor "Monitor[0]"
+ ''}
+
+ ${cfg.screenSection}
+ ${driver.screenSection or ""}
+
+ ${optionalString (cfg.defaultDepth != 0) ''
+ DefaultDepth ${toString cfg.defaultDepth}
+ ''}
+
+ ${optionalString
+ (driver.name != "virtualbox" &&
+ (cfg.resolutions != [] ||
+ cfg.extraDisplaySettings != "" ||
+ cfg.virtualScreen != null))
+ (let
+ f = depth:
+ ''
+ SubSection "Display"
+ Depth ${toString depth}
+ ${optionalString (cfg.resolutions != [])
+ "Modes ${concatMapStrings (res: ''"${toString res.x}x${toString res.y}"'') cfg.resolutions}"}
+ ${cfg.extraDisplaySettings}
+ ${optionalString (cfg.virtualScreen != null)
+ "Virtual ${toString cfg.virtualScreen.x} ${toString cfg.virtualScreen.y}"}
+ EndSubSection
+ '';
+ in concatMapStrings f [8 16 24]
+ )}
- Section "Screen"
- Identifier "Screen-${driver.name}[0]"
- Device "Device-${driver.name}[0]"
- ${optionalString (cfg.monitorSection != "") ''
- Monitor "Monitor[0]"
- ''}
-
- ${cfg.screenSection}
- ${driver.screenSection or ""}
-
- ${optionalString (cfg.defaultDepth != 0) ''
- DefaultDepth ${toString cfg.defaultDepth}
- ''}
-
- ${optionalString
- (driver.name != "virtualbox" &&
- (cfg.resolutions != [] ||
- cfg.extraDisplaySettings != "" ||
- cfg.virtualScreen != null))
- (let
- f = depth:
- ''
- SubSection "Display"
- Depth ${toString depth}
- ${optionalString (cfg.resolutions != [])
- "Modes ${concatMapStrings (res: ''"${toString res.x}x${toString res.y}"'') cfg.resolutions}"}
- ${cfg.extraDisplaySettings}
- ${optionalString (cfg.virtualScreen != null)
- "Virtual ${toString cfg.virtualScreen.x} ${toString cfg.virtualScreen.y}"}
- EndSubSection
- '';
- in concatMapStrings f [8 16 24]
- )}
-
- EndSection
+ EndSection
+ ''}
'')}
${xrandrMonitorSections}