summary refs log tree commit diff
path: root/nixos/modules/services
diff options
context:
space:
mode:
authorVladimír Čunát <vcunat@gmail.com>2016-04-01 10:06:01 +0200
committerVladimír Čunát <vcunat@gmail.com>2016-04-01 10:06:01 +0200
commitab15a62c68bf7bf3b02e3bab00d121cc1426733c (patch)
tree398a82403b04bfa0bae8cadf1c5a64cf83145965 /nixos/modules/services
parentc643ccaa8c91f78b8c89eb87589886b8906d5b38 (diff)
parenta26357eefe017964448b5bb464163646b927a267 (diff)
downloadnixpkgs-ab15a62c68bf7bf3b02e3bab00d121cc1426733c.tar
nixpkgs-ab15a62c68bf7bf3b02e3bab00d121cc1426733c.tar.gz
nixpkgs-ab15a62c68bf7bf3b02e3bab00d121cc1426733c.tar.bz2
nixpkgs-ab15a62c68bf7bf3b02e3bab00d121cc1426733c.tar.lz
nixpkgs-ab15a62c68bf7bf3b02e3bab00d121cc1426733c.tar.xz
nixpkgs-ab15a62c68bf7bf3b02e3bab00d121cc1426733c.tar.zst
nixpkgs-ab15a62c68bf7bf3b02e3bab00d121cc1426733c.zip
Merge branch 'master' into closure-size
Beware that stdenv doesn't build. It seems something more will be needed
than just resolution of merge conflicts.
Diffstat (limited to 'nixos/modules/services')
-rw-r--r--nixos/modules/services/backup/crashplan.nix8
-rw-r--r--nixos/modules/services/backup/tarsnap.nix2
-rw-r--r--nixos/modules/services/backup/znapzend.nix36
-rw-r--r--nixos/modules/services/logging/awstats.nix123
-rw-r--r--nixos/modules/services/mail/dovecot.nix4
-rw-r--r--nixos/modules/services/mail/dspam.nix3
-rw-r--r--nixos/modules/services/mail/mail.nix4
-rw-r--r--nixos/modules/services/mail/postfix.nix2
-rw-r--r--nixos/modules/services/misc/autofs.nix5
-rw-r--r--nixos/modules/services/misc/etcd.nix1
-rw-r--r--nixos/modules/services/misc/gitlab.nix8
-rw-r--r--nixos/modules/services/misc/mantisbt.nix68
-rw-r--r--nixos/modules/services/misc/nix-daemon.nix16
-rw-r--r--nixos/modules/services/misc/octoprint.nix15
-rw-r--r--nixos/modules/services/monitoring/graphite.nix29
-rw-r--r--nixos/modules/services/networking/dnscrypt-proxy.nix98
-rw-r--r--nixos/modules/services/networking/firewall.nix2
-rw-r--r--nixos/modules/services/networking/i2pd.nix10
-rw-r--r--nixos/modules/services/networking/iodined.nix3
-rw-r--r--nixos/modules/services/networking/mjpg-streamer.nix75
-rw-r--r--nixos/modules/services/networking/radicale.nix15
-rw-r--r--nixos/modules/services/networking/vsftpd.nix9
-rw-r--r--nixos/modules/services/networking/wpa_supplicant.nix2
-rw-r--r--nixos/modules/services/printing/cupsd.nix7
-rw-r--r--nixos/modules/services/system/kerberos.nix4
-rw-r--r--nixos/modules/services/torrent/transmission.nix1
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/foswiki.nix78
-rw-r--r--nixos/modules/services/web-servers/uwsgi.nix50
-rw-r--r--nixos/modules/services/x11/colord.nix39
-rw-r--r--nixos/modules/services/x11/desktop-managers/default.nix2
-rw-r--r--nixos/modules/services/x11/desktop-managers/enlightenment.nix (renamed from nixos/modules/services/x11/desktop-managers/e19.nix)27
-rw-r--r--nixos/modules/services/x11/desktop-managers/kde5.nix1
-rw-r--r--nixos/modules/services/x11/display-managers/default.nix11
-rw-r--r--nixos/modules/services/x11/window-managers/default.nix2
-rw-r--r--nixos/modules/services/x11/window-managers/jwm.nix25
-rw-r--r--nixos/modules/services/x11/xserver.nix28
36 files changed, 660 insertions, 153 deletions
diff --git a/nixos/modules/services/backup/crashplan.nix b/nixos/modules/services/backup/crashplan.nix
index 74643d1d463..46d4c5192d9 100644
--- a/nixos/modules/services/backup/crashplan.nix
+++ b/nixos/modules/services/backup/crashplan.nix
@@ -48,6 +48,14 @@ with lib;
         ensureDir ${crashplan.vardir}/cache 700
         ensureDir ${crashplan.vardir}/backupArchives 700
         ensureDir ${crashplan.vardir}/log 777
+        cp -avn ${crashplan}/conf.template/* ${crashplan.vardir}/conf
+        for x in app.asar bin EULA.txt install.vars lang lib libjniwrap64.so libjniwrap.so libjtux64.so libjtux.so libmd564.so libmd5.so share skin upgrade; do
+          if [ -e $x ]; then
+            true;
+          else
+            ln -s ${crashplan}/$x ${crashplan.vardir}/$x;
+          fi;
+        done
       '';
 
       serviceConfig = {
diff --git a/nixos/modules/services/backup/tarsnap.nix b/nixos/modules/services/backup/tarsnap.nix
index 78776786468..24892a2a59a 100644
--- a/nixos/modules/services/backup/tarsnap.nix
+++ b/nixos/modules/services/backup/tarsnap.nix
@@ -293,7 +293,7 @@ in
       # make sure that the tarsnap server is reachable after systemd starts up
       # the service - therefore we sleep in a loop until we can ping the
       # endpoint.
-      preStart = "while ! ping -q -c 1 betatest-server.tarsnap.com &> /dev/null; do sleep 3; done";
+      preStart = "while ! ping -q -c 1 v1-0-0-server.tarsnap.com &> /dev/null; do sleep 3; done";
       scriptArgs = "%i";
       script = ''
         mkdir -p -m 0755 ${dirOf cfg.cachedir}
diff --git a/nixos/modules/services/backup/znapzend.nix b/nixos/modules/services/backup/znapzend.nix
new file mode 100644
index 00000000000..648089f90b7
--- /dev/null
+++ b/nixos/modules/services/backup/znapzend.nix
@@ -0,0 +1,36 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.znapzend;
+in
+{
+  options = {
+    services.znapzend = {
+      enable = mkEnableOption "ZnapZend daemon";
+    };
+  };
+
+  config = mkIf cfg.enable {
+    environment.systemPackages = [ pkgs.znapzend ];
+
+    systemd.services = {
+      "znapzend" = {
+        description = "ZnapZend - ZFS Backup System";
+        after       = [ "zfs.target" ];
+
+        path = with pkgs; [ znapzend zfs mbuffer openssh ];
+
+        script = ''
+          znapzend
+        '';
+
+        reload = ''
+          /bin/kill -HUP $MAINPID
+        '';
+      };
+    };
+
+  };
+}
diff --git a/nixos/modules/services/logging/awstats.nix b/nixos/modules/services/logging/awstats.nix
new file mode 100644
index 00000000000..8ab7e6acd98
--- /dev/null
+++ b/nixos/modules/services/logging/awstats.nix
@@ -0,0 +1,123 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.awstats;
+  package = pkgs.awstats;
+in
+
+{
+  options.services.awstats = {
+    enable = mkOption {
+      type = types.bool;
+      default = cfg.service.enable;
+      description = ''
+        Enable the awstats program (but not service).
+        Currently only simple httpd (Apache) configs are supported,
+        and awstats plugins may not work correctly.
+      '';
+    };
+    vardir = mkOption {
+      type = types.path;
+      default = "/var/lib/awstats";
+      description = "The directory where variable awstats data will be stored.";
+    };
+
+    extraConfig = mkOption {
+      type = types.lines;
+      default = "";
+      description = "Extra configuration to be appendend to awstats.conf.";
+    };
+
+    updateAt = mkOption {
+      type = types.nullOr types.string;
+      default = null;
+      example = "hourly";
+      description = ''
+        Specification of the time at which awstats will get updated.
+        (in the format described by <citerefentry>
+          <refentrytitle>systemd.time</refentrytitle>
+          <manvolnum>5</manvolnum></citerefentry>)
+      '';
+    };
+
+    service = {
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''Enable the awstats web service. This switches on httpd.'';
+      };
+      urlPrefix = mkOption {
+        type = types.string;
+        default = "/awstats";
+        description = "The URL prefix under which the awstats service appears.";
+      };
+    };
+  };
+
+
+  config = mkIf cfg.enable {
+    environment.systemPackages = [ package.bin ];
+    /* TODO:
+      - heed config.services.httpd.logPerVirtualHost, etc.
+      - Can't AllowToUpdateStatsFromBrowser, as CGI scripts don't have permission
+        to read the logs, and our httpd config apparently doesn't an option for that.
+    */
+    environment.etc."awstats/awstats.conf".source = pkgs.runCommand "awstats.conf"
+      { preferLocalBuild = true; }
+      ( let
+          cfg-httpd = config.services.httpd;
+          logFormat =
+            if cfg-httpd.logFormat == "combined" then "1" else
+            if cfg-httpd.logFormat == "common" then "4" else
+            throw "awstats service doesn't support Apache log format `${cfg-httpd.logFormat}`";
+        in
+        ''
+          sed \
+            -e 's|^\(DirData\)=.*$|\1="${cfg.vardir}"|' \
+            -e 's|^\(DirIcons\)=.*$|\1="icons"|' \
+            -e 's|^\(CreateDirDataIfNotExists\)=.*$|\1=1|' \
+            -e 's|^\(SiteDomain\)=.*$|\1="${cfg-httpd.hostName}"|' \
+            -e 's|^\(LogFile\)=.*$|\1="${cfg-httpd.logDir}/access_log"|' \
+            -e 's|^\(LogFormat\)=.*$|\1=${logFormat}|' \
+            < '${package.out}/wwwroot/cgi-bin/awstats.model.conf' > "$out"
+          echo '${cfg.extraConfig}' >> "$out"
+        '');
+
+    # The httpd sub-service showing awstats.
+    services.httpd.enable = mkIf cfg.service.enable true;
+    services.httpd.extraSubservices = mkIf cfg.service.enable [ { function = { serverInfo, ... }: {
+      extraConfig =
+        ''
+          Alias ${cfg.service.urlPrefix}/classes "${package.out}/wwwroot/classes/"
+          Alias ${cfg.service.urlPrefix}/css "${package.out}/wwwroot/css/"
+          Alias ${cfg.service.urlPrefix}/icons "${package.out}/wwwroot/icon/"
+          ScriptAlias ${cfg.service.urlPrefix}/ "${package.out}/wwwroot/cgi-bin/"
+
+          <Directory "${package.out}/wwwroot">
+            Options None
+            AllowOverride None
+            Order allow,deny
+            Allow from all
+          </Directory>
+        '';
+      startupScript =
+        let
+          inherit (serverInfo.serverConfig) user group;
+        in pkgs.writeScript "awstats_startup.sh"
+          ''
+            mkdir -p '${cfg.vardir}'
+            chown '${user}:${group}' '${cfg.vardir}'
+          '';
+    };}];
+
+    systemd.services.awstats-update = mkIf (cfg.updateAt != null) {
+      description = "awstats log collector";
+      script = "exec '${package.bin}/bin/awstats' -update -config=awstats.conf";
+      startAt = cfg.updateAt;
+    };
+  };
+
+}
+
diff --git a/nixos/modules/services/mail/dovecot.nix b/nixos/modules/services/mail/dovecot.nix
index 3935c14dc8c..127c3da69d1 100644
--- a/nixos/modules/services/mail/dovecot.nix
+++ b/nixos/modules/services/mail/dovecot.nix
@@ -98,8 +98,8 @@ in
 
     package = mkOption {
       type = types.package;
-      default = pkgs.dovecot22;
-      defaultText = "pkgs.dovecot22";
+      default = pkgs.dovecot;
+      defaultText = "pkgs.dovecot";
       description = "Dovecot package to use.";
     };
 
diff --git a/nixos/modules/services/mail/dspam.nix b/nixos/modules/services/mail/dspam.nix
index 46e6f216b21..89076ff0546 100644
--- a/nixos/modules/services/mail/dspam.nix
+++ b/nixos/modules/services/mail/dspam.nix
@@ -104,6 +104,7 @@ in {
       systemd.services.dspam = {
         description = "dspam spam filtering daemon";
         wantedBy = [ "multi-user.target" ];
+        after = [ "postgresql.service" ];
         restartTriggers = [ cfgfile ];
 
         serviceConfig = {
@@ -114,7 +115,7 @@ in {
           RuntimeDirectoryMode = optional (cfg.domainSocket == defaultSock) "0750";
           PermissionsStartOnly = true;
           # DSPAM segfaults on just about every error
-          Restart = "on-failure";
+          Restart = "on-abort";
           RestartSec = "1s";
         };
 
diff --git a/nixos/modules/services/mail/mail.nix b/nixos/modules/services/mail/mail.nix
index b7e1d295f2c..63e8d78b5b0 100644
--- a/nixos/modules/services/mail/mail.nix
+++ b/nixos/modules/services/mail/mail.nix
@@ -12,9 +12,9 @@ with lib;
 
       sendmailSetuidWrapper = mkOption {
         default = null;
+        internal = true;
         description = ''
-          Configuration for the sendmail setuid wrwapper (like an element of
-          security.setuidOwners)";
+          Configuration for the sendmail setuid wapper.
         '';
       };
 
diff --git a/nixos/modules/services/mail/postfix.nix b/nixos/modules/services/mail/postfix.nix
index 404cdf0f564..bad9d527f9a 100644
--- a/nixos/modules/services/mail/postfix.nix
+++ b/nixos/modules/services/mail/postfix.nix
@@ -27,7 +27,7 @@ let
 
   mainCf =
     ''
-      compatibility_level = 2
+      compatibility_level = 9999
 
       mail_owner = ${user}
       default_privs = nobody
diff --git a/nixos/modules/services/misc/autofs.nix b/nixos/modules/services/misc/autofs.nix
index 3a95e922820..8913030e0ea 100644
--- a/nixos/modules/services/misc/autofs.nix
+++ b/nixos/modules/services/misc/autofs.nix
@@ -79,6 +79,11 @@ in
         wantedBy = [ "multi-user.target" ];
         after = [ "network.target" ];
 
+        preStart = ''
+          # There should be only one autofs service managed by systemd, so this should be safe.
+          rm -f /tmp/autofs-running
+        '';
+
         serviceConfig = {
           ExecStart = "${pkgs.autofs5}/sbin/automount ${if cfg.debug then "-d" else ""} -f -t ${builtins.toString cfg.timeout} ${autoMaster} ${if cfg.debug then "-l7" else ""}";
           ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
diff --git a/nixos/modules/services/misc/etcd.nix b/nixos/modules/services/misc/etcd.nix
index b3354e33096..bc8064e3c87 100644
--- a/nixos/modules/services/misc/etcd.nix
+++ b/nixos/modules/services/misc/etcd.nix
@@ -114,6 +114,7 @@ in {
       }) // (mapAttrs' (n: v: nameValuePair "ETCD_${n}" v) cfg.extraConf);
 
       serviceConfig = {
+        Type = "notify";
         ExecStart = "${pkgs.etcd}/bin/etcd";
         User = "etcd";
         PermissionsStartOnly = true;
diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix
index cc50bfbea53..267442bd1f8 100644
--- a/nixos/modules/services/misc/gitlab.nix
+++ b/nixos/modules/services/misc/gitlab.nix
@@ -206,12 +206,6 @@ in {
         description = "Gitlab database user.";
       };
 
-      emailFrom = mkOption {
-        type = types.str;
-        default = "example@example.org";
-        description = "The source address for emails sent by gitlab.";
-      };
-
       host = mkOption {
         type = types.str;
         default = config.networking.hostName;
@@ -328,7 +322,7 @@ in {
         Group = cfg.group;
         TimeoutSec = "300";
         WorkingDirectory = "${cfg.packages.gitlab}/share/gitlab";
-        ExecStart="${bundler}/bin/bundle exec \"sidekiq -q post_receive -q mailer -q system_hook -q project_web_hook -q gitlab_shell -q common -q default -e production -P ${cfg.statePath}/tmp/sidekiq.pid\"";
+        ExecStart="${bundler}/bin/bundle exec \"sidekiq -q post_receive -q mailers -q system_hook -q project_web_hook -q gitlab_shell -q common -q default -e production -P ${cfg.statePath}/tmp/sidekiq.pid\"";
       };
     };
 
diff --git a/nixos/modules/services/misc/mantisbt.nix b/nixos/modules/services/misc/mantisbt.nix
new file mode 100644
index 00000000000..7e3474feb67
--- /dev/null
+++ b/nixos/modules/services/misc/mantisbt.nix
@@ -0,0 +1,68 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+let
+  cfg = config.services.mantisbt;
+
+  freshInstall = cfg.extraConfig == "";
+
+  # combined code+config directory
+  mantisbt = let
+    config_inc = pkgs.writeText "config_inc.php" ("<?php\n" + cfg.extraConfig);
+    src = pkgs.fetchurl {
+      url = "mirror://sourceforge/mantisbt/${name}.tar.gz";
+      sha256 = "1pl6xn793p3mxc6ibpr2bhg85vkdlcf57yk7pfc399g47l8x4508";
+    };
+    name = "mantisbt-1.2.19";
+    in
+      # We have to copy every time; otherwise config won't be found.
+      pkgs.runCommand name
+        { preferLocalBuild = true; allowSubstitutes = false; }
+        (''
+          mkdir -p "$out"
+          cd "$out"
+          tar -xf '${src}' --strip-components=1
+          ln -s '${config_inc}' config_inc.php
+        ''
+        + lib.optionalString (!freshInstall) "rm -r admin/"
+        );
+in
+{
+  options.services.mantisbt = {
+    enable = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Enable the mantisbt web service.
+        This switches on httpd with PHP and database.
+      '';
+    };
+    urlPrefix = mkOption {
+      type = types.string;
+      default = "/mantisbt";
+      description = "The URL prefix under which the mantisbt service appears.";
+    };
+    extraConfig = mkOption {
+      type = types.lines;
+      default = "";
+      description = ''
+        The contents of config_inc.php, without leading &lt;?php.
+        If left empty, the admin directory will be accessible.
+      '';
+    };
+  };
+
+
+  config = mkIf cfg.enable {
+    services.mysql.enable = true;
+    services.httpd.enable = true;
+    services.httpd.enablePHP = true;
+    # The httpd sub-service showing mantisbt.
+    services.httpd.extraSubservices = [ { function = { ... }: {
+      extraConfig =
+        ''
+          Alias ${cfg.urlPrefix} "${mantisbt}"
+        '';
+    };}];
+  };
+}
diff --git a/nixos/modules/services/misc/nix-daemon.nix b/nixos/modules/services/misc/nix-daemon.nix
index b0e4bf106d3..911f79e5756 100644
--- a/nixos/modules/services/misc/nix-daemon.nix
+++ b/nixos/modules/services/misc/nix-daemon.nix
@@ -39,7 +39,7 @@ let
         build-users-group = nixbld
         build-max-jobs = ${toString (cfg.maxJobs)}
         build-cores = ${toString (cfg.buildCores)}
-        build-use-chroot = ${if cfg.useChroot then "true" else "false"}
+        build-use-chroot = ${if (builtins.isBool cfg.useChroot) then (if cfg.useChroot then "true" else "false") else cfg.useChroot}
         build-chroot-dirs = ${toString cfg.chrootDirs} /bin/sh=${sh} $(echo $extraPaths)
         binary-caches = ${toString cfg.binaryCaches}
         trusted-binary-caches = ${toString cfg.trustedBinaryCaches}
@@ -99,7 +99,7 @@ in
       };
 
       useChroot = mkOption {
-        type = types.bool;
+        type = types.either types.bool (types.enum ["relaxed"]);
         default = false;
         description = "
           If set, Nix will perform builds in a chroot-environment that it
@@ -257,13 +257,11 @@ in
         type = types.bool;
         default = true;
         description = ''
-          If enabled, Nix will only download binaries from binary
-          caches if they are cryptographically signed with any of the
-          keys listed in
-          <option>nix.binaryCachePublicKeys</option>. If disabled (the
-          default), signatures are neither required nor checked, so
-          it's strongly recommended that you use only trustworthy
-          caches and https to prevent man-in-the-middle attacks.
+          If enabled (the default), Nix will only download binaries from binary caches if
+          they are cryptographically signed with any of the keys listed in
+          <option>nix.binaryCachePublicKeys</option>. If disabled, signatures are neither
+          required nor checked, so it's strongly recommended that you use only
+          trustworthy caches and https to prevent man-in-the-middle attacks.
         '';
       };
 
diff --git a/nixos/modules/services/misc/octoprint.nix b/nixos/modules/services/misc/octoprint.nix
index 9cf46345c22..8ab2a9307a7 100644
--- a/nixos/modules/services/misc/octoprint.nix
+++ b/nixos/modules/services/misc/octoprint.nix
@@ -6,12 +6,16 @@ let
 
   cfg = config.services.octoprint;
 
-  cfgUpdate = pkgs.writeText "octoprint-config.yaml" (builtins.toJSON {
+  baseConfig = {
     plugins.cura.cura_engine = "${pkgs.curaengine}/bin/CuraEngine";
     server.host = cfg.host;
     server.port = cfg.port;
     webcam.ffmpeg = "${pkgs.ffmpeg}/bin/ffmpeg";
-  });
+  };
+
+  fullConfig = recursiveUpdate cfg.extraConfig baseConfig;
+
+  cfgUpdate = pkgs.writeText "octoprint-config.yaml" (builtins.toJSON fullConfig);
 
   pluginsEnv = pkgs.python.buildEnv.override {
     extraLibs = cfg.plugins pkgs.octoprint-plugins;
@@ -62,13 +66,18 @@ in
       };
 
       plugins = mkOption {
-        #type = types.functionTo (types.listOf types.package);
         default = plugins: [];
         defaultText = "plugins: []";
         example = literalExample "plugins: [ m3d-fio ]";
         description = "Additional plugins.";
       };
 
+      extraConfig = mkOption {
+        type = types.attrs;
+        default = {};
+        description = "Extra options which are added to OctoPrint's YAML configuration file.";
+      };
+
     };
 
   };
diff --git a/nixos/modules/services/monitoring/graphite.nix b/nixos/modules/services/monitoring/graphite.nix
index e59be1ea6c3..e50728aff8f 100644
--- a/nixos/modules/services/monitoring/graphite.nix
+++ b/nixos/modules/services/monitoring/graphite.nix
@@ -51,7 +51,13 @@ let
   '';
 
   carbonEnv = {
-    PYTHONPATH = "${pkgs.python27Packages.carbon}/lib/python2.7/site-packages";
+    PYTHONPATH = let
+      cenv = pkgs.python.buildEnv.override {
+        extraLibs = [ pkgs.python27Packages.carbon ];
+      };
+      cenvPack =  "${cenv}/${pkgs.python.sitePackages}";
+    # opt/graphite/lib contains twisted.plugins.carbon-cache
+    in "${cenvPack}/opt/graphite/lib:${cenvPack}";
     GRAPHITE_ROOT = dataDir;
     GRAPHITE_CONF_DIR = configDir;
     GRAPHITE_STORAGE_DIR = dataDir;
@@ -445,10 +451,21 @@ in {
         after = [ "network-interfaces.target" ];
         path = [ pkgs.perl ];
         environment = {
-          PYTHONPATH = "${pkgs.python27Packages.graphite_web}/lib/python2.7/site-packages";
+          PYTHONPATH = let
+              penv = pkgs.python.buildEnv.override {
+                extraLibs = [
+                  pkgs.python27Packages.graphite_web
+                  pkgs.python27Packages.pysqlite
+                ];
+              };
+              penvPack = "${penv}/${pkgs.python.sitePackages}";
+              # opt/graphite/webapp contains graphite/settings.py
+              # explicitly adding pycairo in path because it cannot be imported via buildEnv
+            in "${penvPack}/opt/graphite/webapp:${penvPack}:${pkgs.pycairo}/${pkgs.python.sitePackages}";
           DJANGO_SETTINGS_MODULE = "graphite.settings";
           GRAPHITE_CONF_DIR = configDir;
           GRAPHITE_STORAGE_DIR = dataDir;
+          LD_LIBRARY_PATH = "${pkgs.cairo}/lib";
         };
         serviceConfig = {
           ExecStart = ''
@@ -486,9 +503,11 @@ in {
         wantedBy = [ "multi-user.target" ];
         after = [ "network-interfaces.target" ];
         environment = {
-          PYTHONPATH =
-            "${cfg.api.package}/lib/python2.7/site-packages:" +
-            concatMapStringsSep ":" (f: f + "/lib/python2.7/site-packages") cfg.api.finders;
+          PYTHONPATH = let
+              aenv = pkgs.python.buildEnv.override {
+                extraLibs = [ cfg.api.package pkgs.cairo ] ++ cfg.api.finders;
+              };
+            in "${aenv}/${pkgs.python.sitePackages}";
           GRAPHITE_API_CONFIG = graphiteApiConfig;
           LD_LIBRARY_PATH = "${pkgs.cairo.out}/lib";
         };
diff --git a/nixos/modules/services/networking/dnscrypt-proxy.nix b/nixos/modules/services/networking/dnscrypt-proxy.nix
index 016b6a12cd6..61305f5a755 100644
--- a/nixos/modules/services/networking/dnscrypt-proxy.nix
+++ b/nixos/modules/services/networking/dnscrypt-proxy.nix
@@ -5,13 +5,17 @@ let
   apparmorEnabled = config.security.apparmor.enable;
   dnscrypt-proxy = pkgs.dnscrypt-proxy;
   cfg = config.services.dnscrypt-proxy;
+
   resolverListFile = "${dnscrypt-proxy}/share/dnscrypt-proxy/dnscrypt-resolvers.csv";
   localAddress = "${cfg.localAddress}:${toString cfg.localPort}";
+
   daemonArgs =
     [ "--local-address=${localAddress}"
       (optionalString cfg.tcpOnly "--tcp-only")
+      (optionalString cfg.ephemeralKeys "-E")
     ]
     ++ resolverArgs;
+
   resolverArgs = if (cfg.customResolver != null)
     then
       [ "--resolver-address=${cfg.customResolver.address}:${toString cfg.customResolver.port}"
@@ -27,43 +31,63 @@ in
 {
   options = {
     services.dnscrypt-proxy = {
-      enable = mkEnableOption ''
-        Enable dnscrypt-proxy. The proxy relays regular DNS queries to a
-        DNSCrypt enabled upstream resolver. The traffic between the
-        client and the upstream resolver is encrypted and authenticated,
-        which may mitigate the risk of MITM attacks and third-party
+      enable = mkEnableOption "dnscrypt-proxy" // { description = ''
+        Whether to enable the DNSCrypt client proxy. The 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 and third-party
         snooping (assuming the upstream is trustworthy).
-      '';
+
+        Enabling this option does not alter the system nameserver; to relay
+        local queries, prepend <literal>127.0.0.1</literal> to
+        <option>networking.nameservers</option>.
+
+        The recommended configuration is to run DNSCrypt proxy as a forwarder
+        for a caching DNS client, as in
+        <programlisting>
+        {
+          services.dnscrypt-proxy.enable = true;
+          services.dnscrypt-proxy.localPort = 43;
+          services.dnsmasq.enable = true;
+          services.dnsmasq.servers = [ "127.0.0.1#43" ];
+          services.dnsmasq.resolveLocalQueries = true; # this is the default
+        }
+        </programlisting>
+      ''; };
       localAddress = mkOption {
         default = "127.0.0.1";
         type = types.string;
         description = ''
-          Listen for DNS queries on this address.
+          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 on this port.
+          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 = "opendns";
+        default = "dnscrypt.eu-nl";
         type = types.nullOr types.string;
         description = ''
           The name of the upstream DNSCrypt resolver to use. See
-          <literal>${resolverListFile}</literal> for alternative resolvers
-          (e.g., if you are concerned about logging and/or server
-          location).
+          <filename>${resolverListFile}</filename> for alternative resolvers.
+          The default resolver is located in Holland, supports DNS security
+          extensions, and claims to not keep logs.
         '';
       };
       customResolver = mkOption {
         default = null;
         description = ''
-          Use a resolver not listed in the upstream list (e.g.,
-          a private DNSCrypt provider). For advanced users only.
-          If specified, this option takes precedence.
+          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 {
@@ -80,20 +104,31 @@ in
             type = types.str;
             description = "Provider fully qualified domain name";
             example = "2.dnscrypt-cert.opendns.com";
-         };
-         key = mkOption {
-           type = types.str;
-           description = "Provider public key";
-           example = "B735:1140:206F:225D:3E2B:D822:D7FD:691E:A1C3:3CC8:D666:8D0C:BE04:BFAB:CA43:FB79";
-         }; }; }));
+          };
+          key = mkOption {
+            type = types.str;
+            description = "Provider public key";
+            example = "B735:1140:206F:225D:3E2B:D822:D7FD:691E:A1C3:3CC8:D666:8D0C:BE04:BFAB:CA43:FB79";
+          };
+        }; }));
       };
       tcpOnly = mkOption {
         default = false;
         type = types.bool;
         description = ''
-          Force sending encrypted DNS queries to the upstream resolver
-          over TCP instead of UDP (on port 443). Enabling this option may
-          help circumvent filtering, but should not be used otherwise.
+          Force sending encrypted DNS queries to the upstream resolver over
+          TCP instead of UDP (on port 443). Use only if the UDP port is blocked.
+        '';
+      };
+      ephemeralKeys = mkOption {
+        default = false;
+        type = types.bool;
+        description = ''
+          Compute a new key pair for every query.  Enabling this option
+          increases CPU usage, but makes it more difficult for the upstream
+          resolver to track your usage of their service across IP addresses.
+          The default is to re-use the public key pair for all queries, making
+          tracking trivial.
         '';
       };
     };
@@ -130,16 +165,20 @@ in
         ${pkgs.xz.out}/lib/liblzma.so.* mr,
         ${pkgs.libgcrypt.out}/lib/libgcrypt.so.* mr,
         ${pkgs.libgpgerror.out}/lib/libgpg-error.so.* mr,
+        ${pkgs.libcap}/lib/libcap.so.* mr,
+        ${pkgs.lz4}/lib/liblz4.so.* mr,
+        ${pkgs.attr}/lib/libattr.so.* mr,
 
         ${resolverListFile} r,
       }
     ''));
 
-    users.extraUsers.dnscrypt-proxy = {
-      uid = config.ids.uids.dnscrypt-proxy;
+    users.users.dnscrypt-proxy = {
       description = "dnscrypt-proxy daemon user";
+      isSystemUser = true;
+      group = "dnscrypt-proxy";
     };
-    users.extraGroups.dnscrypt-proxy.gid = config.ids.gids.dnscrypt-proxy;
+    users.groups.dnscrypt-proxy = {};
 
     systemd.sockets.dnscrypt-proxy = {
       description = "dnscrypt-proxy listening socket";
@@ -152,16 +191,21 @@ in
 
     systemd.services.dnscrypt-proxy = {
       description = "dnscrypt-proxy daemon";
+
       after = [ "network.target" ] ++ optional apparmorEnabled "apparmor.service";
       requires = [ "dnscrypt-proxy.socket "] ++ optional apparmorEnabled "apparmor.service";
+
       serviceConfig = {
         Type = "simple";
         NonBlocking = "true";
         ExecStart = "${dnscrypt-proxy}/bin/dnscrypt-proxy ${toString daemonArgs}";
+
         User = "dnscrypt-proxy";
         Group = "dnscrypt-proxy";
+
         PrivateTmp = true;
         PrivateDevices = true;
+        ProtectHome = true;
       };
     };
   };
diff --git a/nixos/modules/services/networking/firewall.nix b/nixos/modules/services/networking/firewall.nix
index e11fe072be6..9221fe15577 100644
--- a/nixos/modules/services/networking/firewall.nix
+++ b/nixos/modules/services/networking/firewall.nix
@@ -338,7 +338,7 @@ in
     };
 
     networking.firewall.allowPing = mkOption {
-      default = false;
+      default = true;
       type = types.bool;
       description =
         ''
diff --git a/nixos/modules/services/networking/i2pd.nix b/nixos/modules/services/networking/i2pd.nix
index c32b935cf94..0cbf57314c4 100644
--- a/nixos/modules/services/networking/i2pd.nix
+++ b/nixos/modules/services/networking/i2pd.nix
@@ -10,9 +10,10 @@ let
 
   extip = "EXTIP=\$(${pkgs.curl.bin}/bin/curl -sf \"http://jsonip.com\" | ${pkgs.gawk}/bin/awk -F'\"' '{print $4}')";
 
-  toOneZero = b: if b then "1" else "0";
+  toYesNo = b: if b then "yes" else "no";
 
   mkEndpointOpt = name: addr: port: {
+    enable = mkEnableOption name;
     name = mkOption {
       type = types.str;
       default = name;
@@ -63,9 +64,9 @@ let
   } // mkEndpointOpt name "127.0.0.1" 0;
 
   i2pdConf = pkgs.writeText "i2pd.conf" ''
-      ipv6 = ${toOneZero cfg.enableIPv6}
-      notransit = ${toOneZero cfg.notransit}
-      floodfill = ${toOneZero cfg.floodfill}
+      ipv6 = ${toYesNo cfg.enableIPv6}
+      notransit = ${toYesNo cfg.notransit}
+      floodfill = ${toYesNo cfg.floodfill}
       ${if isNull cfg.port then "" else "port = ${toString cfg.port}"}
       ${flip concatMapStrings
         (collect (proto: proto ? port && proto ? address && proto ? name) cfg.proto)
@@ -73,6 +74,7 @@ let
       [${proto.name}]
       address = ${proto.address}
       port = ${toString proto.port}
+      enabled = ${toYesNo proto.enable}
       '')
       }
   '';
diff --git a/nixos/modules/services/networking/iodined.nix b/nixos/modules/services/networking/iodined.nix
index 6bfe62e6261..20d371c4e2d 100644
--- a/nixos/modules/services/networking/iodined.nix
+++ b/nixos/modules/services/networking/iodined.nix
@@ -64,8 +64,7 @@ in
 
     systemd.services.iodined = {
       description = "iodine, ip over dns daemon";
-      after = [ "network.target" ];
-      wantedBy = [ "multi-user.target" ];
+      wantedBy = [ "ip-up.target" ];
       serviceConfig.ExecStart = "${pkgs.iodine}/sbin/iodined -f -u ${iodinedUser} ${cfg.extraConfig} ${cfg.ip} ${cfg.domain}";
     };
 
diff --git a/nixos/modules/services/networking/mjpg-streamer.nix b/nixos/modules/services/networking/mjpg-streamer.nix
new file mode 100644
index 00000000000..9986f549aec
--- /dev/null
+++ b/nixos/modules/services/networking/mjpg-streamer.nix
@@ -0,0 +1,75 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.mjpg-streamer;
+
+in {
+
+  options = {
+
+    services.mjpg-streamer = {
+
+      enable = mkEnableOption "mjpg-streamer webcam streamer";
+
+      inputPlugin = mkOption {
+        type = types.str;
+        default = "input_uvc.so";
+        description = ''
+          Input plugin. See plugins documentation for more information.
+        '';
+      };
+
+      outputPlugin = mkOption {
+        type = types.str;
+        default = "output_http.so -w @www@ -n -p 5050";
+        description = ''
+          Output plugin. <literal>@www@</literal> is substituted for default mjpg-streamer www directory.
+          See plugins documentation for more information.
+        '';
+      };
+
+      user = mkOption {
+        type = types.str;
+        default = "mjpg-streamer";
+        description = "mjpg-streamer user name.";
+      };
+
+      group = mkOption {
+        type = types.str;
+        default = "video";
+        description = "mjpg-streamer group name.";
+      };
+
+    };
+
+  };
+
+  config = mkIf cfg.enable {
+
+    users.extraUsers = optional (cfg.user == "mjpg-streamer") {
+      name = "mjpg-streamer";
+      uid = config.ids.uids.mjpg-streamer;
+      group = cfg.group;
+    };
+
+    systemd.services.mjpg-streamer = {
+      description = "mjpg-streamer webcam streamer";
+      wantedBy = [ "multi-user.target" ];
+
+      serviceConfig.User = cfg.user;
+      serviceConfig.Group = cfg.group;
+
+      script = ''
+        IPLUGIN="${cfg.inputPlugin}"
+        OPLUGIN="${cfg.outputPlugin}"
+        OPLUGIN="''${OPLUGIN//@www@/${pkgs.mjpg-streamer}/share/mjpg-streamer/www}"
+        exec ${pkgs.mjpg-streamer}/bin/mjpg_streamer -i "$IPLUGIN" -o "$OPLUGIN"
+      '';
+    };
+
+  };
+
+}
diff --git a/nixos/modules/services/networking/radicale.nix b/nixos/modules/services/networking/radicale.nix
index 4b77ef22ac1..19762f4e570 100644
--- a/nixos/modules/services/networking/radicale.nix
+++ b/nixos/modules/services/networking/radicale.nix
@@ -35,12 +35,27 @@ in
   config = mkIf cfg.enable {
     environment.systemPackages = [ pkgs.pythonPackages.radicale ];
 
+    users.extraUsers = singleton
+      { name = "radicale";
+        uid = config.ids.uids.radicale;
+        description = "radicale user";
+        home = "/var/lib/radicale";
+        createHome = true;
+      };
+
+    users.extraGroups = singleton
+      { name = "radicale";
+        gid = config.ids.gids.radicale;
+      };
+
     systemd.services.radicale = {
       description = "A Simple Calendar and Contact Server";
       after = [ "network-interfaces.target" ];
       wantedBy = [ "multi-user.target" ];
       script = "${pkgs.pythonPackages.radicale}/bin/radicale -C ${confFile} -d";
       serviceConfig.Type = "forking";
+      serviceConfig.User = "radicale";
+      serviceConfig.Group = "radicale";
     };
   };
 }
diff --git a/nixos/modules/services/networking/vsftpd.nix b/nixos/modules/services/networking/vsftpd.nix
index e7301e9ef5f..7ec484941ed 100644
--- a/nixos/modules/services/networking/vsftpd.nix
+++ b/nixos/modules/services/networking/vsftpd.nix
@@ -85,6 +85,9 @@ let
         ssl_enable=YES
         rsa_cert_file=${cfg.rsaCertFile}
       ''}
+      ${optionalString (cfg.rsaKeyFile != null) ''
+        rsa_private_key_file=${cfg.rsaKeyFile}
+      ''}
       ${optionalString (cfg.userlistFile != null) ''
         userlist_file=${cfg.userlistFile}
       ''}
@@ -147,6 +150,12 @@ in
         description = "RSA certificate file.";
       };
 
+      rsaKeyFile = mkOption {
+        type = types.nullOr types.path;
+        default = null;
+        description = "RSA private key file.";
+      };
+
       anonymousUmask = mkOption {
         type = types.string;
         default = "077";
diff --git a/nixos/modules/services/networking/wpa_supplicant.nix b/nixos/modules/services/networking/wpa_supplicant.nix
index a8f445a2c73..53648aef1e0 100644
--- a/nixos/modules/services/networking/wpa_supplicant.nix
+++ b/nixos/modules/services/networking/wpa_supplicant.nix
@@ -125,10 +125,12 @@ in {
       # FIXME: start a separate wpa_supplicant instance per interface.
       systemd.services.wpa_supplicant = let
         ifaces = cfg.interfaces;
+        deviceUnit = interface: [ "sys-subsystem-net-devices-${interface}.device" ];
       in {
         description = "WPA Supplicant";
 
         after = [ "network-interfaces.target" ];
+        requires = lib.concatMap deviceUnit ifaces;
         wantedBy = [ "network.target" ];
 
         path = [ pkgs.wpa_supplicant ];
diff --git a/nixos/modules/services/printing/cupsd.nix b/nixos/modules/services/printing/cupsd.nix
index 59416560655..29166be2399 100644
--- a/nixos/modules/services/printing/cupsd.nix
+++ b/nixos/modules/services/printing/cupsd.nix
@@ -238,7 +238,8 @@ in
         example = literalExample "[ pkgs.splix ]";
         description = ''
           CUPS drivers to use. Drivers provided by CUPS, cups-filters, Ghostscript
-          and Samba are added unconditionally.
+          and Samba are added unconditionally. For adding Gutenprint, see
+          <literal>gutenprint</literal>.
         '';
       };
 
@@ -310,7 +311,9 @@ in
               [ ! -e "/var/lib/cups/$i" ] && ln -s "${rootdir}/etc/cups/$i" "/var/lib/cups/$i"
             done
             ${optionalString cfg.gutenprint ''
-              ${gutenprint}/bin/cups-genppdupdate -p /etc/cups/ppd
+              if [ -d /var/lib/cups/ppd ]; then
+                ${gutenprint}/bin/cups-genppdupdate -p /var/lib/cups/ppd
+              fi
             ''}
           '';
       };
diff --git a/nixos/modules/services/system/kerberos.nix b/nixos/modules/services/system/kerberos.nix
index e0c3f95c3cc..347302c6090 100644
--- a/nixos/modules/services/system/kerberos.nix
+++ b/nixos/modules/services/system/kerberos.nix
@@ -46,7 +46,7 @@ in
       };
 
     systemd.services.kdc = {
-      description = "Kerberos Domain Controller daemon";
+      description = "Key Distribution Center daemon";
       wantedBy = [ "multi-user.target" ];
       preStart = ''
         mkdir -m 0755 -p ${stateDir}
@@ -55,7 +55,7 @@ in
     };
 
     systemd.services.kpasswdd = {
-      description = "Kerberos Domain Controller daemon";
+      description = "Kerberos Password Changing daemon";
       wantedBy = [ "multi-user.target" ];
       script = "${heimdal}/sbin/kpasswdd";
     };
diff --git a/nixos/modules/services/torrent/transmission.nix b/nixos/modules/services/torrent/transmission.nix
index 59ef915af6d..c2220cb0cff 100644
--- a/nixos/modules/services/torrent/transmission.nix
+++ b/nixos/modules/services/torrent/transmission.nix
@@ -128,6 +128,7 @@ in
           ${pkgs.c-ares.out}/lib/libcares*.so*          mr,
           ${pkgs.libcap.out}/lib/libcap*.so*            mr,
           ${pkgs.attr.out}/lib/libattr*.so*             mr,
+          ${pkgs.lz4}/lib/liblz4*.so*               mr,
 
           @{PROC}/sys/kernel/random/uuid   r,
           @{PROC}/sys/vm/overcommit_memory r,
diff --git a/nixos/modules/services/web-servers/apache-httpd/foswiki.nix b/nixos/modules/services/web-servers/apache-httpd/foswiki.nix
new file mode 100644
index 00000000000..8c1ac8935a4
--- /dev/null
+++ b/nixos/modules/services/web-servers/apache-httpd/foswiki.nix
@@ -0,0 +1,78 @@
+{ config, pkgs, lib, serverInfo, ... }:
+let
+  inherit (pkgs) foswiki;
+  inherit (serverInfo.serverConfig) user group;
+  inherit (config) vardir;
+in
+{
+  options.vardir = lib.mkOption {
+    type = lib.types.path;
+    default = "/var/www/foswiki";
+    description = "The directory where variable foswiki data will be stored and served from.";
+  };
+
+  # TODO: this will probably need to be better customizable
+  extraConfig =
+    let httpd-conf = pkgs.runCommand "foswiki-httpd.conf"
+      { preferLocalBuild = true; }
+      ''
+        substitute '${foswiki}/foswiki_httpd_conf.txt' "$out" \
+          --replace /var/www/foswiki/ "${vardir}/"
+      '';
+    in
+      ''
+        RewriteEngine on
+        RewriteRule /foswiki/(.*) ${vardir}/$1
+
+        <Directory "${vardir}">
+          Require all granted
+        </Directory>
+
+        Include ${httpd-conf}
+        <Directory "${vardir}/pub">
+          Options FollowSymlinks
+        </Directory>
+      '';
+
+  /** This handles initial setup and updates.
+      It will probably need some tweaking, maybe per-site.  */
+  startupScript = pkgs.writeScript "foswiki_startup.sh" (
+    let storeLink = "${vardir}/package"; in
+    ''
+      [ -e '${storeLink}' ] || needs_setup=1
+      mkdir -p '${vardir}'
+      cd '${vardir}'
+      ln -sf -T '${foswiki}' '${storeLink}'
+
+      if [ -n "$needs_setup" ]; then # do initial setup
+        mkdir -p bin lib
+        # setup most of data/ as copies only
+        cp -r '${foswiki}'/data '${vardir}/'
+        rm -r '${vardir}'/data/{System,mime.types}
+        ln -sr -t '${vardir}/data/' '${storeLink}'/data/{System,mime.types}
+
+        ln -sr '${storeLink}/locale' .
+
+        mkdir pub
+        ln -sr '${storeLink}/pub/System' pub/
+
+        mkdir templates
+        ln -sr '${storeLink}'/templates/* templates/
+
+        ln -sr '${storeLink}/tools' .
+
+        mkdir -p '${vardir}'/working/{logs,tmp}
+        ln -sr '${storeLink}/working/README' working/ # used to check dir validity
+
+        chown -R '${user}:${group}' .
+        chmod +w -R .
+      fi
+
+      # bin/* and lib/* shall always be overwritten, in case files are added
+      ln -srf '${storeLink}'/bin/* '${vardir}/bin/'
+      ln -srf '${storeLink}'/lib/* '${vardir}/lib/'
+    ''
+    /* Symlinking bin/ one-by-one ensures that ${vardir}/lib/LocalSite.cfg
+        is used instead of ${foswiki}/... */
+  );
+}
diff --git a/nixos/modules/services/web-servers/uwsgi.nix b/nixos/modules/services/web-servers/uwsgi.nix
index e6c25e6215c..56f077e62a8 100644
--- a/nixos/modules/services/web-servers/uwsgi.nix
+++ b/nixos/modules/services/web-servers/uwsgi.nix
@@ -32,17 +32,27 @@ let
         self = pythonPackages;
       };
 
-      json = builtins.toJSON {
+      penv = python.buildEnv.override {
+        extraLibs = (c.pythonPackages or (self: [])) pythonPackages;
+      };
+
+      uwsgiCfg = {
         uwsgi =
           if c.type == "normal"
             then {
               inherit plugins;
             } // removeAttrs c [ "type" "pythonPackages" ]
               // optionalAttrs (python != null) {
-                pythonpath = "@PYTHONPATH@";
-                env = (c.env or {}) // {
-                  PATH = optionalString (c ? env.PATH) "${c.env.PATH}:" + "@PATH@";
-                };
+                pythonpath = "${penv}/${python.sitePackages}";
+                env =
+                  # Argh, uwsgi expects list of key-values there instead of a dictionary.
+                  let env' = c.env or [];
+                      getPath =
+                        x: if hasPrefix "PATH=" x
+                           then substring (stringLength "PATH=") (stringLength x) x
+                           else null;
+                      oldPaths = filter (x: x != null) (map getPath env');
+                  in env' ++ [ "PATH=${optionalString (oldPaths != []) "${last oldPaths}:"}${penv}/bin" ];
               }
           else if c.type == "emperor"
             then {
@@ -55,35 +65,7 @@ let
           else throw "`type` attribute in UWSGI configuration should be either 'normal' or 'emperor'";
       };
 
-    in
-      if python == null || c.type != "normal"
-      then pkgs.writeTextDir "${name}.json" json
-      else pkgs.stdenv.mkDerivation {
-        name = "uwsgi-config";
-        inherit json;
-        passAsFile = [ "json" ];
-        nativeBuildInputs = [ pythonPackages.wrapPython ];
-        pythonInputs = (c.pythonPackages or (self: [])) pythonPackages;
-
-        buildCommand = ''
-          mkdir $out
-          declare -A pythonPathsSeen=()
-          program_PYTHONPATH=
-          program_PATH=
-          if [ -n "$pythonInputs" ]; then
-            for i in $pythonInputs; do
-              _addToPythonPath $i
-            done
-          fi
-          # A hack to replace "@PYTHONPATH@" with a JSON list
-          if [ -n "$program_PYTHONPATH" ]; then
-            program_PYTHONPATH="\"''${program_PYTHONPATH//:/\",\"}\""
-          fi
-          substitute $jsonPath $out/${name}.json \
-            --replace '"@PYTHONPATH@"' "[$program_PYTHONPATH]" \
-            --subst-var-by PATH "$program_PATH"
-        '';
-      };
+    in pkgs.writeTextDir "${name}.json" (builtins.toJSON uwsgiCfg);
 
 in {
 
diff --git a/nixos/modules/services/x11/colord.nix b/nixos/modules/services/x11/colord.nix
new file mode 100644
index 00000000000..d9e81d75072
--- /dev/null
+++ b/nixos/modules/services/x11/colord.nix
@@ -0,0 +1,39 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.colord;
+
+in {
+
+  options = {
+
+    services.colord = {
+      enable = mkEnableOption "colord, the color management daemon";
+    };
+
+  };
+
+  config = mkIf cfg.enable {
+
+    services.dbus.packages = [ pkgs.colord ];
+
+    services.udev.packages = [ pkgs.colord ];
+
+    environment.systemPackages = [ pkgs.colord ];
+
+    systemd.services.colord = {
+      description = "Manage, Install and Generate Color Profiles";
+      serviceConfig = {
+        Type = "dbus";
+        BusName = "org.freedesktop.ColorManager";
+        ExecStart = "${pkgs.colord}/libexec/colord";
+        PrivateTmp = true;
+      };
+    };
+
+  };
+
+}
diff --git a/nixos/modules/services/x11/desktop-managers/default.nix b/nixos/modules/services/x11/desktop-managers/default.nix
index 3e91450a39d..1ea7b5ccf16 100644
--- a/nixos/modules/services/x11/desktop-managers/default.nix
+++ b/nixos/modules/services/x11/desktop-managers/default.nix
@@ -19,7 +19,7 @@ in
   # E.g., if KDE is enabled, it supersedes xterm.
   imports = [
     ./none.nix ./xterm.nix ./xfce.nix ./kde4.nix ./kde5.nix
-    ./e19.nix ./gnome3.nix ./kodi.nix
+    ./enlightenment.nix ./gnome3.nix ./kodi.nix
   ];
 
   options = {
diff --git a/nixos/modules/services/x11/desktop-managers/e19.nix b/nixos/modules/services/x11/desktop-managers/enlightenment.nix
index 2d5c7b192bc..c981b40f74a 100644
--- a/nixos/modules/services/x11/desktop-managers/e19.nix
+++ b/nixos/modules/services/x11/desktop-managers/enlightenment.nix
@@ -4,9 +4,9 @@ with lib;
 
 let
 
+  e = pkgs.enlightenment;
   xcfg = config.services.xserver;
-  cfg = xcfg.desktopManager.e19;
-  e19_enlightenment = pkgs.e19.enlightenment.override { set_freqset_setuid = true; };
+  cfg = xcfg.desktopManager.enlightenment;
   GST_PLUGIN_PATH = lib.makeSearchPath "lib/gstreamer-1.0" [
     pkgs.gst_all_1.gst-plugins-base
     pkgs.gst_all_1.gst-plugins-good
@@ -18,10 +18,10 @@ in
 {
   options = {
 
-    services.xserver.desktopManager.e19.enable = mkOption {
+    services.xserver.desktopManager.enlightenment.enable = mkOption {
       default = false;
       example = true;
-      description = "Enable the E19 desktop environment.";
+      description = "Enable the Enlightenment desktop environment.";
     };
 
   };
@@ -29,8 +29,8 @@ in
   config = mkIf (xcfg.enable && cfg.enable) {
 
     environment.systemPackages = [
-      pkgs.e19.efl pkgs.e19.evas pkgs.e19.emotion pkgs.e19.elementary e19_enlightenment
-      pkgs.e19.terminology pkgs.e19.econnman
+      e.efl e.evas e.emotion e.elementary e.enlightenment
+      e.terminology e.econnman
       pkgs.xorg.xauth # used by kdesu
       pkgs.gtk # To get GTK+'s themes.
       pkgs.tango-icon-theme
@@ -42,7 +42,7 @@ in
     environment.pathsToLink = [ "/etc/enlightenment" "/etc/xdg" "/share/enlightenment" "/share/elementary" "/share/applications" "/share/locale" "/share/icons" "/share/themes" "/share/mime" "/share/desktop-directories" ];
 
     services.xserver.desktopManager.session = [
-    { name = "E19";
+    { name = "Enlightenment";
       start = ''
         # Set GTK_DATA_PREFIX so that GTK+ can find the themes
         export GTK_DATA_PREFIX=${config.system.path}
@@ -53,17 +53,16 @@ in
         export GST_PLUGIN_PATH="${GST_PLUGIN_PATH}"
 
         # make available for D-BUS user services
-        #export XDG_DATA_DIRS=$XDG_DATA_DIRS''${XDG_DATA_DIRS:+:}:${config.system.path}/share:${pkgs.e19.efl}/share
+        #export XDG_DATA_DIRS=$XDG_DATA_DIRS''${XDG_DATA_DIRS:+:}:${config.system.path}/share:${e.efl}/share
 
         # Update user dirs as described in http://freedesktop.org/wiki/Software/xdg-user-dirs/
         ${pkgs.xdg-user-dirs}/bin/xdg-user-dirs-update
 
-        ${e19_enlightenment}/bin/enlightenment_start
-        waitPID=$!
+        exec ${e.enlightenment}/bin/enlightenment_start
       '';
     }];
 
-    security.setuidPrograms = [ "e19_freqset" ];
+    security.setuidPrograms = [ "e_freqset" ];
 
     environment.etc = singleton
       { source = "${pkgs.xkeyboard_config}/etc/X11/xkb";
@@ -75,13 +74,13 @@ in
     services.udisks2.enable = true;
     services.upower.enable = config.powerManagement.enable;
 
-    #services.dbus.packages = [ pkgs.efl ]; # dbus-1 folder is not in /etc but in /share, so needs fixing first
+    services.dbus.packages = [ e.efl ];
 
     systemd.user.services.efreet =
       { enable = true;
         description = "org.enlightenment.Efreet";
         serviceConfig =
-          { ExecStart = "${pkgs.e19.efl}/bin/efreetd";
+          { ExecStart = "${e.efl}/bin/efreetd";
             StandardOutput = "null";
           };
       };
@@ -90,7 +89,7 @@ in
       { enable = true;
         description = "org.enlightenment.Ethumb";
         serviceConfig =
-          { ExecStart = "${pkgs.e19.efl}/bin/ethumbd";
+          { ExecStart = "${e.efl}/bin/ethumbd";
             StandardOutput = "null";
           };
       };
diff --git a/nixos/modules/services/x11/desktop-managers/kde5.nix b/nixos/modules/services/x11/desktop-managers/kde5.nix
index 2dc03b7fe63..1d60637c4ca 100644
--- a/nixos/modules/services/x11/desktop-managers/kde5.nix
+++ b/nixos/modules/services/x11/desktop-managers/kde5.nix
@@ -128,6 +128,7 @@ in
       ++ lib.optional config.networking.networkmanager.enable kde5.plasma-nm
       ++ lib.optional config.hardware.pulseaudio.enable kde5.plasma-pa
       ++ lib.optional config.powerManagement.enable kde5.powerdevil
+      ++ lib.optional config.services.colord.enable kde5.colord-kde
       ++ lib.optionals config.services.samba.enable [ kde5.kdenetwork-filesharing pkgs.samba ]
 
       ++ lib.optionals cfg.phonon.gstreamer.enable
diff --git a/nixos/modules/services/x11/display-managers/default.nix b/nixos/modules/services/x11/display-managers/default.nix
index da7be748d8b..be634fc259a 100644
--- a/nixos/modules/services/x11/display-managers/default.nix
+++ b/nixos/modules/services/x11/display-managers/default.nix
@@ -49,17 +49,6 @@ let
         fi
       ''}
 
-      ${optionalString cfg.startGnuPGAgent ''
-        if test -z "$SSH_AUTH_SOCK"; then
-            # Restart this script as a child of the GnuPG agent.
-            exec "${pkgs.gnupg}/bin/gpg-agent"                         \
-              --enable-ssh-support --daemon                             \
-              --pinentry-program "${pkgs.pinentry}/bin/pinentry-gtk-2"  \
-              --write-env-file "$HOME/.gpg-agent-info"                  \
-              "$0" "$sessionType"
-        fi
-      ''}
-
       # Handle being called by kdm.
       if test "''${1:0:1}" = /; then eval exec "$1"; fi
 
diff --git a/nixos/modules/services/x11/window-managers/default.nix b/nixos/modules/services/x11/window-managers/default.nix
index 26dfbb1f4e1..fce71bbda7e 100644
--- a/nixos/modules/services/x11/window-managers/default.nix
+++ b/nixos/modules/services/x11/window-managers/default.nix
@@ -10,13 +10,13 @@ in
   imports = [
     ./afterstep.nix
     ./bspwm.nix
-    ./clfswm.nix
     ./compiz.nix
     ./dwm.nix
     ./exwm.nix
     ./fluxbox.nix
     ./herbstluftwm.nix
     ./i3.nix
+    ./jwm.nix
     ./metacity.nix
     ./openbox.nix
     ./notion.nix
diff --git a/nixos/modules/services/x11/window-managers/jwm.nix b/nixos/modules/services/x11/window-managers/jwm.nix
new file mode 100644
index 00000000000..0e8dab2e922
--- /dev/null
+++ b/nixos/modules/services/x11/window-managers/jwm.nix
@@ -0,0 +1,25 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.xserver.windowManager.jwm;
+in
+{
+  ###### interface
+  options = {
+    services.xserver.windowManager.jwm.enable = mkEnableOption "jwm";
+  };
+
+  ###### implementation
+  config = mkIf cfg.enable {
+    services.xserver.windowManager.session = singleton {
+      name = "jwm";
+      start = ''
+        ${pkgs.jwm}/bin/jwm &
+        waitPID=$!
+      '';
+    };
+    environment.systemPackages = [ pkgs.jwm ];
+  };
+}
diff --git a/nixos/modules/services/x11/xserver.nix b/nixos/modules/services/x11/xserver.nix
index 60b6a97416a..d5babd5012f 100644
--- a/nixos/modules/services/x11/xserver.nix
+++ b/nixos/modules/services/x11/xserver.nix
@@ -13,9 +13,9 @@ let
 
   # Map video driver names to driver packages. FIXME: move into card-specific modules.
   knownVideoDrivers = {
-    virtualbox   = { modules = [ kernelPackages.virtualboxGuestAdditions ]; driverName = "vboxvideo"; };
-    ati = { modules = [ pkgs.xorg.xf86videoati pkgs.xorg.glamoregl ]; };
-    intel-testing = { modules = with pkgs.xorg; [ xf86videointel-testing glamoregl ]; driverName = "intel"; };
+    virtualbox = { modules = [ kernelPackages.virtualboxGuestAdditions ]; driverName = "vboxvideo"; };
+    ati = { modules = with pkgs.xorg; [ xf86videoati glamoregl ]; };
+    intel = { modules = with pkgs.xorg; [ xf86videointel glamoregl ]; };
   };
 
   fontsForXServer =
@@ -160,7 +160,7 @@ in
           [ '''
               Identifier      "Trackpoint Wheel Emulation"
               MatchProduct    "ThinkPad USB Keyboard with TrackPoint"
-              Option          "EmulateWheel"          "true
+              Option          "EmulateWheel"          "true"
               Option          "EmulateWheelButton"    "2"
               Option          "Emulate3Buttons"       "false"
             '''
@@ -219,17 +219,6 @@ in
         '';
       };
 
-      startGnuPGAgent = mkOption {
-        type = types.bool;
-        default = false;
-        description = ''
-          Whether to start the GnuPG agent when you log in.  The GnuPG agent
-          remembers private keys for you so that you don't have to type in
-          passphrases every time you make an SSH connection or sign/encrypt
-          data.  Use <command>ssh-add</command> to add a key to the agent.
-        '';
-      };
-
       startDbusSession = mkOption {
         type = types.bool;
         default = true;
@@ -444,14 +433,7 @@ in
       in optional (driver != null) ({ inherit name; driverName = name; } // driver));
 
     assertions =
-      [ { assertion = !(config.programs.ssh.startAgent && cfg.startGnuPGAgent);
-          message =
-            ''
-              The OpenSSH agent and GnuPG agent cannot be started both. Please
-              choose between ‘programs.ssh.startAgent’ and ‘services.xserver.startGnuPGAgent’.
-            '';
-        }
-        { assertion = config.security.polkit.enable;
+      [ { assertion = config.security.polkit.enable;
           message = "X11 requires Polkit to be enabled (‘security.polkit.enable = true’).";
         }
       ];