summary refs log tree commit diff
path: root/nixos/modules/services
diff options
context:
space:
mode:
authorParnell Springmeyer <parnell@digitalmentat.com>2017-01-25 11:08:05 -0800
committerParnell Springmeyer <parnell@digitalmentat.com>2017-01-25 11:08:05 -0800
commitbae00e8aa8f3faff90e28e19cd5074b8c26d0d0e (patch)
tree56abaf30f11ad2f24b9fb7729f74c5fff50fbd93 /nixos/modules/services
parent1f9494b752082ec3ac048e56d1c6364a2e23a675 (diff)
parent104c3db6594043dbb81005303f055b02145305a5 (diff)
downloadnixpkgs-bae00e8aa8f3faff90e28e19cd5074b8c26d0d0e.tar
nixpkgs-bae00e8aa8f3faff90e28e19cd5074b8c26d0d0e.tar.gz
nixpkgs-bae00e8aa8f3faff90e28e19cd5074b8c26d0d0e.tar.bz2
nixpkgs-bae00e8aa8f3faff90e28e19cd5074b8c26d0d0e.tar.lz
nixpkgs-bae00e8aa8f3faff90e28e19cd5074b8c26d0d0e.tar.xz
nixpkgs-bae00e8aa8f3faff90e28e19cd5074b8c26d0d0e.tar.zst
nixpkgs-bae00e8aa8f3faff90e28e19cd5074b8c26d0d0e.zip
setcap-wrapper: Merging with upstream master and resolving conflicts
Diffstat (limited to 'nixos/modules/services')
-rw-r--r--nixos/modules/services/audio/alsa.nix41
-rw-r--r--nixos/modules/services/audio/mopidy.nix8
-rw-r--r--nixos/modules/services/audio/mpd.nix20
-rw-r--r--nixos/modules/services/audio/ympd.nix57
-rw-r--r--nixos/modules/services/backup/bacula.nix10
-rw-r--r--nixos/modules/services/backup/crashplan.nix2
-rw-r--r--nixos/modules/services/backup/rsnapshot.nix3
-rw-r--r--nixos/modules/services/backup/tarsnap.nix156
-rw-r--r--nixos/modules/services/cluster/fleet.nix2
-rw-r--r--nixos/modules/services/cluster/kubernetes.nix598
-rw-r--r--nixos/modules/services/cluster/panamax.nix2
-rw-r--r--nixos/modules/services/computing/boinc/client.nix88
-rw-r--r--nixos/modules/services/continuous-integration/buildbot/master.nix250
-rw-r--r--nixos/modules/services/continuous-integration/gitlab-runner.nix51
-rw-r--r--nixos/modules/services/continuous-integration/gocd-agent/default.nix3
-rw-r--r--nixos/modules/services/continuous-integration/gocd-server/default.nix15
-rw-r--r--nixos/modules/services/continuous-integration/hydra/default.nix2
-rw-r--r--nixos/modules/services/databases/4store-endpoint.nix4
-rw-r--r--nixos/modules/services/databases/4store.nix3
-rw-r--r--nixos/modules/services/databases/cassandra.nix2
-rw-r--r--nixos/modules/services/databases/couchdb.nix2
-rw-r--r--nixos/modules/services/databases/influxdb.nix15
-rw-r--r--nixos/modules/services/databases/monetdb.nix88
-rw-r--r--nixos/modules/services/databases/mongodb.nix18
-rw-r--r--nixos/modules/services/databases/mysql.nix17
-rw-r--r--nixos/modules/services/databases/neo4j.nix94
-rw-r--r--nixos/modules/services/databases/openldap.nix9
-rw-r--r--nixos/modules/services/databases/postgresql.nix4
-rw-r--r--nixos/modules/services/databases/riak-cs.nix202
-rw-r--r--nixos/modules/services/databases/riak.nix17
-rw-r--r--nixos/modules/services/databases/stanchion.nix212
-rw-r--r--nixos/modules/services/databases/virtuoso.nix3
-rw-r--r--nixos/modules/services/desktops/accountsservice.nix8
-rw-r--r--nixos/modules/services/desktops/gnome3/evolution-data-server.nix2
-rw-r--r--nixos/modules/services/desktops/gnome3/gnome-terminal-server.nix44
-rw-r--r--nixos/modules/services/desktops/gnome3/gvfs.nix2
-rw-r--r--nixos/modules/services/desktops/gnome3/tracker.nix2
-rw-r--r--nixos/modules/services/desktops/profile-sync-daemon.nix6
-rw-r--r--nixos/modules/services/editors/emacs.nix10
-rw-r--r--nixos/modules/services/editors/emacs.xml79
-rw-r--r--nixos/modules/services/editors/infinoted.nix158
-rw-r--r--nixos/modules/services/games/ghost-one.nix3
-rw-r--r--nixos/modules/services/games/terraria.nix6
-rw-r--r--nixos/modules/services/hardware/brltty.nix4
-rw-r--r--nixos/modules/services/hardware/pommed.nix36
-rw-r--r--nixos/modules/services/hardware/sane.nix111
-rw-r--r--nixos/modules/services/hardware/sane_extra_backends/brscan4.nix5
-rw-r--r--nixos/modules/services/hardware/tlp.nix2
-rw-r--r--nixos/modules/services/hardware/udev.nix26
-rw-r--r--nixos/modules/services/logging/logcheck.nix72
-rw-r--r--nixos/modules/services/logging/syslogd.nix6
-rw-r--r--nixos/modules/services/mail/dovecot.nix5
-rw-r--r--nixos/modules/services/mail/freepops.nix3
-rw-r--r--nixos/modules/services/mail/offlineimap.nix (renamed from nixos/modules/services/networking/offlineimap.nix)2
-rw-r--r--nixos/modules/services/mail/opensmtpd.nix20
-rw-r--r--nixos/modules/services/mail/postgrey.nix194
-rw-r--r--nixos/modules/services/mail/postsrsd.nix34
-rw-r--r--nixos/modules/services/mail/rmilter.nix2
-rw-r--r--nixos/modules/services/misc/apache-kafka.nix2
-rw-r--r--nixos/modules/services/misc/autofs.nix2
-rw-r--r--nixos/modules/services/misc/bepasty.nix2
-rwxr-xr-x[-rw-r--r--]nixos/modules/services/misc/confd.nix2
-rw-r--r--nixos/modules/services/misc/dictd.nix13
-rw-r--r--nixos/modules/services/misc/disnix.nix1
-rw-r--r--nixos/modules/services/misc/docker-registry.nix33
-rw-r--r--nixos/modules/services/misc/emby.nix2
-rw-r--r--nixos/modules/services/misc/errbot.nix101
-rw-r--r--nixos/modules/services/misc/etcd.nix75
-rw-r--r--nixos/modules/services/misc/folding-at-home.nix2
-rw-r--r--nixos/modules/services/misc/gitlab.nix26
-rw-r--r--nixos/modules/services/misc/leaps.nix62
-rw-r--r--nixos/modules/services/misc/matrix-synapse.nix133
-rw-r--r--nixos/modules/services/misc/mesos-master.nix2
-rw-r--r--nixos/modules/services/misc/mesos-slave.nix2
-rw-r--r--nixos/modules/services/misc/nix-daemon.nix8
-rw-r--r--nixos/modules/services/misc/nix-gc.nix2
-rw-r--r--nixos/modules/services/misc/nix-optimise.nix49
-rw-r--r--nixos/modules/services/misc/nscd-sssd.conf36
-rw-r--r--nixos/modules/services/misc/parsoid.nix40
-rw-r--r--nixos/modules/services/misc/plex.nix15
-rw-r--r--nixos/modules/services/misc/redmine.nix2
-rw-r--r--nixos/modules/services/misc/rippled.nix78
-rw-r--r--nixos/modules/services/misc/sssd.nix97
-rw-r--r--nixos/modules/services/misc/svnserve.nix2
-rw-r--r--nixos/modules/services/misc/taskserver/default.nix6
-rw-r--r--nixos/modules/services/misc/zookeeper.nix2
-rw-r--r--nixos/modules/services/monitoring/bosun.nix2
-rw-r--r--nixos/modules/services/monitoring/cadvisor.nix1
-rw-r--r--nixos/modules/services/monitoring/collectd.nix5
-rw-r--r--nixos/modules/services/monitoring/graphite.nix18
-rw-r--r--nixos/modules/services/monitoring/monit.nix13
-rw-r--r--nixos/modules/services/monitoring/munin.nix1
-rw-r--r--nixos/modules/services/monitoring/nagios.nix2
-rw-r--r--nixos/modules/services/monitoring/prometheus/alertmanager.nix116
-rw-r--r--nixos/modules/services/monitoring/prometheus/blackbox-exporter.nix67
-rw-r--r--nixos/modules/services/monitoring/prometheus/default.nix465
-rw-r--r--nixos/modules/services/monitoring/prometheus/json-exporter.nix74
-rw-r--r--nixos/modules/services/monitoring/prometheus/nginx-exporter.nix78
-rw-r--r--nixos/modules/services/monitoring/prometheus/node-exporter.nix81
-rw-r--r--nixos/modules/services/monitoring/prometheus/snmp-exporter.nix127
-rw-r--r--nixos/modules/services/monitoring/prometheus/varnish-exporter.nix61
-rw-r--r--nixos/modules/services/monitoring/riemann-tools.nix1
-rw-r--r--nixos/modules/services/monitoring/smartd.nix3
-rw-r--r--nixos/modules/services/monitoring/telegraf.nix71
-rw-r--r--nixos/modules/services/monitoring/ups.nix10
-rw-r--r--nixos/modules/services/monitoring/zabbix-agent.nix1
-rw-r--r--nixos/modules/services/network-filesystems/cachefilesd.nix59
-rw-r--r--nixos/modules/services/network-filesystems/drbd.nix4
-rw-r--r--nixos/modules/services/network-filesystems/ipfs.nix125
-rw-r--r--nixos/modules/services/network-filesystems/openafs-client/default.nix2
-rw-r--r--nixos/modules/services/network-filesystems/samba.nix13
-rw-r--r--nixos/modules/services/network-filesystems/tahoe.nix336
-rw-r--r--nixos/modules/services/network-filesystems/xtreemfs.nix5
-rw-r--r--nixos/modules/services/network-filesystems/yandex-disk.nix13
-rw-r--r--nixos/modules/services/networking/amuled.nix3
-rw-r--r--nixos/modules/services/networking/asterisk.nix60
-rw-r--r--nixos/modules/services/networking/atftpd.nix24
-rw-r--r--nixos/modules/services/networking/avahi-daemon.nix30
-rw-r--r--nixos/modules/services/networking/bind.nix8
-rw-r--r--nixos/modules/services/networking/bird.nix123
-rw-r--r--nixos/modules/services/networking/bitlbee.nix7
-rw-r--r--nixos/modules/services/networking/chrony.nix5
-rw-r--r--nixos/modules/services/networking/cjdns-hosts.sh11
-rw-r--r--nixos/modules/services/networking/cjdns.nix79
-rw-r--r--nixos/modules/services/networking/cntlm.nix1
-rw-r--r--nixos/modules/services/networking/connman.nix12
-rw-r--r--nixos/modules/services/networking/dante.nix61
-rw-r--r--nixos/modules/services/networking/ddclient.nix19
-rw-r--r--nixos/modules/services/networking/dhcpcd.nix26
-rw-r--r--nixos/modules/services/networking/dhcpd.nix10
-rw-r--r--nixos/modules/services/networking/dnscrypt-proxy.nix130
-rw-r--r--nixos/modules/services/networking/dnscrypt-proxy.xml13
-rw-r--r--nixos/modules/services/networking/docker-registry-server.nix98
-rw-r--r--nixos/modules/services/networking/fakeroute.nix63
-rw-r--r--nixos/modules/services/networking/ferm.nix1
-rw-r--r--nixos/modules/services/networking/firewall.nix17
-rw-r--r--nixos/modules/services/networking/flannel.nix154
-rw-r--r--nixos/modules/services/networking/git-daemon.nix3
-rw-r--r--nixos/modules/services/networking/gvpe.nix2
-rw-r--r--nixos/modules/services/networking/hostapd.nix7
-rw-r--r--nixos/modules/services/networking/htpdate.nix80
-rw-r--r--nixos/modules/services/networking/i2pd.nix285
-rw-r--r--nixos/modules/services/networking/iodine.nix6
-rw-r--r--nixos/modules/services/networking/ircd-hybrid/builder.sh4
-rw-r--r--nixos/modules/services/networking/kippo.nix8
-rw-r--r--nixos/modules/services/networking/miredo.nix93
-rw-r--r--nixos/modules/services/networking/mjpg-streamer.nix8
-rw-r--r--nixos/modules/services/networking/murmur.nix6
-rw-r--r--nixos/modules/services/networking/nat.nix32
-rw-r--r--nixos/modules/services/networking/networkmanager.nix14
-rw-r--r--nixos/modules/services/networking/nntp-proxy.nix4
-rw-r--r--nixos/modules/services/networking/nsd.nix62
-rw-r--r--nixos/modules/services/networking/ntpd.nix10
-rw-r--r--nixos/modules/services/networking/oidentd.nix2
-rw-r--r--nixos/modules/services/networking/openfire.nix4
-rw-r--r--nixos/modules/services/networking/openntpd.nix2
-rw-r--r--nixos/modules/services/networking/openvpn.nix80
-rw-r--r--nixos/modules/services/networking/powerdns.nix49
-rw-r--r--nixos/modules/services/networking/prayer.nix1
-rw-r--r--nixos/modules/services/networking/privoxy.nix23
-rw-r--r--nixos/modules/services/networking/prosody.nix4
-rw-r--r--nixos/modules/services/networking/quagga.nix187
-rw-r--r--nixos/modules/services/networking/quassel.nix12
-rw-r--r--nixos/modules/services/networking/radicale.nix7
-rw-r--r--nixos/modules/services/networking/skydns.nix2
-rw-r--r--nixos/modules/services/networking/smokeping.nix240
-rw-r--r--nixos/modules/services/networking/softether.nix16
-rw-r--r--nixos/modules/services/networking/ssh/lshd.nix2
-rw-r--r--nixos/modules/services/networking/ssh/sshd.nix86
-rw-r--r--nixos/modules/services/networking/supplicant.nix206
-rw-r--r--nixos/modules/services/networking/syncthing.nix115
-rw-r--r--nixos/modules/services/networking/tcpcrypt.nix2
-rw-r--r--nixos/modules/services/networking/tftpd.nix3
-rw-r--r--nixos/modules/services/networking/tinc.nix174
-rw-r--r--nixos/modules/services/networking/toxvpn.nix2
-rw-r--r--nixos/modules/services/networking/unbound.nix35
-rw-r--r--nixos/modules/services/networking/vsftpd.nix11
-rw-r--r--nixos/modules/services/networking/wicd.nix4
-rw-r--r--nixos/modules/services/networking/wireguard.nix231
-rw-r--r--nixos/modules/services/networking/wpa_supplicant.nix21
-rw-r--r--nixos/modules/services/networking/xinetd.nix128
-rw-r--r--nixos/modules/services/networking/zerobin.nix6
-rw-r--r--nixos/modules/services/networking/znc.nix173
-rw-r--r--nixos/modules/services/printing/cupsd.nix9
-rw-r--r--nixos/modules/services/scheduling/chronos.nix2
-rw-r--r--nixos/modules/services/scheduling/marathon.nix2
-rw-r--r--nixos/modules/services/search/elasticsearch.nix2
-rw-r--r--nixos/modules/services/search/hound.nix125
-rw-r--r--nixos/modules/services/search/kibana.nix2
-rw-r--r--nixos/modules/services/security/clamav.nix95
-rw-r--r--nixos/modules/services/security/fail2ban.nix2
-rw-r--r--nixos/modules/services/security/haveged.nix18
-rw-r--r--nixos/modules/services/security/oauth2_proxy.nix2
-rw-r--r--nixos/modules/services/system/cgmanager.nix27
-rw-r--r--nixos/modules/services/system/dbus.nix62
-rw-r--r--nixos/modules/services/system/nscd.nix13
-rw-r--r--nixos/modules/services/torrent/deluge.nix57
-rw-r--r--nixos/modules/services/torrent/flexget.nix6
-rw-r--r--nixos/modules/services/torrent/opentracker.nix45
-rw-r--r--nixos/modules/services/torrent/peerflix.nix2
-rw-r--r--nixos/modules/services/ttys/agetty.nix3
-rw-r--r--nixos/modules/services/web-apps/atlassian/confluence.nix141
-rw-r--r--nixos/modules/services/web-apps/atlassian/crowd.nix156
-rw-r--r--nixos/modules/services/web-apps/atlassian/jira.nix149
-rw-r--r--nixos/modules/services/web-apps/nixbot.nix149
-rw-r--r--nixos/modules/services/web-apps/quassel-webserver.nix101
-rw-r--r--nixos/modules/services/web-apps/selfoss.nix166
-rw-r--r--nixos/modules/services/web-apps/tt-rss.nix158
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/default.nix62
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/mediawiki.nix7
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/moodle.nix5
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/per-server-options.nix25
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/trac.nix3
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/wordpress.nix13
-rw-r--r--nixos/modules/services/web-servers/fcgiwrap.nix2
-rw-r--r--nixos/modules/services/web-servers/lighttpd/inginious.nix3
-rw-r--r--nixos/modules/services/web-servers/nginx/default.nix48
-rw-r--r--nixos/modules/services/web-servers/nginx/vhost-options.nix4
-rw-r--r--nixos/modules/services/web-servers/phpfpm/default.nix35
-rw-r--r--nixos/modules/services/web-servers/tomcat.nix18
-rw-r--r--nixos/modules/services/web-servers/uwsgi.nix1
-rw-r--r--nixos/modules/services/web-servers/winstone.nix3
-rw-r--r--nixos/modules/services/web-servers/zope2.nix3
-rw-r--r--nixos/modules/services/x11/compton.nix1
-rw-r--r--nixos/modules/services/x11/desktop-managers/default.nix3
-rw-r--r--nixos/modules/services/x11/desktop-managers/enlightenment.nix4
-rw-r--r--nixos/modules/services/x11/desktop-managers/gnome3.nix10
-rw-r--r--nixos/modules/services/x11/desktop-managers/kde4.nix37
-rw-r--r--nixos/modules/services/x11/desktop-managers/kde5.nix400
-rw-r--r--nixos/modules/services/x11/desktop-managers/lumina.nix52
-rw-r--r--nixos/modules/services/x11/desktop-managers/lxqt.nix66
-rw-r--r--nixos/modules/services/x11/desktop-managers/xfce.nix3
-rw-r--r--nixos/modules/services/x11/display-managers/default.nix18
-rw-r--r--nixos/modules/services/x11/display-managers/gdm.nix12
-rw-r--r--nixos/modules/services/x11/display-managers/kdm.nix24
-rw-r--r--nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix9
-rw-r--r--nixos/modules/services/x11/display-managers/lightdm.nix9
-rw-r--r--nixos/modules/services/x11/display-managers/sddm.nix16
-rw-r--r--nixos/modules/services/x11/display-managers/slim.nix8
-rw-r--r--nixos/modules/services/x11/hardware/synaptics.nix4
-rw-r--r--nixos/modules/services/x11/hardware/wacom.nix4
-rw-r--r--nixos/modules/services/x11/unclutter-xfixes.nix58
-rw-r--r--nixos/modules/services/x11/urxvtd.nix50
-rw-r--r--nixos/modules/services/x11/window-managers/awesome.nix9
-rw-r--r--nixos/modules/services/x11/window-managers/bspwm.nix83
-rw-r--r--nixos/modules/services/x11/window-managers/i3.nix50
-rw-r--r--nixos/modules/services/x11/xserver.nix43
247 files changed, 8979 insertions, 2518 deletions
diff --git a/nixos/modules/services/audio/alsa.nix b/nixos/modules/services/audio/alsa.nix
index c63f4dc8d7f..53786dbc627 100644
--- a/nixos/modules/services/audio/alsa.nix
+++ b/nixos/modules/services/audio/alsa.nix
@@ -33,16 +33,6 @@ in
         '';
       };
 
-      enableMediaKeys = mkOption {
-        type = types.bool;
-        default = false;
-        description = ''
-          Whether to enable volume and capture control with keyboard media keys.
-
-          Enabling this will turn on <option>services.actkbd</option>.
-        '';
-      };
-
       extraConfig = mkOption {
         type = types.lines;
         default = "";
@@ -54,6 +44,31 @@ in
         '';
       };
 
+      mediaKeys = {
+
+        enable = mkOption {
+          type = types.bool;
+          default = false;
+          description = ''
+            Whether to enable volume and capture control with keyboard media keys.
+
+            Enabling this will turn on <option>services.actkbd</option>.
+          '';
+        };
+
+        volumeStep = mkOption {
+          type = types.string;
+          default = "1";
+          example = "1%";
+          description = ''
+            The value by which to increment/decrement volume on media keys.
+
+            See amixer(1) for allowed values.
+          '';
+        };
+
+      };
+
     };
 
   };
@@ -90,17 +105,17 @@ in
         };
       };
 
-    services.actkbd = mkIf config.sound.enableMediaKeys {
+    services.actkbd = mkIf config.sound.mediaKeys.enable {
       enable = true;
       bindings = [
         # "Mute" media key
         { keys = [ 113 ]; events = [ "key" ];       command = "${alsaUtils}/bin/amixer -q set Master toggle"; }
 
         # "Lower Volume" media key
-        { keys = [ 114 ]; events = [ "key" "rep" ]; command = "${alsaUtils}/bin/amixer -q set Master 1- unmute"; }
+        { keys = [ 114 ]; events = [ "key" "rep" ]; command = "${alsaUtils}/bin/amixer -q set Master ${config.sound.mediaKeys.volumeStep}- unmute"; }
 
         # "Raise Volume" media key
-        { keys = [ 115 ]; events = [ "key" "rep" ]; command = "${alsaUtils}/bin/amixer -q set Master 1+ unmute"; }
+        { keys = [ 115 ]; events = [ "key" "rep" ]; command = "${alsaUtils}/bin/amixer -q set Master ${config.sound.mediaKeys.volumeStep}+ unmute"; }
 
         # "Mic Mute" media key
         { keys = [ 190 ]; events = [ "key" ];       command = "${alsaUtils}/bin/amixer -q set Capture toggle"; }
diff --git a/nixos/modules/services/audio/mopidy.nix b/nixos/modules/services/audio/mopidy.nix
index 029b14ab472..c0a0f037429 100644
--- a/nixos/modules/services/audio/mopidy.nix
+++ b/nixos/modules/services/audio/mopidy.nix
@@ -21,13 +21,7 @@ in {
 
     services.mopidy = {
 
-      enable = mkOption {
-        default = false;
-        type = types.bool;
-        description = ''
-          Whether to enable Mopidy, a music player daemon.
-        '';
-      };
+      enable = mkEnableOption "Mopidy, a music player daemon";
 
       dataDir = mkOption {
         default = "/var/lib/mopidy";
diff --git a/nixos/modules/services/audio/mpd.nix b/nixos/modules/services/audio/mpd.nix
index 5d5fef66794..a89215d7382 100644
--- a/nixos/modules/services/audio/mpd.nix
+++ b/nixos/modules/services/audio/mpd.nix
@@ -33,6 +33,7 @@ in {
     services.mpd = {
 
       enable = mkOption {
+        type = types.bool;
         default = false;
         description = ''
           Whether to enable MPD, the music player daemon.
@@ -40,6 +41,7 @@ in {
       };
 
       musicDirectory = mkOption {
+        type = types.path;
         default = "${cfg.dataDir}/music";
         description = ''
           The directory where mpd reads music from.
@@ -47,6 +49,7 @@ in {
       };
 
       extraConfig = mkOption {
+        type = types.lines;
         default = "";
         description = ''
           Extra directives added to to the end of MPD's configuration file,
@@ -56,6 +59,7 @@ in {
       };
 
       dataDir = mkOption {
+        type = types.path;
         default = "/var/lib/mpd";
         description = ''
           The directory where MPD stores its state, tag cache,
@@ -64,11 +68,13 @@ in {
       };
 
       user = mkOption {
+        type = types.str;
         default = "mpd";
         description = "User account under which MPD runs.";
       };
 
       group = mkOption {
+        type = types.str;
         default = "mpd";
         description = "Group account under which MPD runs.";
       };
@@ -76,15 +82,17 @@ in {
       network = {
 
         listenAddress = mkOption {
-          default = "any";
+          type = types.str;
+          default = "127.0.0.1";
+          example = "any";
           description = ''
-            This setting sets the address for the daemon to listen on. Careful attention
-            should be paid if this is assigned to anything other then the default, any.
-            This setting can deny access to control of the daemon.
+            The address for the daemon to listen on.
+            Use <literal>any</literal> to listen on all addresses.
           '';
         };
 
         port = mkOption {
+          type = types.int;
           default = 6600;
           description = ''
             This setting is the TCP port that is desired for the daemon to get assigned
@@ -114,12 +122,12 @@ in {
       after = [ "network.target" "sound.target" ];
       description = "Music Player Daemon";
       wantedBy = [ "multi-user.target" ];
-      path = [ pkgs.mpd ];
+
       preStart = "mkdir -p ${cfg.dataDir} && chown -R ${cfg.user}:${cfg.group} ${cfg.dataDir}";
-      script = "exec mpd --no-daemon ${mpdConf}";
       serviceConfig = {
         User = "${cfg.user}";
         PermissionsStartOnly = true;
+        ExecStart = "${pkgs.mpd}/bin/mpd --no-daemon ${mpdConf}";
       };
     };
 
diff --git a/nixos/modules/services/audio/ympd.nix b/nixos/modules/services/audio/ympd.nix
new file mode 100644
index 00000000000..d34c1c9d83c
--- /dev/null
+++ b/nixos/modules/services/audio/ympd.nix
@@ -0,0 +1,57 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.ympd;
+in {
+
+  ###### interface
+
+  options = {
+
+    services.ympd = {
+
+      enable = mkEnableOption "ympd, the MPD Web GUI";
+
+      webPort = mkOption {
+        type = types.string;
+        default = "8080";
+        description = "The port where ympd's web interface will be available.";
+        example = "ssl://8080:/path/to/ssl-private-key.pem";
+      };
+
+      mpd = {
+        host = mkOption {
+          type = types.string;
+          default = "localhost";
+          description = "The host where MPD is listening.";
+          example = "localhost";
+        };
+
+        port = mkOption {
+          type = types.int;
+          default = config.services.mpd.network.port;
+          description = "The port where MPD is listening.";
+          example = 6600;
+        };
+      };
+
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    systemd.services.ympd = {
+      description = "Standalone MPD Web GUI written in C";
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig.ExecStart = "${pkgs.ympd}/bin/ympd --host ${cfg.mpd.host} --port ${toString cfg.mpd.port} --webport ${cfg.webPort} --user nobody";
+    };
+
+  };
+
+}
diff --git a/nixos/modules/services/backup/bacula.nix b/nixos/modules/services/backup/bacula.nix
index 8a26aae75fe..340b0cf0723 100644
--- a/nixos/modules/services/backup/bacula.nix
+++ b/nixos/modules/services/backup/bacula.nix
@@ -198,8 +198,7 @@ in {
         description = ''
           This option defines director resources in Bacula File Daemon.
         '';
-        type = types.attrsOf types.optionSet;
-        options = [ directorOptions ];
+        type = with types; attrsOf (submodule directorOptions);
       };
 
       extraClientConfig = mkOption {
@@ -253,8 +252,7 @@ in {
         description = ''
           This option defines Director resources in Bacula Storage Daemon.
         '';
-        type = types.attrsOf types.optionSet;
-        options = [ directorOptions ];
+        type = with types; attrsOf (submodule directorOptions);
       };
 
       device = mkOption {
@@ -262,8 +260,7 @@ in {
         description = ''
           This option defines Device resources in Bacula Storage Daemon.
         '';
-        type = types.attrsOf types.optionSet;
-        options = [ deviceOptions ];
+        type = with types; attrsOf (submodule deviceOptions);
       };
  
       extraStorageConfig = mkOption {
@@ -343,6 +340,7 @@ in {
 
       extraConfig = mkOption {
         default = "";
+        type = types.lines;
         description = ''
           Extra configuration for Bacula Director Daemon.
         '';
diff --git a/nixos/modules/services/backup/crashplan.nix b/nixos/modules/services/backup/crashplan.nix
index 38cf8eb72fb..d0af2e416b6 100644
--- a/nixos/modules/services/backup/crashplan.nix
+++ b/nixos/modules/services/backup/crashplan.nix
@@ -49,7 +49,7 @@ with lib;
         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
+        for x in app.asar bin install.vars lang lib libc42archive64.so libc52archive.so libjniwrap64.so libjniwrap.so libjtux64.so libjtux.so libleveldb64.so libleveldb.so libmd564.so libmd5.so share skin upgrade; do
           rm -f ${crashplan.vardir}/$x;
           ln -sf ${crashplan}/$x ${crashplan.vardir}/$x;
         done
diff --git a/nixos/modules/services/backup/rsnapshot.nix b/nixos/modules/services/backup/rsnapshot.nix
index ce628a72036..16815bcc860 100644
--- a/nixos/modules/services/backup/rsnapshot.nix
+++ b/nixos/modules/services/backup/rsnapshot.nix
@@ -7,11 +7,14 @@ let
   cfgfile = pkgs.writeText "rsnapshot.conf" ''
     config_version	1.2
     cmd_cp	${pkgs.coreutils}/bin/cp
+    cmd_rm	${pkgs.coreutils}/bin/rm
     cmd_rsync	${pkgs.rsync}/bin/rsync
     cmd_ssh	${pkgs.openssh}/bin/ssh
     cmd_logger	${pkgs.inetutils}/bin/logger
     cmd_du	${pkgs.coreutils}/bin/du
+    cmd_rsnapshot_diff	${pkgs.rsnapshot}/bin/rsnapshot-diff
     lockfile	/run/rsnapshot.pid
+    link_dest	1
 
     ${cfg.extraConfig}
   '';
diff --git a/nixos/modules/services/backup/tarsnap.nix b/nixos/modules/services/backup/tarsnap.nix
index 24892a2a59a..67112343c33 100644
--- a/nixos/modules/services/backup/tarsnap.nix
+++ b/nixos/modules/services/backup/tarsnap.nix
@@ -1,25 +1,25 @@
-{ config, lib, pkgs, ... }:
+{ config, lib, pkgs, utils, ... }:
 
 with lib;
 
 let
-  cfg = config.services.tarsnap;
+  gcfg = config.services.tarsnap;
 
   configFile = name: cfg: ''
-    cachedir ${config.services.tarsnap.cachedir}/${name}
-    keyfile  ${cfg.keyfile}
+    keyfile ${cfg.keyfile}
+    ${optionalString (cfg.cachedir != null) "cachedir ${cfg.cachedir}"}
     ${optionalString cfg.nodump "nodump"}
     ${optionalString cfg.printStats "print-stats"}
     ${optionalString cfg.printStats "humanize-numbers"}
     ${optionalString (cfg.checkpointBytes != null) ("checkpoint-bytes "+cfg.checkpointBytes)}
     ${optionalString cfg.aggressiveNetworking "aggressive-networking"}
-    ${concatStringsSep "\n" (map (v: "exclude "+v) cfg.excludes)}
-    ${concatStringsSep "\n" (map (v: "include "+v) cfg.includes)}
+    ${concatStringsSep "\n" (map (v: "exclude ${v}") cfg.excludes)}
+    ${concatStringsSep "\n" (map (v: "include ${v}") cfg.includes)}
     ${optionalString cfg.lowmem "lowmem"}
     ${optionalString cfg.verylowmem "verylowmem"}
-    ${optionalString (cfg.maxbw != null) ("maxbw "+toString cfg.maxbw)}
-    ${optionalString (cfg.maxbwRateUp != null) ("maxbw-rate-up "+toString cfg.maxbwRateUp)}
-    ${optionalString (cfg.maxbwRateDown != null) ("maxbw-rate-down "+toString cfg.maxbwRateDown)}
+    ${optionalString (cfg.maxbw != null) "maxbw ${toString cfg.maxbw}"}
+    ${optionalString (cfg.maxbwRateUp != null) "maxbw-rate-up ${toString cfg.maxbwRateUp}"}
+    ${optionalString (cfg.maxbwRateDown != null) "maxbw-rate-down ${toString cfg.maxbwRateDown}"}
   '';
 in
 {
@@ -60,34 +60,13 @@ in
         '';
       };
 
-      cachedir = mkOption {
-        type    = types.nullOr types.path;
-        default = "/var/cache/tarsnap";
-        description = ''
-          The cache allows tarsnap to identify previously stored data
-          blocks, reducing archival time and bandwidth usage.
-
-          Should the cache become desynchronized or corrupted, tarsnap
-          will refuse to run until you manually rebuild the cache with
-          <command>tarsnap --fsck</command>.
-
-          Note that each individual archive (specified below) has its own cache
-          directory specified under <literal>cachedir</literal>; this is because
-          tarsnap locks the cache during backups, meaning multiple services
-          archives cannot be backed up concurrently or overlap with a shared
-          cache.
-
-          Set to <literal>null</literal> to disable caching.
-        '';
-      };
-
       archives = mkOption {
-        type = types.attrsOf (types.submodule (
+        type = types.attrsOf (types.submodule ({ config, ... }:
           {
             options = {
               keyfile = mkOption {
                 type = types.str;
-                default = config.services.tarsnap.keyfile;
+                default = gcfg.keyfile;
                 description = ''
                   Set a specific keyfile for this archive. This defaults to
                   <literal>"/root/tarsnap.key"</literal> if left unspecified.
@@ -107,6 +86,21 @@ in
                 '';
               };
 
+              cachedir = mkOption {
+                type = types.nullOr types.path;
+                default = "/var/cache/tarsnap/${utils.escapeSystemdPath config.keyfile}";
+                description = ''
+                  The cache allows tarsnap to identify previously stored data
+                  blocks, reducing archival time and bandwidth usage.
+
+                  Should the cache become desynchronized or corrupted, tarsnap
+                  will refuse to run until you manually rebuild the cache with
+                  <command>tarsnap --fsck</command>.
+
+                  Set to <literal>null</literal> to disable caching.
+                '';
+              };
+
               nodump = mkOption {
                 type = types.bool;
                 default = true;
@@ -249,7 +243,7 @@ in
               };
 
             gamedata =
-              { directories = [ "/var/lib/minecraft "];
+              { directories = [ "/var/lib/minecraft" ];
                 period      = "*:30";
               };
           }
@@ -262,8 +256,8 @@ in
           archive names are suffixed by a 1 second resolution timestamp.
 
           For each member of the set is created a timer which triggers the
-          instanced <literal>tarsnap@</literal> service unit. You may use
-          <command>systemctl start tarsnap@archive-name</command> to
+          instanced <literal>tarsnap-archive-name</literal> service unit. You may use
+          <command>systemctl start tarsnap-archive-name</command> to
           manually trigger creation of <literal>archive-name</literal> at
           any time.
         '';
@@ -271,63 +265,73 @@ in
     };
   };
 
-  config = mkIf cfg.enable {
+  config = mkIf gcfg.enable {
     assertions =
       (mapAttrsToList (name: cfg:
         { assertion = cfg.directories != [];
           message = "Must specify paths for tarsnap to back up";
-        }) cfg.archives) ++
+        }) gcfg.archives) ++
       (mapAttrsToList (name: cfg:
         { assertion = !(cfg.lowmem && cfg.verylowmem);
           message = "You cannot set both lowmem and verylowmem";
-        }) cfg.archives);
-
-    systemd.services."tarsnap@" = {
-      description = "Tarsnap archive '%i'";
-      requires    = [ "network-online.target" ];
-      after       = [ "network-online.target" ];
-
-      path = [ pkgs.iputils pkgs.tarsnap pkgs.coreutils ];
-
-      # In order for the persistent tarsnap timer to work reliably, we have to
-      # 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 v1-0-0-server.tarsnap.com &> /dev/null; do sleep 3; done";
-      scriptArgs = "%i";
-      script = ''
-        mkdir -p -m 0755 ${dirOf cfg.cachedir}
-        mkdir -p -m 0700 ${cfg.cachedir}
-        chown root:root ${cfg.cachedir}
-        chmod 0700 ${cfg.cachedir}
-        mkdir -p -m 0700 ${cfg.cachedir}/$1
-        DIRS=`cat /etc/tarsnap/$1.dirs`
-        exec tarsnap --configfile /etc/tarsnap/$1.conf -c -f $1-$(date +"%Y%m%d%H%M%S") $DIRS
-      '';
-
-      serviceConfig = {
-        IOSchedulingClass = "idle";
-        NoNewPrivileges = "true";
-        CapabilityBoundingSet = "CAP_DAC_READ_SEARCH";
-        PermissionsStartOnly = "true";
-      };
-    };
+        }) gcfg.archives);
+
+    systemd.services =
+      mapAttrs' (name: cfg: nameValuePair "tarsnap-${name}" {
+        description = "Tarsnap archive '${name}'";
+        requires    = [ "network-online.target" ];
+        after       = [ "network-online.target" ];
+
+        path = [ pkgs.iputils pkgs.tarsnap pkgs.utillinux ];
+
+        # In order for the persistent tarsnap timer to work reliably, we have to
+        # 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 v1-0-0-server.tarsnap.com &> /dev/null; do sleep 3; done
+        '';
+
+        script =
+          let run = ''tarsnap --configfile "/etc/tarsnap/${name}.conf" -c -f "${name}-$(date +"%Y%m%d%H%M%S")" ${concatStringsSep " " cfg.directories}'';
+          in if (cfg.cachedir != null) then ''
+            mkdir -p ${cfg.cachedir}
+            chmod 0700 ${cfg.cachedir}
+
+            ( flock 9
+              if [ ! -e ${cfg.cachedir}/firstrun ]; then
+                ( flock 10
+                  flock -u 9
+                  tarsnap --configfile "/etc/tarsnap/${name}.conf" --fsck
+                  flock 9
+                ) 10>${cfg.cachedir}/firstrun
+              fi
+            ) 9>${cfg.cachedir}/lockf
+
+             exec flock ${cfg.cachedir}/firstrun ${run}
+          '' else "exec ${run}";
+
+        serviceConfig = {
+          Type = "oneshot";
+          IOSchedulingClass = "idle";
+          NoNewPrivileges = "true";
+          CapabilityBoundingSet = [ "CAP_DAC_READ_SEARCH" ];
+          PermissionsStartOnly = "true";
+        };
+      }) gcfg.archives;
 
     # Note: the timer must be Persistent=true, so that systemd will start it even
     # if e.g. your laptop was asleep while the latest interval occurred.
-    systemd.timers = mapAttrs' (name: cfg: nameValuePair "tarsnap@${name}"
+    systemd.timers = mapAttrs' (name: cfg: nameValuePair "tarsnap-${name}"
       { timerConfig.OnCalendar = cfg.period;
         timerConfig.Persistent = "true";
         wantedBy = [ "timers.target" ];
-      }) cfg.archives;
+      }) gcfg.archives;
 
     environment.etc =
-      (mapAttrs' (name: cfg: nameValuePair "tarsnap/${name}.conf"
+      mapAttrs' (name: cfg: nameValuePair "tarsnap/${name}.conf"
         { text = configFile name cfg;
-        }) cfg.archives) //
-      (mapAttrs' (name: cfg: nameValuePair "tarsnap/${name}.dirs"
-        { text = concatStringsSep " " cfg.directories;
-        }) cfg.archives);
+        }) gcfg.archives;
 
     environment.systemPackages = [ pkgs.tarsnap ];
   };
diff --git a/nixos/modules/services/cluster/fleet.nix b/nixos/modules/services/cluster/fleet.nix
index 78d4ea93c49..ec03be39594 100644
--- a/nixos/modules/services/cluster/fleet.nix
+++ b/nixos/modules/services/cluster/fleet.nix
@@ -28,7 +28,7 @@ in {
 
     etcdServers = mkOption {
       type = types.listOf types.str;
-      default = [ "http://127.0.0.1:4001" ];
+      default = [ "http://127.0.0.1:2379" ];
       description = ''
         Fleet list of etcd endpoints to use.
       '';
diff --git a/nixos/modules/services/cluster/kubernetes.nix b/nixos/modules/services/cluster/kubernetes.nix
index 42efde36678..fbf7412a6cd 100644
--- a/nixos/modules/services/cluster/kubernetes.nix
+++ b/nixos/modules/services/cluster/kubernetes.nix
@@ -5,14 +5,77 @@ with lib;
 let
   cfg = config.services.kubernetes;
 
+  skipAttrs = attrs: map (filterAttrs (k: v: k != "enable"))
+    (filter (v: !(hasAttr "enable" v) || v.enable) attrs);
+
+  infraContainer = pkgs.dockerTools.buildImage {
+    name = "pause";
+    tag = "latest";
+    contents = cfg.package.pause;
+    config.Cmd = "/bin/pause";
+  };
+
+  kubeconfig = pkgs.writeText "kubeconfig" (builtins.toJSON {
+    apiVersion = "v1";
+    kind = "Config";
+    clusters = [{
+      name = "local";
+      cluster.certificate-authority = cfg.kubeconfig.caFile;
+      cluster.server = cfg.kubeconfig.server;
+    }];
+    users = [{
+      name = "kubelet";
+      user = {
+        client-certificate = cfg.kubeconfig.certFile;
+        client-key = cfg.kubeconfig.keyFile;
+      };
+    }];
+    contexts = [{
+      context = {
+        cluster = "local";
+        user = "kubelet";
+      };
+      current-context = "kubelet-context";
+    }];
+  });
+
+  policyFile = pkgs.writeText "kube-policy"
+    concatStringsSep "\n" (map (builtins.toJSON cfg.apiserver.authorizationPolicy));
+
+  cniConfig = pkgs.buildEnv {
+    name = "kubernetes-cni-config";
+    paths = imap (i: entry:
+      pkgs.writeTextDir "${10+i}-${entry.type}.conf" (builtins.toJSON entry)
+    ) cfg.kubelet.cni.config;
+  };
+
+  manifests = pkgs.buildEnv {
+    name = "kubernetes-manifests";
+    paths = mapAttrsToList (name: manifest:
+      pkgs.writeTextDir "${name}.json" (builtins.toJSON manifest)
+    ) cfg.kubelet.manifests;
+  };
+
 in {
 
   ###### interface
 
   options.services.kubernetes = {
+    roles = mkOption {
+      description = ''
+        Kubernetes role that this machine should take.
+
+        Master role will enable etcd, apiserver, scheduler and controller manager
+        services. Node role will enable etcd, docker, kubelet and proxy services.
+      '';
+      default = [];
+      type = types.listOf (types.enum ["master" "node"]);
+    };
+
     package = mkOption {
       description = "Kubernetes package to use.";
       type = types.package;
+      default = pkgs.kubernetes;
     };
 
     verbose = mkOption {
@@ -21,21 +84,56 @@ in {
       type = types.bool;
     };
 
-    etcdServers = mkOption {
-      description = "Kubernetes list of etcd servers to watch.";
-      default = [ "127.0.0.1:4001" ];
-      type = types.listOf types.str;
+    etcd = {
+      servers = mkOption {
+        description = "List of etcd servers. By default etcd is started, except if this option is changed.";
+        default = ["http://127.0.0.1:2379"];
+        type = types.listOf types.str;
+      };
+
+      keyFile = mkOption {
+        description = "Etcd key file";
+        default = null;
+        type = types.nullOr types.path;
+      };
+
+      certFile = mkOption {
+        description = "Etcd cert file";
+        default = null;
+        type = types.nullOr types.path;
+      };
+
+      caFile = mkOption {
+        description = "Etcd ca file";
+        default = null;
+        type = types.nullOr types.path;
+      };
     };
 
-    roles = mkOption {
-      description = ''
-        Kubernetes role that this machine should take.
+    kubeconfig = {
+      server = mkOption {
+        description = "Kubernetes apiserver server address";
+        default = "http://${cfg.apiserver.address}:${toString cfg.apiserver.port}";
+        type = types.str;
+      };
 
-        Master role will enable etcd, apiserver, scheduler and controller manager
-        services. Node role will enable etcd, docker, kubelet and proxy services.
-      '';
-      default = [];
-      type = types.listOf (types.enum ["master" "node"]);
+      caFile = mkOption {
+        description = "Certificate authrority file to use to connect to kuberentes apiserver";
+        type = types.nullOr types.path;
+        default = null;
+      };
+
+      certFile = mkOption {
+        description = "Client certificate file to use to connect to kubernetes";
+        type = types.nullOr types.path;
+        default = null;
+      };
+
+      keyFile = mkOption {
+        description = "Client key file to use to connect to kubernetes";
+        type = types.nullOr types.path;
+        default = null;
+      };
     };
 
     dataDir = mkOption {
@@ -44,12 +142,6 @@ in {
       type = types.path;
     };
 
-    dockerCfg = mkOption {
-      description = "Kubernetes contents of dockercfg file.";
-      default = "";
-      type = types.lines;
-    };
-
     apiserver = {
       enable = mkOption {
         description = "Whether to enable kubernetes apiserver.";
@@ -72,6 +164,16 @@ in {
         type = types.str;
       };
 
+      advertiseAddress = mkOption {
+        description = ''
+          Kubernetes apiserver IP address on which to advertise the apiserver
+          to members of the cluster. This address must be reachable by the rest
+          of the cluster.
+        '';
+        default = null;
+        type = types.nullOr types.str;
+      };
+
       port = mkOption {
         description = "Kubernetes apiserver listening port.";
         default = 8080;
@@ -80,41 +182,36 @@ in {
 
       securePort = mkOption {
         description = "Kubernetes apiserver secure port.";
-        default = 6443;
+        default = 443;
         type = types.int;
       };
 
       tlsCertFile = mkOption {
         description = "Kubernetes apiserver certificate file.";
-        default = "";
-        type = types.str;
+        default = null;
+        type = types.nullOr types.path;
       };
 
-      tlsPrivateKeyFile = mkOption {
+      tlsKeyFile = mkOption {
         description = "Kubernetes apiserver private key file.";
-        default = "";
-        type = types.str;
+        default = null;
+        type = types.nullOr types.path;
       };
 
       clientCaFile = mkOption {
         description = "Kubernetes apiserver CA file for client auth.";
-        default = "";
-        type = types.str;
+        default = null;
+        type = types.nullOr types.path;
       };
 
       tokenAuth = mkOption {
         description = ''
           Kubernetes apiserver token authentication file. See
-          <link xlink:href="http://kubernetes.io/v1.0/docs/admin/authentication.html"/>
+          <link xlink:href="http://kubernetes.io/docs/admin/authentication.html"/>
         '';
-        default = {};
-        example = literalExample ''
-          {
-            alice = "abc123";
-            bob = "xyz987";
-          }
-        '';
-        type = types.attrsOf types.str;
+        default = null;
+        example = ''token,user,uid,"group1,group2,group3"'';
+        type = types.nullOr types.lines;
       };
 
       authorizationMode = mkOption {
@@ -148,13 +245,13 @@ in {
 
       allowPrivileged = mkOption {
         description = "Whether to allow privileged containers on kubernetes.";
-        default = false;
+        default = true;
         type = types.bool;
       };
 
       portalNet = mkOption {
         description = "Kubernetes CIDR notation IP range from which to assign portal IPs";
-        default = "10.10.10.10/16";
+        default = "10.10.10.10/24";
         type = types.str;
       };
 
@@ -171,9 +268,9 @@ in {
       admissionControl = mkOption {
         description = ''
           Kubernetes admission control plugins to use. See
-          <link xlink:href="http://kubernetes.io/v1.0/docs/admin/admission-controllers.html"/>
+          <link xlink:href="http://kubernetes.io/docs/admin/admission-controllers/"/>
         '';
-        default = ["AlwaysAdmit"];
+        default = ["NamespaceLifecycle" "LimitRanger" "ServiceAccount" "ResourceQuota"];
         example = [
           "NamespaceLifecycle" "NamespaceExists" "LimitRanger"
           "SecurityContextDeny" "ServiceAccount" "ResourceQuota"
@@ -181,15 +278,40 @@ in {
         type = types.listOf types.str;
       };
 
-      serviceAccountKey = mkOption {
+      serviceAccountKeyFile = mkOption {
         description = ''
           Kubernetes apiserver PEM-encoded x509 RSA private or public key file,
-          used to verify ServiceAccount tokens.
+          used to verify ServiceAccount tokens. By default tls private key file
+          is used.
         '';
         default = null;
         type = types.nullOr types.path;
       };
 
+      kubeletClientCaFile = mkOption {
+        description = "Path to a cert file for connecting to kubelet";
+        default = null;
+        type = types.nullOr types.path;
+      };
+
+      kubeletClientCertFile = mkOption {
+        description = "Client certificate to use for connections to kubelet";
+        default = null;
+        type = types.nullOr types.path;
+      };
+
+      kubeletClientKeyFile = mkOption {
+        description = "Key to use for connections to kubelet";
+        default = null;
+        type = types.nullOr types.path;
+      };
+
+      kubeletHttps = mkOption {
+        description = "Whether to use https for connections to kubelet";
+        default = true;
+        type = types.bool;
+      };
+
       extraOpts = mkOption {
         description = "Kubernetes apiserver extra command line options.";
         default = "";
@@ -216,10 +338,10 @@ in {
         type = types.int;
       };
 
-      master = mkOption {
-        description = "Kubernetes apiserver address";
-        default = "${cfg.apiserver.address}:${toString cfg.apiserver.port}";
-        type = types.str;
+      leaderElect = mkOption {
+        description = "Whether to start leader election before executing main loop";
+        type = types.bool;
+        default = false;
       };
 
       extraOpts = mkOption {
@@ -248,13 +370,13 @@ in {
         type = types.int;
       };
 
-      master = mkOption {
-        description = "Kubernetes apiserver address";
-        default = "${cfg.apiserver.address}:${toString cfg.apiserver.port}";
-        type = types.str;
+      leaderElect = mkOption {
+        description = "Whether to start leader election before executing main loop";
+        type = types.bool;
+        default = false;
       };
 
-      serviceAccountPrivateKey = mkOption {
+      serviceAccountKeyFile = mkOption {
         description = ''
           Kubernetes controller manager PEM-encoded private RSA key file used to
           sign service account tokens
@@ -272,6 +394,12 @@ in {
         type = types.nullOr types.path;
       };
 
+      clusterCidr = mkOption {
+        description = "Kubernetes controller manager CIDR Range for Pods in cluster";
+        default = "10.10.0.0/16";
+        type = types.str;
+      };
+
       extraOpts = mkOption {
         description = "Kubernetes controller manager extra command line options.";
         default = "";
@@ -292,6 +420,12 @@ in {
         type = types.bool;
       };
 
+      registerSchedulable = mkOption {
+        description = "Register the node as schedulable. No-op if register-node is false.";
+        default = true;
+        type = types.bool;
+      };
+
       address = mkOption {
         description = "Kubernetes kubelet info server listening address.";
         default = "0.0.0.0";
@@ -304,6 +438,18 @@ in {
         type = types.int;
       };
 
+      tlsCertFile = mkOption {
+        description = "File containing x509 Certificate for HTTPS.";
+        default = null;
+        type = types.nullOr types.path;
+      };
+
+      tlsKeyFile = mkOption {
+        description = "File containing x509 private key matching tlsCertFile.";
+        default = null;
+        type = types.nullOr types.path;
+      };
+
       healthz = {
         bind = mkOption {
           description = "Kubernetes kubelet healthz listening address.";
@@ -326,19 +472,10 @@ in {
 
       allowPrivileged = mkOption {
         description = "Whether to allow kubernetes containers to request privileged mode.";
-        default = false;
+        default = true;
         type = types.bool;
       };
 
-      apiServers = mkOption {
-        description = ''
-          Kubernetes kubelet list of Kubernetes API servers for publishing events,
-          and reading pods and services.
-        '';
-        default = ["${cfg.apiserver.address}:${toString cfg.apiserver.port}"];
-        type = types.listOf types.str;
-      };
-
       cadvisorPort = mkOption {
         description = "Kubernetes kubelet local cadvisor port.";
         default = 4194;
@@ -347,16 +484,62 @@ in {
 
       clusterDns = mkOption {
         description = "Use alternative dns.";
-        default = "";
+        default = "10.10.0.1";
         type = types.str;
       };
 
       clusterDomain = mkOption {
         description = "Use alternative domain.";
-        default = "kubernetes.io";
+        default = "cluster.local";
         type = types.str;
       };
 
+      networkPlugin = mkOption {
+        description = "Network plugin to use by kubernetes";
+        type = types.nullOr (types.enum ["cni" "kubenet"]);
+        default = "kubenet";
+      };
+
+      cni = {
+        packages = mkOption {
+          description = "List of network plugin packages to install";
+          type = types.listOf types.package;
+          default = [];
+        };
+
+        config = mkOption {
+          description = "Kubernetes CNI configuration";
+          type = types.listOf types.attrs;
+          default = [];
+          example = literalExample ''
+            [{
+              "cniVersion": "0.2.0",
+              "name": "mynet",
+              "type": "bridge",
+              "bridge": "cni0",
+              "isGateway": true,
+              "ipMasq": true,
+              "ipam": {
+                  "type": "host-local",
+                  "subnet": "10.22.0.0/16",
+                  "routes": [
+                      { "dst": "0.0.0.0/0" }
+                  ]
+              }
+            } {
+              "cniVersion": "0.2.0",
+              "type": "loopback"
+            }]
+          '';
+        };
+      };
+
+      manifests = mkOption {
+        description = "List of manifests to bootstrap with kubelet";
+        type = types.attrsOf types.attrs;
+        default = {};
+      };
+
       extraOpts = mkOption {
         description = "Kubernetes kubelet extra command line options.";
         default = "";
@@ -377,12 +560,6 @@ in {
         type = types.str;
       };
 
-      master = mkOption {
-        description = "Kubernetes apiserver address";
-        default = "${cfg.apiserver.address}:${toString cfg.apiserver.port}";
-        type = types.str;
-      };
-
       extraOpts = mkOption {
         description = "Kubernetes proxy extra command line options.";
         default = "";
@@ -390,23 +567,23 @@ in {
       };
     };
 
-    kube2sky = {
-      enable = mkEnableOption "Whether to enable kube2sky dns service.";
+    dns = {
+      enable = mkEnableOption "kubernetes dns service.";
 
-      domain = mkOption  {
-        description = "Kuberntes kube2sky domain under which all DNS names will be hosted.";
-        default = cfg.kubelet.clusterDomain;
-        type = types.str;
+      port = mkOption {
+        description = "Kubernetes dns listening port";
+        default = 53;
+        type = types.int;
       };
 
-      master = mkOption {
-        description = "Kubernetes apiserver address";
-        default = "${cfg.apiserver.address}:${toString cfg.apiserver.port}";
+      domain = mkOption  {
+        description = "Kuberntes dns domain under which to create names.";
+        default = cfg.kubelet.clusterDomain;
         type = types.str;
       };
 
       extraOpts = mkOption {
-        description = "Kubernetes kube2sky extra command line options.";
+        description = "Kubernetes dns extra command line options.";
         default = "";
         type = types.str;
       };
@@ -416,50 +593,118 @@ in {
   ###### implementation
 
   config = mkMerge [
+    (mkIf cfg.kubelet.enable {
+      systemd.services.kubelet = {
+        description = "Kubernetes Kubelet Service";
+        wantedBy = [ "multi-user.target" ];
+        after = [ "network.target" "docker.service" "kube-apiserver.service" ];
+        path = with pkgs; [ gitMinimal openssh docker utillinux iproute ethtool thin-provisioning-tools iptables ];
+        preStart = ''
+          docker load < ${infraContainer}
+          rm /opt/cni/bin/* || true
+          ${concatMapStringsSep "\n" (p: "ln -fs ${p.plugins}/* /opt/cni/bin") cfg.kubelet.cni.packages}
+        '';
+        serviceConfig = {
+          ExecStart = ''${cfg.package}/bin/kubelet \
+            --pod-manifest-path=${manifests} \
+            --kubeconfig=${kubeconfig} \
+            --require-kubeconfig \
+            --address=${cfg.kubelet.address} \
+            --port=${toString cfg.kubelet.port} \
+            --register-node=${if cfg.kubelet.registerNode then "true" else "false"} \
+            --register-schedulable=${if cfg.kubelet.registerSchedulable then "true" else "false"} \
+            ${optionalString (cfg.kubelet.tlsCertFile != null)
+              "--tls-cert-file=${cfg.kubelet.tlsCertFile}"} \
+            ${optionalString (cfg.kubelet.tlsKeyFile != null)
+              "--tls-private-key-file=${cfg.kubelet.tlsKeyFile}"} \
+            --healthz-bind-address=${cfg.kubelet.healthz.bind} \
+            --healthz-port=${toString cfg.kubelet.healthz.port} \
+            --hostname-override=${cfg.kubelet.hostname} \
+            --allow-privileged=${if cfg.kubelet.allowPrivileged then "true" else "false"} \
+            --root-dir=${cfg.dataDir} \
+            --cadvisor_port=${toString cfg.kubelet.cadvisorPort} \
+            ${optionalString (cfg.kubelet.clusterDns != "")
+              "--cluster-dns=${cfg.kubelet.clusterDns}"} \
+            ${optionalString (cfg.kubelet.clusterDomain != "")
+              "--cluster-domain=${cfg.kubelet.clusterDomain}"} \
+            --pod-infra-container-image=pause \
+            ${optionalString (cfg.kubelet.networkPlugin != null)
+              "--network-plugin=${cfg.kubelet.networkPlugin}"} \
+            --cni-conf-dir=${cniConfig} \
+            --reconcile-cidr \
+            --hairpin-mode=hairpin-veth \
+            ${optionalString cfg.verbose "--v=6 --log_flush_frequency=1s"} \
+            ${cfg.kubelet.extraOpts}
+          '';
+          WorkingDirectory = cfg.dataDir;
+        };
+      };
+
+      environment.etc = mapAttrs' (name: manifest:
+        nameValuePair "kubernetes/manifests/${name}.json" {
+          text = builtins.toJSON manifest;
+          mode = "0755";
+        }
+      ) cfg.kubelet.manifests;
+
+      # Allways include cni plugins
+      services.kubernetes.kubelet.cni.packages = [pkgs.cni];
+    })
+
     (mkIf cfg.apiserver.enable {
       systemd.services.kube-apiserver = {
-        description = "Kubernetes Api Server";
+        description = "Kubernetes Kubelet Service";
         wantedBy = [ "multi-user.target" ];
-        requires = ["kubernetes-setup.service"];
-        after = [ "network-interfaces.target" "etcd.service" ];
+        after = [ "network.target" "docker.service" ];
         serviceConfig = {
-          ExecStart = let
-            authorizationPolicyFile =
-              pkgs.writeText "kubernetes-policy"
-                (builtins.toJSON cfg.apiserver.authorizationPolicy);
-            tokenAuthFile =
-              pkgs.writeText "kubernetes-auth"
-                (concatImapStringsSep "\n" (i: v: v + "," + (toString i))
-                    (mapAttrsToList (name: token: token + "," + name) cfg.apiserver.tokenAuth));
-          in ''${cfg.package}/bin/kube-apiserver \
-            --etcd-servers=${concatMapStringsSep "," (f: "http://${f}") cfg.etcdServers} \
-            --insecure-bind-address=${cfg.apiserver.address} \
+          ExecStart = ''${cfg.package}/bin/kube-apiserver \
+            --etcd-servers=${concatStringsSep "," cfg.etcd.servers} \
+            ${optionalString (cfg.etcd.caFile != null)
+              "--etcd-cafile=${cfg.etcd.caFile}"} \
+            ${optionalString (cfg.etcd.certFile != null)
+              "--etcd-certfile=${cfg.etcd.certFile}"} \
+            ${optionalString (cfg.etcd.keyFile != null)
+              "--etcd-keyfile=${cfg.etcd.keyFile}"} \
             --insecure-port=${toString cfg.apiserver.port} \
-            --bind-address=${cfg.apiserver.publicAddress} \
+            --bind-address=0.0.0.0 \
+            ${optionalString (cfg.apiserver.advertiseAddress != null)
+              "--advertise-address=${cfg.apiserver.advertiseAddress}"} \
             --allow-privileged=${if cfg.apiserver.allowPrivileged then "true" else "false"} \
-            ${optionalString (cfg.apiserver.tlsCertFile!="")
+            ${optionalString (cfg.apiserver.tlsCertFile != null)
               "--tls-cert-file=${cfg.apiserver.tlsCertFile}"} \
-            ${optionalString (cfg.apiserver.tlsPrivateKeyFile!="")
-              "--tls-private-key-file=${cfg.apiserver.tlsPrivateKeyFile}"} \
-            ${optionalString (cfg.apiserver.tokenAuth!=[])
-              "--token-auth-file=${tokenAuthFile}"} \
-            ${optionalString (cfg.apiserver.clientCaFile!="")
+            ${optionalString (cfg.apiserver.tlsKeyFile != null)
+              "--tls-private-key-file=${cfg.apiserver.tlsKeyFile}"} \
+            ${optionalString (cfg.apiserver.tokenAuth != null)
+              "--token-auth-file=${cfg.apiserver.tokenAuth}"} \
+            --kubelet-https=${if cfg.apiserver.kubeletHttps then "true" else "false"} \
+            ${optionalString (cfg.apiserver.kubeletClientCaFile != null)
+              "--kubelet-certificate-authority=${cfg.apiserver.kubeletClientCaFile}"} \
+            ${optionalString (cfg.apiserver.kubeletClientCertFile != null)
+              "--kubelet-client-certificate=${cfg.apiserver.kubeletClientCertFile}"} \
+            ${optionalString (cfg.apiserver.kubeletClientKeyFile != null)
+              "--kubelet-client-key=${cfg.apiserver.kubeletClientKeyFile}"} \
+            ${optionalString (cfg.apiserver.clientCaFile != null)
               "--client-ca-file=${cfg.apiserver.clientCaFile}"} \
             --authorization-mode=${cfg.apiserver.authorizationMode} \
             ${optionalString (cfg.apiserver.authorizationMode == "ABAC")
-              "--authorization-policy-file=${authorizationPolicyFile}"} \
+              "--authorization-policy-file=${policyFile}"} \
             --secure-port=${toString cfg.apiserver.securePort} \
             --service-cluster-ip-range=${cfg.apiserver.portalNet} \
-            ${optionalString (cfg.apiserver.runtimeConfig!="")
+            ${optionalString (cfg.apiserver.runtimeConfig != "")
               "--runtime-config=${cfg.apiserver.runtimeConfig}"} \
             --admission_control=${concatStringsSep "," cfg.apiserver.admissionControl} \
-            ${optionalString (cfg.apiserver.serviceAccountKey!=null)
-              "--service-account-key-file=${cfg.apiserver.serviceAccountKey}"} \
-            --logtostderr=true \
-            ${optionalString cfg.verbose "--v=6 --log-flush-frequency=1s"} \
+            ${optionalString (cfg.apiserver.serviceAccountKeyFile!=null)
+              "--service-account-key-file=${cfg.apiserver.serviceAccountKeyFile}"} \
+            ${optionalString cfg.verbose "--v=6"} \
+            ${optionalString cfg.verbose "--log-flush-frequency=1s"} \
             ${cfg.apiserver.extraOpts}
           '';
+          WorkingDirectory = cfg.dataDir;
           User = "kubernetes";
+          Group = "kubernetes";
+          AmbientCapabilities = "cap_net_bind_service";
+          Restart = "on-failure";
+          RestartSec = 5;
         };
       };
     })
@@ -468,17 +713,20 @@ in {
       systemd.services.kube-scheduler = {
         description = "Kubernetes Scheduler Service";
         wantedBy = [ "multi-user.target" ];
-        after = [ "network-interfaces.target" "kubernetes-apiserver.service" ];
+        after = [ "kube-apiserver.service" ];
         serviceConfig = {
           ExecStart = ''${cfg.package}/bin/kube-scheduler \
             --address=${cfg.scheduler.address} \
             --port=${toString cfg.scheduler.port} \
-            --master=${cfg.scheduler.master} \
-            --logtostderr=true \
-            ${optionalString cfg.verbose "--v=6 --log-flush-frequency=1s"} \
+            --leader-elect=${if cfg.scheduler.leaderElect then "true" else "false"} \
+            --kubeconfig=${kubeconfig} \
+            ${optionalString cfg.verbose "--v=6"} \
+            ${optionalString cfg.verbose "--log-flush-frequency=1s"} \
             ${cfg.scheduler.extraOpts}
           '';
+          WorkingDirectory = cfg.dataDir;
           User = "kubernetes";
+          Group = "kubernetes";
         };
       };
     })
@@ -487,113 +735,94 @@ in {
       systemd.services.kube-controller-manager = {
         description = "Kubernetes Controller Manager Service";
         wantedBy = [ "multi-user.target" ];
-        after = [ "network-interfaces.target" "kubernetes-apiserver.service" ];
+        after = [ "kube-apiserver.service" ];
         serviceConfig = {
           ExecStart = ''${cfg.package}/bin/kube-controller-manager \
             --address=${cfg.controllerManager.address} \
             --port=${toString cfg.controllerManager.port} \
-            --master=${cfg.controllerManager.master} \
-            ${optionalString (cfg.controllerManager.serviceAccountPrivateKey!=null)
-              "--service-account-private-key-file=${cfg.controllerManager.serviceAccountPrivateKey}"} \
+            --kubeconfig=${kubeconfig} \
+            --leader-elect=${if cfg.controllerManager.leaderElect then "true" else "false"} \
+            ${if (cfg.controllerManager.serviceAccountKeyFile!=null)
+              then "--service-account-private-key-file=${cfg.controllerManager.serviceAccountKeyFile}"
+              else "--service-account-private-key-file=/var/run/kubernetes/apiserver.key"} \
             ${optionalString (cfg.controllerManager.rootCaFile!=null)
               "--root-ca-file=${cfg.controllerManager.rootCaFile}"} \
-            --logtostderr=true \
-            ${optionalString cfg.verbose "--v=6 --log-flush-frequency=1s"} \
+            ${optionalString (cfg.controllerManager.clusterCidr!=null)
+              "--cluster-cidr=${cfg.controllerManager.clusterCidr}"} \
+            --allocate-node-cidrs=true \
+            ${optionalString cfg.verbose "--v=6"} \
+            ${optionalString cfg.verbose "--log-flush-frequency=1s"} \
             ${cfg.controllerManager.extraOpts}
           '';
+          WorkingDirectory = cfg.dataDir;
           User = "kubernetes";
+          Group = "kubernetes";
         };
       };
     })
 
-    (mkIf cfg.kubelet.enable {
-      systemd.services.kubelet = {
-        description = "Kubernetes Kubelet Service";
-        wantedBy = [ "multi-user.target" ];
-        requires = ["kubernetes-setup.service"];
-        after = [ "network-interfaces.target" "etcd.service" "docker.service" ];
-        path = [ pkgs.gitMinimal pkgs.openssh ];
-        script = ''
-          export PATH="/bin:/sbin:/usr/bin:/usr/sbin:$PATH"
-          exec ${cfg.package}/bin/kubelet \
-            --api-servers=${concatMapStringsSep "," (f: "http://${f}") cfg.kubelet.apiServers}  \
-            --register-node=${if cfg.kubelet.registerNode then "true" else "false"} \
-            --address=${cfg.kubelet.address} \
-            --port=${toString cfg.kubelet.port} \
-            --healthz-bind-address=${cfg.kubelet.healthz.bind} \
-            --healthz-port=${toString cfg.kubelet.healthz.port} \
-            --hostname-override=${cfg.kubelet.hostname} \
-            --allow-privileged=${if cfg.kubelet.allowPrivileged then "true" else "false"} \
-            --root-dir=${cfg.dataDir} \
-            --cadvisor_port=${toString cfg.kubelet.cadvisorPort} \
-            ${optionalString (cfg.kubelet.clusterDns != "")
-                ''--cluster-dns=${cfg.kubelet.clusterDns}''} \
-            ${optionalString (cfg.kubelet.clusterDomain != "")
-                ''--cluster-domain=${cfg.kubelet.clusterDomain}''} \
-            --logtostderr=true \
-            ${optionalString cfg.verbose "--v=6 --log_flush_frequency=1s"} \
-            ${cfg.kubelet.extraOpts}
-          '';
-        serviceConfig.WorkingDirectory = cfg.dataDir;
-      };
-    })
-
     (mkIf cfg.proxy.enable {
       systemd.services.kube-proxy = {
         description = "Kubernetes Proxy Service";
         wantedBy = [ "multi-user.target" ];
-        after = [ "network-interfaces.target" "etcd.service" ];
+        after = [ "kube-apiserver.service" ];
+        path = [pkgs.iptables];
         serviceConfig = {
           ExecStart = ''${cfg.package}/bin/kube-proxy \
-            --master=${cfg.proxy.master} \
+            --kubeconfig=${kubeconfig} \
             --bind-address=${cfg.proxy.address} \
-            --logtostderr=true \
-            ${optionalString cfg.verbose "--v=6 --log-flush-frequency=1s"} \
-            ${cfg.proxy.extraOpts}
+            ${optionalString cfg.verbose "--v=6"} \
+            ${optionalString cfg.verbose "--log-flush-frequency=1s"} \
+            ${cfg.controllerManager.extraOpts}
           '';
-          Restart = "always"; # Retry connection
-          RestartSec = "5s";
+          WorkingDirectory = cfg.dataDir;
         };
       };
     })
 
-    (mkIf cfg.kube2sky.enable {
-      systemd.services.kube2sky = {
-        description = "Kubernetes Dns Bridge Service";
+    (mkIf cfg.dns.enable {
+      systemd.services.kube-dns = {
+        description = "Kubernetes Dns Service";
         wantedBy = [ "multi-user.target" ];
-        after = [ "network.target" "skydns.service" "etcd.service" "kubernetes-apiserver.service" ];
+        after = [ "kube-apiserver.service" ];
         serviceConfig = {
-          ExecStart = ''${cfg.package}/bin/kube2sky \
-            -etcd-server=http://${head cfg.etcdServers} \
-            -domain=${cfg.kube2sky.domain} \
-            -kube_master_url=http://${cfg.kube2sky.master} \
-            -logtostderr=true \
-            ${optionalString cfg.verbose "--v=6 --log-flush-frequency=1s"} \
-            ${cfg.kube2sky.extraOpts}
+          ExecStart = ''${cfg.package}/bin/kube-dns \
+            --kubecfg-file=${kubeconfig} \
+            --dns-port=${toString cfg.dns.port} \
+            --domain=${cfg.dns.domain} \
+            ${optionalString cfg.verbose "--v=6"} \
+            ${optionalString cfg.verbose "--log-flush-frequency=1s"} \
+            ${cfg.dns.extraOpts}
           '';
+          WorkingDirectory = cfg.dataDir;
           User = "kubernetes";
+          Group = "kubernetes";
+          AmbientCapabilities = "cap_net_bind_service";
+          SendSIGHUP = true;
         };
       };
     })
 
+    (mkIf cfg.kubelet.enable {
+      boot.kernelModules = ["br_netfilter"];
+    })
+
     (mkIf (any (el: el == "master") cfg.roles) {
+      virtualisation.docker.enable = mkDefault true;
+      services.kubernetes.kubelet.enable = mkDefault true;
+      services.kubernetes.kubelet.allowPrivileged = mkDefault true;
       services.kubernetes.apiserver.enable = mkDefault true;
       services.kubernetes.scheduler.enable = mkDefault true;
       services.kubernetes.controllerManager.enable = mkDefault true;
-      services.kubernetes.kube2sky.enable = mkDefault true;
+      services.etcd.enable = mkDefault (cfg.etcd.servers == ["http://127.0.0.1:2379"]);
     })
 
     (mkIf (any (el: el == "node") cfg.roles) {
       virtualisation.docker.enable = mkDefault true;
+      virtualisation.docker.logDriver = mkDefault "json-file";
       services.kubernetes.kubelet.enable = mkDefault true;
       services.kubernetes.proxy.enable = mkDefault true;
-    })
-
-    (mkIf (any (el: el == "node" || el == "master") cfg.roles) {
-      services.etcd.enable = mkDefault true;
-
-      services.skydns.enable = mkDefault true;
-      services.skydns.domain = mkDefault cfg.kubelet.clusterDomain;
+      services.kubernetes.dns.enable = mkDefault true;
     })
 
     (mkIf (
@@ -601,24 +830,16 @@ in {
         cfg.scheduler.enable ||
         cfg.controllerManager.enable ||
         cfg.kubelet.enable ||
-        cfg.proxy.enable
+        cfg.proxy.enable ||
+        cfg.dns.enable
     ) {
-      systemd.services.kubernetes-setup = {
-        description = "Kubernetes setup.";
-        serviceConfig.Type = "oneshot";
-        script = ''
-          mkdir -p /var/run/kubernetes
-          chown kubernetes /var/lib/kubernetes
-
-          rm ${cfg.dataDir}/.dockercfg || true
-          ln -fs ${pkgs.writeText "kubernetes-dockercfg" cfg.dockerCfg} ${cfg.dataDir}/.dockercfg
-        '';
-      };
-
-      services.kubernetes.package = mkDefault pkgs.kubernetes;
+      systemd.tmpfiles.rules = [
+        "d /opt/cni/bin 0755 root root -"
+        "d /var/run/kubernetes 0755 kubernetes kubernetes -"
+        "d /var/lib/kubernetes 0755 kubernetes kubernetes -"
+      ];
 
       environment.systemPackages = [ cfg.package ];
-
       users.extraUsers = singleton {
         name = "kubernetes";
         uid = config.ids.uids.kubernetes;
@@ -630,6 +851,5 @@ in {
       };
       users.extraGroups.kubernetes.gid = config.ids.gids.kubernetes;
     })
-
   ];
 }
diff --git a/nixos/modules/services/cluster/panamax.nix b/nixos/modules/services/cluster/panamax.nix
index b47ff744fc2..4475e8d8c24 100644
--- a/nixos/modules/services/cluster/panamax.nix
+++ b/nixos/modules/services/cluster/panamax.nix
@@ -46,7 +46,7 @@ in {
 
     fleetctlEndpoint = mkOption {
       type = types.str;
-      default = "http://127.0.0.1:4001";
+      default = "http://127.0.0.1:2379";
       description = ''
         Panamax fleetctl endpoint.
       '';
diff --git a/nixos/modules/services/computing/boinc/client.nix b/nixos/modules/services/computing/boinc/client.nix
new file mode 100644
index 00000000000..91bd463732d
--- /dev/null
+++ b/nixos/modules/services/computing/boinc/client.nix
@@ -0,0 +1,88 @@
+{config, lib, pkgs, ...}:
+
+with lib;
+
+let
+  cfg = config.services.boinc;
+  allowRemoteGuiRpcFlag = optionalString cfg.allowRemoteGuiRpc "--allow_remote_gui_rpc";
+
+in
+  {
+    options.services.boinc = {
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        example = true;
+        description = ''
+          Whether to enable the BOINC distributed computing client. If this
+          option is set to true, the boinc_client daemon will be run as a
+          background service. The boinccmd command can be used to control the
+          daemon.
+        '';
+      };
+
+      package = mkOption {
+        type = types.package;
+        default = pkgs.boinc;
+        defaultText = "pkgs.boinc";
+        description = ''
+          Which BOINC package to use.
+        '';
+      };
+
+      dataDir = mkOption {
+        type = types.path;
+        default = "/var/lib/boinc";
+        description = ''
+          The directory in which to store BOINC's configuration and data files.
+        '';
+      };
+
+      allowRemoteGuiRpc = mkOption {
+        type = types.bool;
+        default = false;
+        example = true;
+        description = ''
+          If set to true, any remote host can connect to and control this BOINC
+          client (subject to password authentication). If instead set to false,
+          only the hosts listed in <varname>dataDir</varname>/remote_hosts.cfg will be allowed to
+          connect.
+
+          See also: <link xlink:href="http://boinc.berkeley.edu/wiki/Controlling_BOINC_remotely#Remote_access"/>
+        '';
+      };
+    };
+
+    config = mkIf cfg.enable {
+      environment.systemPackages = [cfg.package];
+
+      users.users.boinc = {
+        createHome = false;
+        description = "BOINC Client";
+        home = cfg.dataDir;
+        isSystemUser = true;
+      };
+
+      systemd.services.boinc = {
+        description = "BOINC Client";
+        after = ["network.target" "local-fs.target"];
+        wantedBy = ["multi-user.target"];
+        preStart = ''
+          mkdir -p ${cfg.dataDir}
+          chown boinc ${cfg.dataDir}
+        '';
+        script = ''
+          ${cfg.package}/bin/boinc_client --dir ${cfg.dataDir} --redirectio ${allowRemoteGuiRpcFlag}
+        '';
+        serviceConfig = {
+          PermissionsStartOnly = true; # preStart must be run as root
+          User = "boinc";
+          Nice = 10;
+        };
+      };
+    };
+
+    meta = {
+      maintainers = with lib.maintainers; [kierdavis];
+    };
+  }
diff --git a/nixos/modules/services/continuous-integration/buildbot/master.nix b/nixos/modules/services/continuous-integration/buildbot/master.nix
new file mode 100644
index 00000000000..a40be4f546e
--- /dev/null
+++ b/nixos/modules/services/continuous-integration/buildbot/master.nix
@@ -0,0 +1,250 @@
+# NixOS module for Buildbot continous integration server.
+
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.buildbot-master;
+  escapeStr = s: escape ["'"] s;
+  masterCfg = pkgs.writeText "master.cfg" ''
+    from buildbot.plugins import *
+    factory = util.BuildFactory()
+    c = BuildmasterConfig = dict(
+     workers       = [${concatStringsSep "," cfg.workers}],
+     protocols     = { 'pb': {'port': ${cfg.bpPort} } },
+     title         = '${escapeStr cfg.title}',
+     titleURL      = '${escapeStr cfg.titleUrl}',
+     buildbotURL   = '${escapeStr cfg.buildbotUrl}',
+     db            = dict(db_url='${escapeStr cfg.dbUrl}'),
+     www           = dict(port=${toString cfg.port}),
+     change_source = [ ${concatStringsSep "," cfg.changeSource} ],
+     schedulers    = [ ${concatStringsSep "," cfg.schedulers} ],
+     builders      = [ ${concatStringsSep "," cfg.builders} ],
+     status        = [ ${concatStringsSep "," cfg.status} ],
+    )
+    for step in [ ${concatStringsSep "," cfg.factorySteps} ]:
+      factory.addStep(step)
+
+    ${cfg.extraConfig}
+  '';
+
+  configFile = if cfg.masterCfg == null then masterCfg else cfg.masterCfg;
+
+in {
+  options = {
+    services.buildbot-master = {
+
+      factorySteps = mkOption {
+        type = types.listOf types.str;
+        description = "Factory Steps";
+        default = [];
+        example = [
+          "steps.Git(repourl='git://github.com/buildbot/pyflakes.git', mode='incremental')"
+          "steps.ShellCommand(command=['trial', 'pyflakes'])"
+        ];
+      };
+
+      changeSource = mkOption {
+        type = types.listOf types.str;
+        description = "List of Change Sources.";
+        default = [];
+        example = [
+          "changes.GitPoller('git://github.com/buildbot/pyflakes.git', workdir='gitpoller-workdir', branch='master', pollinterval=300)"
+        ];
+      };
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Whether to enable the Buildbot continuous integration server.";
+      };
+
+      extraConfig = mkOption {
+        type = types.str;
+        description = "Extra configuration to append to master.cfg";
+        default = "";
+      };
+
+      masterCfg = mkOption {
+        type = with types; nullOr path;
+        description = ''
+          Optionally pass path to raw master.cfg file.
+          Other options in this configuration will be ignored.
+        '';
+        default = null;
+        example = literalExample ''
+          pkgs.writeText "master.cfg" "BuildmasterConfig = c = {}"
+        '';
+      };
+
+      schedulers = mkOption {
+        type = types.listOf types.str;
+        description = "List of Schedulers.";
+        default = [
+          "schedulers.SingleBranchScheduler(name='all', change_filter=util.ChangeFilter(branch='master'), treeStableTimer=None, builderNames=['runtests'])"
+          "schedulers.ForceScheduler(name='force',builderNames=['runtests'])"
+        ];
+      };
+
+      builders = mkOption {
+        type = types.listOf types.str;
+        description = "List of Builders.";
+        default = [
+          "util.BuilderConfig(name='runtests',workernames=['default-worker'],factory=factory)"
+        ];
+      };
+
+      workers = mkOption {
+        type = types.listOf types.str;
+        description = "List of Workers.";
+        default = [
+          "worker.Worker('default-worker', 'password')"
+        ];
+        example = [ "worker.LocalWorker('default-worker')" ];
+      };
+
+      status = mkOption {
+        default = [];
+        type = types.listOf types.str;
+        description = "List of status notification endpoints.";
+      };
+
+      user = mkOption {
+        default = "buildbot";
+        type = types.str;
+        description = "User the buildbot server should execute under.";
+      };
+
+      group = mkOption {
+        default = "buildbot";
+        type = types.str;
+        description = "Primary group of buildbot user.";
+      };
+
+      extraGroups = mkOption {
+        type = types.listOf types.str;
+        default = [ "nixbld" ];
+        description = "List of extra groups that the buildbot user should be a part of.";
+      };
+
+      home = mkOption {
+        default = "/home/buildbot";
+        type = types.path;
+        description = "Buildbot home directory.";
+      };
+
+      buildbotDir = mkOption {
+        default = "${cfg.home}/master";
+        type = types.path;
+        description = "Specifies the Buildbot directory.";
+      };
+
+      bpPort = mkOption {
+        default = "9989";
+        type = types.string;
+        example = "tcp:10000:interface=127.0.0.1";
+        description = "Port where the master will listen to Buildbot Worker.";
+      };
+
+      listenAddress = mkOption {
+        default = "0.0.0.0";
+        type = types.str;
+        description = "Specifies the bind address on which the buildbot HTTP interface listens.";
+      };
+
+      buildbotUrl = mkOption {
+        default = "http://localhost:8010/";
+        type = types.str;
+        description = "Specifies the Buildbot URL.";
+      };
+
+      title = mkOption {
+        default = "Buildbot";
+        type = types.str;
+        description = "Specifies the Buildbot Title.";
+      };
+
+      titleUrl = mkOption {
+        default = "Buildbot";
+        type = types.str;
+        description = "Specifies the Buildbot TitleURL.";
+      };
+
+      dbUrl = mkOption {
+        default = "sqlite:///state.sqlite";
+        type = types.str;
+        description = "Specifies the database connection string.";
+      };
+
+      port = mkOption {
+        default = 8010;
+        type = types.int;
+        description = "Specifies port number on which the buildbot HTTP interface listens.";
+      };
+
+      package = mkOption {
+        type = types.package;
+        default = pkgs.buildbot-ui;
+        description = ''
+          Package to use for buildbot.
+          <literal>buildbot-full</literal> is required in order to use local workers.
+        '';
+        example = pkgs.buildbot-full;
+      };
+
+      packages = mkOption {
+        default = [ ];
+        example = [ pkgs.git ];
+        type = types.listOf types.package;
+        description = "Packages to add to PATH for the buildbot process.";
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    users.extraGroups = optional (cfg.group == "buildbot") {
+      name = "buildbot";
+    };
+
+    users.extraUsers = optional (cfg.user == "buildbot") {
+      name = "buildbot";
+      description = "buildbot user";
+      isNormalUser = true;
+      createHome = true;
+      home = cfg.home;
+      group = cfg.group;
+      extraGroups = cfg.extraGroups;
+      useDefaultShell = true;
+    };
+
+    systemd.services.buildbot-master = {
+      description = "Buildbot Continuous Integration Server";
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+      path = cfg.packages;
+
+      serviceConfig = {
+        Type = "forking";
+        User = cfg.user;
+        Group = cfg.group;
+        WorkingDirectory = cfg.home;
+        ExecStart = "${cfg.package}/bin/buildbot start ${cfg.buildbotDir}";
+      };
+
+      preStart = ''
+        mkdir -vp ${cfg.buildbotDir}
+        chown -c ${cfg.user}:${cfg.group} ${cfg.buildbotDir}
+        ln -sf ${configFile} ${cfg.buildbotDir}/master.cfg
+        ${cfg.package}/bin/buildbot create-master ${cfg.buildbotDir}
+      '';
+
+      postStart = ''
+        until [[ $(${pkgs.curl}/bin/curl -s --head -w '\n%{http_code}' http://localhost:${toString cfg.port} | tail -n1) =~ ^(200|403)$ ]]; do
+          sleep 1
+        done
+      '';
+    };
+  };
+
+}
diff --git a/nixos/modules/services/continuous-integration/gitlab-runner.nix b/nixos/modules/services/continuous-integration/gitlab-runner.nix
new file mode 100644
index 00000000000..1fe4d28f9f3
--- /dev/null
+++ b/nixos/modules/services/continuous-integration/gitlab-runner.nix
@@ -0,0 +1,51 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.gitlab-runner;
+  configFile = pkgs.writeText "config.toml" cfg.configText;
+in
+{
+  options.services.gitlab-runner = {
+    enable = mkEnableOption "Gitlab Runner";
+
+    configText = mkOption {
+      description = "Verbatim config.toml to use";
+    };
+
+    workDir = mkOption {
+      default = "/var/lib/gitlab-runner";
+      type = types.path;
+      description = "The working directory used";
+    };
+
+  };
+
+  config = mkIf cfg.enable {
+    systemd.services.gitlab-runner = {
+      description = "Gitlab Runner";
+      after = [ "network.target" "docker.service" ];
+      requires = [ "docker.service" ];
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        ExecStart = ''${pkgs.gitlab-runner.bin}/bin/gitlab-runner run \
+          --working-directory ${cfg.workDir} \
+          --config ${configFile} \
+          --service gitlab-runner \
+          --user gitlab-runner \
+        '';
+      };
+    };
+
+    users.extraUsers.gitlab-runner = {
+      group = "gitlab-runner";
+      extraGroups = [ "docker" ];
+      uid = config.ids.uids.gitlab-runner;
+      home = cfg.workDir;
+      createHome = true;
+    };
+
+    users.extraGroups.gitlab-runner.gid = config.ids.gids.gitlab-runner;
+  };
+}
diff --git a/nixos/modules/services/continuous-integration/gocd-agent/default.nix b/nixos/modules/services/continuous-integration/gocd-agent/default.nix
index 21f319f7fcf..05adb18fbe9 100644
--- a/nixos/modules/services/continuous-integration/gocd-agent/default.nix
+++ b/nixos/modules/services/continuous-integration/gocd-agent/default.nix
@@ -37,6 +37,7 @@ in {
 
       packages = mkOption {
         default = [ pkgs.stdenv pkgs.jre pkgs.git config.programs.ssh.package pkgs.nix ];
+        defaultText = "[ pkgs.stdenv pkgs.jre pkgs.git config.programs.ssh.package pkgs.nix ]";
         type = types.listOf types.package;
         description = ''
           Packages to add to PATH for the Go.CD agent process.
@@ -98,7 +99,7 @@ in {
         ];
         description = ''
           Specifies startup command line arguments to pass to Go.CD agent
-          java process.  Example contains debug and gcLog arguments.
+          java process.
         '';
       };
 
diff --git a/nixos/modules/services/continuous-integration/gocd-server/default.nix b/nixos/modules/services/continuous-integration/gocd-server/default.nix
index 2d198630121..07e00f17f1e 100644
--- a/nixos/modules/services/continuous-integration/gocd-server/default.nix
+++ b/nixos/modules/services/continuous-integration/gocd-server/default.nix
@@ -68,6 +68,7 @@ in {
 
       packages = mkOption {
         default = [ pkgs.stdenv pkgs.jre pkgs.git config.programs.ssh.package pkgs.nix ];
+        defaultText = "[ pkgs.stdenv pkgs.jre pkgs.git config.programs.ssh.package pkgs.nix ]";
         type = types.listOf types.package;
         description = ''
           Packages to add to PATH for the Go.CD server's process.
@@ -90,7 +91,7 @@ in {
         '';
       };
 
-      extraOptions = mkOption {
+      startupOptions = mkOption {
         default = [
           "-Xms${cfg.initialJavaHeapSize}"
           "-Xmx${cfg.maxJavaHeapMemory}"
@@ -103,6 +104,15 @@ in {
           "-Dcruise.server.port=${toString cfg.port}"
           "-Dcruise.server.ssl.port=${toString cfg.sslPort}"
         ];
+
+        description = ''
+          Specifies startup command line arguments to pass to Go.CD server
+          java process.
+        '';
+      };
+
+      extraOptions = mkOption {
+        default = [ ];
         example = [ 
           "-X debug" 
           "-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005"
@@ -169,7 +179,8 @@ in {
 
       script = ''
         ${pkgs.git}/bin/git config --global --add http.sslCAinfo /etc/ssl/certs/ca-certificates.crt
-        ${pkgs.jre}/bin/java -server ${concatStringsSep " " cfg.extraOptions} \
+        ${pkgs.jre}/bin/java -server ${concatStringsSep " " cfg.startupOptions} \
+                               ${concatStringsSep " " cfg.extraOptions}  \
                               -jar ${pkgs.gocd-server}/go-server/go.jar
       '';
 
diff --git a/nixos/modules/services/continuous-integration/hydra/default.nix b/nixos/modules/services/continuous-integration/hydra/default.nix
index b1b3404add0..fa550f68b33 100644
--- a/nixos/modules/services/continuous-integration/hydra/default.nix
+++ b/nixos/modules/services/continuous-integration/hydra/default.nix
@@ -343,7 +343,7 @@ in
       { wantedBy = [ "multi-user.target" ];
         requires = [ "hydra-init.service" ];
         after = [ "hydra-init.service" "network.target" ];
-        path = [ pkgs.nettools ];
+        path = [ cfg.package pkgs.nettools ];
         environment = env;
         serviceConfig =
           { ExecStart = "@${cfg.package}/bin/hydra-evaluator hydra-evaluator";
diff --git a/nixos/modules/services/databases/4store-endpoint.nix b/nixos/modules/services/databases/4store-endpoint.nix
index 5c55ef406d5..906cb320df9 100644
--- a/nixos/modules/services/databases/4store-endpoint.nix
+++ b/nixos/modules/services/databases/4store-endpoint.nix
@@ -61,7 +61,9 @@ with lib;
     services.avahi.enable = true;
 
     systemd.services."4store-endpoint" = {
-      wantedBy = [ "ip-up.target" ];
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+
       script = ''
         ${run} '${pkgs.rdf4store}/bin/4s-httpd -D ${cfg.options} ${if cfg.listenAddress!=null then "-H ${cfg.listenAddress}" else "" } -p ${toString cfg.port} ${cfg.database}'
       '';
diff --git a/nixos/modules/services/databases/4store.nix b/nixos/modules/services/databases/4store.nix
index 33e731e9681..62856822f90 100644
--- a/nixos/modules/services/databases/4store.nix
+++ b/nixos/modules/services/databases/4store.nix
@@ -53,7 +53,8 @@ with lib;
     services.avahi.enable = true;
 
     systemd.services."4store" = {
-      wantedBy = [ "ip-up.target" ];
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
 
       preStart = ''
         mkdir -p ${stateDir}/
diff --git a/nixos/modules/services/databases/cassandra.nix b/nixos/modules/services/databases/cassandra.nix
index c98af617587..b43b448ed7e 100644
--- a/nixos/modules/services/databases/cassandra.nix
+++ b/nixos/modules/services/databases/cassandra.nix
@@ -377,7 +377,7 @@ in {
     systemd.services.cassandra = {
       description = "Cassandra Daemon";
       wantedBy = [ "multi-user.target" ];
-      after = [ "network-interfaces.target" ];
+      after = [ "network.target" ];
       environment = cassandraEnvironment;
       restartTriggers = [ cassandraConfFile cassandraLogFile cassandraRackFile ];
       serviceConfig = {
diff --git a/nixos/modules/services/databases/couchdb.nix b/nixos/modules/services/databases/couchdb.nix
index ae0589b399e..d4d231456c5 100644
--- a/nixos/modules/services/databases/couchdb.nix
+++ b/nixos/modules/services/databases/couchdb.nix
@@ -162,7 +162,7 @@ in {
 
         if [ "$(id -u)" = 0 ]; then
           chown ${cfg.user}:${cfg.group} `dirname ${cfg.uriFile}`;
-          (-f ${cfg.uriFile} && chown ${cfg.user}:${cfg.group} ${cfg.uriFile}) || true
+          (test -f ${cfg.uriFile} && chown ${cfg.user}:${cfg.group} ${cfg.uriFile}) || true
           chown ${cfg.user}:${cfg.group} ${cfg.databaseDir}
           chown ${cfg.user}:${cfg.group} ${cfg.viewIndexDir}
           chown ${cfg.user}:${cfg.group} ${cfg.configFile}
diff --git a/nixos/modules/services/databases/influxdb.nix b/nixos/modules/services/databases/influxdb.nix
index e2268bd556e..dd88624f406 100644
--- a/nixos/modules/services/databases/influxdb.nix
+++ b/nixos/modules/services/databases/influxdb.nix
@@ -66,16 +66,16 @@ let
       enabled = false;
     }];
 
-    collectd = {
+    collectd = [{
       enabled = false;
       typesdb = "${pkgs.collectd}/share/collectd/types.db";
       database = "collectd_db";
       port = 25826;
-    };
+    }];
 
-    opentsdb = {
+    opentsdb = [{
       enabled = false;
-    };
+    }];
 
     continuous_queries = {
       enabled = true;
@@ -160,7 +160,7 @@ in
     systemd.services.influxdb = {
       description = "InfluxDB Server";
       wantedBy = [ "multi-user.target" ];
-      after = [ "network-interfaces.target" ];
+      after = [ "network.target" ];
       serviceConfig = {
         ExecStart = ''${cfg.package}/bin/influxd -config "${configFile}"'';
         User = "${cfg.user}";
@@ -171,6 +171,11 @@ in
         mkdir -m 0770 -p ${cfg.dataDir}
         if [ "$(id -u)" = 0 ]; then chown -R ${cfg.user}:${cfg.group} ${cfg.dataDir}; fi
       '';
+      postStart = mkBefore ''
+        until ${pkgs.curl.bin}/bin/curl -s -o /dev/null 'http://127.0.0.1${toString configOptions.http.bind-address}'/ping; do
+          sleep 1;
+        done
+      '';
     };
 
     users.extraUsers = optional (cfg.user == "influxdb") {
diff --git a/nixos/modules/services/databases/monetdb.nix b/nixos/modules/services/databases/monetdb.nix
deleted file mode 100644
index 9f09c71e005..00000000000
--- a/nixos/modules/services/databases/monetdb.nix
+++ /dev/null
@@ -1,88 +0,0 @@
-{ config, lib, pkgs, ... }:
-let
-  cfg = config.services.monetdb;
-  monetdbUser = "monetdb";
-in
-with lib;
-{
-
-  ###### interface
-
-  options = {
-
-    services.monetdb = {
-
-      enable = mkOption {
-        type = types.bool;
-        default = false;
-        description = "Whether to enable MonetDB database server.";
-      };
-
-      package = mkOption {
-        type = types.path;
-        description = "MonetDB package to use.";
-      };
-
-      dbfarmDir = mkOption {
-        type = types.path;
-        default = "/var/lib/monetdb";
-        description = ''
-          Specifies location of Monetdb dbfarm (keeps database and auxiliary files).
-        '';
-      };
-
-      port = mkOption {
-        default = "50000";
-        example = "50000";
-        description = "Port to listen on.";
-      };
-    };
-
-  };
-
-
-  ###### implementation
-
-  config = mkIf cfg.enable {
-
-    users.extraUsers.monetdb = 
-      { name = monetdbUser;
-        uid = config.ids.uids.monetdb;
-        description = "monetdb user";
-        home = cfg.dbfarmDir;
-      };
-
-    users.extraGroups.monetdb.gid = config.ids.gids.monetdb;
-
-    environment.systemPackages = [ cfg.package ];
-
-    systemd.services.monetdb =
-      { description = "MonetDB Server";
-
-        wantedBy = [ "multi-user.target" ];
-
-        after = [ "network.target" ];
-
-        path = [ cfg.package ];
-
-        preStart =
-          ''
-            # Initialise the database.
-            if ! test -e ${cfg.dbfarmDir}/.merovingian_properties; then
-                mkdir -m 0700 -p ${cfg.dbfarmDir}
-                chown -R ${monetdbUser} ${cfg.dbfarmDir}
-                ${cfg.package}/bin/monetdbd create ${cfg.dbfarmDir}
-                ${cfg.package}/bin/monetdbd set port=${cfg.port} ${cfg.dbfarmDir}
-            fi
-          '';
-
-        serviceConfig.ExecStart = "${cfg.package}/bin/monetdbd start -n ${cfg.dbfarmDir}";
-
-        serviceConfig.ExecStop = "${cfg.package}/bin/monetdbd stop ${cfg.dbfarmDir}";
-
-        unitConfig.RequiresMountsFor = "${cfg.dbfarmDir}";
-      };
-
-  };
-
-}
diff --git a/nixos/modules/services/databases/mongodb.nix b/nixos/modules/services/databases/mongodb.nix
index ef9bc46e4a0..38e46a0c6ef 100644
--- a/nixos/modules/services/databases/mongodb.nix
+++ b/nixos/modules/services/databases/mongodb.nix
@@ -12,13 +12,11 @@ let
 
   mongoCnf = pkgs.writeText "mongodb.conf"
   ''
-    bind_ip = ${cfg.bind_ip}
-    ${optionalString cfg.quiet "quiet = true"}
-    dbpath = ${cfg.dbpath}
-    syslog = true
-    fork = true
-    pidfilepath = ${cfg.pidFile}
-    ${optionalString (cfg.replSetName != "") "replSet = ${cfg.replSetName}"}
+    net.bindIp: ${cfg.bind_ip}
+    ${optionalString cfg.quiet "systemLog.quiet: true"}
+    systemLog.destination: syslog
+    storage.dbPath: ${cfg.dbpath}
+    ${optionalString (cfg.replSetName != "") "replication.replSetName: ${cfg.replSetName}"}
     ${cfg.extraConfig}
   '';
 
@@ -84,9 +82,9 @@ in
       extraConfig = mkOption {
         default = "";
         example = ''
-          nojournal = true
+          storage.journal.enabled: false
         '';
-        description = "MongoDB extra configuration";
+        description = "MongoDB extra configuration in YAML format";
       };
     };
 
@@ -112,7 +110,7 @@ in
         after = [ "network.target" ];
 
         serviceConfig = {
-          ExecStart = "${mongodb}/bin/mongod --quiet --config ${mongoCnf}";
+          ExecStart = "${mongodb}/bin/mongod --quiet --config ${mongoCnf} --fork --pidfilepath ${cfg.pidFile}";
           User = cfg.user;
           PIDFile = cfg.pidFile;
           Type = "forking";
diff --git a/nixos/modules/services/databases/mysql.nix b/nixos/modules/services/databases/mysql.nix
index 0b2f99f8fff..fcf1f123cfb 100644
--- a/nixos/modules/services/databases/mysql.nix
+++ b/nixos/modules/services/databases/mysql.nix
@@ -43,6 +43,7 @@ in
     services.mysql = {
 
       enable = mkOption {
+        type = types.bool;
         default = false;
         description = "
           Whether to enable the MySQL server.
@@ -58,16 +59,19 @@ in
       };
 
       port = mkOption {
-        default = "3306";
+        type = types.int;
+        default = 3306;
         description = "Port of MySQL";
       };
 
       user = mkOption {
+        type = types.str;
         default = "mysql";
         description = "User account under which MySQL runs";
       };
 
       dataDir = mkOption {
+        type = types.path;
         default = "/var/mysql"; # !!! should be /var/db/mysql
         description = "Location where MySQL stores its table files";
       };
@@ -78,6 +82,7 @@ in
       };
 
       extraOptions = mkOption {
+        type = types.lines;
         default = "";
         example = ''
           key_buffer_size = 6G
@@ -115,32 +120,39 @@ in
 
       replication = {
         role = mkOption {
+          type = types.enum [ "master" "slave" "none" ];
           default = "none";
-          description = "Role of the MySQL server instance. Can be either: master, slave or none";
+          description = "Role of the MySQL server instance.";
         };
 
         serverId = mkOption {
+          type = types.int;
           default = 1;
           description = "Id of the MySQL server instance. This number must be unique for each instance";
         };
 
         masterHost = mkOption {
+          type = types.str;
           description = "Hostname of the MySQL master server";
         };
 
         slaveHost = mkOption {
+          type = types.str;
           description = "Hostname of the MySQL slave server";
         };
 
         masterUser = mkOption {
+          type = types.str;
           description = "Username of the MySQL replication user";
         };
 
         masterPassword = mkOption {
+          type = types.str;
           description = "Password of the MySQL replication user";
         };
 
         masterPort = mkOption {
+          type = types.int;
           default = 3306;
           description = "Port number on which the MySQL master server runs";
         };
@@ -167,6 +179,7 @@ in
     systemd.services.mysql =
       { description = "MySQL Server";
 
+        after = [ "network.target" ];
         wantedBy = [ "multi-user.target" ];
 
         unitConfig.RequiresMountsFor = "${cfg.dataDir}";
diff --git a/nixos/modules/services/databases/neo4j.nix b/nixos/modules/services/databases/neo4j.nix
index 41b96068590..7b51f1af689 100644
--- a/nixos/modules/services/databases/neo4j.nix
+++ b/nixos/modules/services/databases/neo4j.nix
@@ -5,34 +5,34 @@ with lib;
 let
   cfg = config.services.neo4j;
 
-  serverConfig = pkgs.writeText "neo4j-server.properties" ''
-    org.neo4j.server.database.location=${cfg.dataDir}/data/graph.db
-    org.neo4j.server.webserver.address=${cfg.listenAddress}
-    org.neo4j.server.webserver.port=${toString cfg.port}
+  serverConfig = pkgs.writeText "neo4j.conf" ''
+    dbms.directories.data=${cfg.dataDir}/data
+    dbms.directories.certificates=${cfg.certDir}
+    dbms.directories.logs=${cfg.dataDir}/logs
+    dbms.directories.plugins=${cfg.dataDir}/plugins
+    dbms.connector.http.type=HTTP
+    dbms.connector.http.enabled=true
+    dbms.connector.http.address=${cfg.listenAddress}:${toString cfg.port}
+    ${optionalString cfg.enableBolt ''
+      dbms.connector.bolt.type=BOLT
+      dbms.connector.bolt.enabled=true
+      dbms.connector.bolt.tls_level=OPTIONAL
+      dbms.connector.bolt.address=${cfg.listenAddress}:${toString cfg.boltPort}
+    ''}
     ${optionalString cfg.enableHttps ''
-      org.neo4j.server.webserver.https.enabled=true
-      org.neo4j.server.webserver.https.port=${toString cfg.httpsPort}
-      org.neo4j.server.webserver.https.cert.location=${cfg.cert}
-      org.neo4j.server.webserver.https.key.location=${cfg.key}
-      org.neo4j.server.webserver.https.keystore.location=${cfg.dataDir}/data/keystore
+      dbms.connector.https.type=HTTP
+      dbms.connector.https.enabled=true
+      dbms.connector.https.encryption=TLS
+      dbms.connector.https.address=${cfg.listenAddress}:${toString cfg.httpsPort}
     ''}
-    org.neo4j.server.webadmin.rrdb.location=${cfg.dataDir}/data/rrd
-    org.neo4j.server.webadmin.data.uri=/db/data/
-    org.neo4j.server.webadmin.management.uri=/db/manage/
-    org.neo4j.server.db.tuning.properties=${cfg.package}/share/neo4j/conf/neo4j.properties
-    org.neo4j.server.manage.console_engines=shell
+    dbms.shell.enabled=true
     ${cfg.extraServerConfig}
   '';
 
-  loggingConfig = pkgs.writeText "logging.properties" cfg.loggingConfig;
-
   wrapperConfig = pkgs.writeText "neo4j-wrapper.conf" ''
-    wrapper.java.additional=-Dorg.neo4j.server.properties=${serverConfig}
-    wrapper.java.additional=-Djava.util.logging.config.file=${loggingConfig}
-    wrapper.java.additional=-XX:+UseConcMarkSweepGC
-    wrapper.java.additional=-XX:+CMSClassUnloadingEnabled
-    wrapper.pidfile=${cfg.dataDir}/neo4j-server.pid
-    wrapper.name=neo4j
+    dbms.jvm.additional=-Dunsupported.dbms.udc.source=tarball
+    dbms.jvm.additional=-XX:+UseConcMarkSweepGC
+    dbms.jvm.additional=-XX:+CMSClassUnloadingEnabled
   '';
 
 in {
@@ -65,6 +65,18 @@ in {
       type = types.int;
     };
 
+    enableBolt = mkOption {
+      description = "Enable bolt for Neo4j.";
+      default = true;
+      type = types.bool;
+    };
+
+    boltPort = mkOption {
+      description = "Neo4j port to listen for BOLT traffic.";
+      default = 7687;
+      type = types.int;
+    };
+
     enableHttps = mkOption {
       description = "Enable https for Neo4j.";
       default = false;
@@ -77,15 +89,9 @@ in {
       type = types.int;
     };
 
-    cert = mkOption {
-      description = "Neo4j https certificate.";
-      default = "${cfg.dataDir}/conf/ssl/neo4j.cert";
-      type = types.path;
-    };
-
-    key = mkOption {
-      description = "Neo4j https certificate key.";
-      default = "${cfg.dataDir}/conf/ssl/neo4j.key";
+    certDir = mkOption {
+      description = "Neo4j TLS certificates directory.";
+      default = "${cfg.dataDir}/certificates";
       type = types.path;
     };
 
@@ -95,26 +101,11 @@ in {
       type = types.path;
     };
 
-    loggingConfig = mkOption {
-      description = "Neo4j logging configuration.";
-      default = ''
-        handlers=java.util.logging.ConsoleHandler
-        .level=INFO
-        org.neo4j.server.level=INFO
-
-        java.util.logging.ConsoleHandler.level=INFO
-        java.util.logging.ConsoleHandler.formatter=org.neo4j.server.logging.SimpleConsoleFormatter
-        java.util.logging.ConsoleHandler.filter=org.neo4j.server.logging.NeoLogFilter
-      '';
-      type = types.lines;
-    };
-
     extraServerConfig = mkOption {
       description = "Extra configuration for neo4j server.";
       default = "";
       type = types.lines;
     };
-
   };
 
   ###### implementation
@@ -123,15 +114,19 @@ in {
     systemd.services.neo4j = {
       description = "Neo4j Daemon";
       wantedBy = [ "multi-user.target" ];
-      after = [ "network-interfaces.target" ];
-      environment = { NEO4J_INSTANCE = cfg.dataDir; };
+      after = [ "network.target" ];
+      environment = {
+        NEO4J_HOME = "${cfg.package}/share/neo4j";
+        NEO4J_CONF = "${cfg.dataDir}/conf";
+      };
       serviceConfig = {
         ExecStart = "${cfg.package}/bin/neo4j console";
         User = "neo4j";
         PermissionsStartOnly = true;
       };
       preStart = ''
-        mkdir -m 0700 -p ${cfg.dataDir}/{data/graph.db,conf}
+        mkdir -m 0700 -p ${cfg.dataDir}/{data/graph.db,conf,logs}
+        ln -fs ${serverConfig} ${cfg.dataDir}/conf/neo4j.conf
         ln -fs ${wrapperConfig} ${cfg.dataDir}/conf/neo4j-wrapper.conf
         if [ "$(id -u)" = 0 ]; then chown -R neo4j ${cfg.dataDir}; fi
       '';
@@ -146,5 +141,4 @@ in {
       home = cfg.dataDir;
     };
   };
-
 }
diff --git a/nixos/modules/services/databases/openldap.nix b/nixos/modules/services/databases/openldap.nix
index 9f22aa7c92b..b8e6c0cec3d 100644
--- a/nixos/modules/services/databases/openldap.nix
+++ b/nixos/modules/services/databases/openldap.nix
@@ -53,6 +53,13 @@ in
         description = "The database directory.";
       };
 
+      configDir = mkOption {
+        type = types.nullOr types.path;
+        default = null;
+        description = "Use this optional config directory instead of using slapd.conf";
+        example = "/var/db/slapd.d";
+      };
+
       extraConfig = mkOption {
         type = types.lines;
         default = "";
@@ -96,7 +103,7 @@ in
         mkdir -p ${cfg.dataDir}
         chown -R ${cfg.user}:${cfg.group} ${cfg.dataDir}
       '';
-      serviceConfig.ExecStart = "${openldap.out}/libexec/slapd -u ${cfg.user} -g ${cfg.group} -d 0 -h \"${concatStringsSep " " cfg.urlList}\" -f ${configFile}";
+      serviceConfig.ExecStart = "${openldap.out}/libexec/slapd -u ${cfg.user} -g ${cfg.group} -d 0 -h \"${concatStringsSep " " cfg.urlList}\" ${if cfg.configDir == null then "-f "+configFile else "-F "+cfg.configDir}";
     };
 
     users.extraUsers.openldap =
diff --git a/nixos/modules/services/databases/postgresql.nix b/nixos/modules/services/databases/postgresql.nix
index 9988fc6e63b..24ef4637ec9 100644
--- a/nixos/modules/services/databases/postgresql.nix
+++ b/nixos/modules/services/databases/postgresql.nix
@@ -11,12 +11,14 @@ let
     if cfg.extraPlugins == [] then pg
     else pkgs.buildEnv {
       name = "postgresql-and-plugins-${(builtins.parseDrvName pg.name).version}";
-      paths = [ pg ] ++ cfg.extraPlugins;
+      paths = [ pg pg.lib ] ++ cfg.extraPlugins;
+      buildInputs = [ pkgs.makeWrapper ];
       postBuild =
         ''
           mkdir -p $out/bin
           rm $out/bin/{pg_config,postgres,pg_ctl}
           cp --target-directory=$out/bin ${pg}/bin/{postgres,pg_config,pg_ctl}
+          wrapProgram $out/bin/postgres --set NIX_PGLIBDIR $out/lib
         '';
     };
 
diff --git a/nixos/modules/services/databases/riak-cs.nix b/nixos/modules/services/databases/riak-cs.nix
new file mode 100644
index 00000000000..198efc29222
--- /dev/null
+++ b/nixos/modules/services/databases/riak-cs.nix
@@ -0,0 +1,202 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.riak-cs;
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.riak-cs = {
+
+      enable = mkEnableOption "riak-cs";
+
+      package = mkOption {
+        type = types.package;
+        default = pkgs.riak-cs;
+        defaultText = "pkgs.riak-cs";
+        example = literalExample "pkgs.riak-cs";
+        description = ''
+          Riak package to use.
+        '';
+      };
+
+      nodeName = mkOption {
+        type = types.str;
+        default = "riak-cs@127.0.0.1";
+        description = ''
+          Name of the Erlang node.
+        '';
+      };
+      
+      anonymousUserCreation = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Anonymous user creation.
+        '';
+      };
+
+      riakHost = mkOption {
+        type = types.str;
+        default = "127.0.0.1:8087";
+        description = ''
+          Name of riak hosting service.
+        '';
+      };
+
+      listener = mkOption {
+        type = types.str;
+        default = "127.0.0.1:8080";
+        description = ''
+          Name of Riak CS listening service.
+        '';
+      };
+
+      stanchionHost = mkOption {
+        type = types.str;
+        default = "127.0.0.1:8085";
+        description = ''
+          Name of stanchion hosting service.
+        '';
+      };
+
+      stanchionSsl = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Tell stanchion to use SSL.
+        '';
+      };
+
+      distributedCookie = mkOption {
+        type = types.str;
+        default = "riak";
+        description = ''
+          Cookie for distributed node communication.  All nodes in the
+          same cluster should use the same cookie or they will not be able to
+          communicate.
+        '';
+      };
+
+      dataDir = mkOption {
+        type = types.path;
+        default = "/var/db/riak-cs";
+        description = ''
+          Data directory for Riak CS.
+        '';
+      };
+
+      logDir = mkOption {
+        type = types.path;
+        default = "/var/log/riak-cs";
+        description = ''
+          Log directory for Riak CS.
+        '';
+      };
+
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Additional text to be appended to <filename>riak-cs.conf</filename>.
+        '';
+      };
+
+      extraAdvancedConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Additional text to be appended to <filename>advanced.config</filename>.
+        '';
+      };
+    };
+
+  };
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    environment.systemPackages = [ cfg.package ];
+    environment.etc."riak-cs/riak-cs.conf".text = ''
+      nodename = ${cfg.nodeName}
+      distributed_cookie = ${cfg.distributedCookie}
+
+      platform_log_dir = ${cfg.logDir}
+
+      riak_host = ${cfg.riakHost}
+      listener = ${cfg.listener}
+      stanchion_host = ${cfg.stanchionHost}
+
+      anonymous_user_creation = ${if cfg.anonymousUserCreation then "on" else "off"}
+
+      ${cfg.extraConfig}
+    '';
+
+    environment.etc."riak-cs/advanced.config".text = ''
+      ${cfg.extraAdvancedConfig}
+    '';
+
+    users.extraUsers.riak-cs = {
+      name = "riak-cs";
+      uid = config.ids.uids.riak-cs;
+      group = "riak";
+      description = "Riak CS server user";
+    };
+
+  systemd.services.riak-cs = {
+      description = "Riak CS Server";
+
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+
+      path = [
+        pkgs.utillinux # for `logger`
+        pkgs.bash
+      ];
+
+      environment.HOME = "${cfg.dataDir}";
+      environment.RIAK_CS_DATA_DIR = "${cfg.dataDir}";
+      environment.RIAK_CS_LOG_DIR = "${cfg.logDir}";
+      environment.RIAK_CS_ETC_DIR = "/etc/riak";
+
+      preStart = ''
+        if ! test -e ${cfg.logDir}; then
+          mkdir -m 0755 -p ${cfg.logDir}
+          chown -R riak-cs ${cfg.logDir}
+        fi
+
+        if ! test -e ${cfg.dataDir}; then
+          mkdir -m 0700 -p ${cfg.dataDir}
+          chown -R riak-cs ${cfg.dataDir}
+        fi
+      '';
+
+      serviceConfig = {
+        ExecStart = "${cfg.package}/bin/riak-cs console";
+        ExecStop = "${cfg.package}/bin/riak-cs stop";
+        StandardInput = "tty";
+        User = "riak-cs";
+        Group = "riak-cs";
+        PermissionsStartOnly = true;
+        # Give Riak a decent amount of time to clean up.
+        TimeoutStopSec = 120;
+        LimitNOFILE = 65536;
+      };
+
+      unitConfig.RequiresMountsFor = [
+        "${cfg.dataDir}"
+        "${cfg.logDir}"
+        "/etc/riak"
+      ];
+    };
+  };
+}
diff --git a/nixos/modules/services/databases/riak.nix b/nixos/modules/services/databases/riak.nix
index bee768fa42a..e0ebf164aef 100644
--- a/nixos/modules/services/databases/riak.nix
+++ b/nixos/modules/services/databases/riak.nix
@@ -20,7 +20,9 @@ in
 
       package = mkOption {
         type = types.package;
-        example = literalExample "pkgs.riak2";
+        default = pkgs.riak;
+        defaultText = "pkgs.riak";
+        example = literalExample "pkgs.riak";
         description = ''
           Riak package to use.
         '';
@@ -68,6 +70,14 @@ in
         '';
       };
 
+      extraAdvancedConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Additional text to be appended to <filename>advanced.config</filename>.
+        '';
+      };
+
     };
 
   };
@@ -88,6 +98,10 @@ in
       ${cfg.extraConfig}
     '';
 
+    environment.etc."riak/advanced.config".text = ''
+      ${cfg.extraAdvancedConfig}
+    '';
+
     users.extraUsers.riak = {
       name = "riak";
       uid = config.ids.uids.riak;
@@ -108,6 +122,7 @@ in
         pkgs.bash
       ];
 
+      environment.HOME = "${cfg.dataDir}";
       environment.RIAK_DATA_DIR = "${cfg.dataDir}";
       environment.RIAK_LOG_DIR = "${cfg.logDir}";
       environment.RIAK_ETC_DIR = "/etc/riak";
diff --git a/nixos/modules/services/databases/stanchion.nix b/nixos/modules/services/databases/stanchion.nix
new file mode 100644
index 00000000000..f2dbb78b5c4
--- /dev/null
+++ b/nixos/modules/services/databases/stanchion.nix
@@ -0,0 +1,212 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.stanchion;
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.stanchion = {
+
+      enable = mkEnableOption "stanchion";
+
+      package = mkOption {
+        type = types.package;
+        default = pkgs.stanchion;
+        defaultText = "pkgs.stanchion";
+        example = literalExample "pkgs.stanchion";
+        description = ''
+          Stanchion package to use.
+        '';
+      };
+
+      nodeName = mkOption {
+        type = types.str;
+        default = "stanchion@127.0.0.1";
+        description = ''
+          Name of the Erlang node.
+        '';
+      };
+
+      adminKey = mkOption {
+        type = types.str;
+        default = "";
+        description = ''
+          Name of admin user.
+        '';
+      };
+
+      adminSecret = mkOption {
+        type = types.str;
+        default = "";
+        description = ''
+          Name of admin secret
+        '';
+      };
+
+      riakHost = mkOption {
+        type = types.str;
+        default = "127.0.0.1:8087";
+        description = ''
+          Name of riak hosting service.
+        '';
+      };
+
+      listener = mkOption {
+        type = types.str;
+        default = "127.0.0.1:8085";
+        description = ''
+          Name of Riak CS listening service.
+        '';
+      };
+
+      stanchionHost = mkOption {
+        type = types.str;
+        default = "127.0.0.1:8085";
+        description = ''
+          Name of stanchion hosting service.
+        '';
+      };
+
+      stanchionSsl = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Tell stanchion to use SSL.
+        '';
+      };
+
+      distributedCookie = mkOption {
+        type = types.str;
+        default = "riak";
+        description = ''
+          Cookie for distributed node communication.  All nodes in the
+          same cluster should use the same cookie or they will not be able to
+          communicate.
+        '';
+      };
+
+      dataDir = mkOption {
+        type = types.path;
+        default = "/var/db/stanchion";
+        description = ''
+          Data directory for Stanchion.
+        '';
+      };
+
+      logDir = mkOption {
+        type = types.path;
+        default = "/var/log/stanchion";
+        description = ''
+          Log directory for Stanchino.
+        '';
+      };
+
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Additional text to be appended to <filename>stanchion.conf</filename>.
+        '';
+      };
+    };
+  };
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    environment.systemPackages = [ cfg.package ];
+
+    environment.etc."stanchion/advanced.config".text = ''
+      [{stanchion, []}].
+    '';
+
+    environment.etc."stanchion/stanchion.conf".text = ''
+      listener = ${cfg.listener}
+
+      riak_host = ${cfg.riakHost}
+
+      ${optionalString (cfg.adminKey == "") "#"} admin.key=${optionalString (cfg.adminKey != "") cfg.adminKey}
+      ${optionalString (cfg.adminSecret == "") "#"} admin.secret=${optionalString (cfg.adminSecret != "") cfg.adminSecret}
+
+      platform_bin_dir = ${pkgs.stanchion}/bin
+      platform_data_dir = ${cfg.dataDir}
+      platform_etc_dir = /etc/stanchion
+      platform_lib_dir = ${pkgs.stanchion}/lib
+      platform_log_dir = ${cfg.logDir}
+
+      nodename = ${cfg.nodeName}
+
+      distributed_cookie = ${cfg.distributedCookie}
+
+      stanchion_ssl=${if cfg.stanchionSsl then "on" else "off"}
+
+      ${cfg.extraConfig}
+    '';
+
+    users.extraUsers.stanchion = {
+      name = "stanchion";
+      uid = config.ids.uids.stanchion;
+      group = "stanchion";
+      description = "Stanchion server user";
+    };
+
+    users.extraGroups.stanchion.gid = config.ids.gids.stanchion;
+
+    systemd.services.stanchion = {
+      description = "Stanchion Server";
+
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+
+      path = [
+        pkgs.utillinux # for `logger`
+        pkgs.bash
+      ];
+
+      environment.HOME = "${cfg.dataDir}";
+      environment.STANCHION_DATA_DIR = "${cfg.dataDir}";
+      environment.STANCHION_LOG_DIR = "${cfg.logDir}";
+      environment.STANCHION_ETC_DIR = "/etc/stanchion";
+
+      preStart = ''
+        if ! test -e ${cfg.logDir}; then
+          mkdir -m 0755 -p ${cfg.logDir}
+          chown -R stanchion:stanchion ${cfg.logDir}
+        fi
+
+        if ! test -e ${cfg.dataDir}; then
+          mkdir -m 0700 -p ${cfg.dataDir}
+          chown -R stanchion:stanchion ${cfg.dataDir}
+        fi
+      '';
+
+      serviceConfig = {
+        ExecStart = "${cfg.package}/bin/stanchion console";
+        ExecStop = "${cfg.package}/bin/stanchion stop";
+        StandardInput = "tty";
+        User = "stanchion";
+        Group = "stanchion";
+        PermissionsStartOnly = true;
+        # Give Stanchion a decent amount of time to clean up.
+        TimeoutStopSec = 120;
+        LimitNOFILE = 65536;
+      };
+
+      unitConfig.RequiresMountsFor = [
+        "${cfg.dataDir}"
+        "${cfg.logDir}"
+        "/etc/stanchion"
+      ];
+    };
+  };
+}
diff --git a/nixos/modules/services/databases/virtuoso.nix b/nixos/modules/services/databases/virtuoso.nix
index bdd210a2550..3231fede08f 100644
--- a/nixos/modules/services/databases/virtuoso.nix
+++ b/nixos/modules/services/databases/virtuoso.nix
@@ -62,7 +62,8 @@ with lib;
       };
 
     systemd.services.virtuoso = {
-      wantedBy = [ "ip-up.target" ];
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
 
       preStart = ''
         mkdir -p ${stateDir}
diff --git a/nixos/modules/services/desktops/accountsservice.nix b/nixos/modules/services/desktops/accountsservice.nix
index c28c2729576..2a7450669ea 100644
--- a/nixos/modules/services/desktops/accountsservice.nix
+++ b/nixos/modules/services/desktops/accountsservice.nix
@@ -35,6 +35,14 @@ with lib;
     services.dbus.packages = [ pkgs.accountsservice ];
 
     systemd.packages = [ pkgs.accountsservice ];
+
+    systemd.services.accounts-daemon= {
+
+      wantedBy = [ "graphical.target" ];
+
+    } // (mkIf (!config.users.mutableUsers) {
+      environment.NIXOS_USERS_PURE = "true";
+    });
   };
 
 }
diff --git a/nixos/modules/services/desktops/gnome3/evolution-data-server.nix b/nixos/modules/services/desktops/gnome3/evolution-data-server.nix
index a8f8da0eed5..2db2e2fe1c3 100644
--- a/nixos/modules/services/desktops/gnome3/evolution-data-server.nix
+++ b/nixos/modules/services/desktops/gnome3/evolution-data-server.nix
@@ -37,6 +37,8 @@ in
 
     services.dbus.packages = [ gnome3.evolution_data_server ];
 
+    systemd.packages = [ gnome3.evolution_data_server ];
+
   };
 
 }
diff --git a/nixos/modules/services/desktops/gnome3/gnome-terminal-server.nix b/nixos/modules/services/desktops/gnome3/gnome-terminal-server.nix
new file mode 100644
index 00000000000..384cede679c
--- /dev/null
+++ b/nixos/modules/services/desktops/gnome3/gnome-terminal-server.nix
@@ -0,0 +1,44 @@
+# GNOME Documents daemon.
+
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  gnome3 = config.environment.gnome3.packageSet;
+in
+{
+
+  ###### interface
+
+  options = {
+
+    services.gnome3.gnome-terminal-server = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to enable GNOME Terminal server service,
+          needed for gnome-terminal.
+        '';
+      };
+
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf config.services.gnome3.gnome-terminal-server.enable {
+
+    environment.systemPackages = [ gnome3.gnome_terminal ];
+
+    services.dbus.packages = [ gnome3.gnome_terminal ];
+
+    systemd.packages = [ gnome3.gnome_terminal ];
+
+  };
+
+}
diff --git a/nixos/modules/services/desktops/gnome3/gvfs.nix b/nixos/modules/services/desktops/gnome3/gvfs.nix
index a07cdadbb12..6bbabe8d3c5 100644
--- a/nixos/modules/services/desktops/gnome3/gvfs.nix
+++ b/nixos/modules/services/desktops/gnome3/gvfs.nix
@@ -37,6 +37,8 @@ in
 
     services.dbus.packages = [ gnome3.gvfs ];
 
+    systemd.packages = [ gnome3.gvfs ];
+
     services.udev.packages = [ pkgs.libmtp.bin ];
 
   };
diff --git a/nixos/modules/services/desktops/gnome3/tracker.nix b/nixos/modules/services/desktops/gnome3/tracker.nix
index 8c5935a5ee3..dcaa60103a3 100644
--- a/nixos/modules/services/desktops/gnome3/tracker.nix
+++ b/nixos/modules/services/desktops/gnome3/tracker.nix
@@ -37,6 +37,8 @@ in
 
     services.dbus.packages = [ gnome3.tracker ];
 
+    systemd.packages = [ gnome3.tracker ];
+
   };
 
 }
diff --git a/nixos/modules/services/desktops/profile-sync-daemon.nix b/nixos/modules/services/desktops/profile-sync-daemon.nix
index d66ecef2385..e3f74df3e57 100644
--- a/nixos/modules/services/desktops/profile-sync-daemon.nix
+++ b/nixos/modules/services/desktops/profile-sync-daemon.nix
@@ -86,6 +86,12 @@ in {
   };
 
   config = mkIf cfg.enable {
+    assertions = [
+      { assertion = cfg.users != [];
+        message = "services.psd.users must contain at least one user";
+      }
+    ];
+
     systemd = {
       services = {
         psd = {
diff --git a/nixos/modules/services/editors/emacs.nix b/nixos/modules/services/editors/emacs.nix
index 6795ec52fe4..08fa6de6374 100644
--- a/nixos/modules/services/editors/emacs.nix
+++ b/nixos/modules/services/editors/emacs.nix
@@ -79,9 +79,13 @@ in {
 
     environment.systemPackages = [ cfg.package editorScript ];
 
-    environment.variables = if cfg.defaultEditor then {
-      EDITOR = mkOverride 900 "${editorScript}/bin/emacseditor";
-    } else {};
+    environment.variables = {
+      # This is required so that GTK applications launched from Emacs
+      # get properly themed:
+      GTK_DATA_PREFIX = "${config.system.path}";
+    } // (if cfg.defaultEditor then {
+        EDITOR = mkOverride 900 "${editorScript}/bin/emacseditor";
+      } else {});
   };
 
   meta.doc = ./emacs.xml;
diff --git a/nixos/modules/services/editors/emacs.xml b/nixos/modules/services/editors/emacs.xml
index ee8ef512bc7..e03f6046de8 100644
--- a/nixos/modules/services/editors/emacs.xml
+++ b/nixos/modules/services/editors/emacs.xml
@@ -43,9 +43,10 @@
     <title>Installing <application>Emacs</application></title>
 
     <para>
-      Emacs can installed in the normal way for Nix (see <xref
-      linkend="sec-package-management" />). In addition, a NixOS
-      <emphasis>service</emphasis> can be enabled.
+      Emacs can be installed in the normal way for Nix (see
+      <xref linkend="sec-package-management" />).
+      In addition, a NixOS <emphasis>service</emphasis>
+      can be enabled.
     </para>
 
     <section>
@@ -59,20 +60,20 @@
         <variablelist>
           <varlistentry>
             <term><varname>emacs</varname></term>
-            <term><varname>emacs24</varname></term>
+            <term><varname>emacs25</varname></term>
             <listitem>
               <para>
-                The latest stable version of Emacs 24 using the <link
+                The latest stable version of Emacs 25 using the <link
                 xlink:href="http://www.gtk.org">GTK+ 2</link> widget
                 toolkit.
               </para>
             </listitem>
           </varlistentry>
           <varlistentry>
-            <term><varname>emacs24-nox</varname></term>
+            <term><varname>emacs25-nox</varname></term>
             <listitem>
               <para>
-                Emacs 24 built without any dependency on X11
+                Emacs 25 built without any dependency on X11
                 libraries.
               </para>
             </listitem>
@@ -86,15 +87,6 @@
               </para>
             </listitem>
           </varlistentry>
-          <varlistentry>
-            <term><varname>emacs25pre</varname></term>
-            <listitem>
-              <para>
-                A pretest version of what will become the first
-                version of Emacs 25.
-              </para>
-            </listitem>
-          </varlistentry>
         </variablelist>
       </para>
 
@@ -364,14 +356,14 @@ https://nixos.org/nixpkgs/manual/#sec-modify-via-packageOverrides
         <programlisting><![CDATA[
 { pkgs ? import <nixpkgs> {} }:
 let
-  myEmacs = pkgs.lib.overrideDerivation (pkgs.emacs.override {
+  myEmacs = (pkgs.emacs.override {
     # Use gtk3 instead of the default gtk2
     withGTK3 = true;
     withGTK2 = false;
-  }) (attrs: {
+  }).overrideAttrs (attrs: {
     # I don't want emacs.desktop file because I only use
     # emacsclient.
-    postInstall = attrs.postInstall + ''
+    postInstall = (attrs.postInstall or "") + ''
       rm $out/share/applications/emacs.desktop
     '';
   });
@@ -573,6 +565,55 @@ services.emacs.install = true;
       &lt;RET&gt; nixos-rebuild &lt;RET&gt;.</literal>
     </para>
   </section>
+
+  <section xml:id="sec-emacs-docbook-xml">
+    <title>Editing DocBook 5 XML Documents</title>
+    <para>
+      Emacs includes <link
+      xlink:href="https://www.gnu.org/software/emacs/manual/html_node/nxml-mode/Introduction.html">nXML</link>,
+      a major-mode for validating and editing XML documents.
+      When editing DocBook 5.0 documents, such as
+      <link linkend="book-nixos-manual">this one</link>,
+      nXML needs to be configured with the relevant schema, which is
+      not included.
+    </para>
+
+    <para>
+      To install the DocBook 5.0 schemas, either add
+      <varname>pkgs.docbook5</varname> to
+      <varname>environment.systemPackages</varname> (<link
+      linkend="sec-declarative-package-mgmt">NixOS</link>), or run
+      <literal>nix-env -i pkgs.docbook5</literal>
+      (<link linkend="sec-ad-hoc-packages">Nix</link>).
+    </para>
+
+    <para>
+      Then customize the variable <varname>rng-schema-locating-files</varname> to include <filename>~/.emacs.d/schemas.xml</filename> and put the following text into that file:
+      <example xml:id="ex-emacs-docbook-xml">
+        <title>nXML Schema Configuration (<filename>~/.emacs.d/schemas.xml</filename>)</title>
+        <programlisting language="xml"><![CDATA[
+<?xml version="1.0"?>
+<!--
+  To let emacs find this file, evaluate:
+  (add-to-list 'rng-schema-locating-files "~/.emacs.d/schemas.xml")
+-->
+<locatingRules xmlns="http://thaiopensource.com/ns/locating-rules/1.0">
+  <!--
+    Use this variation if pkgs.docbook5 is added to environment.systemPackages
+  -->
+  <namespace ns="http://docbook.org/ns/docbook"
+             uri="/run/current-system/sw/share/xml/docbook-5.0/rng/docbookxi.rnc"/>
+  <!--
+    Use this variation if installing schema with "nix-env -iA pkgs.docbook5".
+  <namespace ns="http://docbook.org/ns/docbook"
+             uri="../.nix-profile/share/xml/docbook-5.0/rng/docbookxi.rnc"/>
+  -->
+</locatingRules>
+]]></programlisting>
+    </example>
+  </para>
+
+  </section>
 </section>
 
 </chapter>
diff --git a/nixos/modules/services/editors/infinoted.nix b/nixos/modules/services/editors/infinoted.nix
new file mode 100644
index 00000000000..963147b18a0
--- /dev/null
+++ b/nixos/modules/services/editors/infinoted.nix
@@ -0,0 +1,158 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.infinoted;
+in {
+  options.services.infinoted = {
+    enable = mkEnableOption "infinoted";
+
+    package = mkOption {
+      type = types.package;
+      default = pkgs.libinfinity.override { daemon = true; };
+      defaultText = "pkgs.libinfinity.override { daemon = true; }";
+      description = ''
+        Package providing infinoted
+      '';
+    };
+
+    keyFile = mkOption {
+      type = types.nullOr types.path;
+      default = null;
+      description = ''
+        Private key to use for TLS
+      '';
+    };
+
+    certificateFile = mkOption {
+      type = types.nullOr types.path;
+      default = null;
+      description = ''
+        Server certificate to use for TLS
+      '';
+    };
+
+    certificateChain = mkOption {
+      type = types.nullOr types.path;
+      default = null;
+      description = ''
+        Chain of CA-certificates to which our `certificateFile` is relative.
+        Optional for TLS.
+      '';
+    };
+
+    securityPolicy = mkOption {
+      type = types.enum ["no-tls" "allow-tls" "require-tls"];
+      default = "require-tls";
+      description = ''
+        How strictly to enforce clients connection with TLS.
+      '';
+    };
+
+    port = mkOption {
+      type = types.int;
+      default = 6523;
+      description = ''
+        Port to listen on
+      '';
+    };
+
+    rootDirectory = mkOption {
+      type = types.path;
+      default = "/var/lib/infinoted/documents/";
+      description = ''
+        Root of the directory structure to serve
+      '';
+    };
+
+    plugins = mkOption {
+      type = types.listOf types.str;
+      default = [ "note-text" "note-chat" "logging" "autosave" ];
+      description = ''
+        Plugins to enable
+      '';
+    };
+
+    passwordFile = mkOption {
+      type = types.nullOr types.path;
+      default = null;
+      description = ''
+        File to read server-wide password from
+      '';
+    };
+
+    extraConfig = mkOption {
+      type = types.lines;
+      default = ''
+        [autosave]
+        interval=10
+      '';
+      description = ''
+        Additional configuration to append to infinoted.conf
+      '';
+    };
+
+    user = mkOption {
+      type = types.str;
+      default = "infinoted";
+      description = ''
+        What to call the dedicated user under which infinoted is run
+      '';
+    };
+
+    group = mkOption {
+      type = types.str;
+      default = "infinoted";
+      description = ''
+        What to call the primary group of the dedicated user under which infinoted is run
+      '';
+    };
+  };
+
+  config = mkIf (cfg.enable) {
+    users.extraUsers = optional (cfg.user == "infinoted")
+      { name = "infinoted";
+        description = "Infinoted user";
+        group = cfg.group;
+      };
+    users.extraGroups = optional (cfg.group == "infinoted")
+      { name = "infinoted";
+      };
+  
+    systemd.services.infinoted =
+      { description = "Gobby Dedicated Server";
+
+        wantedBy = [ "multi-user.target" ];
+        after = [ "network.target" ];
+
+        serviceConfig = {
+          Type = "simple";
+          Restart = "always";
+          ExecStart = "${cfg.package}/bin/infinoted-0.6 --config-file=/var/lib/infinoted/infinoted.conf";
+          User = cfg.user;
+          Group = cfg.group;
+          PermissionsStartOnly = true;
+        };
+        preStart = ''
+          mkdir -p /var/lib/infinoted
+          install -o ${cfg.user} -g ${cfg.group} -m 0600 /dev/null /var/lib/infinoted/infinoted.conf
+          cat >>/var/lib/infinoted/infinoted.conf <<EOF
+          [infinoted]
+          ${optionalString (cfg.keyFile != null) ''key-file=${cfg.keyFile}''}
+          ${optionalString (cfg.certificateFile != null) ''certificate-file=${cfg.certificateFile}''}
+          ${optionalString (cfg.certificateChain != null) ''certificate-chain=${cfg.certificateChain}''}
+          port=${toString cfg.port}
+          security-policy=${cfg.securityPolicy}
+          root-directory=${cfg.rootDirectory}
+          plugins=${concatStringsSep ";" cfg.plugins}
+          ${optionalString (cfg.passwordFile != null) ''password=$(head -n 1 ${cfg.passwordFile})''}
+
+          ${cfg.extraConfig}
+          EOF
+
+          install -o ${cfg.user} -g ${cfg.group} -m 0750 -d ${cfg.rootDirectory}
+        '';
+      };
+  };
+}
diff --git a/nixos/modules/services/games/ghost-one.nix b/nixos/modules/services/games/ghost-one.nix
index 5762148df2b..71ff6bb2f3f 100644
--- a/nixos/modules/services/games/ghost-one.nix
+++ b/nixos/modules/services/games/ghost-one.nix
@@ -21,8 +21,7 @@ in
 
       language = mkOption {
         default = "English";
-        type = types.addCheck types.str
-          (lang: elem lang [ "English" "Spanish" "Russian" "Serbian" "Turkish" ]);
+        type = types.enum [ "English" "Spanish" "Russian" "Serbian" "Turkish" ];
         description = "The language of bot messages: English, Spanish, Russian, Serbian or Turkish.";
       };
 
diff --git a/nixos/modules/services/games/terraria.nix b/nixos/modules/services/games/terraria.nix
index 57ac37bb1bd..21aff780b67 100644
--- a/nixos/modules/services/games/terraria.nix
+++ b/nixos/modules/services/games/terraria.nix
@@ -64,7 +64,7 @@ in
       };
 
       worldPath = mkOption {
-        type        = types.path;
+        type        = types.nullOr types.path;
         default     = null;
         description = ''
           The path to the world file (<literal>.wld</literal>) which should be loaded.
@@ -126,8 +126,8 @@ in
         User    = "terraria";
         Type = "oneshot";
         RemainAfterExit = true;
-        ExecStart = "${pkgs.tmux.bin}/bin/tmux -S /var/lib/terraria/terraria.sock new -d ${pkgs.terraria-server}/bin/TerrariaServer ${concatStringsSep " " flags}";
-        ExecStop = "${pkgs.tmux.bin}/bin/tmux -S /var/lib/terraria/terraria.sock send-keys Enter \"exit\" Enter";
+        ExecStart = "${getBin pkgs.tmux}/bin/tmux -S /var/lib/terraria/terraria.sock new -d ${pkgs.terraria-server}/bin/TerrariaServer ${concatStringsSep " " flags}";
+        ExecStop = "${getBin pkgs.tmux}/bin/tmux -S /var/lib/terraria/terraria.sock send-keys Enter \"exit\" Enter";
       };
 
       postStart = ''
diff --git a/nixos/modules/services/hardware/brltty.nix b/nixos/modules/services/hardware/brltty.nix
index 03e530b2c96..1266e8f81e5 100644
--- a/nixos/modules/services/hardware/brltty.nix
+++ b/nixos/modules/services/hardware/brltty.nix
@@ -28,7 +28,7 @@ in {
       };
       serviceConfig = {
         ExecStart = "${pkgs.brltty}/bin/brltty --no-daemon";
-        Type = "simple";        # Change to notidy after next releae
+        Type = "notify";
         TimeoutStartSec = 5;
         TimeoutStopSec = 10;
         Restart = "always";
@@ -39,6 +39,8 @@ in {
         ProtectSystem = "full";
         SystemCallArchitectures = "native";
       };
+      wants = [ "systemd-udev-settle.service" ];
+      after = [ "local-fs.target" "systemd-udev-settle.service" ];
       before = [ "sysinit.target" ];
       wantedBy = [ "sysinit.target" ];
     };
diff --git a/nixos/modules/services/hardware/pommed.nix b/nixos/modules/services/hardware/pommed.nix
index 7be4dc1e846..bf7d6a46a29 100644
--- a/nixos/modules/services/hardware/pommed.nix
+++ b/nixos/modules/services/hardware/pommed.nix
@@ -2,7 +2,9 @@
 
 with lib;
 
-{
+let cfg = config.services.hardware.pommed;
+    defaultConf = "${pkgs.pommed_light}/etc/pommed.conf.mactel";
+in {
 
   options = {
 
@@ -12,37 +14,37 @@ with lib;
         type = types.bool;
         default = false;
         description = ''
-          Whether to use the pommed tool to handle Apple laptop keyboard hotkeys.
+          Whether to use the pommed tool to handle Apple laptop
+          keyboard hotkeys.
         '';
       };
 
       configFile = mkOption {
-        type = types.path;
+        type = types.nullOr types.path;
+        default = null;
         description = ''
-          The path to the <filename>pommed.conf</filename> file.
+          The path to the <filename>pommed.conf</filename> file. Leave
+          to null to use the default config file
+          (<filename>/etc/pommed.conf.mactel</filename>). See the
+          files <filename>/etc/pommed.conf.mactel</filename> and
+          <filename>/etc/pommed.conf.pmac</filename> for examples to
+          build on.
         '';
       };
     };
 
   };
 
-  config = mkIf config.services.hardware.pommed.enable {
-    environment.systemPackages = [ pkgs.polkit ];
+  config = mkIf cfg.enable {
+    environment.systemPackages = [ pkgs.polkit pkgs.pommed_light ];
 
-    environment.etc."pommed.conf".source = config.services.hardware.pommed.configFile;
-
-    services.hardware.pommed.configFile = "${pkgs.pommed}/etc/pommed.conf";
-
-    services.dbus.packages = [ pkgs.pommed ];
+    environment.etc."pommed.conf".source =
+      if cfg.configFile == null then defaultConf else cfg.configFile;
 
     systemd.services.pommed = {
-      description = "Pommed hotkey management";
+      description = "Pommed Apple Hotkeys Daemon";
       wantedBy = [ "multi-user.target" ];
-      after = [ "dbus.service" ];
-      postStop = "rm -f /var/run/pommed.pid";
-      script = "${pkgs.pommed}/bin/pommed";
-      serviceConfig.Type = "forking";
-      path = [ pkgs.eject ];
+      script = "${pkgs.pommed_light}/bin/pommed -f";
     };
   };
 }
diff --git a/nixos/modules/services/hardware/sane.nix b/nixos/modules/services/hardware/sane.nix
index a3403740312..8ddb9ef9c53 100644
--- a/nixos/modules/services/hardware/sane.nix
+++ b/nixos/modules/services/hardware/sane.nix
@@ -7,9 +7,35 @@ let
   pkg = if config.hardware.sane.snapshot
     then pkgs.sane-backends-git
     else pkgs.sane-backends;
-  backends = [ pkg ] ++ config.hardware.sane.extraBackends;
+
+  sanedConf = pkgs.writeTextFile {
+    name = "saned.conf";
+    destination = "/etc/sane.d/saned.conf";
+    text = ''
+      localhost
+      ${config.services.saned.extraConfig}
+    '';
+  };
+
+  netConf = pkgs.writeTextFile {
+    name = "net.conf";
+    destination = "/etc/sane.d/net.conf";
+    text = ''
+      ${lib.optionalString config.services.saned.enable "localhost"}
+      ${config.hardware.sane.netConf}
+    '';
+  };
+
+  env = {
+    SANE_CONFIG_DIR = config.hardware.sane.configDir;
+    LD_LIBRARY_PATH = [ "${saneConfig}/lib/sane" ];
+  };
+
+  backends = [ pkg netConf ] ++ optional config.services.saned.enable sanedConf ++ config.hardware.sane.extraBackends;
   saneConfig = pkgs.mkSaneConfig { paths = backends; };
 
+  enabled = config.hardware.sane.enable || config.services.saned.enable;
+
 in
 
 {
@@ -51,27 +77,86 @@ in
 
     hardware.sane.configDir = mkOption {
       type = types.string;
+      internal = true;
       description = "The value of SANE_CONFIG_DIR.";
     };
 
-  };
+    hardware.sane.netConf = mkOption {
+      type = types.lines;
+      default = "";
+      example = "192.168.0.16";
+      description = ''
+        Network hosts that should be probed for remote scanners.
+      '';
+    };
 
+    services.saned.enable = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Enable saned network daemon for remote connection to scanners.
 
-  ###### implementation
+        saned would be runned from <literal>scanner</literal> user; to allow
+        access to hardware that doesn't have <literal>scanner</literal> group
+        you should add needed groups to this user.
+      '';
+    };
 
-  config = mkIf config.hardware.sane.enable {
+    services.saned.extraConfig = mkOption {
+      type = types.lines;
+      default = "";
+      example = "192.168.0.0/24";
+      description = ''
+        Extra saned configuration lines.
+      '';
+    };
 
-    hardware.sane.configDir = mkDefault "${saneConfig}/etc/sane.d";
+  };
 
-    environment.systemPackages = backends;
-    environment.sessionVariables = {
-      SANE_CONFIG_DIR = config.hardware.sane.configDir;
-      LD_LIBRARY_PATH = [ "${saneConfig}/lib/sane" ];
-    };
-    services.udev.packages = backends;
 
-    users.extraGroups."scanner".gid = config.ids.gids.scanner;
+  ###### implementation
 
-  };
+  config = mkMerge [
+    (mkIf enabled {
+      hardware.sane.configDir = mkDefault "${saneConfig}/etc/sane.d";
+
+      environment.systemPackages = backends;
+      environment.sessionVariables = env;
+      services.udev.packages = backends;
+
+      users.extraGroups."scanner".gid = config.ids.gids.scanner;
+    })
+
+    (mkIf config.services.saned.enable {
+      networking.firewall.connectionTrackingModules = [ "sane" ];
+
+      systemd.services."saned@" = {
+        description = "Scanner Service";
+        environment = mapAttrs (name: val: toString val) env;
+        serviceConfig = {
+          User = "scanner";
+          Group = "scanner";
+          ExecStart = "${pkg}/bin/saned";
+        };
+      };
+
+      systemd.sockets.saned = {
+        description = "saned incoming socket";
+        wantedBy = [ "sockets.target" ];
+        listenStreams = [ "0.0.0.0:6566" "[::]:6566" ];
+        socketConfig = {
+          # saned needs to distinguish between IPv4 and IPv6 to open matching data sockets.
+          BindIPv6Only = "ipv6-only";
+          Accept = true;
+          MaxConnections = 1;
+        };
+      };
+
+      users.extraUsers."scanner" = {
+        uid = config.ids.uids.scanner;
+        group = "scanner";
+      };
+    })
+  ];
 
 }
diff --git a/nixos/modules/services/hardware/sane_extra_backends/brscan4.nix b/nixos/modules/services/hardware/sane_extra_backends/brscan4.nix
index 3ec74458cd2..1923addeb3a 100644
--- a/nixos/modules/services/hardware/sane_extra_backends/brscan4.nix
+++ b/nixos/modules/services/hardware/sane_extra_backends/brscan4.nix
@@ -81,12 +81,11 @@ in
         { office1 = { model = "MFC-7860DW"; ip = "192.168.1.2"; };
           office2 = { model = "MFC-7860DW"; nodename = "BRW0080927AFBCE"; };
         };
-      type = types.loaOf types.optionSet;
+      type = with types; loaOf (submodule netDeviceOpts);
       description = ''
         The list of network devices that will be registered against the brscan4
         sane backend.
       '';
-      options = [ netDeviceOpts ];
     };
   };
 
@@ -113,4 +112,4 @@ in
     ];
 
   };
-}
\ No newline at end of file
+}
diff --git a/nixos/modules/services/hardware/tlp.nix b/nixos/modules/services/hardware/tlp.nix
index 281d02a8c65..f36a9e7b459 100644
--- a/nixos/modules/services/hardware/tlp.nix
+++ b/nixos/modules/services/hardware/tlp.nix
@@ -40,7 +40,7 @@ in
       };
 
       extraConfig = mkOption {
-        type = types.str;
+        type = types.lines;
         default = "";
         description = "Additional configuration variables for TLP";
       };
diff --git a/nixos/modules/services/hardware/udev.nix b/nixos/modules/services/hardware/udev.nix
index 7c4c93d0fcb..14d65978c32 100644
--- a/nixos/modules/services/hardware/udev.nix
+++ b/nixos/modules/services/hardware/udev.nix
@@ -32,13 +32,11 @@ let
   '';
 
   # Perform substitutions in all udev rules files.
-  udevRules = stdenv.mkDerivation {
-    name = "udev-rules";
-
-    preferLocalBuild = true;
-    allowSubstitutes = false;
-
-    buildCommand = ''
+  udevRules = pkgs.runCommand "udev-rules"
+    { preferLocalBuild = true;
+      allowSubstitutes = false;
+    }
+    ''
       mkdir -p $out
       shopt -s nullglob
       set +o pipefail
@@ -130,15 +128,12 @@ let
         ln -s /dev/null $out/80-drivers.rules
       ''}
     ''; # */
-  };
 
-  hwdbBin = stdenv.mkDerivation {
-    name = "hwdb.bin";
-
-    preferLocalBuild = true;
-    allowSubstitutes = false;
-
-    buildCommand = ''
+  hwdbBin = pkgs.runCommand "hwdb.bin"
+    { preferLocalBuild = true;
+      allowSubstitutes = false;
+    }
+    ''
       mkdir -p etc/udev/hwdb.d
       for i in ${toString ([udev] ++ cfg.packages)}; do
         echo "Adding hwdb files for package $i"
@@ -151,7 +146,6 @@ let
       ${udev}/bin/udevadm hwdb --update --root=$(pwd)
       mv etc/udev/hwdb.bin $out
     '';
-  };
 
   # Udev has a 512-character limit for ENV{PATH}, so create a symlink
   # tree to work around this.
diff --git a/nixos/modules/services/logging/logcheck.nix b/nixos/modules/services/logging/logcheck.nix
index 755599ff621..86451ec318c 100644
--- a/nixos/modules/services/logging/logcheck.nix
+++ b/nixos/modules/services/logging/logcheck.nix
@@ -55,49 +55,53 @@ let
 
   levelOption = mkOption {
     default = "server";
-    type = types.str;
+    type = types.enum [ "workstation" "server" "paranoid" ];
     description = ''
-      Set the logcheck level. Either "workstation", "server", or "paranoid".
+      Set the logcheck level.
     '';
   };
 
   ignoreOptions = {
-    level = levelOption;
+    options = {
+      level = levelOption;
 
-    regex = mkOption {
-      default = "";
-      type = types.str;
-      description = ''
-        Regex specifying which log lines to ignore.
-      '';
+      regex = mkOption {
+        default = "";
+        type = types.str;
+        description = ''
+          Regex specifying which log lines to ignore.
+        '';
+      };
     };
   };
 
   ignoreCronOptions = {
-    user = mkOption {
-      default = "root";
-      type = types.str;
-      description = ''
-        User that runs the cronjob.
-      '';
-    };
+    options = {
+      user = mkOption {
+        default = "root";
+        type = types.str;
+        description = ''
+          User that runs the cronjob.
+        '';
+      };
 
-    cmdline = mkOption {
-      default = "";
-      type = types.str;
-      description = ''
-        Command line for the cron job. Will be turned into a regex for the logcheck ignore rule.
-      '';
-    };
+      cmdline = mkOption {
+        default = "";
+        type = types.str;
+        description = ''
+          Command line for the cron job. Will be turned into a regex for the logcheck ignore rule.
+        '';
+      };
 
-    timeArgs = mkOption {
-      default = null;
-      type = types.nullOr (types.str);
-      example = "02 06 * * *";
-      description = ''
-        "min hr dom mon dow" crontab time args, to auto-create a cronjob too.
-        Leave at null to not do this and just add a logcheck ignore rule.
-      '';
+      timeArgs = mkOption {
+        default = null;
+        type = types.nullOr (types.str);
+        example = "02 06 * * *";
+        description = ''
+          "min hr dom mon dow" crontab time args, to auto-create a cronjob too.
+          Leave at null to not do this and just add a logcheck ignore rule.
+        '';
+      };
     };
   };
 
@@ -180,8 +184,7 @@ in
         description = ''
           This option defines extra ignore rules.
         '';
-        type = types.loaOf types.optionSet;
-        options = [ ignoreOptions ];
+        type = with types; loaOf (submodule ignoreOptions);
       };
 
       ignoreCron = mkOption {
@@ -189,8 +192,7 @@ in
         description = ''
           This option defines extra ignore rules for cronjobs.
         '';
-        type = types.loaOf types.optionSet;
-        options = [ ignoreOptions ignoreCronOptions ];
+        type = with types; loaOf (submodule ignoreCronOptions);
       };
 
       extraGroups = mkOption {
diff --git a/nixos/modules/services/logging/syslogd.nix b/nixos/modules/services/logging/syslogd.nix
index a0f8e89fa69..fe0b0490811 100644
--- a/nixos/modules/services/logging/syslogd.nix
+++ b/nixos/modules/services/logging/syslogd.nix
@@ -100,6 +100,12 @@ in
 
   config = mkIf cfg.enable {
 
+    assertions =
+      [ { assertion = !config.services.rsyslogd.enable;
+          message = "rsyslogd conflicts with syslogd";
+        }
+      ];
+
     environment.systemPackages = [ pkgs.sysklogd ];
 
     services.syslogd.extraParams = optional cfg.enableNetworkInput "-r";
diff --git a/nixos/modules/services/mail/dovecot.nix b/nixos/modules/services/mail/dovecot.nix
index 7848288850a..1d427429b9c 100644
--- a/nixos/modules/services/mail/dovecot.nix
+++ b/nixos/modules/services/mail/dovecot.nix
@@ -111,7 +111,7 @@ in
     };
 
     extraConfig = mkOption {
-      type = types.str;
+      type = types.lines;
       default = "";
       example = "mail_debug = yes";
       description = "Additional entries to put verbatim into Dovecot's config file.";
@@ -271,6 +271,9 @@ in
       { assertion = cfg.showPAMFailure -> cfg.enablePAM;
         message = "dovecot is configured with showPAMFailure while enablePAM is disabled";
       }
+      { 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/nixos/modules/services/mail/freepops.nix b/nixos/modules/services/mail/freepops.nix
index e8c30a36923..5b729ca50a5 100644
--- a/nixos/modules/services/mail/freepops.nix
+++ b/nixos/modules/services/mail/freepops.nix
@@ -74,7 +74,8 @@ in
   config = mkIf cfg.enable {
     systemd.services.freepopsd = {
       description = "Freepopsd (webmail over POP3)";
-      wantedBy = [ "ip-up.target" ];
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
       script = ''
         ${pkgs.freepops}/bin/freepopsd \
           -p ${toString cfg.port} \
diff --git a/nixos/modules/services/networking/offlineimap.nix b/nixos/modules/services/mail/offlineimap.nix
index daf6196d370..85ece020905 100644
--- a/nixos/modules/services/networking/offlineimap.nix
+++ b/nixos/modules/services/mail/offlineimap.nix
@@ -59,7 +59,7 @@ in {
       };
       path = cfg.path;
     };
-    environment.systemPackages = [ "${cfg.package}" ];
+    environment.systemPackages = [ cfg.package ];
     systemd.user.timers.offlineimap = {
       description = "offlineimap timer";
       timerConfig               = {
diff --git a/nixos/modules/services/mail/opensmtpd.nix b/nixos/modules/services/mail/opensmtpd.nix
index fb94560e10a..53acdba4245 100644
--- a/nixos/modules/services/mail/opensmtpd.nix
+++ b/nixos/modules/services/mail/opensmtpd.nix
@@ -1,17 +1,16 @@
 { config, lib, pkgs, ... }:
 
-with pkgs;
 with lib;
 
 let
 
   cfg = config.services.opensmtpd;
-  conf = writeText "smtpd.conf" cfg.serverConfiguration;
+  conf = pkgs.writeText "smtpd.conf" cfg.serverConfiguration;
   args = concatStringsSep " " cfg.extraServerArgs;
 
   sendmail = pkgs.runCommand "opensmtpd-sendmail" {} ''
     mkdir -p $out/bin
-    ln -s ${opensmtpd}/sbin/smtpctl $out/bin/sendmail
+    ln -s ${pkgs.opensmtpd}/sbin/smtpctl $out/bin/sendmail
   '';
 
 in {
@@ -48,21 +47,19 @@ in {
       };
 
       serverConfiguration = mkOption {
-        type = types.string;
-        default = "";
+        type = types.lines;
         example = ''
           listen on lo
           accept for any deliver to lmtp localhost:24
-        ''; 
+        '';
         description = ''
           The contents of the smtpd.conf configuration file. See the
-          OpenSMTPD documentation for syntax information. If this option
-          is left empty, the OpenSMTPD server will not start.
+          OpenSMTPD documentation for syntax information.
         '';
       };
 
       procPackages = mkOption {
-        type = types.listOf types.path;
+        type = types.listOf types.package;
         default = [];
         description = ''
           Packages to search for filters, tables, queues, and schedulers.
@@ -100,12 +97,11 @@ in {
     systemd.services.opensmtpd = let
       procEnv = pkgs.buildEnv {
         name = "opensmtpd-procs";
-        paths = [ opensmtpd ] ++ cfg.procPackages;
+        paths = [ pkgs.opensmtpd ] ++ cfg.procPackages;
         pathsToLink = [ "/libexec/opensmtpd" ];
       };
     in {
       wantedBy = [ "multi-user.target" ];
-      wants = [ "network.target" ];
       after = [ "network.target" ];
       preStart = ''
         mkdir -p /var/spool/smtpd
@@ -119,7 +115,7 @@ in {
         chown smtpq.root /var/spool/smtpd/purge
         chmod 700 /var/spool/smtpd/purge
       '';
-      serviceConfig.ExecStart = "${opensmtpd}/sbin/smtpd -d -f ${conf} ${args}";
+      serviceConfig.ExecStart = "${pkgs.opensmtpd}/sbin/smtpd -d -f ${conf} ${args}";
       environment.OPENSMTPD_PROC_PATH = "${procEnv}/libexec/opensmtpd";
     };
 
diff --git a/nixos/modules/services/mail/postgrey.nix b/nixos/modules/services/mail/postgrey.nix
new file mode 100644
index 00000000000..d4ae25c066a
--- /dev/null
+++ b/nixos/modules/services/mail/postgrey.nix
@@ -0,0 +1,194 @@
+{ config, lib, pkgs, ... }:
+
+with lib; let
+
+  cfg = config.services.postgrey;
+
+  natural = with types; addCheck int (x: x >= 0);
+  natural' = with types; addCheck int (x: x > 0);
+
+  socket = with types; addCheck (either (submodule unixSocket) (submodule inetSocket)) (x: x ? "path" || x ? "port");
+
+  inetSocket = with types; {
+    options = {
+      addr = mkOption {
+        type = nullOr string;
+        default = null;
+        example = "127.0.0.1";
+        description = "The address to bind to. Localhost if null";
+      };
+      port = mkOption {
+        type = natural';
+        default = 10030;
+        description = "Tcp port to bind to";
+      };
+    };
+  };
+
+  unixSocket = with types; {
+    options = {
+      path = mkOption {
+        type = path;
+        default = "/var/run/postgrey.sock";
+        description = "Path of the unix socket";
+      };
+
+      mode = mkOption {
+        type = string;
+        default = "0777";
+        description = "Mode of the unix socket";
+      };
+    };
+  };
+
+in {
+
+  options = {
+    services.postgrey = with types; {
+      enable = mkOption {
+        type = bool;
+        default = false;
+        description = "Whether to run the Postgrey daemon";
+      };
+      socket = mkOption {
+        type = socket;
+        default = {
+          path = "/var/run/postgrey.sock";
+          mode = "0777";
+        };
+        example = {
+          addr = "127.0.0.1";
+          port = 10030;
+        };
+        description = "Socket to bind to";
+      };
+      greylistText = mkOption {
+        type = string;
+        default = "Greylisted for %%s seconds";
+        description = "Response status text for greylisted messages; use %%s for seconds left until greylisting is over and %%r for mail domain of recipient";
+      };
+      greylistAction = mkOption {
+        type = string;
+        default = "DEFER_IF_PERMIT";
+        description = "Response status for greylisted messages (see access(5))";
+      };
+      greylistHeader = mkOption {
+        type = string;
+        default = "X-Greylist: delayed %%t seconds by postgrey-%%v at %%h; %%d";
+        description = "Prepend header to greylisted mails; use %%t for seconds delayed due to greylisting, %%v for the version of postgrey, %%d for the date, and %%h for the host";
+      };
+      delay = mkOption {
+        type = natural;
+        default = 300;
+        description = "Greylist for N seconds";
+      };
+      maxAge = mkOption {
+        type = natural;
+        default = 35;
+        description = "Delete entries from whitelist if they haven't been seen for N days";
+      };
+      retryWindow = mkOption {
+        type = either string natural;
+        default = 2;
+        example = "12h";
+        description = "Allow N days for the first retry. Use string with appended 'h' to specify time in hours";
+      };
+      lookupBySubnet = mkOption {
+        type = bool;
+        default = true;
+        description = "Strip the last N bits from IP addresses, determined by IPv4CIDR and IPv6CIDR";
+      };
+      IPv4CIDR = mkOption {
+        type = natural;
+        default = 24;
+        description = "Strip N bits from IPv4 addresses if lookupBySubnet is true";
+      };
+      IPv6CIDR = mkOption {
+        type = natural;
+        default = 64;
+        description = "Strip N bits from IPv6 addresses if lookupBySubnet is true";
+      };
+      privacy = mkOption {
+        type = bool;
+        default = true;
+        description = "Store data using one-way hash functions (SHA1)";
+      };
+      autoWhitelist = mkOption {
+        type = nullOr natural';
+        default = 5;
+        description = "Whitelist clients after successful delivery of N messages";
+      };
+      whitelistClients = mkOption {
+        type = listOf path;
+        default = [];
+        description = "Client address whitelist files (see postgrey(8))";
+      };
+      whitelistRecipients = mkOption {
+        type = listOf path;
+        default = [];
+        description = "Recipient address whitelist files (see postgrey(8))";
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+
+    environment.systemPackages = [ pkgs.postgrey ];
+
+    users = {
+      extraUsers = {
+        postgrey = {
+          description = "Postgrey Daemon";
+          uid = config.ids.uids.postgrey;
+          group = "postgrey";
+        };
+      };
+      extraGroups = {
+        postgrey = {
+          gid = config.ids.gids.postgrey;
+        };
+      };
+    };
+
+    systemd.services.postgrey = let
+      bind-flag = if cfg.socket ? "path" then
+        ''--unix=${cfg.socket.path} --socketmode=${cfg.socket.mode}''
+      else
+        ''--inet=${optionalString (cfg.socket.addr != null) (cfg.socket.addr + ":")}${toString cfg.socket.port}'';
+    in {
+      description = "Postfix Greylisting Service";
+      wantedBy = [ "multi-user.target" ];
+      before = [ "postfix.service" ];
+      preStart = ''
+        mkdir -p /var/postgrey
+        chown postgrey:postgrey /var/postgrey
+        chmod 0770 /var/postgrey
+      '';
+      serviceConfig = {
+        Type = "simple";
+        ExecStart = ''${pkgs.postgrey}/bin/postgrey \
+          ${bind-flag} \
+          --group=postgrey --user=postgrey \
+          --dbdir=/var/postgrey \
+          --delay=${toString cfg.delay} \
+          --max-age=${toString cfg.maxAge} \
+          --retry-window=${toString cfg.retryWindow} \
+          ${if cfg.lookupBySubnet then "--lookup-by-subnet" else "--lookup-by-host"} \
+          --ipv4cidr=${toString cfg.IPv4CIDR} --ipv6cidr=${toString cfg.IPv6CIDR} \
+          ${optionalString cfg.privacy "--privacy"} \
+          --auto-whitelist-clients=${toString (if cfg.autoWhitelist == null then 0 else cfg.autoWhitelist)} \
+          --greylist-action=${cfg.greylistAction} \
+          --greylist-text="${cfg.greylistText}" \
+          --x-greylist-header="${cfg.greylistHeader}" \
+          ${concatMapStringsSep " " (x: "--whitelist-clients=" + x) cfg.whitelistClients} \
+          ${concatMapStringsSep " " (x: "--whitelist-recipients=" + x) cfg.whitelistRecipients}
+        '';
+        Restart = "always";
+        RestartSec = 5;
+        TimeoutSec = 10;
+      };
+    };
+
+  };
+
+}
diff --git a/nixos/modules/services/mail/postsrsd.nix b/nixos/modules/services/mail/postsrsd.nix
index 68a4c101206..a1af16ec9ac 100644
--- a/nixos/modules/services/mail/postsrsd.nix
+++ b/nixos/modules/services/mail/postsrsd.nix
@@ -20,17 +20,29 @@ in {
         description = "Whether to enable the postsrsd SRS server for Postfix.";
       };
 
+      secretsFile = mkOption {
+        type = types.path;
+        default = "/var/lib/postsrsd/postsrsd.secret";
+        description = "Secret keys used for signing and verification";
+      };
+
       domain = mkOption {
         type = types.str;
         description = "Domain name for rewrite";
       };
 
-      secretsFile = mkOption {
-        type = types.path;
-        default = "/var/lib/postsrsd/postsrsd.secret";
-        description = "Secret keys used for signing and verification";
+      separator = mkOption {
+        type = types.enum ["-" "=" "+"];
+        default = "=";
+        description = "First separator character in generated addresses";
       };
 
+      # bindAddress = mkOption { # uncomment once 1.5 is released
+      #   type = types.str;
+      #   default = "127.0.0.1";
+      #   description = "Socket listen address";
+      # };
+
       forwardPort = mkOption {
         type = types.int;
         default = 10001;
@@ -43,6 +55,18 @@ in {
         description = "Port for the reverse SRS lookup";
       };
 
+      timeout = mkOption {
+        type = types.int;
+        default = 1800;
+        description = "Timeout for idle client connections in seconds";
+      };
+
+      excludeDomains = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = "Origin domains to exclude from rewriting in addition to primary domain";
+      };
+
       user = mkOption {
         type = types.str;
         default = "postsrsd";
@@ -86,7 +110,7 @@ in {
       path = [ pkgs.coreutils ];
 
       serviceConfig = {
-        ExecStart = ''${pkgs.postsrsd}/sbin/postsrsd "-s${cfg.secretsFile}" "-d${cfg.domain}" -f${toString cfg.forwardPort} -r${toString cfg.reversePort}'';
+        ExecStart = ''${pkgs.postsrsd}/sbin/postsrsd "-s${cfg.secretsFile}" "-d${cfg.domain}" -a${cfg.separator} -f${toString cfg.forwardPort} -r${toString cfg.reversePort} -t${toString cfg.timeout} "-X${concatStringsSep "," cfg.excludeDomains}"'';
         User = cfg.user;
         Group = cfg.group;
         PermissionsStartOnly = true;
diff --git a/nixos/modules/services/mail/rmilter.nix b/nixos/modules/services/mail/rmilter.nix
index e27b38bc0e2..8f18b929c11 100644
--- a/nixos/modules/services/mail/rmilter.nix
+++ b/nixos/modules/services/mail/rmilter.nix
@@ -203,7 +203,7 @@ milter_default_action = accept
         PermissionsStartOnly = true;
         Restart = "always";
         RuntimeDirectory = "rmilter";
-        RuntimeDirectoryPermissions="0755";
+        RuntimeDirectoryMode = "0755";
       };
 
     };
diff --git a/nixos/modules/services/misc/apache-kafka.nix b/nixos/modules/services/misc/apache-kafka.nix
index 88ce8b5a23f..c856d3294c0 100644
--- a/nixos/modules/services/misc/apache-kafka.nix
+++ b/nixos/modules/services/misc/apache-kafka.nix
@@ -139,7 +139,7 @@ in {
     systemd.services.apache-kafka = {
       description = "Apache Kafka Daemon";
       wantedBy = [ "multi-user.target" ];
-      after = [ "network-interfaces.target" ];
+      after = [ "network.target" ];
       serviceConfig = {
         ExecStart = ''
           ${pkgs.jre}/bin/java \
diff --git a/nixos/modules/services/misc/autofs.nix b/nixos/modules/services/misc/autofs.nix
index 18f0c3eb83d..40b48f70f7e 100644
--- a/nixos/modules/services/misc/autofs.nix
+++ b/nixos/modules/services/misc/autofs.nix
@@ -22,7 +22,7 @@ in
         default = false;
         description = "
           Mount filesystems on demand. Unmount them automatically.
-          You may also be interested in afuese.
+          You may also be interested in afuse.
         ";
       };
 
diff --git a/nixos/modules/services/misc/bepasty.nix b/nixos/modules/services/misc/bepasty.nix
index 5bda73ab64f..52719222db6 100644
--- a/nixos/modules/services/misc/bepasty.nix
+++ b/nixos/modules/services/misc/bepasty.nix
@@ -53,7 +53,7 @@ in
           };
 
           extraConfig = mkOption {
-            type = types.str;
+            type = types.lines;
             description = ''
               Extra configuration for bepasty server to be appended on the
               configuration.
diff --git a/nixos/modules/services/misc/confd.nix b/nixos/modules/services/misc/confd.nix
index 72ec68dee6b..fe13013286b 100644..100755
--- a/nixos/modules/services/misc/confd.nix
+++ b/nixos/modules/services/misc/confd.nix
@@ -33,7 +33,7 @@ in {
 
     nodes = mkOption {
       description = "Confd list of nodes to connect to.";
-      default = [ "http://127.0.0.1:4001" ];
+      default = [ "http://127.0.0.1:2379" ];
       type = types.listOf types.str;
     };
 
diff --git a/nixos/modules/services/misc/dictd.nix b/nixos/modules/services/misc/dictd.nix
index ef744439c3d..7e3b6431a13 100644
--- a/nixos/modules/services/misc/dictd.nix
+++ b/nixos/modules/services/misc/dictd.nix
@@ -2,6 +2,10 @@
 
 with lib;
 
+let
+  cfg = config.services.dictd;
+in
+
 {
 
   ###### interface
@@ -20,8 +24,9 @@ with lib;
 
       DBs = mkOption {
         type = types.listOf types.package;
-        default = [];
-        example = [ pkgs.dictdDBs.nld2eng ];
+        default = with pkgs.dictdDBs; [ wiktionary wordnet ];
+        defaultText = "with pkgs.dictdDBs; [ wiktionary wordnet ]";
+        example = literalExample "[ pkgs.dictdDBs.nld2eng ]";
         description = ''List of databases to make available.'';
       };
 
@@ -34,8 +39,8 @@ with lib;
 
   config = let dictdb = pkgs.dictDBCollector { dictlist = map (x: {
                name = x.name;
-               filename = x; } ) config.services.dictd.DBs; };
-  in mkIf config.services.dictd.enable {
+               filename = x; } ) cfg.DBs; };
+  in mkIf cfg.enable {
 
     # get the command line client on system path to make some use of the service
     environment.systemPackages = [ pkgs.dict ];
diff --git a/nixos/modules/services/misc/disnix.nix b/nixos/modules/services/misc/disnix.nix
index e5a125ad324..e96645c79c7 100644
--- a/nixos/modules/services/misc/disnix.nix
+++ b/nixos/modules/services/misc/disnix.nix
@@ -41,6 +41,7 @@ in
         type = types.path;
         description = "The Disnix package";
         default = pkgs.disnix;
+        defaultText = "pkgs.disnix";
       };
 
     };
diff --git a/nixos/modules/services/misc/docker-registry.nix b/nixos/modules/services/misc/docker-registry.nix
index add339f9bdf..96ac2a1cf2c 100644
--- a/nixos/modules/services/misc/docker-registry.nix
+++ b/nixos/modules/services/misc/docker-registry.nix
@@ -6,14 +6,8 @@ let
   cfg = config.services.dockerRegistry;
 
 in {
-  ###### interface
-
   options.services.dockerRegistry = {
-    enable = mkOption {
-      description = "Whether to enable docker registry server.";
-      default = false;
-      type = types.bool;
-    };
+    enable = mkEnableOption "Docker Registry";
 
     listenAddress = mkOption {
       description = "Docker registry host or ip to bind to.";
@@ -35,8 +29,7 @@ in {
 
     extraConfig = mkOption {
       description = ''
-        Docker extra registry configuration. See
-        <link xlink:href="https://github.com/docker/docker-registry/blob/master/config/config_sample.yml"/>
+        Docker extra registry configuration via environment variables.
       '';
       default = {};
       type = types.attrsOf types.str;
@@ -50,32 +43,24 @@ in {
       after = [ "network.target" ];
 
       environment = {
-        REGISTRY_HOST = cfg.listenAddress;
-        REGISTRY_PORT = toString cfg.port;
-        GUNICORN_OPTS = "[--preload]"; # see https://github.com/docker/docker-registry#sqlalchemy
-        STORAGE_PATH = cfg.storagePath;
+        REGISTRY_HTTP_ADDR = "${cfg.listenAddress}:${toString cfg.port}";
+        REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY = cfg.storagePath;
       } // cfg.extraConfig;
 
+      script = ''
+        ${pkgs.docker-distribution}/bin/registry serve \
+          ${pkgs.docker-distribution.out}/share/go/src/github.com/docker/distribution/cmd/registry/config-example.yml
+      '';
+
       serviceConfig = {
-        ExecStart = "${pkgs.pythonPackages.docker_registry}/bin/docker-registry";
         User = "docker-registry";
-        Group = "docker";
-        PermissionsStartOnly = true;
         WorkingDirectory = cfg.storagePath;
       };
-
-      postStart = ''
-        until ${pkgs.curl.bin}/bin/curl -s -o /dev/null 'http://${cfg.listenAddress}:${toString cfg.port}/'; do
-          sleep 1;
-        done
-      '';
     };
 
-    users.extraGroups.docker.gid = mkDefault config.ids.gids.docker;
     users.extraUsers.docker-registry = {
       createHome = true;
       home = cfg.storagePath;
-      uid = config.ids.uids.docker-registry;
     };
   };
 }
diff --git a/nixos/modules/services/misc/emby.nix b/nixos/modules/services/misc/emby.nix
index fe872349f45..9f290ed70c9 100644
--- a/nixos/modules/services/misc/emby.nix
+++ b/nixos/modules/services/misc/emby.nix
@@ -43,7 +43,7 @@ in
         User = cfg.user;
         Group = cfg.group;
         PermissionsStartOnly = "true";
-        ExecStart = "${pkgs.mono}/bin/mono ${pkgs.emby}/bin/MediaBrowser.Server.Mono.exe";
+        ExecStart = "${pkgs.emby}/bin/MediaBrowser.Server.Mono";
         Restart = "on-failure";
       };
     };
diff --git a/nixos/modules/services/misc/errbot.nix b/nixos/modules/services/misc/errbot.nix
new file mode 100644
index 00000000000..427cb7c546d
--- /dev/null
+++ b/nixos/modules/services/misc/errbot.nix
@@ -0,0 +1,101 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.errbot;
+  pluginEnv = plugins: pkgs.buildEnv {
+    name = "errbot-plugins";
+    paths = plugins;
+  };
+  mkConfigDir = instanceCfg: dataDir: pkgs.writeTextDir "config.py" ''
+    import logging
+    BACKEND = '${instanceCfg.backend}'
+    BOT_DATA_DIR = '${dataDir}'
+    BOT_EXTRA_PLUGIN_DIR = '${pluginEnv instanceCfg.plugins}'
+
+    BOT_LOG_LEVEL = logging.${instanceCfg.logLevel}
+    BOT_LOG_FILE = False
+
+    BOT_ADMINS = (${concatMapStringsSep "," (name: "'${name}'") instanceCfg.admins})
+
+    BOT_IDENTITY = ${builtins.toJSON instanceCfg.identity}
+
+    ${instanceCfg.extraConfig}
+  '';
+in {
+  options = {
+    services.errbot.instances = mkOption {
+      default = {};
+      description = "Errbot instance configs";
+      type = types.attrsOf (types.submodule {
+        options = {
+          dataDir = mkOption {
+            type = types.nullOr types.path;
+            default = null;
+            description = "Data directory for errbot instance.";
+          };
+
+          plugins = mkOption {
+            type = types.listOf types.package;
+            default = [];
+            description = "List of errbot plugin derivations.";
+          };
+
+          logLevel = mkOption {
+            type = types.str;
+            default = "INFO";
+            description = "Errbot log level";
+          };
+
+          admins = mkOption {
+            type = types.listOf types.str;
+            default = [];
+            description = "List of identifiers of errbot admins.";
+          };
+
+          backend = mkOption {
+            type = types.str;
+            default = "XMPP";
+            description = "Errbot backend name.";
+          };
+
+          identity = mkOption {
+            type = types.attrs;
+            description = "Errbot identity configuration";
+          };
+
+          extraConfig = mkOption {
+            type = types.lines;
+            default = "";
+            description = "String to be appended to the config verbatim";
+          };
+        };
+      });
+    };
+  };
+
+  config = mkIf (cfg.instances != {}) {
+    users.extraUsers.errbot.group = "errbot";
+    users.extraGroups.errbot = {};
+
+    systemd.services = mapAttrs' (name: instanceCfg: nameValuePair "errbot-${name}" (
+    let
+      dataDir = if !isNull instanceCfg.dataDir then instanceCfg.dataDir else
+        "/var/lib/errbot/${name}";
+    in {
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+      preStart = ''
+        mkdir -p ${dataDir}
+        chown -R errbot:errbot ${dataDir}
+      '';
+      serviceConfig = {
+        User = "errbot";
+        Restart = "on-failure";
+        ExecStart = "${pkgs.errbot}/bin/errbot -c ${mkConfigDir instanceCfg dataDir}/config.py";
+        PermissionsStartOnly = true;
+      };
+    })) cfg.instances;
+  };
+}
diff --git a/nixos/modules/services/misc/etcd.nix b/nixos/modules/services/misc/etcd.nix
index 0d6ed8eb904..1de02d76ba0 100644
--- a/nixos/modules/services/misc/etcd.nix
+++ b/nixos/modules/services/misc/etcd.nix
@@ -28,13 +28,13 @@ in {
 
     listenClientUrls = mkOption {
       description = "Etcd list of URLs to listen on for client traffic.";
-      default = ["http://localhost:4001"];
+      default = ["http://127.0.0.1:2379"];
       type = types.listOf types.str;
     };
 
     listenPeerUrls = mkOption {
       description = "Etcd list of URLs to listen on for peer traffic.";
-      default = ["http://localhost:7001"];
+      default = ["http://127.0.0.1:2380"];
       type = types.listOf types.str;
     };
 
@@ -46,7 +46,7 @@ in {
 
     initialCluster = mkOption {
       description = "Etcd initial cluster configuration for bootstrapping.";
-      default = ["${cfg.name}=http://localhost:7001"];
+      default = ["${cfg.name}=http://127.0.0.1:2380"];
       type = types.listOf types.str;
     };
 
@@ -68,6 +68,54 @@ in {
       type = types.str;
     };
 
+    clientCertAuth = mkOption {
+      description = "Whether to use certs for client authentication";
+      default = false;
+      type = types.bool;
+    };
+
+    trustedCaFile = mkOption {
+      description = "Certificate authority file to use for clients";
+      default = null;
+      type = types.nullOr types.path;
+    };
+
+    certFile = mkOption {
+      description = "Cert file to use for clients";
+      default = null;
+      type = types.nullOr types.path;
+    };
+
+    keyFile = mkOption {
+      description = "Key file to use for clients";
+      default = null;
+      type = types.nullOr types.path;
+    };
+
+    peerCertFile = mkOption {
+      description = "Cert file to use for peer to peer communication";
+      default = cfg.certFile;
+      type = types.nullOr types.path;
+    };
+
+    peerKeyFile = mkOption {
+      description = "Key file to use for peer to peer communication";
+      default = cfg.keyFile;
+      type = types.nullOr types.path;
+    };
+
+    peerTrustedCaFile = mkOption {
+      description = "Certificate authority file to use for peer to peer communication";
+      default = cfg.trustedCaFile;
+      type = types.nullOr types.path;
+    };
+
+    peerClientCertAuth = mkOption {
+      description = "Whether to check all incoming peer requests from the cluster for valid client certificates signed by the supplied CA";
+      default = false;
+      type = types.bool;
+    };
+
     extraConf = mkOption {
       description = ''
         Etcd extra configuration. See
@@ -95,11 +143,11 @@ in {
 
   config = mkIf cfg.enable {
     systemd.services.etcd = {
-      description = "Etcd Daemon";
+      description = "etcd key-value store";
       wantedBy = [ "multi-user.target" ];
-      after = [ "network-interfaces.target" ];
+      after = [ "network.target" ];
 
-      environment = {
+      environment = (filterAttrs (n: v: v != null) {
         ETCD_NAME = cfg.name;
         ETCD_DISCOVERY = cfg.discovery;
         ETCD_DATA_DIR = cfg.dataDir;
@@ -107,18 +155,31 @@ in {
         ETCD_LISTEN_CLIENT_URLS = concatStringsSep "," cfg.listenClientUrls;
         ETCD_LISTEN_PEER_URLS = concatStringsSep "," cfg.listenPeerUrls;
         ETCD_INITIAL_ADVERTISE_PEER_URLS = concatStringsSep "," cfg.initialAdvertisePeerUrls;
-      } // (optionalAttrs (cfg.discovery == ""){
+        ETCD_PEER_TRUSTED_CA_FILE = cfg.peerTrustedCaFile;
+        ETCD_PEER_CERT_FILE = cfg.peerCertFile;
+        ETCD_PEER_KEY_FILE = cfg.peerKeyFile;
+        ETCD_CLIENT_CERT_AUTH = toString cfg.peerClientCertAuth;
+        ETCD_TRUSTED_CA_FILE = cfg.trustedCaFile;
+        ETCD_CERT_FILE = cfg.certFile;
+        ETCD_KEY_FILE = cfg.keyFile;
+      }) // (optionalAttrs (cfg.discovery == ""){
         ETCD_INITIAL_CLUSTER = concatStringsSep "," cfg.initialCluster;
         ETCD_INITIAL_CLUSTER_STATE = cfg.initialClusterState;
         ETCD_INITIAL_CLUSTER_TOKEN = cfg.initialClusterToken;
       }) // (mapAttrs' (n: v: nameValuePair "ETCD_${n}" v) cfg.extraConf);
 
+      unitConfig = {
+        Documentation = "https://github.com/coreos/etcd";
+      };
+
       serviceConfig = {
         Type = "notify";
         ExecStart = "${pkgs.etcd.bin}/bin/etcd";
         User = "etcd";
         PermissionsStartOnly = true;
+        LimitNOFILE = 40000;
       };
+
       preStart = ''
         mkdir -m 0700 -p ${cfg.dataDir}
         if [ "$(id -u)" = 0 ]; then chown etcd ${cfg.dataDir}; fi
diff --git a/nixos/modules/services/misc/folding-at-home.nix b/nixos/modules/services/misc/folding-at-home.nix
index 4f09cbfdd79..053e7e95635 100644
--- a/nixos/modules/services/misc/folding-at-home.nix
+++ b/nixos/modules/services/misc/folding-at-home.nix
@@ -50,7 +50,7 @@ in {
       };
 
     systemd.services.foldingathome = {
-      after = [ "network-interfaces.target" ];
+      after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
       preStart = ''
         mkdir -m 0755 -p ${stateDir}
diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix
index b3f09999adb..1fc3a5cc869 100644
--- a/nixos/modules/services/misc/gitlab.nix
+++ b/nixos/modules/services/misc/gitlab.nix
@@ -164,18 +164,21 @@ in {
       packages.gitlab = mkOption {
         type = types.package;
         default = pkgs.gitlab;
+        defaultText = "pkgs.gitlab";
         description = "Reference to the gitlab package";
       };
 
       packages.gitlab-shell = mkOption {
         type = types.package;
         default = pkgs.gitlab-shell;
+        defaultText = "pkgs.gitlab-shell";
         description = "Reference to the gitlab-shell package";
       };
 
       packages.gitlab-workhorse = mkOption {
         type = types.package;
         default = pkgs.gitlab-workhorse;
+        defaultText = "pkgs.gitlab-workhorse";
         description = "Reference to the gitlab-workhorse package";
       };
 
@@ -425,7 +428,7 @@ in {
         TimeoutSec = "300";
         Restart = "on-failure";
         WorkingDirectory = "${cfg.packages.gitlab}/share/gitlab";
-        ExecStart="${cfg.packages.gitlab.env}/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\"";
+        ExecStart="${cfg.packages.gitlab.env}/bin/bundle exec \"sidekiq -C \"${cfg.packages.gitlab}/share/gitlab/config/sidekiq_queues.yml\" -e production -P ${cfg.statePath}/tmp/sidekiq.pid\"";
       };
     };
 
@@ -449,18 +452,21 @@ in {
         Group = cfg.group;
         TimeoutSec = "300";
         Restart = "on-failure";
+        WorkingDirectory = gitlabEnv.HOME;
         ExecStart =
           "${cfg.packages.gitlab-workhorse}/bin/gitlab-workhorse "
           + "-listenUmask 0 "
           + "-listenNetwork unix "
           + "-listenAddr /run/gitlab/gitlab-workhorse.socket "
           + "-authSocket ${gitlabSocket} "
-          + "-documentRoot ${cfg.packages.gitlab}/share/gitlab/public";
+          + "-documentRoot ${cfg.packages.gitlab}/share/gitlab/public "
+          + "-secretPath ${cfg.packages.gitlab}/share/gitlab/.gitlab_workhorse_secret";
       };
     };
 
     systemd.services.gitlab = {
       after = [ "network.target" "postgresql.service" "redis.service" ];
+      requires = [ "gitlab-sidekiq.service" ];
       wantedBy = [ "multi-user.target" ];
       environment = gitlabEnv;
       path = with pkgs; [
@@ -525,17 +531,23 @@ in {
             psql postgres -c "CREATE ROLE gitlab WITH LOGIN NOCREATEDB NOCREATEROLE NOCREATEUSER ENCRYPTED PASSWORD '${cfg.databasePassword}'"
             ${config.services.postgresql.package}/bin/createdb --owner gitlab gitlab || true
             touch "${cfg.statePath}/db-created"
-
-            # The gitlab:setup task is horribly broken somehow, these two tasks will do the same for setting up the initial database
-            ${gitlab-rake}/bin/gitlab-rake db:migrate RAILS_ENV=production
-            ${gitlab-rake}/bin/gitlab-rake db:seed_fu RAILS_ENV=production \
-              GITLAB_ROOT_PASSWORD="${cfg.initialRootPassword}" GITLAB_ROOT_EMAIL="${cfg.initialRootEmail}";
           fi
         fi
 
+        # enable required pg_trgm extension for gitlab
+        psql gitlab -c "CREATE EXTENSION IF NOT EXISTS pg_trgm"
         # Always do the db migrations just to be sure the database is up-to-date
         ${gitlab-rake}/bin/gitlab-rake db:migrate RAILS_ENV=production
 
+        # The gitlab:setup task is horribly broken somehow, the db:migrate
+        # task above and the db:seed_fu below will do the same for setting
+        # up the initial database
+        if ! test -e "${cfg.statePath}/db-seeded"; then
+          ${gitlab-rake}/bin/gitlab-rake db:seed_fu RAILS_ENV=production \
+            GITLAB_ROOT_PASSWORD="${cfg.initialRootPassword}" GITLAB_ROOT_EMAIL="${cfg.initialRootEmail}"
+          touch "${cfg.statePath}/db-seeded"
+        fi
+
         # Change permissions in the last step because some of the
         # intermediary scripts like to create directories as root.
         chown -R ${cfg.user}:${cfg.group} ${cfg.statePath}
diff --git a/nixos/modules/services/misc/leaps.nix b/nixos/modules/services/misc/leaps.nix
new file mode 100644
index 00000000000..b92cf27f58d
--- /dev/null
+++ b/nixos/modules/services/misc/leaps.nix
@@ -0,0 +1,62 @@
+{ config, pkgs, lib, ... } @ args:
+
+with lib;
+
+let
+  cfg = config.services.leaps;
+  stateDir = "/var/lib/leaps/";
+in
+{
+  options = {
+    services.leaps = {
+      enable = mkEnableOption "leaps";
+      port = mkOption {
+        type = types.int;
+        default = 8080;
+        description = "A port where leaps listens for incoming http requests";
+      };
+      address = mkOption {
+        default = "";
+        type = types.str;
+        example = "127.0.0.1";
+        description = "Hostname or IP-address to listen to. By default it will listen on all interfaces.";
+      };
+      path = mkOption {
+        default = "/";
+        type = types.path;
+        description = "Subdirectory used for reverse proxy setups";
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    users = {
+      users.leaps = {
+        uid             = config.ids.uids.leaps;
+        description     = "Leaps server user";
+        group           = "leaps";
+        home            = stateDir;
+        createHome      = true;
+      };
+
+      groups.leaps = {
+        gid = config.ids.gids.leaps;
+      };
+    };
+
+    systemd.services.leaps = {
+      description   = "leaps service";
+      wantedBy      = [ "multi-user.target" ];
+      after         = [ "network.target" ];
+
+      serviceConfig = {
+        User = "leaps";
+        Group = "leaps";
+        Restart = "on-failure";
+        WorkingDirectory = stateDir;
+        PrivateTmp = true;
+        ExecStart = "${pkgs.leaps.bin}/bin/leaps -path ${toString cfg.path} -address ${cfg.address}:${toString cfg.port}";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/misc/matrix-synapse.nix b/nixos/modules/services/misc/matrix-synapse.nix
index bb8dc640f98..4a1bea50c14 100644
--- a/nixos/modules/services/misc/matrix-synapse.nix
+++ b/nixos/modules/services/misc/matrix-synapse.nix
@@ -5,15 +5,20 @@ with lib;
 let
   cfg = config.services.matrix-synapse;
   logConfigFile = pkgs.writeText "log_config.yaml" cfg.logConfig;
-  mkResource = r: ''{names: ${builtins.toJSON r.names}, compress: ${if r.compress then "true" else "false"}}'';
-  mkListener = l: ''{port: ${toString l.port}, bind_address: "${l.bind_address}", type: ${l.type}, tls: ${if l.tls then "true" else "false"}, x_forwarded: ${if l.x_forwarded then "true" else "false"}, resources: [${concatStringsSep "," (map mkResource l.resources)}]}'';
+  mkResource = r: ''{names: ${builtins.toJSON r.names}, compress: ${fromBool r.compress}}'';
+  mkListener = l: ''{port: ${toString l.port}, bind_address: "${l.bind_address}", type: ${l.type}, tls: ${fromBool l.tls}, x_forwarded: ${fromBool l.x_forwarded}, resources: [${concatStringsSep "," (map mkResource l.resources)}]}'';
+  fromBool = x: if x then "true" else "false";
   configFile = pkgs.writeText "homeserver.yaml" ''
+${optionalString (cfg.tls_certificate_path != null) ''
 tls_certificate_path: "${cfg.tls_certificate_path}"
+''}
 ${optionalString (cfg.tls_private_key_path != null) ''
 tls_private_key_path: "${cfg.tls_private_key_path}"
 ''}
+${optionalString (cfg.tls_dh_params_path != null) ''
 tls_dh_params_path: "${cfg.tls_dh_params_path}"
-no_tls: ${if cfg.no_tls then "true" else "false"}
+''}
+no_tls: ${fromBool cfg.no_tls}
 ${optionalString (cfg.bind_port != null) ''
 bind_port: ${toString cfg.bind_port}
 ''}
@@ -25,7 +30,7 @@ bind_host: "${cfg.bind_host}"
 ''}
 server_name: "${cfg.server_name}"
 pid_file: "/var/run/matrix-synapse.pid"
-web_client: ${if cfg.web_client then "true" else "false"}
+web_client: ${fromBool cfg.web_client}
 ${optionalString (cfg.public_baseurl != null) ''
 public_baseurl: "${cfg.public_baseurl}"
 ''}
@@ -53,14 +58,19 @@ media_store_path: "/var/lib/matrix-synapse/media"
 uploads_path: "/var/lib/matrix-synapse/uploads"
 max_upload_size: "${cfg.max_upload_size}"
 max_image_pixels: "${cfg.max_image_pixels}"
-dynamic_thumbnails: ${if cfg.dynamic_thumbnails then "true" else "false"}
-url_preview_enabled: False
+dynamic_thumbnails: ${fromBool cfg.dynamic_thumbnails}
+url_preview_enabled: ${fromBool cfg.url_preview_enabled}
+${optionalString (cfg.url_preview_enabled == true) ''
+url_preview_ip_range_blacklist: ${builtins.toJSON cfg.url_preview_ip_range_blacklist}
+url_preview_ip_range_whitelist: ${builtins.toJSON cfg.url_preview_ip_range_whitelist}
+url_preview_url_blacklist: ${builtins.toJSON cfg.url_preview_url_blacklist}
+''}
 recaptcha_private_key: "${cfg.recaptcha_private_key}"
 recaptcha_public_key: "${cfg.recaptcha_public_key}"
-enable_registration_captcha: ${if cfg.enable_registration_captcha then "true" else "false"}
+enable_registration_captcha: ${fromBool cfg.enable_registration_captcha}
 turn_uris: ${builtins.toJSON cfg.turn_uris}
 turn_shared_secret: "${cfg.turn_shared_secret}"
-enable_registration: ${if cfg.enable_registration then "true" else "false"}
+enable_registration: ${fromBool cfg.enable_registration}
 ${optionalString (cfg.registration_shared_secret != null) ''
 registration_shared_secret: "${cfg.registration_shared_secret}"
 ''}
@@ -68,9 +78,15 @@ recaptcha_siteverify_api: "https://www.google.com/recaptcha/api/siteverify"
 turn_user_lifetime: "${cfg.turn_user_lifetime}"
 user_creation_max_duration: ${cfg.user_creation_max_duration}
 bcrypt_rounds: ${cfg.bcrypt_rounds}
-allow_guest_access: {if cfg.allow_guest_access then "true" else "false"}
-enable_metrics: ${if cfg.enable_metrics then "true" else "false"}
-report_stats: ${if cfg.report_stats then "true" else "false"}
+allow_guest_access: ${fromBool cfg.allow_guest_access}
+trusted_third_party_id_servers: ${builtins.toJSON cfg.trusted_third_party_id_servers}
+room_invite_state_types: ${builtins.toJSON cfg.room_invite_state_types}
+${optionalString (cfg.macaroon_secret_key != null) ''
+  macaroon_secret_key: "${cfg.macaroon_secret_key}"
+''}
+expire_access_token: ${fromBool cfg.expire_access_token}
+enable_metrics: ${fromBool cfg.enable_metrics}
+report_stats: ${fromBool cfg.report_stats}
 signing_key_path: "/var/lib/matrix-synapse/homeserver.signing.key"
 key_refresh_interval: "${cfg.key_refresh_interval}"
 perspectives:
@@ -139,8 +155,9 @@ in {
         '';
       };
       tls_certificate_path = mkOption {
-        type = types.str;
-        default = "/var/lib/matrix-synapse/homeserver.tls.crt";
+        type = types.nullOr types.str;
+        default = null;
+        example = "/var/lib/matrix-synapse/homeserver.tls.crt";
         description = ''
           PEM encoded X509 certificate for TLS.
           You can replace the self-signed certificate that synapse
@@ -151,16 +168,17 @@ in {
       };
       tls_private_key_path = mkOption {
         type = types.nullOr types.str;
-        default = "/var/lib/matrix-synapse/homeserver.tls.key";
-        example = null;
+        default = null;
+        example = "/var/lib/matrix-synapse/homeserver.tls.key";
         description = ''
           PEM encoded private key for TLS. Specify null if synapse is not
           speaking TLS directly.
         '';
       };
       tls_dh_params_path = mkOption {
-        type = types.str;
-        default = "/var/lib/matrix-synapse/homeserver.tls.dh";
+        type = types.nullOr types.str;
+        default = null;
+        example = "/var/lib/matrix-synapse/homeserver.tls.dh";
         description = ''
           PEM dh parameters for ephemeral keys
         '';
@@ -342,6 +360,47 @@ in {
         default = "10K";
         description = "Number of events to cache in memory.";
       };
+      url_preview_enabled = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Is the preview URL API enabled?  If enabled, you *must* specify an
+          explicit url_preview_ip_range_blacklist of IPs that the spider is
+          denied from accessing.
+        '';
+      };
+      url_preview_ip_range_blacklist = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = ''
+          List of IP address CIDR ranges that the URL preview spider is denied
+          from accessing.
+        '';
+      };
+      url_preview_ip_range_whitelist = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = ''
+          List of IP address CIDR ranges that the URL preview spider is allowed
+          to access even if they are specified in
+          url_preview_ip_range_blacklist.
+        '';
+      };
+      url_preview_url_blacklist = mkOption {
+        type = types.listOf types.str;
+        default = [
+          "127.0.0.0/8"
+          "10.0.0.0/8"
+          "172.16.0.0/12"
+          "192.168.0.0/16"
+          "100.64.0.0/10"
+          "169.254.0.0/16"
+        ];
+        description = ''
+          Optional list of URL matches that the URL preview spider is
+          denied from accessing.
+        '';
+      };
       recaptcha_private_key = mkOption {
         type = types.str;
         default = "";
@@ -469,6 +528,34 @@ in {
           accessible to anonymous users.
         '';
       };
+      trusted_third_party_id_servers = mkOption {
+        type = types.listOf types.str;
+        default = ["matrix.org"];
+        description = ''
+          The list of identity servers trusted to verify third party identifiers by this server.
+        '';
+      };
+      room_invite_state_types = mkOption {
+        type = types.listOf types.str;
+        default = ["m.room.join_rules" "m.room.canonical_alias" "m.room.avatar" "m.room.name"];
+        description = ''
+          A list of event types that will be included in the room_invite_state
+        '';
+      };
+      macaroon_secret_key = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          Secret key for authentication tokens
+        '';
+      };
+      expire_access_token = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to enable access token expiration.
+        '';
+      };
       key_refresh_interval = mkOption {
         type = types.str;
         default = "1d";
@@ -522,12 +609,10 @@ in {
       after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
       preStart = ''
-        if ! test -e /var/lib/matrix-synapse; then
-          mkdir -p /var/lib/matrix-synapse
-          chmod 700 /var/lib/matrix-synapse
-          chown -R matrix-synapse:matrix-synapse /var/lib/matrix-synapse
-          ${cfg.package}/bin/homeserver --config-path ${configFile} --keys-directory /var/lib/matrix-synapse/ --generate-keys
-        fi
+        ${cfg.package}/bin/homeserver \
+          --config-path ${configFile} \
+          --keys-directory /var/lib/matrix-synapse \
+          --generate-keys
       '';
       serviceConfig = {
         Type = "simple";
@@ -535,7 +620,7 @@ in {
         Group = "matrix-synapse";
         WorkingDirectory = "/var/lib/matrix-synapse";
         PermissionsStartOnly = true;
-        ExecStart = "${cfg.package}/bin/homeserver --config-path ${configFile}";
+        ExecStart = "${cfg.package}/bin/homeserver --config-path ${configFile} --keys-directory /var/lib/matrix-synapse";
       };
     };
   };
diff --git a/nixos/modules/services/misc/mesos-master.nix b/nixos/modules/services/misc/mesos-master.nix
index 497646b2b41..99583ebeebd 100644
--- a/nixos/modules/services/misc/mesos-master.nix
+++ b/nixos/modules/services/misc/mesos-master.nix
@@ -80,7 +80,7 @@ in {
     systemd.services.mesos-master = {
       description = "Mesos Master";
       wantedBy = [ "multi-user.target" ];
-      after = [ "network-interfaces.target" ];
+      after = [ "network.target" ];
       serviceConfig = {
         ExecStart = ''
           ${pkgs.mesos}/bin/mesos-master \
diff --git a/nixos/modules/services/misc/mesos-slave.nix b/nixos/modules/services/misc/mesos-slave.nix
index 8c29734813a..9ddecb6fe30 100644
--- a/nixos/modules/services/misc/mesos-slave.nix
+++ b/nixos/modules/services/misc/mesos-slave.nix
@@ -105,7 +105,7 @@ in {
     systemd.services.mesos-slave = {
       description = "Mesos Slave";
       wantedBy = [ "multi-user.target" ];
-      after = [ "network-interfaces.target" ];
+      after = [ "network.target" ];
       environment.MESOS_CONTAINERIZERS = concatStringsSep "," containerizers;
       serviceConfig = {
         ExecStart = ''
diff --git a/nixos/modules/services/misc/nix-daemon.nix b/nixos/modules/services/misc/nix-daemon.nix
index 333782d15bc..7101cadfeed 100644
--- a/nixos/modules/services/misc/nix-daemon.nix
+++ b/nixos/modules/services/misc/nix-daemon.nix
@@ -105,7 +105,9 @@ in
           If set, Nix will perform builds in a sandboxed environment that it
           will set up automatically for each build.  This prevents
           impurities in builds by disallowing access to dependencies
-          outside of the Nix store.
+          outside of the Nix store. This isn't enabled by default for
+          performance. It doesn't affect derivation hashes, so changing
+          this option will not trigger a rebuild of packages.
         ";
       };
 
@@ -172,8 +174,8 @@ in
             sshKey = "/root/.ssh/id_buildfarm";
             system = "x86_64-linux";
             maxJobs = 2;
-            supportedFeatures = "kvm";
-            mandatoryFeatures = "perf";
+            supportedFeatures = [ "kvm" ];
+            mandatoryFeatures = [ "perf" ];
           }
         ];
         description = ''
diff --git a/nixos/modules/services/misc/nix-gc.nix b/nixos/modules/services/misc/nix-gc.nix
index 5c13da6e83d..304168c65b0 100644
--- a/nixos/modules/services/misc/nix-gc.nix
+++ b/nixos/modules/services/misc/nix-gc.nix
@@ -53,7 +53,7 @@ in
     systemd.services.nix-gc =
       { description = "Nix Garbage Collector";
         script = "exec ${config.nix.package.out}/bin/nix-collect-garbage ${cfg.options}";
-        startAt = optionalString cfg.automatic cfg.dates;
+        startAt = optional cfg.automatic cfg.dates;
       };
 
   };
diff --git a/nixos/modules/services/misc/nix-optimise.nix b/nixos/modules/services/misc/nix-optimise.nix
new file mode 100644
index 00000000000..a76bfd9f1f1
--- /dev/null
+++ b/nixos/modules/services/misc/nix-optimise.nix
@@ -0,0 +1,49 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.nix.optimise;
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    nix.optimise = {
+
+      automatic = mkOption {
+        default = false;
+        type = types.bool;
+        description = "Automatically run the nix store optimiser at a specific time.";
+      };
+
+      dates = mkOption {
+        default = ["03:45"];
+        type = types.listOf types.str;
+        description = ''
+          Specification (in the format described by
+          <citerefentry><refentrytitle>systemd.time</refentrytitle>
+          <manvolnum>5</manvolnum></citerefentry>) of the time at
+          which the optimiser will run.
+        '';
+      };
+    };
+  };
+
+
+  ###### implementation
+
+  config = {
+
+    systemd.services.nix-optimise =
+      { description = "Nix Store Optimiser";
+        serviceConfig.ExecStart = "${config.nix.package}/bin/nix-store --optimise";
+        startAt = optionals cfg.automatic cfg.dates;
+      };
+
+  };
+
+}
diff --git a/nixos/modules/services/misc/nscd-sssd.conf b/nixos/modules/services/misc/nscd-sssd.conf
new file mode 100644
index 00000000000..92380f3e4ba
--- /dev/null
+++ b/nixos/modules/services/misc/nscd-sssd.conf
@@ -0,0 +1,36 @@
+server-user             nscd
+threads                 1
+paranoia                no
+debug-level             0
+
+enable-cache            passwd          yes
+positive-time-to-live   passwd          0
+negative-time-to-live   passwd          0
+suggested-size          passwd          211
+check-files             passwd          yes
+persistent              passwd          no
+shared                  passwd          yes
+
+enable-cache            group           yes
+positive-time-to-live   group           0
+negative-time-to-live   group           0
+suggested-size          group           211
+check-files             group           yes
+persistent              group           no
+shared                  group           yes
+
+enable-cache            hosts           yes
+positive-time-to-live   hosts           600
+negative-time-to-live   hosts           5
+suggested-size          hosts           211
+check-files             hosts           yes
+persistent              hosts           no
+shared                  hosts           yes
+
+enable-cache            services        yes
+positive-time-to-live   services        0
+negative-time-to-live   services        0
+suggested-size          services        211
+check-files             services        yes
+persistent              services        no
+shared                  services        yes
diff --git a/nixos/modules/services/misc/parsoid.nix b/nixos/modules/services/misc/parsoid.nix
index 0844190a549..ae3f84333d2 100644
--- a/nixos/modules/services/misc/parsoid.nix
+++ b/nixos/modules/services/misc/parsoid.nix
@@ -6,20 +6,21 @@ let
 
   cfg = config.services.parsoid;
 
-  conf = ''
-    exports.setup = function( parsoidConfig ) {
-      ${toString (mapAttrsToList (name: str: "parsoidConfig.setInterwiki('${name}', '${str}');") cfg.interwikis)}
-
-      parsoidConfig.serverInterface = "${cfg.interface}";
-      parsoidConfig.serverPort = ${toString cfg.port};
-
-      parsoidConfig.useSelser = true;
-
-      ${cfg.extraConfig}
-    };
-  '';
+  confTree = {
+    worker_heartbeat_timeout = 300000;
+    logging = { level = "info"; };
+    services = [{
+      module = "lib/index.js";
+      entrypoint = "apiServiceWorker";
+      conf = {
+        mwApis = map (x: if isAttrs x then x else { uri = x; }) cfg.wikis;
+        serverInterface = cfg.interface;
+        serverPort = cfg.port;
+      };
+    }];
+  };
 
-  confFile = builtins.toFile "localsettings.js" conf;
+  confFile = pkgs.writeText "config.yml" (builtins.toJSON (recursiveUpdate confTree cfg.extraConfig));
 
 in
 {
@@ -38,9 +39,9 @@ in
         '';
       };
 
-      interwikis = mkOption {
-        type = types.attrsOf types.str;
-        example = { localhost = "http://localhost/api.php"; };
+      wikis = mkOption {
+        type = types.listOf (types.either types.str types.attrs);
+        example = [ "http://localhost/api.php" ];
         description = ''
           Used MediaWiki API endpoints.
         '';
@@ -71,8 +72,8 @@ in
       };
 
       extraConfig = mkOption {
-        type = types.lines;
-        default = "";
+        type = types.attrs;
+        default = {};
         description = ''
           Extra configuration to add to parsoid configuration.
         '';
@@ -91,7 +92,8 @@ in
       wantedBy = [ "multi-user.target" ];
       after = [ "network.target" ];
       serviceConfig = {
-        ExecStart = "${pkgs.nodePackages.parsoid}/lib/node_modules/parsoid/api/server.js -c ${confFile} -n ${toString cfg.workers}";
+        User = "nobody";
+        ExecStart = "${pkgs.nodePackages.parsoid}/lib/node_modules/parsoid/bin/server.js -c ${confFile} -n ${toString cfg.workers}";
       };
     };
 
diff --git a/nixos/modules/services/misc/plex.nix b/nixos/modules/services/misc/plex.nix
index 92b352db416..f6bf2dee986 100644
--- a/nixos/modules/services/misc/plex.nix
+++ b/nixos/modules/services/misc/plex.nix
@@ -19,6 +19,14 @@ in
         description = "The directory where Plex stores its data files.";
       };
 
+      openFirewall = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Open ports in the firewall for the media server
+        '';
+      };
+
       user = mkOption {
         type = types.str;
         default = "plex";
@@ -127,7 +135,7 @@ in
         User = cfg.user;
         Group = cfg.group;
         PermissionsStartOnly = "true";
-        ExecStart = "/bin/sh -c '${cfg.package}/usr/lib/plexmediaserver/Plex\\ Media\\ Server'";
+        ExecStart = "/bin/sh -c ${cfg.package}/usr/lib/plexmediaserver/Plex\\ Media\\ Server";
         Restart = "on-failure";
       };
       environment = {
@@ -141,6 +149,11 @@ in
       };
     };
 
+    networking.firewall = mkIf cfg.openFirewall {
+      allowedTCPPorts = [ 32400 3005 8324 32469 ];
+      allowedUDPPorts = [ 1900 5353 32410 32412 32413 32414 ];
+    };
+
     users.extraUsers = mkIf (cfg.user == "plex") {
       plex = {
         group = cfg.group;
diff --git a/nixos/modules/services/misc/redmine.nix b/nixos/modules/services/misc/redmine.nix
index 7c9483911f2..e3f1ec67cbb 100644
--- a/nixos/modules/services/misc/redmine.nix
+++ b/nixos/modules/services/misc/redmine.nix
@@ -71,7 +71,7 @@ in {
       };
 
       extraConfig = mkOption {
-        type = types.str;
+        type = types.lines;
         default = "";
         description = "Extra configuration in configuration.yml";
       };
diff --git a/nixos/modules/services/misc/rippled.nix b/nixos/modules/services/misc/rippled.nix
index c6b67e8498c..8bcf35a8ad3 100644
--- a/nixos/modules/services/misc/rippled.nix
+++ b/nixos/modules/services/misc/rippled.nix
@@ -154,43 +154,45 @@ let
   };
 
   dbOptions = {
-    type = mkOption {
-      description = "Rippled database type.";
-      type = types.enum ["rocksdb" "nudb"];
-      default = "rocksdb";
-    };
+    options = {
+      type = mkOption {
+        description = "Rippled database type.";
+        type = types.enum ["rocksdb" "nudb"];
+        default = "rocksdb";
+      };
 
-    path = mkOption {
-      description = "Location to store the database.";
-      type = types.path;
-      default = cfg.databasePath;
-    };
+      path = mkOption {
+        description = "Location to store the database.";
+        type = types.path;
+        default = cfg.databasePath;
+      };
 
-    compression = mkOption {
-      description = "Whether to enable snappy compression.";
-      type = types.nullOr types.bool;
-      default = null;
-    };
+      compression = mkOption {
+        description = "Whether to enable snappy compression.";
+        type = types.nullOr types.bool;
+        default = null;
+      };
 
-    onlineDelete = mkOption {
-      description = "Enable automatic purging of older ledger information.";
-      type = types.addCheck (types.nullOr types.int) (v: v > 256);
-      default = cfg.ledgerHistory;
-    };
+      onlineDelete = mkOption {
+        description = "Enable automatic purging of older ledger information.";
+        type = types.addCheck (types.nullOr types.int) (v: v > 256);
+        default = cfg.ledgerHistory;
+      };
 
-    advisoryDelete = mkOption {
-      description = ''
-	If set, then require administrative RPC call "can_delete"
-	to enable online deletion of ledger records.
-      '';
-      type = types.nullOr types.bool;
-      default = null;
-    };
+      advisoryDelete = mkOption {
+        description = ''
+	        If set, then require administrative RPC call "can_delete"
+	        to enable online deletion of ledger records.
+        '';
+        type = types.nullOr types.bool;
+        default = null;
+      };
 
-    extraOpts = mkOption {
-      description = "Extra database options.";
-      type = types.lines;
-      default = "";
+      extraOpts = mkOption {
+        description = "Extra database options.";
+        type = types.lines;
+        default = "";
+      };
     };
   };
 
@@ -213,8 +215,7 @@ in
 
       ports = mkOption {
 	description = "Ports exposed by rippled";
-	type = types.attrsOf types.optionSet;
-	options = [portOptions];
+	type = with types; attrsOf (submodule portOptions);
 	default = {
 	  rpc = {
 	    port = 5005;
@@ -238,8 +239,7 @@ in
 
       nodeDb = mkOption {
 	description = "Rippled main database options.";
-	type = types.nullOr types.optionSet;
-	options = dbOptions;
+	type = with types; nullOr (submodule dbOptions);
 	default = {
 	  type = "rocksdb";
 	  extraOpts = ''
@@ -254,15 +254,13 @@ in
 
       tempDb = mkOption {
 	description = "Rippled temporary database options.";
-	type = types.nullOr types.optionSet;
-	options = dbOptions;
+	type = with types; nullOr (submodule dbOptions);
 	default = null;
       };
 
       importDb = mkOption {
 	description = "Settings for performing a one-time import.";
-	type = types.nullOr types.optionSet;
-	options = dbOptions;
+	type = with types; nullOr (submodule dbOptions);
 	default = null;
       };
 
diff --git a/nixos/modules/services/misc/sssd.nix b/nixos/modules/services/misc/sssd.nix
new file mode 100644
index 00000000000..e818f4a4804
--- /dev/null
+++ b/nixos/modules/services/misc/sssd.nix
@@ -0,0 +1,97 @@
+{ config, lib, pkgs, ... }:
+with lib;
+let
+  cfg = config.services.sssd;
+  nscd = config.services.nscd;
+in {
+  options = {
+    services.sssd = {
+      enable = mkEnableOption "the System Security Services Daemon.";
+
+      config = mkOption {
+        type = types.lines;
+        description = "Contents of <filename>sssd.conf</filename>.";
+        default = ''
+          [sssd]
+          config_file_version = 2
+          services = nss, pam
+          domains = shadowutils
+
+          [nss]
+
+          [pam]
+
+          [domain/shadowutils]
+          id_provider = proxy
+          proxy_lib_name = files
+          auth_provider = proxy
+          proxy_pam_target = sssd-shadowutils
+          proxy_fast_alias = True
+        '';
+      };
+
+      sshAuthorizedKeysIntegration = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to make sshd look up authorized keys from SSS.
+          For this to work, the <literal>ssh</literal> SSS service must be enabled in the sssd configuration.
+        '';
+      };
+    };
+  };
+  config = mkMerge [
+    (mkIf cfg.enable {
+      assertions = singleton {
+        assertion = nscd.enable;
+        message = "nscd must be enabled through `services.nscd.enable` for SSSD to work.";
+      };
+
+      systemd.services.sssd = {
+        description = "System Security Services Daemon";
+        wantedBy    = [ "multi-user.target" ];
+        before = [ "systemd-user-sessions.service" "nss-user-lookup.target" ];
+        after = [ "network-online.target" "nscd.service" ];
+        requires = [ "network-online.target" "nscd.service" ];
+        wants = [ "nss-user-lookup.target" ];
+        restartTriggers = [
+          config.environment.etc."nscd.conf".source
+          config.environment.etc."sssd/sssd.conf".source
+        ];
+        script = ''
+          export LDB_MODULES_PATH+="''${LDB_MODULES_PATH+:}${pkgs.ldb}/modules/ldb:${pkgs.sssd}/modules/ldb"
+          mkdir -p /var/lib/sss/{pubconf,db,mc,pipes,gpo_cache,secrets} /var/lib/sss/pipes/private /var/lib/sss/pubconf/krb5.include.d
+          ${pkgs.sssd}/bin/sssd -D
+        '';
+        serviceConfig = {
+          Type = "forking";
+          PIDFile = "/run/sssd.pid";
+        };
+      };
+
+      environment.etc."sssd/sssd.conf" = {
+        text = cfg.config;
+        mode = "0400";
+      };
+
+      system.nssModules = optional cfg.enable pkgs.sssd;
+      services.nscd.config = builtins.readFile ./nscd-sssd.conf;
+      services.dbus.packages = [ pkgs.sssd ];
+    })
+
+    (mkIf cfg.sshAuthorizedKeysIntegration {
+    # Ugly: sshd refuses to start if a store path is given because /nix/store is group-writable.
+    # So indirect by a symlink.
+    environment.etc."ssh/authorized_keys_command" = {
+      mode = "0755";
+      text = ''
+        #!/bin/sh
+        exec ${pkgs.sssd}/bin/sss_ssh_authorizedkeys "$@"
+      '';
+    };
+    services.openssh.extraConfig = ''
+      AuthorizedKeysCommand /etc/ssh/authorized_keys_command
+      AuthorizedKeysCommandUser nobody
+    '';
+  })];
+}
diff --git a/nixos/modules/services/misc/svnserve.nix b/nixos/modules/services/misc/svnserve.nix
index c74befac749..04a6cd7bfa9 100644
--- a/nixos/modules/services/misc/svnserve.nix
+++ b/nixos/modules/services/misc/svnserve.nix
@@ -35,7 +35,7 @@ in
 
   config = mkIf cfg.enable {
     systemd.services.svnserve = {
-      after = [ "network-interfaces.target" ];
+      after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
       preStart = "mkdir -p ${cfg.svnBaseDir}";
       script = "${pkgs.subversion.out}/bin/svnserve -r ${cfg.svnBaseDir} -d --foreground --pid-file=/var/run/svnserve.pid";
diff --git a/nixos/modules/services/misc/taskserver/default.nix b/nixos/modules/services/misc/taskserver/default.nix
index 6d458feec34..ca82a733f6f 100644
--- a/nixos/modules/services/misc/taskserver/default.nix
+++ b/nixos/modules/services/misc/taskserver/default.nix
@@ -154,7 +154,7 @@ let
 
   certtool = "${pkgs.gnutls.bin}/bin/certtool";
 
-  nixos-taskserver = pkgs.buildPythonPackage {
+  nixos-taskserver = pkgs.pythonPackages.buildPythonPackage {
     name = "nixos-taskserver";
     namePrefix = "";
 
@@ -292,7 +292,7 @@ in {
       };
 
       allowedClientIDs = mkOption {
-        type = with types; loeOf (either (enum ["all" "none"]) str);
+        type = with types; either str (listOf str);
         default = [];
         example = [ "[Tt]ask [2-9]+" ];
         description = ''
@@ -306,7 +306,7 @@ in {
       };
 
       disallowedClientIDs = mkOption {
-        type = with types; loeOf (either (enum ["all" "none"]) str);
+        type = with types; either str (listOf str);
         default = [];
         example = [ "[Tt]ask [2-9]+" ];
         description = ''
diff --git a/nixos/modules/services/misc/zookeeper.nix b/nixos/modules/services/misc/zookeeper.nix
index 4ce692b6f6a..b7bca8b56b2 100644
--- a/nixos/modules/services/misc/zookeeper.nix
+++ b/nixos/modules/services/misc/zookeeper.nix
@@ -113,7 +113,7 @@ in {
     systemd.services.zookeeper = {
       description = "Zookeeper Daemon";
       wantedBy = [ "multi-user.target" ];
-      after = [ "network-interfaces.target" ];
+      after = [ "network.target" ];
       environment = { ZOOCFGDIR = configDir; };
       serviceConfig = {
         ExecStart = ''
diff --git a/nixos/modules/services/monitoring/bosun.nix b/nixos/modules/services/monitoring/bosun.nix
index 9a1e790d3ab..496838a131b 100644
--- a/nixos/modules/services/monitoring/bosun.nix
+++ b/nixos/modules/services/monitoring/bosun.nix
@@ -107,7 +107,7 @@ in {
       };
 
       extraConfig = mkOption {
-        type = types.string;
+        type = types.lines;
         default = "";
         description = ''
           Extra configuration options for Bosun. You should describe your
diff --git a/nixos/modules/services/monitoring/cadvisor.nix b/nixos/modules/services/monitoring/cadvisor.nix
index a67df158be4..8ae8b12056c 100644
--- a/nixos/modules/services/monitoring/cadvisor.nix
+++ b/nixos/modules/services/monitoring/cadvisor.nix
@@ -90,6 +90,7 @@ in {
             ${optionalString cfg.storageDriverSecure "-storage_driver_secure"}
           ''}
         '';
+        TimeoutStartSec=300;
       };
     };
 
diff --git a/nixos/modules/services/monitoring/collectd.nix b/nixos/modules/services/monitoring/collectd.nix
index 3c3d83c66ed..641da60e9ad 100644
--- a/nixos/modules/services/monitoring/collectd.nix
+++ b/nixos/modules/services/monitoring/collectd.nix
@@ -9,7 +9,7 @@ let
     BaseDir "${cfg.dataDir}"
     PIDFile "${cfg.pidFile}"
     AutoLoadPlugin ${if cfg.autoLoadPlugin then "true" else "false"}
-    Hostname ${config.networking.hostName}
+    Hostname "${config.networking.hostName}"
 
     LoadPlugin syslog
     <Plugin "syslog">
@@ -108,7 +108,8 @@ in {
       };
 
       preStart = ''
-        mkdir -m 0700 -p ${cfg.dataDir}
+        mkdir -p ${cfg.dataDir}
+        chmod 755 ${cfg.dataDir}
         install -D /dev/null ${cfg.pidFile}
         if [ "$(id -u)" = 0 ]; then
           chown -R ${cfg.user} ${cfg.dataDir};
diff --git a/nixos/modules/services/monitoring/graphite.nix b/nixos/modules/services/monitoring/graphite.nix
index 08fc3f04dbf..c5352e5887d 100644
--- a/nixos/modules/services/monitoring/graphite.nix
+++ b/nixos/modules/services/monitoring/graphite.nix
@@ -167,7 +167,7 @@ in {
             CACHE_TYPE: 'filesystem'
             CACHE_DIR: '/tmp/graphite-api-cache'
         '';
-        type = types.str;
+        type = types.lines;
       };
     };
 
@@ -387,7 +387,7 @@ in {
       systemd.services.carbonCache = let name = "carbon-cache"; in {
         description = "Graphite Data Storage Backend";
         wantedBy = [ "multi-user.target" ];
-        after = [ "network-interfaces.target" ];
+        after = [ "network.target" ];
         environment = carbonEnv;
         serviceConfig = {
           ExecStart = "${pkgs.pythonPackages.twisted}/bin/twistd ${carbonOpts name}";
@@ -410,7 +410,7 @@ in {
         enable = cfg.carbon.enableAggregator;
         description = "Carbon Data Aggregator";
         wantedBy = [ "multi-user.target" ];
-        after = [ "network-interfaces.target" ];
+        after = [ "network.target" ];
         environment = carbonEnv;
         serviceConfig = {
           ExecStart = "${pkgs.pythonPackages.twisted}/bin/twistd ${carbonOpts name}";
@@ -426,7 +426,7 @@ in {
       systemd.services.carbonRelay = let name = "carbon-relay"; in {
         description = "Carbon Data Relay";
         wantedBy = [ "multi-user.target" ];
-        after = [ "network-interfaces.target" ];
+        after = [ "network.target" ];
         environment = carbonEnv;
         serviceConfig = {
           ExecStart = "${pkgs.pythonPackages.twisted}/bin/twistd ${carbonOpts name}";
@@ -448,7 +448,7 @@ in {
       systemd.services.graphiteWeb = {
         description = "Graphite Web Interface";
         wantedBy = [ "multi-user.target" ];
-        after = [ "network-interfaces.target" ];
+        after = [ "network.target" ];
         path = [ pkgs.perl ];
         environment = {
           PYTHONPATH = let
@@ -501,7 +501,7 @@ in {
       systemd.services.graphiteApi = {
         description = "Graphite Api Interface";
         wantedBy = [ "multi-user.target" ];
-        after = [ "network-interfaces.target" ];
+        after = [ "network.target" ];
         environment = {
           PYTHONPATH = let
               aenv = pkgs.python.buildEnv.override {
@@ -538,7 +538,7 @@ in {
       systemd.services.seyren = {
         description = "Graphite Alerting Dashboard";
         wantedBy = [ "multi-user.target" ];
-        after = [ "network-interfaces.target" "mongodb.service" ];
+        after = [ "network.target" "mongodb.service" ];
         environment = seyrenConfig;
         serviceConfig = {
           ExecStart = "${pkgs.seyren}/bin/seyren -httpPort ${toString cfg.seyren.port}";
@@ -561,7 +561,7 @@ in {
       systemd.services.graphitePager = {
         description = "Graphite Pager Alerting Daemon";
         wantedBy = [ "multi-user.target" ];
-        after = [ "network-interfaces.target" "redis.service" ];
+        after = [ "network.target" "redis.service" ];
         environment = {
           REDIS_URL = cfg.pager.redisUrl;
           GRAPHITE_URL = cfg.pager.graphiteUrl;
@@ -585,7 +585,7 @@ in {
         serviceConfig = {
           ExecStart = ''
             ${pkgs.pythonPackages.graphite_beacon}/bin/graphite-beacon \
-              --config ${pkgs.writeText "graphite-beacon.json" (builtins.toJSON cfg.beacon.config)}
+              --config=${pkgs.writeText "graphite-beacon.json" (builtins.toJSON cfg.beacon.config)}
           '';
           User = "graphite";
           Group = "graphite";
diff --git a/nixos/modules/services/monitoring/monit.nix b/nixos/modules/services/monitoring/monit.nix
index 704693969a3..e07ffd2e8b5 100644
--- a/nixos/modules/services/monitoring/monit.nix
+++ b/nixos/modules/services/monitoring/monit.nix
@@ -36,11 +36,16 @@ in
     ];
 
     systemd.services.monit = {
-      description = "Monit system watcher";
-      after = [ "network-interfaces.target" ];
+      description = "Pro-active monitoring utility for unix systems";
+      after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
-      script = "${pkgs.monit}/bin/monit -I -c /etc/monit.conf";
-      serviceConfig.Restart = "always";
+      serviceConfig = {
+        ExecStart = "${pkgs.monit}/bin/monit -I -c /etc/monit.conf";
+        ExecStop = "${pkgs.monit}/bin/monit -c /etc/monit.conf quit";
+        ExecReload = "${pkgs.monit}/bin/monit -c /etc/monit.conf reload";
+        KillMode = "process";
+        Restart = "always";
+      };
     };
   };
 }
diff --git a/nixos/modules/services/monitoring/munin.nix b/nixos/modules/services/monitoring/munin.nix
index 08ba161d38b..a80565fa280 100644
--- a/nixos/modules/services/monitoring/munin.nix
+++ b/nixos/modules/services/monitoring/munin.nix
@@ -100,6 +100,7 @@ in
 
       extraConfig = mkOption {
         default = "";
+        type = types.lines;
         description = ''
           <filename>munin-node.conf</filename> extra configuration. See
           <link xlink:href='http://munin-monitoring.org/wiki/munin-node.conf' />
diff --git a/nixos/modules/services/monitoring/nagios.nix b/nixos/modules/services/monitoring/nagios.nix
index f2f7710de9e..4914c5db97d 100644
--- a/nixos/modules/services/monitoring/nagios.nix
+++ b/nixos/modules/services/monitoring/nagios.nix
@@ -163,7 +163,7 @@ in
       description = "Nagios monitoring daemon";
       path     = [ pkgs.nagios ];
       wantedBy = [ "multi-user.target" ];
-      after    = [ "network-interfaces.target" ];
+      after    = [ "network.target" ];
 
       serviceConfig = {
         User = "nagios";
diff --git a/nixos/modules/services/monitoring/prometheus/alertmanager.nix b/nixos/modules/services/monitoring/prometheus/alertmanager.nix
new file mode 100644
index 00000000000..da2cd02eaa3
--- /dev/null
+++ b/nixos/modules/services/monitoring/prometheus/alertmanager.nix
@@ -0,0 +1,116 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.services.prometheus.alertmanager;
+  mkConfigFile = pkgs.writeText "alertmanager.yml" (builtins.toJSON cfg.configuration);
+in {
+  options = {
+    services.prometheus.alertmanager = {
+      enable = mkEnableOption "Prometheus Alertmanager";
+
+      user = mkOption {
+        type = types.str;
+        default = "nobody";
+        description = ''
+          User name under which Alertmanager shall be run.
+        '';
+      };
+
+      group = mkOption {
+        type = types.str;
+        default = "nogroup";
+        description = ''
+          Group under which Alertmanager shall be run.
+        '';
+      };
+
+      configuration = mkOption {
+        type = types.attrs;
+        default = {};
+        description = ''
+          Alertmanager configuration as nix attribute set.
+        '';
+      };
+
+      logFormat = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          If set use a syslog logger or JSON logging.
+        '';
+      };
+
+      logLevel = mkOption {
+        type = types.enum ["debug" "info" "warn" "error" "fatal"];
+        default = "warn";
+        description = ''
+          Only log messages with the given severity or above.
+        '';
+      };
+
+      webExternalUrl = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          The URL under which Alertmanager is externally reachable (for example, if Alertmanager is served via a reverse proxy).
+          Used for generating relative and absolute links back to Alertmanager itself.
+          If the URL has a path portion, it will be used to prefix all HTTP endoints served by Alertmanager.
+          If omitted, relevant URL components will be derived automatically.
+        '';
+      };
+
+      listenAddress = mkOption {
+        type = types.str;
+        default = "";
+        description = ''
+          Address to listen on for the web interface and API.
+        '';
+      };
+
+      port = mkOption {
+        type = types.int;
+        default = 9093;
+        description = ''
+          Port to listen on for the web interface and API.
+        '';
+      };
+
+      openFirewall = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Open port in firewall for incoming connections.
+        '';
+      };
+    };
+  };
+
+
+  config = mkIf cfg.enable {
+    networking.firewall.allowedTCPPorts = optional cfg.openFirewall cfg.port;
+
+    systemd.services.alertmanager = {
+      wantedBy = [ "multi-user.target" ];
+      after    = [ "network.target" ];
+      script = ''
+        ${pkgs.prometheus-alertmanager.bin}/bin/alertmanager \
+        -config.file ${mkConfigFile} \
+        -web.listen-address ${cfg.listenAddress}:${toString cfg.port} \
+        -log.level ${cfg.logLevel} \
+        ${optionalString (cfg.webExternalUrl != null) ''-web.external-url ${cfg.webExternalUrl} \''}
+        ${optionalString (cfg.logFormat != null) "-log.format ${cfg.logFormat}"}
+      '';
+
+      serviceConfig = {
+        User = cfg.user;
+        Group = cfg.group;
+        Restart  = "always";
+        PrivateTmp = true;
+        WorkingDirectory = "/tmp";
+        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/monitoring/prometheus/blackbox-exporter.nix b/nixos/modules/services/monitoring/prometheus/blackbox-exporter.nix
new file mode 100644
index 00000000000..7a343299c31
--- /dev/null
+++ b/nixos/modules/services/monitoring/prometheus/blackbox-exporter.nix
@@ -0,0 +1,67 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.services.prometheus.blackboxExporter;
+in {
+  options = {
+    services.prometheus.blackboxExporter = {
+      enable = mkEnableOption "prometheus blackbox exporter";
+
+      configFile = mkOption {
+        type = types.path;
+        description = ''
+          Path to configuration file.
+        '';
+      };
+
+      port = mkOption {
+        type = types.int;
+        default = 9115;
+        description = ''
+          Port to listen on.
+        '';
+      };
+
+      extraFlags = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = ''
+          Extra commandline options when launching the blackbox exporter.
+        '';
+      };
+
+      openFirewall = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Open port in firewall for incoming connections.
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    networking.firewall.allowedTCPPorts = optional cfg.openFirewall cfg.port;
+
+    systemd.services.prometheus-blackbox-exporter = {
+      description = "Prometheus exporter for blackbox probes";
+      unitConfig.Documentation = "https://github.com/prometheus/blackbox_exporter";
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        User = "nobody";
+        Restart = "always";
+        PrivateTmp = true;
+        WorkingDirectory = /tmp;
+        ExecStart = ''
+          ${pkgs.prometheus-blackbox-exporter}/bin/blackbox_exporter \
+            -web.listen-address :${toString cfg.port} \
+            -config.file ${cfg.configFile} \
+            ${concatStringsSep " \\\n  " cfg.extraFlags}
+        '';
+        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/monitoring/prometheus/default.nix b/nixos/modules/services/monitoring/prometheus/default.nix
new file mode 100644
index 00000000000..a07445ce167
--- /dev/null
+++ b/nixos/modules/services/monitoring/prometheus/default.nix
@@ -0,0 +1,465 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.services.prometheus;
+  promUser = "prometheus";
+  promGroup = "prometheus";
+
+  # Get a submodule without any embedded metadata:
+  _filter = x: filterAttrs (k: v: k != "_module") x;
+
+  # Pretty-print JSON to a file
+  writePrettyJSON = name: x:
+    pkgs.runCommand name { } ''
+      echo '${builtins.toJSON x}' | ${pkgs.jq}/bin/jq . > $out
+    '';
+
+  # This becomes the main config file
+  promConfig = {
+    global = cfg.globalConfig;
+    rule_files = cfg.ruleFiles ++ [
+      (pkgs.writeText "prometheus.rules" (concatStringsSep "\n" cfg.rules))
+    ];
+    scrape_configs = cfg.scrapeConfigs;
+  };
+
+  generatedPrometheusYml = writePrettyJSON "prometheus.yml" promConfig;
+
+  prometheusYml =
+    if cfg.configText != null then
+      pkgs.writeText "prometheus.yml" cfg.configText
+    else generatedPrometheusYml;
+
+  cmdlineArgs = cfg.extraFlags ++ [
+    "-storage.local.path=${cfg.dataDir}/metrics"
+    "-config.file=${prometheusYml}"
+    "-web.listen-address=${cfg.listenAddress}"
+    "-alertmanager.notification-queue-capacity=${toString cfg.alertmanagerNotificationQueueCapacity}"
+    "-alertmanager.timeout=${toString cfg.alertmanagerTimeout}s"
+    (optionalString (cfg.alertmanagerURL != []) "-alertmanager.url=${concatStringsSep "," cfg.alertmanagerURL}")
+  ];
+
+  promTypes.globalConfig = types.submodule {
+    options = {
+      scrape_interval = mkOption {
+        type = types.str;
+        default = "1m";
+        description = ''
+          How frequently to scrape targets by default.
+        '';
+      };
+
+      scrape_timeout = mkOption {
+        type = types.str;
+        default = "10s";
+        description = ''
+          How long until a scrape request times out.
+        '';
+      };
+
+      evaluation_interval = mkOption {
+        type = types.str;
+        default = "1m";
+        description = ''
+          How frequently to evaluate rules by default.
+        '';
+      };
+
+      labels = mkOption {
+        type = types.attrsOf types.str;
+        default = {};
+        description = ''
+          The labels to add to any timeseries that this Prometheus instance
+          scrapes.
+        '';
+      };
+    };
+  };
+
+  promTypes.scrape_config = types.submodule {
+    options = {
+      job_name = mkOption {
+        type = types.str;
+        description = ''
+          The job name assigned to scraped metrics by default.
+        '';
+      };
+      scrape_interval = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          How frequently to scrape targets from this job. Defaults to the
+          globally configured default.
+        '';
+      };
+      scrape_timeout = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          Per-target timeout when scraping this job. Defaults to the
+          globally configured default.
+        '';
+      };
+      metrics_path = mkOption {
+        type = types.str;
+        default = "/metrics";
+        description = ''
+          The HTTP resource path on which to fetch metrics from targets.
+        '';
+      };
+      scheme = mkOption {
+        type = types.enum ["http" "https"];
+        default = "http";
+        description = ''
+          The URL scheme with which to fetch metrics from targets.
+        '';
+      };
+      basic_auth = mkOption {
+        type = types.nullOr (types.submodule {
+          options = {
+            username = mkOption {
+              type = types.str;
+              description = ''
+                HTTP username
+              '';
+            };
+            password = mkOption {
+              type = types.str;
+              description = ''
+                HTTP password
+              '';
+            };
+          };
+        });
+        default = null;
+        description = ''
+          Optional http login credentials for metrics scraping.
+        '';
+      };
+      dns_sd_configs = mkOption {
+        type = types.listOf promTypes.dns_sd_config;
+        default = [];
+        apply = x: map _filter x;
+        description = ''
+          List of DNS service discovery configurations.
+        '';
+      };
+      consul_sd_configs = mkOption {
+        type = types.listOf promTypes.consul_sd_config;
+        default = [];
+        apply = x: map _filter x;
+        description = ''
+          List of Consul service discovery configurations.
+        '';
+      };
+      file_sd_configs = mkOption {
+        type = types.listOf promTypes.file_sd_config;
+        default = [];
+        apply = x: map _filter x;
+        description = ''
+          List of file service discovery configurations.
+        '';
+      };
+      static_configs = mkOption {
+        type = types.listOf promTypes.static_config;
+        default = [];
+        apply = x: map _filter x;
+        description = ''
+          List of labeled target groups for this job.
+        '';
+      };
+      relabel_configs = mkOption {
+        type = types.listOf promTypes.relabel_config;
+        default = [];
+        apply = x: map _filter x;
+        description = ''
+          List of relabel configurations.
+        '';
+      };
+    };
+  };
+
+  promTypes.static_config = types.submodule {
+    options = {
+      targets = mkOption {
+        type = types.listOf types.str;
+        description = ''
+          The targets specified by the target group.
+        '';
+      };
+      labels = mkOption {
+        type = types.attrsOf types.str;
+        default = {};
+        description = ''
+          Labels assigned to all metrics scraped from the targets.
+        '';
+      };
+    };
+  };
+
+  promTypes.dns_sd_config = types.submodule {
+    options = {
+      names = mkOption {
+        type = types.listOf types.str;
+        description = ''
+          A list of DNS SRV record names to be queried.
+        '';
+      };
+      refresh_interval = mkOption {
+        type = types.str;
+        default = "30s";
+        description = ''
+          The time after which the provided names are refreshed.
+        '';
+      };
+    };
+  };
+
+  promTypes.consul_sd_config = types.submodule {
+    options = {
+      server = mkOption {
+        type = types.str;
+        description = "Consul server to query.";
+      };
+      token = mkOption {
+        type = types.nullOr types.str;
+        description = "Consul token";
+      };
+      datacenter = mkOption {
+        type = types.nullOr types.str;
+        description = "Consul datacenter";
+      };
+      scheme = mkOption {
+        type = types.nullOr types.str;
+        description = "Consul scheme";
+      };
+      username = mkOption {
+        type = types.nullOr types.str;
+        description = "Consul username";
+      };
+      password = mkOption {
+        type = types.nullOr types.str;
+        description = "Consul password";
+      };
+
+      services = mkOption {
+        type = types.listOf types.str;
+        description = ''
+          A list of services for which targets are retrieved.
+        '';
+      };
+      tag_separator = mkOption {
+        type = types.str;
+        default = ",";
+        description = ''
+          The string by which Consul tags are joined into the tag label.
+        '';
+      };
+    };
+  };
+
+  promTypes.file_sd_config = types.submodule {
+    options = {
+      files = mkOption {
+        type = types.listOf types.str;
+        description = ''
+          Patterns for files from which target groups are extracted. Refer
+          to the Prometheus documentation for permitted filename patterns
+          and formats.
+
+        '';
+      };
+      refresh_interval = mkOption {
+        type = types.str;
+        default = "30s";
+        description = ''
+          Refresh interval to re-read the files.
+        '';
+      };
+    };
+  };
+
+  promTypes.relabel_config = types.submodule {
+    options = {
+      source_labels = mkOption {
+        type = types.listOf types.str;
+        description = ''
+          The source labels select values from existing labels. Their content
+          is concatenated using the configured separator and matched against
+          the configured regular expression.
+        '';
+      };
+      separator = mkOption {
+        type = types.str;
+        default = ";";
+        description = ''
+          Separator placed between concatenated source label values.
+        '';
+      };
+      target_label = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          Label to which the resulting value is written in a replace action.
+          It is mandatory for replace actions.
+        '';
+      };
+      regex = mkOption {
+        type = types.str;
+        default = "(.*)";
+        description = ''
+          Regular expression against which the extracted value is matched.
+        '';
+      };
+      replacement = mkOption {
+        type = types.str;
+        default = "$1";
+        description = ''
+          Replacement value against which a regex replace is performed if the
+          regular expression matches.
+        '';
+      };
+      action = mkOption {
+        type = types.enum ["replace" "keep" "drop"];
+        default = "replace";
+        description = ''
+          Action to perform based on regex matching.
+        '';
+      };
+    };
+  };
+
+in {
+  options = {
+    services.prometheus = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Enable the Prometheus monitoring daemon.
+        '';
+      };
+
+      listenAddress = mkOption {
+        type = types.str;
+        default = "0.0.0.0:9090";
+        description = ''
+          Address to listen on for the web interface, API, and telemetry.
+        '';
+      };
+
+      dataDir = mkOption {
+        type = types.path;
+        default = "/var/lib/prometheus";
+        description = ''
+          Directory to store Prometheus metrics data.
+        '';
+      };
+
+      extraFlags = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = ''
+          Extra commandline options when launching Prometheus.
+        '';
+      };
+
+      configText = mkOption {
+        type = types.nullOr types.lines;
+        default = null;
+        description = ''
+          If non-null, this option defines the text that is written to
+          prometheus.yml. If null, the contents of prometheus.yml is generated
+          from the structured config options.
+        '';
+      };
+
+      globalConfig = mkOption {
+        type = promTypes.globalConfig;
+        default = {};
+        apply = _filter;
+        description = ''
+          Parameters that are valid in all  configuration contexts. They
+          also serve as defaults for other configuration sections
+        '';
+      };
+
+      rules = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = ''
+          Alerting and/or Recording rules to evaluate at runtime.
+        '';
+      };
+
+      ruleFiles = mkOption {
+        type = types.listOf types.path;
+        default = [];
+        description = ''
+          Any additional rules files to include in this configuration.
+        '';
+      };
+
+      scrapeConfigs = mkOption {
+        type = types.listOf promTypes.scrape_config;
+        default = [];
+        apply = x: map _filter x;
+        description = ''
+          A list of scrape configurations.
+        '';
+      };
+
+      alertmanagerURL = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = ''
+          List of Alertmanager URLs to send notifications to.
+        '';
+      };
+
+      alertmanagerNotificationQueueCapacity = mkOption {
+        type = types.int;
+        default = 10000;
+        description = ''
+          The capacity of the queue for pending alert manager notifications.
+        '';
+      };
+
+      alertmanagerTimeout = mkOption {
+        type = types.int;
+        default = 10;
+        description = ''
+          Alert manager HTTP API timeout (in seconds).
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    users.extraGroups.${promGroup}.gid = config.ids.gids.prometheus;
+    users.extraUsers.${promUser} = {
+      description = "Prometheus daemon user";
+      uid = config.ids.uids.prometheus;
+      group = promGroup;
+      home = cfg.dataDir;
+      createHome = true;
+    };
+    systemd.services.prometheus = {
+      wantedBy = [ "multi-user.target" ];
+      after    = [ "network.target" ];
+      script = ''
+        #!/bin/sh
+        exec ${pkgs.prometheus}/bin/prometheus \
+          ${concatStringsSep " \\\n  " cmdlineArgs}
+      '';
+      serviceConfig = {
+        User = promUser;
+        Restart  = "always";
+        WorkingDirectory = cfg.dataDir;
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/monitoring/prometheus/json-exporter.nix b/nixos/modules/services/monitoring/prometheus/json-exporter.nix
new file mode 100644
index 00000000000..6bc56df9834
--- /dev/null
+++ b/nixos/modules/services/monitoring/prometheus/json-exporter.nix
@@ -0,0 +1,74 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.services.prometheus.jsonExporter;
+in {
+  options = {
+    services.prometheus.jsonExporter = {
+      enable = mkEnableOption "prometheus JSON exporter";
+
+      url = mkOption {
+        type = types.str;
+        description = ''
+          URL to scrape JSON from.
+        '';
+      };
+
+      configFile = mkOption {
+        type = types.path;
+        description = ''
+          Path to configuration file.
+        '';
+      };
+
+      port = mkOption {
+        type = types.int;
+        default = 7979;
+        description = ''
+          Port to listen on.
+        '';
+      };
+
+      extraFlags = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = ''
+          Extra commandline options when launching the JSON exporter.
+        '';
+      };
+
+      openFirewall = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Open port in firewall for incoming connections.
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    networking.firewall.allowedTCPPorts = optional cfg.openFirewall cfg.port;
+
+    systemd.services.prometheus-json-exporter = {
+      description = "Prometheus exporter for JSON over HTTP";
+      unitConfig.Documentation = "https://github.com/kawamuray/prometheus-json-exporter";
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        User = "nobody";
+        Restart = "always";
+        PrivateTmp = true;
+        WorkingDirectory = /tmp;
+        ExecStart = ''
+          ${pkgs.prometheus-json-exporter}/bin/prometheus-json-exporter \
+            --port ${toString cfg.port} \
+            ${cfg.url} ${cfg.configFile} \
+            ${concatStringsSep " \\\n  " cfg.extraFlags}
+        '';
+        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/monitoring/prometheus/nginx-exporter.nix b/nixos/modules/services/monitoring/prometheus/nginx-exporter.nix
new file mode 100644
index 00000000000..1ccafee3b18
--- /dev/null
+++ b/nixos/modules/services/monitoring/prometheus/nginx-exporter.nix
@@ -0,0 +1,78 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.services.prometheus.nginxExporter;
+in {
+  options = {
+    services.prometheus.nginxExporter = {
+      enable = mkEnableOption "prometheus nginx exporter";
+
+      port = mkOption {
+        type = types.int;
+        default = 9113;
+        description = ''
+          Port to listen on.
+        '';
+      };
+
+      listenAddress = mkOption {
+        type = types.string;
+        default = "0.0.0.0";
+        description = ''
+          Address to listen on.
+        '';
+      };
+
+      scrapeUri = mkOption {
+        type = types.string;
+        default = "http://localhost/nginx_status";
+        description = ''
+          Address to access the nginx status page.
+          Can be enabled with services.nginx.statusPage = true.
+        '';
+      };
+
+      extraFlags = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = ''
+          Extra commandline options when launching the nginx exporter.
+        '';
+      };
+
+      openFirewall = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Open port in firewall for incoming connections.
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    networking.firewall.allowedTCPPorts = optional cfg.openFirewall cfg.port;
+
+    systemd.services.prometheus-nginx-exporter = {
+      after = [ "network.target" "nginx.service" ];
+      description = "Prometheus exporter for nginx metrics";
+      unitConfig.Documentation = "https://github.com/discordianfish/nginx_exporter";
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        User = "nobody";
+        Restart  = "always";
+        PrivateTmp = true;
+        WorkingDirectory = /tmp;
+        ExecStart = ''
+          ${pkgs.prometheus-nginx-exporter}/bin/nginx_exporter \
+            -nginx.scrape_uri '${cfg.scrapeUri}' \
+            -telemetry.address ${cfg.listenAddress}:${toString cfg.port} \
+            ${concatStringsSep " \\\n  " cfg.extraFlags}
+        '';
+        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/monitoring/prometheus/node-exporter.nix b/nixos/modules/services/monitoring/prometheus/node-exporter.nix
new file mode 100644
index 00000000000..0cf0b85afb5
--- /dev/null
+++ b/nixos/modules/services/monitoring/prometheus/node-exporter.nix
@@ -0,0 +1,81 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.services.prometheus.nodeExporter;
+  cmdlineArgs = cfg.extraFlags ++ [
+    "-web.listen-address=${cfg.listenAddress}"
+  ];
+in {
+  options = {
+    services.prometheus.nodeExporter = {
+      enable = mkEnableOption "prometheus node exporter";
+
+      port = mkOption {
+        type = types.int;
+        default = 9100;
+        description = ''
+          Port to listen on.
+        '';
+      };
+
+      listenAddress = mkOption {
+        type = types.string;
+        default = "0.0.0.0";
+        description = ''
+          Address to listen on.
+        '';
+      };
+
+      enabledCollectors = mkOption {
+        type = types.listOf types.string;
+        default = [];
+        example = ''[ "systemd" ]'';
+        description = ''
+          Collectors to enable, additionally to the defaults.
+        '';
+      };
+
+      extraFlags = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = ''
+          Extra commandline options when launching the node exporter.
+        '';
+      };
+
+      openFirewall = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Open port in firewall for incoming connections.
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    networking.firewall.allowedTCPPorts = optional cfg.openFirewall cfg.port;
+
+    systemd.services.prometheus-node-exporter = {
+      description = "Prometheus exporter for machine metrics";
+      unitConfig.Documentation = "https://github.com/prometheus/node_exporter";
+      wantedBy = [ "multi-user.target" ];
+      script = ''
+        exec ${pkgs.prometheus-node-exporter}/bin/node_exporter \
+          ${optionalString (cfg.enabledCollectors != [])
+            ''-collectors.enabled ${concatStringsSep "," cfg.enabledCollectors}''} \
+          -web.listen-address ${cfg.listenAddress}:${toString cfg.port} \
+          ${concatStringsSep " \\\n  " cfg.extraFlags}
+      '';
+      serviceConfig = {
+        User = "nobody";
+        Restart  = "always";
+        PrivateTmp = true;
+        WorkingDirectory = /tmp;
+        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/monitoring/prometheus/snmp-exporter.nix b/nixos/modules/services/monitoring/prometheus/snmp-exporter.nix
new file mode 100644
index 00000000000..fe33f8c1f04
--- /dev/null
+++ b/nixos/modules/services/monitoring/prometheus/snmp-exporter.nix
@@ -0,0 +1,127 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.services.prometheus.snmpExporter;
+  mkConfigFile = pkgs.writeText "snmp.yml" (if cfg.configurationPath == null then builtins.toJSON cfg.configuration else builtins.readFile cfg.configurationPath);
+in {
+  options = {
+    services.prometheus.snmpExporter = {
+      enable = mkEnableOption "Prometheus snmp exporter";
+
+      user = mkOption {
+        type = types.str;
+        default = "nobody";
+        description = ''
+          User name under which snmp exporter shall be run.
+        '';
+      };
+
+      group = mkOption {
+        type = types.str;
+        default = "nogroup";
+        description = ''
+          Group under which snmp exporter shall be run.
+        '';
+      };
+
+      port = mkOption {
+        type = types.int;
+        default = 9116;
+        description = ''
+          Port to listen on.
+        '';
+      };
+
+      listenAddress = mkOption {
+        type = types.nullOr types.str;
+        default = null;
+        description = ''
+          Address to listen on for web interface and telemetry.
+        '';
+      };
+
+      configurationPath = mkOption {
+        type = types.nullOr types.path;
+        default = null;
+        description = ''
+          Path to a snmp exporter configuration file. Mutually exclusive with 'configuration' option.
+        '';
+        example = "./snmp.yml";
+      };
+
+      configuration = mkOption {
+        type = types.nullOr types.attrs;
+        default = {};
+        description = ''
+          Snmp exporter configuration as nix attribute set. Mutually exclusive with 'configurationPath' option.
+        '';
+        example = ''
+          {
+            "default" = {
+              "version" = 2;
+              "auth" = {
+                "community" = "public";
+              };
+            };
+          };
+        '';
+      };
+
+      logFormat = mkOption {
+        type = types.str;
+        default = "logger:stderr";
+        description = ''
+          Set the log target and format.
+        '';
+      };
+
+      logLevel = mkOption {
+        type = types.enum ["debug" "info" "warn" "error" "fatal"];
+        default = "info";
+        description = ''
+          Only log messages with the given severity or above.
+        '';
+      };
+
+      openFirewall = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Open port in firewall for incoming connections.
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    networking.firewall.allowedTCPPorts = optional cfg.openFirewall cfg.port;
+
+    assertions = singleton
+      {
+        assertion = (cfg.configurationPath == null) != (cfg.configuration == null);
+        message = "Please ensure you have either 'configuration' or 'configurationPath' set!";
+      };
+
+    systemd.services.prometheus-snmp-exporter = {
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+      script = ''
+        ${pkgs.prometheus-snmp-exporter.bin}/bin/snmp_exporter \
+          -config.file ${mkConfigFile} \
+          -log.format ${cfg.logFormat} \
+          -log.level ${cfg.logLevel} \
+          -web.listen-address ${optionalString (cfg.listenAddress != null) cfg.listenAddress}:${toString cfg.port}
+      '';
+
+      serviceConfig = {
+        User = cfg.user;
+        Group = cfg.group;
+        Restart  = "always";
+        PrivateTmp = true;
+        WorkingDirectory = "/tmp";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/monitoring/prometheus/varnish-exporter.nix b/nixos/modules/services/monitoring/prometheus/varnish-exporter.nix
new file mode 100644
index 00000000000..143ebb62aea
--- /dev/null
+++ b/nixos/modules/services/monitoring/prometheus/varnish-exporter.nix
@@ -0,0 +1,61 @@
+{ config, pkgs, lib, ... }:
+
+# Shamelessly cribbed from nginx-exporter.nix. ~ C.
+with lib;
+
+let
+  cfg = config.services.prometheus.varnishExporter;
+in {
+  options = {
+    services.prometheus.varnishExporter = {
+      enable = mkEnableOption "prometheus Varnish exporter";
+
+      port = mkOption {
+        type = types.int;
+        default = 9131;
+        description = ''
+          Port to listen on.
+        '';
+      };
+
+      extraFlags = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = ''
+          Extra commandline options when launching the Varnish exporter.
+        '';
+      };
+
+      openFirewall = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Open port in firewall for incoming connections.
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    networking.firewall.allowedTCPPorts = optional cfg.openFirewall cfg.port;
+
+    systemd.services.prometheus-varnish-exporter = {
+      description = "Prometheus exporter for Varnish metrics";
+      unitConfig.Documentation = "https://github.com/jonnenauha/prometheus_varnish_exporter";
+      wantedBy = [ "multi-user.target" ];
+      path = [ pkgs.varnish ];
+      script = ''
+        exec ${pkgs.prometheus-varnish-exporter}/bin/prometheus_varnish_exporter \
+          -web.listen-address :${toString cfg.port} \
+          ${concatStringsSep " \\\n  " cfg.extraFlags}
+      '';
+      serviceConfig = {
+        User = "nobody";
+        Restart = "always";
+        PrivateTmp = true;
+        WorkingDirectory = /tmp;
+        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/monitoring/riemann-tools.nix b/nixos/modules/services/monitoring/riemann-tools.nix
index ce277f09464..de858813a76 100644
--- a/nixos/modules/services/monitoring/riemann-tools.nix
+++ b/nixos/modules/services/monitoring/riemann-tools.nix
@@ -50,6 +50,7 @@ in {
 
     systemd.services.riemann-health = {
       wantedBy = [ "multi-user.target" ];
+      path = [ procps ];
       serviceConfig = {
         User = "riemanntools";
         ExecStart = "${healthLauncher}/bin/riemann-health";
diff --git a/nixos/modules/services/monitoring/smartd.nix b/nixos/modules/services/monitoring/smartd.nix
index b67519b3424..99fd5c4d367 100644
--- a/nixos/modules/services/monitoring/smartd.nix
+++ b/nixos/modules/services/monitoring/smartd.nix
@@ -197,8 +197,7 @@ in
       devices = mkOption {
         default = [];
         example = [ { device = "/dev/sda"; } { device = "/dev/sdb"; options = "-d sat"; } ];
-        type = types.listOf types.optionSet;
-        options = [ smartdOpts ];
+        type = with types; listOf (submodule smartdOpts);
         description = "List of devices to monitor.";
       };
 
diff --git a/nixos/modules/services/monitoring/telegraf.nix b/nixos/modules/services/monitoring/telegraf.nix
new file mode 100644
index 00000000000..49dc9d8143e
--- /dev/null
+++ b/nixos/modules/services/monitoring/telegraf.nix
@@ -0,0 +1,71 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.telegraf;
+
+  configFile = pkgs.runCommand "config.toml" {
+    buildInputs = [ pkgs.remarshal ];
+  } ''
+    remarshal -if json -of toml \
+      < ${pkgs.writeText "config.json" (builtins.toJSON cfg.extraConfig)} \
+      > $out
+  '';
+in {
+  ###### interface
+  options = {
+    services.telegraf = {
+      enable = mkEnableOption "telegraf server";
+
+      package = mkOption {
+        default = pkgs.telegraf;
+        defaultText = "pkgs.telegraf";
+        description = "Which telegraf derivation to use";
+        type = types.package;
+      };
+
+      extraConfig = mkOption {
+        default = {};
+        description = "Extra configuration options for telegraf";
+        type = types.attrs;
+        example = {
+          outputs = {
+            influxdb = {
+              urls = ["http://localhost:8086"];
+              database = "telegraf";
+            };
+          };
+          inputs = {
+            statsd = {
+              service_address = ":8125";
+              delete_timings = true;
+            };
+          };
+        };
+      };
+    };
+  };
+
+
+  ###### implementation
+  config = mkIf config.services.telegraf.enable {
+    systemd.services.telegraf = {
+      description = "Telegraf Agent";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network-online.target" ];
+      serviceConfig = {
+        ExecStart=''${cfg.package}/bin/telegraf -config "${configFile}"'';
+        ExecReload="${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+        User = "telegraf";
+        Restart = "on-failure";
+      };
+    };
+
+    users.extraUsers = [{
+      name = "telegraf";
+      uid = config.ids.uids.telegraf;
+      description = "telegraf daemon user";
+    }];
+  };
+}
diff --git a/nixos/modules/services/monitoring/ups.nix b/nixos/modules/services/monitoring/ups.nix
index 5f80d547dbc..c4c4ed227b3 100644
--- a/nixos/modules/services/monitoring/ups.nix
+++ b/nixos/modules/services/monitoring/ups.nix
@@ -169,8 +169,7 @@ in
           monitoring directly.  These are usually attached to serial ports,
           but USB devices are also supported.
         '';
-        type = types.attrsOf types.optionSet;
-        options = [ upsOptions ];
+        type = with types; attrsOf (submodule upsOptions);
       };
 
     };
@@ -182,7 +181,8 @@ in
 
     systemd.services.upsmon = {
       description = "Uninterruptible Power Supplies (Monitor)";
-      wantedBy = [ "ip-up.target" ];
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
       serviceConfig.Type = "forking";
       script = "${pkgs.nut}/sbin/upsmon";
       environment.NUT_CONFPATH = "/etc/nut/";
@@ -191,8 +191,8 @@ in
 
     systemd.services.upsd = {
       description = "Uninterruptible Power Supplies (Daemon)";
+      after = [ "network.target" "upsmon.service" ];
       wantedBy = [ "multi-user.target" ];
-      after = [ "network-interfaces.target" "upsmon.service" ];
       serviceConfig.Type = "forking";
       # TODO: replace 'root' by another username.
       script = "${pkgs.nut}/sbin/upsd -u root";
@@ -202,8 +202,8 @@ in
 
     systemd.services.upsdrv = {
       description = "Uninterruptible Power Supplies (Register all UPS)";
-      wantedBy = [ "multi-user.target" ];
       after = [ "upsd.service" ];
+      wantedBy = [ "multi-user.target" ];
       # TODO: replace 'root' by another username.
       script = ''${pkgs.nut}/bin/upsdrvctl -u root start'';
       serviceConfig = {
diff --git a/nixos/modules/services/monitoring/zabbix-agent.nix b/nixos/modules/services/monitoring/zabbix-agent.nix
index a943075be0c..88a63b4bf16 100644
--- a/nixos/modules/services/monitoring/zabbix-agent.nix
+++ b/nixos/modules/services/monitoring/zabbix-agent.nix
@@ -53,6 +53,7 @@ in
 
       extraConfig = mkOption {
         default = "";
+        type = types.lines;
         description = ''
           Configuration that is injected verbatim into the configuration file.
         '';
diff --git a/nixos/modules/services/network-filesystems/cachefilesd.nix b/nixos/modules/services/network-filesystems/cachefilesd.nix
new file mode 100644
index 00000000000..61981340840
--- /dev/null
+++ b/nixos/modules/services/network-filesystems/cachefilesd.nix
@@ -0,0 +1,59 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.cachefilesd;
+
+  cfgFile = pkgs.writeText "cachefilesd.conf" ''
+    dir ${cfg.cacheDir}
+    ${cfg.extraConfig}
+  '';
+
+in
+
+{
+  options = {
+    services.cachefilesd = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Whether to enable cachefilesd network filesystems caching daemon.";
+      };
+
+      cacheDir = mkOption {
+        type = types.str;
+        default = "/var/cache/fscache";
+        description = "Directory to contain filesystem cache.";
+      };
+
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        example = "brun 10%";
+        description = "Additional configuration file entries. See cachefilesd.conf(5) for more information.";
+      };
+
+    };
+  };
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    systemd.services.cachefilesd = {
+      description = "Local network file caching management daemon";
+      wantedBy = [ "multi-user.target" ];
+      path = [ pkgs.kmod pkgs.cachefilesd ];
+      script = ''
+        modprobe -qab cachefiles
+        mkdir -p ${cfg.cacheDir}
+        chmod 700 ${cfg.cacheDir}
+        exec cachefilesd -n -f ${cfgFile}
+      '';
+    };
+
+  };
+}
diff --git a/nixos/modules/services/network-filesystems/drbd.nix b/nixos/modules/services/network-filesystems/drbd.nix
index 9896a93b189..57b1fbb597c 100644
--- a/nixos/modules/services/network-filesystems/drbd.nix
+++ b/nixos/modules/services/network-filesystems/drbd.nix
@@ -53,9 +53,9 @@ let cfg = config.services.drbd; in
       };
 
     systemd.services.drbd = {
-      after = [ "systemd-udev.settle.service" ];
+      after = [ "systemd-udev.settle.service" "network.target" ];
       wants = [ "systemd-udev.settle.service" ];
-      wantedBy = [ "ip-up.target" ];
+      wantedBy = [ "multi-user.target" ];
       script = ''
         ${pkgs.drbd}/sbin/drbdadm up all
       '';
diff --git a/nixos/modules/services/network-filesystems/ipfs.nix b/nixos/modules/services/network-filesystems/ipfs.nix
new file mode 100644
index 00000000000..104b5b92620
--- /dev/null
+++ b/nixos/modules/services/network-filesystems/ipfs.nix
@@ -0,0 +1,125 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  inherit (pkgs) ipfs;
+
+  cfg = config.services.ipfs;
+
+  ipfsFlags = ''${if cfg.autoMigrate then "--migrate" else ""} ${if cfg.enableGC then "--enable-gc" else ""} ${toString cfg.extraFlags}'';
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.ipfs = {
+
+      enable = mkEnableOption "Interplanetary File System";
+
+      user = mkOption {
+        type = types.str;
+        default = "ipfs";
+        description = "User under which the IPFS daemon runs";
+      };
+
+      group = mkOption {
+        type = types.str;
+        default = "ipfs";
+        description = "Group under which the IPFS daemon runs";
+      };
+
+      dataDir = mkOption {
+        type = types.str;
+        default = "/var/lib/ipfs";
+        description = "The data dir for IPFS";
+      };
+
+      autoMigrate = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether IPFS should try to migrate the file system automatically.
+        '';
+      };
+
+      gatewayAddress = mkOption {
+        type = types.str;
+        default = "/ip4/127.0.0.1/tcp/8080";
+        description = "Where the IPFS Gateway can be reached";
+      };
+
+      apiAddress = mkOption {
+        type = types.str;
+        default = "/ip4/127.0.0.1/tcp/5001";
+        description = "Where IPFS exposes its API to";
+      };
+
+      enableGC = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to enable automatic garbage collection.
+        '';
+      };
+
+      extraFlags = mkOption {
+        type = types.listOf types.str;
+        description = "Extra flags passed to the IPFS daemon";
+        default = [];
+      };
+    };
+  };
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+    environment.systemPackages = [ pkgs.ipfs ];
+
+    users.extraUsers = mkIf (cfg.user == "ipfs") {
+      ipfs = {
+        group = cfg.group;
+        home = cfg.dataDir;
+        createHome = false;
+        uid = config.ids.uids.ipfs;
+        description = "IPFS daemon user";
+      };
+    };
+
+    users.extraGroups = mkIf (cfg.group == "ipfs") {
+      ipfs = {
+        gid = config.ids.gids.ipfs;
+      };
+    };
+
+    systemd.services.ipfs = {
+      description = "IPFS Daemon";
+
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" "local-fs.target" ];
+      path  = [ pkgs.ipfs pkgs.su pkgs.bash ];
+
+      preStart =
+        ''
+          install -m 0755 -o ${cfg.user} -g ${cfg.group} -d ${cfg.dataDir}
+          if [[ ! -d ${cfg.dataDir}/.ipfs ]]; then
+            cd ${cfg.dataDir}
+            ${pkgs.su}/bin/su -s ${pkgs.bash}/bin/sh ${cfg.user} -c "${ipfs}/bin/ipfs init"
+          fi
+          ${pkgs.su}/bin/su -s ${pkgs.bash}/bin/sh ${cfg.user} -c "${ipfs}/bin/ipfs config Addresses.API ${cfg.apiAddress}"
+          ${pkgs.su}/bin/su -s ${pkgs.bash}/bin/sh ${cfg.user} -c "${ipfs}/bin/ipfs config Addresses.Gateway ${cfg.gatewayAddress}"
+        '';
+
+      serviceConfig = {
+        ExecStart = "${ipfs}/bin/ipfs daemon ${ipfsFlags}";
+        User = cfg.user;
+        Group = cfg.group;
+        PermissionsStartOnly = true;
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/network-filesystems/openafs-client/default.nix b/nixos/modules/services/network-filesystems/openafs-client/default.nix
index 891f41c8dcd..6f51e287910 100644
--- a/nixos/modules/services/network-filesystems/openafs-client/default.nix
+++ b/nixos/modules/services/network-filesystems/openafs-client/default.nix
@@ -75,7 +75,7 @@ in
     systemd.services.afsd = {
       description = "AFS client";
       wantedBy = [ "multi-user.target" ];
-      after = [ "network-interfaces.target" ];
+      after = [ "network.target" ];
 
       preStart = ''
         mkdir -p -m 0755 /afs
diff --git a/nixos/modules/services/network-filesystems/samba.nix b/nixos/modules/services/network-filesystems/samba.nix
index 91f1a333be7..884966363b8 100644
--- a/nixos/modules/services/network-filesystems/samba.nix
+++ b/nixos/modules/services/network-filesystems/samba.nix
@@ -56,6 +56,7 @@ let
       serviceConfig = {
         ExecStart = "${samba}/sbin/${appName} ${args}";
         ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+        Type = "notify";
       };
 
       restartTriggers = [ configFile ];
@@ -167,12 +168,12 @@ in
         type = types.attrsOf (types.attrsOf types.unspecified);
         example =
           { public =
-             { path = "/srv/public";
-               "read only" = true;
-               browseable = "yes";
-               "guest ok" = "yes";
-                comment = "Public samba share.";
-             };
+            { path = "/srv/public";
+              "read only" = true;
+              browseable = "yes";
+              "guest ok" = "yes";
+              comment = "Public samba share.";
+            };
           };
       };
 
diff --git a/nixos/modules/services/network-filesystems/tahoe.nix b/nixos/modules/services/network-filesystems/tahoe.nix
index d4b6c05e943..ab9eac3829f 100644
--- a/nixos/modules/services/network-filesystems/tahoe.nix
+++ b/nixos/modules/services/network-filesystems/tahoe.nix
@@ -8,148 +8,189 @@ in
     options.services.tahoe = {
       introducers = mkOption {
         default = {};
-        type = types.loaOf types.optionSet;
+        type = with types; loaOf (submodule {
+          options = {
+            nickname = mkOption {
+              type = types.str;
+              description = ''
+                The nickname of this Tahoe introducer.
+              '';
+            };
+            tub.port = mkOption {
+              default = 3458;
+              type = types.int;
+              description = ''
+                The port on which the introducer will listen.
+              '';
+            };
+            tub.location = mkOption {
+              default = null;
+              type = types.nullOr types.str;
+              description = ''
+                The external location that the introducer should listen on.
+
+                If specified, the port should be included.
+              '';
+            };
+            package = mkOption {
+              default = pkgs.tahoelafs;
+              defaultText = "pkgs.tahoelafs";
+              type = types.package;
+              example = literalExample "pkgs.tahoelafs";
+              description = ''
+                The package to use for the Tahoe LAFS daemon.
+              '';
+            };
+          };
+        });
         description = ''
           The Tahoe introducers.
         '';
-        options = {
-          nickname = mkOption {
-            type = types.str;
-            description = ''
-              The nickname of this Tahoe introducer.
-            '';
-          };
-          tub.port = mkOption {
-            default = 3458;
-            type = types.int;
-            description = ''
-              The port on which the introducer will listen.
-            '';
-          };
-          tub.location = mkOption {
-            default = null;
-            type = types.nullOr types.str;
-            description = ''
-              The external location that the introducer should listen on.
-
-              If specified, the port should be included.
-            '';
-          };
-          package = mkOption {
-            default = pkgs.tahoelafs;
-            defaultText = "pkgs.tahoelafs";
-            type = types.package;
-            example = literalExample "pkgs.tahoelafs";
-            description = ''
-              The package to use for the Tahoe LAFS daemon.
-            '';
-          };
-        };
       };
       nodes = mkOption {
         default = {};
-        type = types.loaOf types.optionSet;
-        description = ''
-          The Tahoe nodes.
-        '';
-        options = {
-          nickname = mkOption {
-            type = types.str;
-            description = ''
-              The nickname of this Tahoe node.
-            '';
-          };
-          tub.port = mkOption {
-            default = 3457;
-            type = types.int;
-            description = ''
-              The port on which the tub will listen.
+        type = with types; loaOf (submodule {
+          options = {
+            nickname = mkOption {
+              type = types.str;
+              description = ''
+                The nickname of this Tahoe node.
+              '';
+            };
+            tub.port = mkOption {
+              default = 3457;
+              type = types.int;
+              description = ''
+                The port on which the tub will listen.
 
-              This is the correct setting to tweak if you want Tahoe's storage
-              system to listen on a different port.
-            '';
-          };
-          tub.location = mkOption {
-            default = null;
-            type = types.nullOr types.str;
-            description = ''
-              The external location that the node should listen on.
+                This is the correct setting to tweak if you want Tahoe's storage
+                system to listen on a different port.
+              '';
+            };
+            tub.location = mkOption {
+              default = null;
+              type = types.nullOr types.str;
+              description = ''
+                The external location that the node should listen on.
 
-              This is the setting to tweak if there are multiple interfaces
-              and you want to alter which interface Tahoe is advertising.
+                This is the setting to tweak if there are multiple interfaces
+                and you want to alter which interface Tahoe is advertising.
 
-              If specified, the port should be included.
-            '';
-          };
-          web.port = mkOption {
-            default = 3456;
-            type = types.int;
-            description = ''
-              The port on which the Web server will listen.
+                If specified, the port should be included.
+              '';
+            };
+            web.port = mkOption {
+              default = 3456;
+              type = types.int;
+              description = ''
+                The port on which the Web server will listen.
 
-              This is the correct setting to tweak if you want Tahoe's WUI to
-              listen on a different port.
-            '';
-          };
-          client.introducer = mkOption {
-            default = null;
-            type = types.nullOr types.str;
-            description = ''
-              The furl for a Tahoe introducer node.
+                This is the correct setting to tweak if you want Tahoe's WUI to
+                listen on a different port.
+              '';
+            };
+            client.introducer = mkOption {
+              default = null;
+              type = types.nullOr types.str;
+              description = ''
+                The furl for a Tahoe introducer node.
 
-              Like all furls, keep this safe and don't share it.
-            '';
-          };
-          client.helper = mkOption {
-            default = null;
-            type = types.nullOr types.str;
-            description = ''
-              The furl for a Tahoe helper node.
+                Like all furls, keep this safe and don't share it.
+              '';
+            };
+            client.helper = mkOption {
+              default = null;
+              type = types.nullOr types.str;
+              description = ''
+                The furl for a Tahoe helper node.
 
-              Like all furls, keep this safe and don't share it.
-            '';
-          };
-          client.shares.needed = mkOption {
-            default = 3;
-            type = types.int;
-            description = ''
-              The number of shares required to reconstitute a file.
-            '';
-          };
-          client.shares.happy = mkOption {
-            default = 7;
-            type = types.int;
-            description = ''
-              The number of distinct storage nodes required to store
-              a file.
-            '';
-          };
-          client.shares.total = mkOption {
-            default = 10;
-            type = types.int;
-            description = ''
-              The number of shares required to store a file.
-            '';
-          };
-          storage.enable = mkEnableOption "storage service";
-          storage.reservedSpace = mkOption {
-            default = "1G";
-            type = types.str;
-            description = ''
-              The amount of filesystem space to not use for storage.
-            '';
-          };
-          helper.enable = mkEnableOption "helper service";
-          package = mkOption {
-            default = pkgs.tahoelafs;
-            defaultText = "pkgs.tahoelafs";
-            type = types.package;
-            example = literalExample "pkgs.tahoelafs";
-            description = ''
-              The package to use for the Tahoe LAFS daemon.
-            '';
+                Like all furls, keep this safe and don't share it.
+              '';
+            };
+            client.shares.needed = mkOption {
+              default = 3;
+              type = types.int;
+              description = ''
+                The number of shares required to reconstitute a file.
+              '';
+            };
+            client.shares.happy = mkOption {
+              default = 7;
+              type = types.int;
+              description = ''
+                The number of distinct storage nodes required to store
+                a file.
+              '';
+            };
+            client.shares.total = mkOption {
+              default = 10;
+              type = types.int;
+              description = ''
+                The number of shares required to store a file.
+              '';
+            };
+            storage.enable = mkEnableOption "storage service";
+            storage.reservedSpace = mkOption {
+              default = "1G";
+              type = types.str;
+              description = ''
+                The amount of filesystem space to not use for storage.
+              '';
+            };
+            helper.enable = mkEnableOption "helper service";
+            sftpd.enable = mkEnableOption "SFTP service";
+            sftpd.port = mkOption {
+              default = null;
+              type = types.nullOr types.int;
+              description = ''
+                The port on which the SFTP server will listen.
+
+                This is the correct setting to tweak if you want Tahoe's SFTP
+                daemon to listen on a different port.
+              '';
+            };
+            sftpd.hostPublicKeyFile = mkOption {
+              default = null;
+              type = types.nullOr types.path;
+              description = ''
+                Path to the SSH host public key.
+              '';
+            };
+            sftpd.hostPrivateKeyFile = mkOption {
+              default = null;
+              type = types.nullOr types.path;
+              description = ''
+                Path to the SSH host private key.
+              '';
+            };
+            sftpd.accounts.file = mkOption {
+              default = null;
+              type = types.nullOr types.path;
+              description = ''
+                Path to the accounts file.
+              '';
+            };
+            sftpd.accounts.url = mkOption {
+              default = null;
+              type = types.nullOr types.str;
+              description = ''
+                URL of the accounts server.
+              '';
+            };
+            package = mkOption {
+              default = pkgs.tahoelafs;
+              defaultText = "pkgs.tahoelafs";
+              type = types.package;
+              example = literalExample "pkgs.tahoelafs";
+              description = ''
+                The package to use for the Tahoe LAFS daemon.
+              '';
+            };
           };
-        };
+        });
+        description = ''
+          The Tahoe nodes.
+        '';
       };
     };
     config = mkMerge [
@@ -192,6 +233,12 @@ in
             serviceConfig = {
               Type = "simple";
               PIDFile = pidfile;
+              # Believe it or not, Tahoe is very brittle about the order of
+              # arguments to $(tahoe start). The node directory must come first,
+              # and arguments which alter Twisted's behavior come afterwards.
+              ExecStart = ''
+                ${settings.package}/bin/tahoe start ${nodedir} -n -l- --pidfile=${pidfile}
+              '';
             };
             preStart = ''
               if [ \! -d ${nodedir} ]; then
@@ -207,12 +254,6 @@ in
               # ln -s /etc/tahoe-lafs/introducer-${node}.cfg ${nodedir}/tahoe.cfg
               cp /etc/tahoe-lafs/introducer-${node}.cfg ${nodedir}/tahoe.cfg
             '';
-            # Believe it or not, Tahoe is very brittle about the order of
-            # arguments to $(tahoe start). The node directory must come first,
-            # and arguments which alter Twisted's behavior come afterwards.
-            script = ''
-              tahoe start ${nodedir} -n -l- --pidfile=${pidfile}
-            '';
           });
         users.extraUsers = flip mapAttrs' cfg.introducers (node: _:
           nameValuePair "tahoe.introducer-${node}" {
@@ -254,6 +295,19 @@ in
 
                 [helper]
                 enabled = ${if settings.helper.enable then "true" else "false"}
+
+                [sftpd]
+                enabled = ${if settings.sftpd.enable then "true" else "false"}
+                ${optionalString (settings.sftpd.port != null)
+                  "port = ${toString settings.sftpd.port}"}
+                ${optionalString (settings.sftpd.hostPublicKeyFile != null)
+                  "host_pubkey_file = ${settings.sftpd.hostPublicKeyFile}"}
+                ${optionalString (settings.sftpd.hostPrivateKeyFile != null)
+                  "host_privkey_file = ${settings.sftpd.hostPrivateKeyFile}"}
+                ${optionalString (settings.sftpd.accounts.file != null)
+                  "accounts.file = ${settings.sftpd.accounts.file}"}
+                ${optionalString (settings.sftpd.accounts.url != null)
+                  "accounts.url = ${settings.sftpd.accounts.url}"}
               '';
             });
           # Actually require Tahoe, so that we will have it installed.
@@ -279,6 +333,12 @@ in
             serviceConfig = {
               Type = "simple";
               PIDFile = pidfile;
+              # Believe it or not, Tahoe is very brittle about the order of
+              # arguments to $(tahoe start). The node directory must come first,
+              # and arguments which alter Twisted's behavior come afterwards.
+              ExecStart = ''
+                ${settings.package}/bin/tahoe start ${nodedir} -n -l- --pidfile=${pidfile}
+              '';
             };
             preStart = ''
               if [ \! -d ${nodedir} ]; then
@@ -294,12 +354,6 @@ in
               # ln -s /etc/tahoe-lafs/${node}.cfg ${nodedir}/tahoe.cfg
               cp /etc/tahoe-lafs/${node}.cfg ${nodedir}/tahoe.cfg
             '';
-            # Believe it or not, Tahoe is very brittle about the order of
-            # arguments to $(tahoe start). The node directory must come first,
-            # and arguments which alter Twisted's behavior come afterwards.
-            script = ''
-              tahoe start ${nodedir} -n -l- --pidfile=${pidfile}
-            '';
           });
         users.extraUsers = flip mapAttrs' cfg.nodes (node: _:
           nameValuePair "tahoe.${node}" {
diff --git a/nixos/modules/services/network-filesystems/xtreemfs.nix b/nixos/modules/services/network-filesystems/xtreemfs.nix
index b051214e1d0..0c6714563d8 100644
--- a/nixos/modules/services/network-filesystems/xtreemfs.nix
+++ b/nixos/modules/services/network-filesystems/xtreemfs.nix
@@ -153,6 +153,7 @@ in
           '';
         };
         extraConfig = mkOption {
+          type = types.lines;
           default = "";
           example = ''
             # specify whether SSL is required
@@ -173,6 +174,7 @@ in
         replication = {
           enable = mkEnableOption "XtreemFS DIR replication plugin";
           extraConfig = mkOption {
+            type = types.lines;
             example = ''
               # participants of the replication including this replica
               babudb.repl.participant.0 = 192.168.0.10
@@ -269,6 +271,7 @@ in
           '';
         };
         extraConfig = mkOption {
+          type = types.lines;
           example = ''
             osd_check_interval = 300
             no_atime = true
@@ -307,6 +310,7 @@ in
         replication = {
           enable = mkEnableOption "XtreemFS MRC replication plugin";
           extraConfig = mkOption {
+            type = types.lines;
             example = ''
               # participants of the replication including this replica
               babudb.repl.participant.0 = 192.168.0.10
@@ -385,6 +389,7 @@ in
           '';
         };
         extraConfig = mkOption {
+          type = types.lines;
           example = ''
             local_clock_renewal = 0
             remote_time_sync = 30000
diff --git a/nixos/modules/services/network-filesystems/yandex-disk.nix b/nixos/modules/services/network-filesystems/yandex-disk.nix
index 982b6ca5ea7..4de20664133 100644
--- a/nixos/modules/services/network-filesystems/yandex-disk.nix
+++ b/nixos/modules/services/network-filesystems/yandex-disk.nix
@@ -55,6 +55,15 @@ in
         description = "The directory to use for Yandex.Disk storage";
       };
 
+      excludes = mkOption {
+        default = "";
+        type = types.string;
+        example = "data,backup";
+        description = ''
+          Comma-separated list of directories which are excluded from synchronization.
+        '';
+      };
+
     };
 
   };
@@ -86,7 +95,7 @@ in
         chown ${u} ${dir}
 
         if ! test -d "${cfg.directory}" ; then
-          mkdir -p -m 755 ${cfg.directory} ||
+          (mkdir -p -m 755 ${cfg.directory} && chown ${u} ${cfg.directory}) ||
             exit 1
         fi
 
@@ -94,7 +103,7 @@ in
           -c '${pkgs.yandex-disk}/bin/yandex-disk token -p ${cfg.password} ${cfg.username} ${dir}/token'
 
         ${pkgs.su}/bin/su -s ${pkgs.stdenv.shell} ${u} \
-          -c '${pkgs.yandex-disk}/bin/yandex-disk start --no-daemon -a ${dir}/token -d ${cfg.directory}'
+          -c '${pkgs.yandex-disk}/bin/yandex-disk start --no-daemon -a ${dir}/token -d ${cfg.directory} --exclude-dirs=${cfg.excludes}'
       '';
 
     };
diff --git a/nixos/modules/services/networking/amuled.nix b/nixos/modules/services/networking/amuled.nix
index bc488d0e910..fc7d56a24fa 100644
--- a/nixos/modules/services/networking/amuled.nix
+++ b/nixos/modules/services/networking/amuled.nix
@@ -59,7 +59,8 @@ in
 
     systemd.services.amuled = {
       description = "AMule daemon";
-      wantedBy = [ "ip-up.target" ];
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
 
       preStart = ''
         mkdir -p ${cfg.dataDir}
diff --git a/nixos/modules/services/networking/asterisk.nix b/nixos/modules/services/networking/asterisk.nix
index 13617a1b6c5..5c71a1d8dda 100644
--- a/nixos/modules/services/networking/asterisk.nix
+++ b/nixos/modules/services/networking/asterisk.nix
@@ -6,29 +6,38 @@ let
   cfg = config.services.asterisk;
 
   asteriskUser = "asterisk";
+  asteriskGroup = "asterisk";
 
   varlibdir = "/var/lib/asterisk";
   spooldir = "/var/spool/asterisk";
   logdir = "/var/log/asterisk";
 
+  # Add filecontents from files of useTheseDefaultConfFiles to confFiles, do not override
+  defaultConfFiles = subtractLists (attrNames cfg.confFiles) cfg.useTheseDefaultConfFiles;
+  allConfFiles =
+    cfg.confFiles //
+    builtins.listToAttrs (map (x: { name = x;
+                                    value = builtins.readFile (pkgs.asterisk + "/etc/asterisk/" + x); })
+                              defaultConfFiles);
+
   asteriskEtc = pkgs.stdenv.mkDerivation
   ((mapAttrs' (name: value: nameValuePair
         # Fudge the names to make bash happy
         ((replaceChars ["."] ["_"] name) + "_")
         (value)
-      ) cfg.confFiles) //
+      ) allConfFiles) //
   {
     confFilesString = concatStringsSep " " (
-      attrNames cfg.confFiles
+      attrNames allConfFiles
     );
 
-    name = "asterisk.etc";
+    name = "asterisk-etc";
 
     # Default asterisk.conf file
     # (Notice that astetcdir will be set to the path of this derivation)
     asteriskConf = ''
       [directories]
-      astetcdir => @out@
+      astetcdir => /etc/asterisk
       astmoddir => ${pkgs.asterisk}/lib/asterisk/modules
       astvarlibdir => /var/lib/asterisk
       astdbdir => /var/lib/asterisk
@@ -169,6 +178,16 @@ in
         '';
       };
 
+      useTheseDefaultConfFiles = mkOption {
+        default = [ "ari.conf" "acl.conf" "agents.conf" "amd.conf" "calendar.conf" "cdr.conf" "cdr_syslog.conf" "cdr_custom.conf" "cel.conf" "cel_custom.conf" "cli_aliases.conf" "confbridge.conf" "dundi.conf" "features.conf" "hep.conf" "iax.conf" "pjsip.conf" "pjsip_wizard.conf" "phone.conf" "phoneprov.conf" "queues.conf" "res_config_sqlite3.conf" "res_parking.conf" "statsd.conf" "udptl.conf" "unistim.conf" ];
+        type = types.listOf types.str;
+        example = [ "sip.conf" "dundi.conf" ];
+        description = ''Sets these config files to the default content. The default value for
+          this option contains all necesscary files to avoid errors at startup.
+          This does not override settings via <option>services.asterisk.confFiles</option>.
+        '';
+      };
+
       extraArguments = mkOption {
         default = [];
         type = types.listOf types.str;
@@ -182,12 +201,22 @@ in
   };
 
   config = mkIf cfg.enable {
-    users.extraUsers = singleton
-    { name = asteriskUser;
-      uid = config.ids.uids.asterisk;
-      description = "Asterisk daemon user";
-      home = varlibdir;
-    };
+    environment.systemPackages = [ pkgs.asterisk ];
+
+    environment.etc.asterisk.source = asteriskEtc;
+
+    users.extraUsers.asterisk =
+      { name = asteriskUser;
+        group = asteriskGroup;
+        uid = config.ids.uids.asterisk;
+        description = "Asterisk daemon user";
+        home = varlibdir;
+      };
+
+    users.extraGroups.asterisk =
+      { name = asteriskGroup;
+        gid = config.ids.gids.asterisk;
+      };
 
     systemd.services.asterisk = {
       description = ''
@@ -196,14 +225,17 @@ in
 
       wantedBy = [ "multi-user.target" ];
 
+      # Do not restart, to avoid disruption of running calls. Restart unit by yourself!
+      restartIfChanged = false;
+
       preStart = ''
         # Copy skeleton directory tree to /var
         for d in '${varlibdir}' '${spooldir}' '${logdir}'; do
           # TODO: Make exceptions for /var directories that likely should be updated
           if [ ! -e "$d" ]; then
             mkdir -p "$d"
-            cp --recursive ${pkgs.asterisk}/"$d" "$d"
-            chown --recursive ${asteriskUser} "$d"
+            cp --recursive ${pkgs.asterisk}/"$d"/* "$d"/
+            chown --recursive ${asteriskUser}:${asteriskGroup} "$d"
             find "$d" -type d | xargs chmod 0755
           fi
         done
@@ -215,7 +247,9 @@ in
             # FIXME: This doesn't account for arguments with spaces
             argString = concatStringsSep " " cfg.extraArguments;
           in
-          "${pkgs.asterisk}/bin/asterisk -U ${asteriskUser} -C ${asteriskEtc}/asterisk.conf ${argString} -F";
+          "${pkgs.asterisk}/bin/asterisk -U ${asteriskUser} -C /etc/asterisk/asterisk.conf ${argString} -F";
+        ExecReload = ''${pkgs.asterisk}/bin/asterisk -x "core reload"
+          '';
         Type = "forking";
         PIDFile = "/var/run/asterisk/asterisk.pid";
       };
diff --git a/nixos/modules/services/networking/atftpd.nix b/nixos/modules/services/networking/atftpd.nix
index d875ddc6352..e7fd48c99a8 100644
--- a/nixos/modules/services/networking/atftpd.nix
+++ b/nixos/modules/services/networking/atftpd.nix
@@ -20,13 +20,27 @@ in
         default = false;
         type = types.bool;
         description = ''
-          Whenever to enable the atftpd TFTP server.
+          Whether to enable the atftpd TFTP server. By default, the server
+          binds to address 0.0.0.0.
+        '';
+      };
+
+      extraOptions = mkOption {
+        default = [];
+        type = types.listOf types.str;
+        example = literalExample ''
+          [ "--bind-address 192.168.9.1"
+            "--verbose=7"
+          ]
+        '';
+        description = ''
+          Extra command line arguments to pass to atftp.
         '';
       };
 
       root = mkOption {
-        default = "/var/empty";
-        type = types.str;
+        default = "/srv/tftp";
+        type = types.path;
         description = ''
           Document root directory for the atftpd.
         '';
@@ -39,11 +53,11 @@ in
   config = mkIf cfg.enable {
 
     systemd.services.atftpd = {
-      description = "atftpd TFTP server";
+      description = "TFTP Server";
       after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
       # runs as nobody
-      serviceConfig.ExecStart = "${pkgs.atftp}/sbin/atftpd --daemon --no-fork --bind-address 0.0.0.0 ${cfg.root}";
+      serviceConfig.ExecStart = "${pkgs.atftp}/sbin/atftpd --daemon --no-fork ${lib.concatStringsSep " " cfg.extraOptions} ${cfg.root}";
     };
 
   };
diff --git a/nixos/modules/services/networking/avahi-daemon.nix b/nixos/modules/services/networking/avahi-daemon.nix
index 7650f45c557..6a786e75bbc 100644
--- a/nixos/modules/services/networking/avahi-daemon.nix
+++ b/nixos/modules/services/networking/avahi-daemon.nix
@@ -7,10 +7,6 @@ let
 
   cfg = config.services.avahi;
 
-  # We must escape interfaces due to the systemd interpretation
-  subsystemDevice = interface:
-    "sys-subsystem-net-devices-${utils.escapeSystemdPath interface}.device";
-
   avahiDaemonConf = with cfg; pkgs.writeText "avahi-daemon.conf" ''
     [server]
     ${# Users can set `networking.hostName' to the empty string, when getting
@@ -75,7 +71,8 @@ in
       };
 
       browseDomains = mkOption {
-        default = [ "0pointer.de" "zeroconf.org" ];
+        default = [ ];
+        example = [ "0pointer.de" "zeroconf.org" ];
         description = ''
           List of non-local DNS domains to be browsed.
         '';
@@ -178,17 +175,20 @@ in
 
     environment.systemPackages = [ pkgs.avahi ];
 
+    systemd.sockets.avahi-daemon =
+      { description = "Avahi mDNS/DNS-SD Stack Activation Socket";
+        listenStreams = [ "/var/run/avahi-daemon/socket" ];
+        wantedBy = [ "sockets.target" ];
+      };
+
     systemd.services.avahi-daemon =
-      let
-        deps = optionals (cfg.interfaces!=null) (map subsystemDevice cfg.interfaces);
-      in
-      { description = "Avahi daemon";
-        wantedBy = [ "ip-up.target" ];
-        bindsTo = deps;
-        after = deps;
-        before = [ "ip-up.target" ];
-        # Receive restart event after resume
-        partOf = [ "post-resume.target" ];
+      { description = "Avahi mDNS/DNS-SD Stack";
+        wantedBy = [ "multi-user.target" ];
+        requires = [ "avahi-daemon.socket" ];
+
+        serviceConfig."NotifyAccess" = "main";
+        serviceConfig."BusName" = "org.freedesktop.Avahi";
+        serviceConfig."Type" = "dbus";
 
         path = [ pkgs.coreutils pkgs.avahi ];
 
diff --git a/nixos/modules/services/networking/bind.nix b/nixos/modules/services/networking/bind.nix
index 08afafceff2..0272b6ceff2 100644
--- a/nixos/modules/services/networking/bind.nix
+++ b/nixos/modules/services/networking/bind.nix
@@ -113,6 +113,7 @@ in
       };
 
       extraConfig = mkOption {
+        type = types.lines;
         default = "";
         description = "
           Extra lines to be added verbatim to the generated named configuration file.
@@ -145,8 +146,8 @@ in
       };
 
     systemd.services.bind = {
-      description = "BIND name server job";
-      after = [ "network-interfaces.target" ];
+      description = "BIND Domain Name Server";
+      after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
 
       preStart = ''
@@ -154,7 +155,8 @@ in
         chown ${bindUser} /var/run/named
       '';
 
-      script = "${pkgs.bind.bin}/sbin/named -u ${bindUser} ${optionalString cfg.ipv4Only "-4"} -c ${cfg.configFile} -f";
+      script = "${pkgs.bind.out}/sbin/named -u ${bindUser} ${optionalString cfg.ipv4Only "-4"} -c ${cfg.configFile} -f";
+      unitConfig.Documentation = "man:named(8)";
     };
   };
 }
diff --git a/nixos/modules/services/networking/bird.nix b/nixos/modules/services/networking/bird.nix
index e76cdac14ca..1a7a1e24b70 100644
--- a/nixos/modules/services/networking/bird.nix
+++ b/nixos/modules/services/networking/bird.nix
@@ -1,76 +1,69 @@
 { config, lib, pkgs, ... }:
 
 let
-  inherit (lib) mkEnableOption mkIf mkOption singleton types;
-  inherit (pkgs) bird;
-  cfg = config.services.bird;
-
-  configFile = pkgs.writeText "bird.conf" ''
-    ${cfg.config}
-  '';
-in
-
-{
-
-  ###### interface
-
-  options = {
-
-    services.bird = {
-
-      enable = mkEnableOption "BIRD Internet Routing Daemon";
-
-      config = mkOption {
-        type = types.string;
-        description = ''
-          BIRD Internet Routing Daemon configuration file.
-          <link xlink:href='http://bird.network.cz/'/>
+  inherit (lib) mkEnableOption mkIf mkOption types;
+
+  generic = variant:
+    let
+      cfg = config.services.${variant};
+      pkg = pkgs.${variant};
+      birdc = if variant == "bird6" then "birdc6" else "birdc";
+      configFile = pkgs.stdenv.mkDerivation {
+        name = "${variant}.conf";
+        text = cfg.config;
+        preferLocalBuild = true;
+        buildCommand = ''
+          echo -n "$text" > $out
+          ${pkg}/bin/${variant} -d -p -c $out
         '';
       };
-
-      user = mkOption {
-        type = types.string;
-        default = "bird";
-        description = ''
-          BIRD Internet Routing Daemon user.
-        '';
+    in {
+      ###### interface
+      options = {
+        services.${variant} = {
+          enable = mkEnableOption "BIRD Internet Routing Daemon";
+          config = mkOption {
+            type = types.lines;
+            description = ''
+              BIRD Internet Routing Daemon configuration file.
+              <link xlink:href='http://bird.network.cz/'/>
+            '';
+          };
+        };
       };
 
-      group = mkOption {
-        type = types.string;
-        default = "bird";
-        description = ''
-          BIRD Internet Routing Daemon group.
-        '';
+      ###### implementation
+      config = mkIf cfg.enable {
+        environment.systemPackages = [ pkg ];
+        systemd.services.${variant} = {
+          description = "BIRD Internet Routing Daemon";
+          wantedBy = [ "multi-user.target" ];
+          serviceConfig = {
+            Type = "forking";
+            Restart = "on-failure";
+            ExecStart = "${pkg}/bin/${variant} -c ${configFile} -u ${variant} -g ${variant}";
+            ExecReload = "${pkg}/bin/${birdc} configure";
+            ExecStop = "${pkg}/bin/${birdc} down";
+            CapabilityBoundingSet = [ "CAP_CHOWN" "CAP_FOWNER" "CAP_DAC_OVERRIDE" "CAP_SETUID" "CAP_SETGID"
+                                      # see bird/sysdep/linux/syspriv.h
+                                      "CAP_NET_BIND_SERVICE" "CAP_NET_BROADCAST" "CAP_NET_ADMIN" "CAP_NET_RAW" ];
+            ProtectSystem = "full";
+            ProtectHome = "yes";
+            SystemCallFilter="~@cpu-emulation @debug @keyring @module @mount @obsolete @raw-io";
+            MemoryDenyWriteExecute = "yes";
+          };
+        };
+        users = {
+          extraUsers.${variant} = {
+            description = "BIRD Internet Routing Daemon user";
+            group = "${variant}";
+          };
+          extraGroups.${variant} = {};
+        };
       };
-
     };
 
-  };
-
-
-  ###### implementation
-
-  config = mkIf cfg.enable {
-
-    users.extraUsers = singleton {
-      name = cfg.user;
-      description = "BIRD Internet Routing Daemon user";
-      uid = config.ids.uids.bird;
-      group = cfg.group;
-    };
-
-    users.extraGroups = singleton {
-      name = cfg.group;
-      gid = config.ids.gids.bird;
-    };
-
-    systemd.services.bird = {
-      description = "BIRD Internet Routing Daemon";
-      wantedBy = [ "multi-user.target" ];
-      serviceConfig = {
-        ExecStart   = "${bird}/bin/bird -d -c ${configFile} -s /var/run/bird.ctl -u ${cfg.user} -g ${cfg.group}";
-      };
-    };
-  };
+  inherit (config.services) bird bird6;
+in {
+  imports = [(generic "bird") (generic "bird6")];
 }
diff --git a/nixos/modules/services/networking/bitlbee.nix b/nixos/modules/services/networking/bitlbee.nix
index 5e6847097a9..e72ea20ccce 100644
--- a/nixos/modules/services/networking/bitlbee.nix
+++ b/nixos/modules/services/networking/bitlbee.nix
@@ -7,11 +7,6 @@ let
   cfg = config.services.bitlbee;
   bitlbeeUid = config.ids.uids.bitlbee;
 
-  authModeCheck = v:
-    v == "Open" ||
-    v == "Closed" ||
-    v == "Registered";
-
   bitlbeeConfig = pkgs.writeText "bitlbee.conf"
     ''
     [settings]
@@ -67,7 +62,7 @@ in
 
       authMode = mkOption {
         default = "Open";
-        type = types.addCheck types.str authModeCheck;
+        type = types.enum [ "Open" "Closed" "Registered" ];
         description = ''
           The following authentication modes are available:
             Open -- Accept connections from anyone, use NickServ for user authentication.
diff --git a/nixos/modules/services/networking/chrony.nix b/nixos/modules/services/networking/chrony.nix
index a38142b4a08..f2ff11633b1 100644
--- a/nixos/modules/services/networking/chrony.nix
+++ b/nixos/modules/services/networking/chrony.nix
@@ -31,7 +31,7 @@ in
       };
 
       servers = mkOption {
-        default = config.services.ntp.servers;
+        default = config.networking.timeServers;
         description = ''
           The set of NTP servers from which to synchronise.
         '';
@@ -51,6 +51,7 @@ in
       };
 
       extraConfig = mkOption {
+        type = types.lines;
         default = "";
         description = ''
           Extra configuration directives that should be added to
@@ -101,7 +102,7 @@ in
         home = stateDir;
       };
 
-    systemd.services.ntpd.enable = mkForce false;
+    systemd.services.timesyncd.enable = mkForce false;
 
     systemd.services.chronyd =
       { description = "chrony NTP daemon";
diff --git a/nixos/modules/services/networking/cjdns-hosts.sh b/nixos/modules/services/networking/cjdns-hosts.sh
deleted file mode 100644
index 8a2b47e5214..00000000000
--- a/nixos/modules/services/networking/cjdns-hosts.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-pubs=($pubs)
-hosts=($hosts)
-
-lines="''\n"
-for ((i = 0; i < ${#pubs[*]}; i++)); do
-    addr=$($cjdns/bin/publictoip6 ${pubs[i]})
-    lines="${lines}$addr ${hosts[i]}\n"
-done
-lines="${lines}''"
-
-echo -ne $lines > $out
diff --git a/nixos/modules/services/networking/cjdns.nix b/nixos/modules/services/networking/cjdns.nix
index 0495b32c6fa..a10851c1652 100644
--- a/nixos/modules/services/networking/cjdns.nix
+++ b/nixos/modules/services/networking/cjdns.nix
@@ -28,21 +28,18 @@ let
     };
   };
 
-  peers = mapAttrsToList (n: v: v) (cfg.ETHInterface.connectTo // cfg.UDPInterface.connectTo);
-
-  pubs  = toString (map (p: if p.hostname == "" then "" else p.publicKey) peers);
-  hosts = toString (map (p: if p.hostname == "" then "" else p.hostname)  peers);
-
-  cjdnsHosts =
-    if hosts != "" then
-      import (pkgs.stdenv.mkDerivation {
-        name = "cjdns-hosts";
-        builder = ./cjdns-hosts.sh;
-
-        inherit (pkgs) cjdns;
-        inherit pubs hosts;
-      })
-    else "";
+  # 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 \'\'
+    '');
 
   parseModules = x:
     x // { connectTo = mapAttrs (name: value: { inherit (value) password publicKey; }) x.connectTo; };
@@ -95,8 +92,8 @@ in
       };
 
       confFile = mkOption {
-        type = types.str;
-        default = "";
+        type = types.nullOr types.path;
+        default = null;
         example = "/etc/cjdroute.conf";
         description = ''
           Ignore all other cjdns options and load configuration from this file.
@@ -112,14 +109,14 @@ in
           "49275fut6tmzu354pq70sr5b95qq0vj"
         ];
         description = ''
-          Any remote cjdns nodes that offer these passwords on 
+          Any remote cjdns nodes that offer these passwords on
           connection will be allowed to route through this node.
         '';
       };
-    
+
       admin = {
         bind = mkOption {
-          type = types.string;
+          type = types.str;
           default = "127.0.0.1:11234";
           description = ''
             Bind the administration port to this address and port.
@@ -129,7 +126,7 @@ in
 
       UDPInterface = {
         bind = mkOption {
-          type = types.string;
+          type = types.str;
           default = "";
           example = "192.168.1.32:43211";
           description = ''
@@ -154,6 +151,7 @@ in
 
       ETHInterface = {
         bind = mkOption {
+          type = types.str;
           default = "";
           example = "eth0";
           description =
@@ -197,22 +195,33 @@ in
         };
       };
 
+      addExtraHosts = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to add cjdns peers with an associated hostname to
+          <filename>/etc/hosts</filename>.  Beware that enabling this
+          incurs heavy eval-time costs.
+        '';
+      };
+
     };
 
   };
 
-  config = mkIf config.services.cjdns.enable {
+  config = mkIf cfg.enable {
 
     boot.kernelModules = [ "tun" ];
 
     # networking.firewall.allowedUDPPorts = ...
 
     systemd.services.cjdns = {
-      description = "encrypted networking for everybody";
-      wantedBy = [ "network.target" ];
-      after = [ "networkSetup.service" "network-interfaces.target" ];
+      description = "cjdns: routing engine designed for security, scalability, speed and ease of use";
+      wantedBy = [ "multi-user.target" "sleep.target"];
+      after = [ "network-online.target" ];
+      bindsTo = [ "network-online.target" ];
 
-      preStart = if cfg.confFile != "" then "" else ''
+      preStart = if cfg.confFile != null then "" else ''
         [ -e /etc/cjdns.keys ] && source /etc/cjdns.keys
 
         if [ -z "$CJDNS_PRIVATE_KEY" ]; then
@@ -228,13 +237,13 @@ in
         fi
 
         if [ -z "$CJDNS_ADMIN_PASSWORD" ]; then
-            echo "CJDNS_ADMIN_PASSWORD=$(${pkgs.coreutils}/bin/head -c 96 /dev/urandom | ${pkgs.coreutils}/bin/tr -dc A-Za-z0-9)" \
+            echo "CJDNS_ADMIN_PASSWORD=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 96)" \
                 >> /etc/cjdns.keys
         fi
       '';
 
       script = (
-        if cfg.confFile != "" then "${pkg}/bin/cjdroute < ${cfg.confFile}" else
+        if cfg.confFile != null then "${pkg}/bin/cjdroute < ${cfg.confFile}" else
           ''
             source /etc/cjdns.keys
             echo '${cjdrouteConf}' | sed \
@@ -246,14 +255,22 @@ in
 
       serviceConfig = {
         Type = "forking";
-        Restart = "on-failure";
+        Restart = "always";
+        StartLimitInterval = 0;
+        RestartSec = 1;
+        CapabilityBoundingSet = "CAP_NET_ADMIN CAP_NET_RAW";
+        AmbientCapabilities = "CAP_NET_ADMIN CAP_NET_RAW";
+        ProtectSystem = "full";
+        MemoryDenyWriteExecute = true;
+        ProtectHome = true;
+        PrivateTmp = true;
       };
     };
 
-    networking.extraHosts = "${cjdnsHosts}";
+    networking.extraHosts = mkIf cfg.addExtraHosts cjdnsExtraHosts;
 
     assertions = [
-      { assertion = ( cfg.ETHInterface.bind != "" || cfg.UDPInterface.bind != "" || cfg.confFile != "" );
+      { assertion = ( cfg.ETHInterface.bind != "" || cfg.UDPInterface.bind != "" || cfg.confFile != null );
         message = "Neither cjdns.ETHInterface.bind nor cjdns.UDPInterface.bind defined.";
       }
       { assertion = config.networking.enableIPv6;
diff --git a/nixos/modules/services/networking/cntlm.nix b/nixos/modules/services/networking/cntlm.nix
index 76c0fd7d0ea..890ff508407 100644
--- a/nixos/modules/services/networking/cntlm.nix
+++ b/nixos/modules/services/networking/cntlm.nix
@@ -61,6 +61,7 @@ in
       };
 
      extraConfig = mkOption {
+        type = types.lines;
         default = "";
         description = "Verbatim contents of <filename>cntlm.conf</filename>.";
      };
diff --git a/nixos/modules/services/networking/connman.nix b/nixos/modules/services/networking/connman.nix
index 3fecfbb13a0..d0683b87780 100644
--- a/nixos/modules/services/networking/connman.nix
+++ b/nixos/modules/services/networking/connman.nix
@@ -27,6 +27,14 @@ in {
         '';
       };
 
+      enableVPN = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Whether to enable ConnMan VPN service.
+        '';
+      };
+
       extraConfig = mkOption {
         type = types.lines;
         default = ''
@@ -78,7 +86,7 @@ in {
       };
     };
 
-    systemd.services."connman-vpn" = {
+    systemd.services."connman-vpn" = mkIf cfg.enableVPN {
       description = "ConnMan VPN service";
       wantedBy = [ "multi-user.target" ];
       after = [ "syslog.target" ];
@@ -91,7 +99,7 @@ in {
       };
     };
 
-    systemd.services."net-connman-vpn" = {
+    systemd.services."net-connman-vpn" = mkIf cfg.enableVPN {
       description = "D-BUS Service";
       serviceConfig = {
         Name = "net.connman.vpn";
diff --git a/nixos/modules/services/networking/dante.nix b/nixos/modules/services/networking/dante.nix
new file mode 100644
index 00000000000..a9a77f3412a
--- /dev/null
+++ b/nixos/modules/services/networking/dante.nix
@@ -0,0 +1,61 @@
+{ config, lib, pkgs, ... }:
+with lib;
+
+let
+  cfg = config.services.dante;
+  confFile = pkgs.writeText "dante-sockd.conf" ''
+    user.privileged: root
+    user.unprivileged: dante
+
+    ${cfg.config}
+  '';
+in
+
+{
+  meta = {
+    maintainers = with maintainers; [ arobyn ];
+  };
+
+  options = {
+    services.dante = {
+      enable = mkEnableOption "Dante SOCKS proxy";
+
+      config = mkOption {
+        default     = null;
+        type        = types.nullOr types.str;
+        description = ''
+          Contents of Dante's configuration file
+          NOTE: user.privileged/user.unprivileged are set by the service
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    assertions = [
+      { assertion   = cfg.config != null;
+        message     = "please provide Dante configuration file contents";
+      }
+    ];
+
+    users.users.dante = {
+      description   = "Dante SOCKS proxy daemon user";
+      isSystemUser  = true;
+      group         = "dante";
+    };
+    users.groups.dante = {};
+
+    systemd.services.dante = {
+      description   = "Dante SOCKS v4 and v5 compatible proxy server";
+      after         = [ "network.target" ];
+      wantedBy      = [ "multi-user.target" ];
+
+      serviceConfig = {
+        Type        = "simple";
+        ExecStart   = "${pkgs.dante}/bin/sockd -f ${confFile}";
+        ExecReload  = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+        Restart     = "always";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/networking/ddclient.nix b/nixos/modules/services/networking/ddclient.nix
index 005c57dce7c..d1900deceaf 100644
--- a/nixos/modules/services/networking/ddclient.nix
+++ b/nixos/modules/services/networking/ddclient.nix
@@ -7,7 +7,7 @@ let
 
   stateDir = "/var/spool/ddclient";
   ddclientUser = "ddclient";
-  ddclientFlags = "-foreground -verbose -noquiet -file /etc/ddclient.conf";
+  ddclientFlags = "-foreground -verbose -noquiet -file ${config.services.ddclient.configFile}";
   ddclientPIDFile = "${stateDir}/ddclient.pid";
 
 in
@@ -52,6 +52,17 @@ in
         '';
       };
 
+      configFile = mkOption {
+        default = "/etc/ddclient.conf";
+        type = path;
+        description = ''
+          Path to configuration file.
+          When set to the default '/etc/ddclient.conf' it will be populated with the various other options in this module. When it is changed (for example: '/root/nixos/secrets/ddclient.conf') the file read directly to configure ddclient. This is a source of impurity.
+          The purpose of this is to avoid placing secrets into the store.
+        '';
+        example = "/root/nixos/secrets/ddclient.conf";
+      };
+
       protocol = mkOption {
         default = "dyndns2";
         type = str;
@@ -78,7 +89,7 @@ in
 
       extraConfig = mkOption {
         default = "";
-        type = str;
+        type = lines;
         description = ''
           Extra configuration. Contents will be added verbatim to the configuration file.
         '';
@@ -88,7 +99,7 @@ in
         default = "web, web=checkip.dyndns.com/, web-skip='Current IP Address: '";
         type = str;
         description = ''
-          Method to determine the IP address to send to the dymanic DNS provider.
+          Method to determine the IP address to send to the dynamic DNS provider.
         '';
       };
     };
@@ -109,9 +120,11 @@ in
     };
 
     environment.etc."ddclient.conf" = {
+      enable = config.services.ddclient.configFile == "/etc/ddclient.conf";
       uid = config.ids.uids.ddclient;
       mode = "0600";
       text = ''
+        # This file can be used as a template for configFile or is automatically generated by Nix options.
         daemon=600
         cache=${stateDir}/ddclient.cache
         pid=${ddclientPIDFile}
diff --git a/nixos/modules/services/networking/dhcpcd.nix b/nixos/modules/services/networking/dhcpcd.nix
index b31d479ab4f..87c0aa50a1f 100644
--- a/nixos/modules/services/networking/dhcpcd.nix
+++ b/nixos/modules/services/networking/dhcpcd.nix
@@ -10,7 +10,8 @@ let
 
   interfaces = attrValues config.networking.interfaces;
 
-  enableDHCP = config.networking.useDHCP || any (i: i.useDHCP == true) interfaces;
+  enableDHCP = config.networking.dhcpcd.enable &&
+        (config.networking.useDHCP || any (i: i.useDHCP == true) interfaces);
 
   # Don't start dhcpcd on explicitly configured interfaces or on
   # interfaces that are part of a bridge, bond or sit device.
@@ -61,7 +62,6 @@ let
       ${cfg.extraConfig}
     '';
 
-  # Hook for emitting ip-up/ip-down events.
   exitHook = pkgs.writeText "dhcpcd.exit-hook"
     ''
       if [ "$reason" = BOUND -o "$reason" = REBOOT ]; then
@@ -73,14 +73,8 @@ let
           # applies to openntpd.
           ${config.systemd.package}/bin/systemctl try-restart ntpd.service
           ${config.systemd.package}/bin/systemctl try-restart openntpd.service
-
-          ${config.systemd.package}/bin/systemctl start ip-up.target
       fi
 
-      #if [ "$reason" = EXPIRE -o "$reason" = RELEASE -o "$reason" = NOCARRIER ] ; then
-      #    ${config.systemd.package}/bin/systemctl start ip-down.target
-      #fi
-
       ${cfg.runHook}
     '';
 
@@ -92,6 +86,15 @@ in
 
   options = {
 
+    networking.dhcpcd.enable = mkOption {
+      type = types.bool;
+      default = true;
+      description = ''
+        Whether to enable dhcpcd for device configuration. This is mainly to
+        explicitly disable dhcpcd (for example when using networkd).
+      '';
+    };
+
     networking.dhcpcd.persistent = mkOption {
       type = types.bool;
       default = false;
@@ -154,10 +157,9 @@ in
     systemd.services.dhcpcd =
       { description = "DHCP Client";
 
-        wantedBy = [ "network.target" ];
-        # Work-around to deal with problems where the kernel would remove &
-        # re-create Wifi interfaces early during boot.
-        after = [ "network-interfaces.target" ];
+        wantedBy = [ "multi-user.target" ];
+        after = [ "network.target" ];
+        wants = [ "network.target" ];
 
         # Stopping dhcpcd during a reconfiguration is undesirable
         # because it brings down the network interfaces configured by
diff --git a/nixos/modules/services/networking/dhcpd.nix b/nixos/modules/services/networking/dhcpd.nix
index 900df67b53a..d2cd00e74a1 100644
--- a/nixos/modules/services/networking/dhcpd.nix
+++ b/nixos/modules/services/networking/dhcpd.nix
@@ -47,6 +47,7 @@ in
       };
 
       extraConfig = mkOption {
+        type = types.lines;
         default = "";
         example = ''
           option subnet-mask 255.255.255.0;
@@ -66,6 +67,14 @@ in
         ";
       };
 
+      extraFlags = mkOption {
+        default = "";
+        example = "-6";
+        description = "
+          Additional command line flags to be passed to the dhcpd daemon.
+        ";
+      };
+
       configFile = mkOption {
         default = null;
         description = "
@@ -138,6 +147,7 @@ in
           { ExecStart = "@${pkgs.dhcp}/sbin/dhcpd dhcpd"
               + " -pf /run/dhcpd/dhcpd.pid -cf ${configFile}"
               + " -lf ${stateDir}/dhcpd.leases -user dhcpd -group nogroup"
+              + " ${cfg.extraFlags}"
               + " ${toString cfg.interfaces}";
             Restart = "always";
             Type = "forking";
diff --git a/nixos/modules/services/networking/dnscrypt-proxy.nix b/nixos/modules/services/networking/dnscrypt-proxy.nix
index 2714e8d7599..462039803f8 100644
--- a/nixos/modules/services/networking/dnscrypt-proxy.nix
+++ b/nixos/modules/services/networking/dnscrypt-proxy.nix
@@ -5,15 +5,25 @@ let
   apparmorEnabled = config.security.apparmor.enable;
   dnscrypt-proxy = pkgs.dnscrypt-proxy;
   cfg = config.services.dnscrypt-proxy;
+  stateDirectory = "/var/lib/dnscrypt-proxy";
 
   localAddress = "${cfg.localAddress}:${toString cfg.localPort}";
 
-  daemonArgs =
-    [ "--local-address=${localAddress}"
-      (optionalString cfg.tcpOnly "--tcp-only")
-      (optionalString cfg.ephemeralKeys "-E")
-    ]
-    ++ resolverArgs;
+  # 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/jedisct1/dnscrypt-proxy/master/minisign.pub;
+    sha256 = "18lnp8qr6ghfc2sd46nn1rhcpr324fqlvgsp4zaigw396cd7vnnh";
+  };
+
+  # Internal flag indicating whether the upstream resolver list is used
+  useUpstreamResolverList = cfg.resolverList == null && cfg.customResolver == null;
+
+  resolverList =
+    if (cfg.resolverList != null)
+      then cfg.resolverList
+      else "${stateDirectory}/dnscrypt-resolvers.csv";
 
   resolverArgs = if (cfg.customResolver != null)
     then
@@ -22,9 +32,16 @@ let
         "--provider-key=${cfg.customResolver.key}"
       ]
     else
-      [ "--resolvers-list=${cfg.resolverList}"
-        "--resolver-name=${toString cfg.resolverName}"
+      [ "--resolvers-list=${resolverList}"
+        "--resolver-name=${cfg.resolverName}"
       ];
+
+  # The final command line arguments passed to the daemon
+  daemonArgs =
+    [ "--local-address=${localAddress}" ]
+    ++ optional cfg.tcpOnly "--tcp-only"
+    ++ optional cfg.ephemeralKeys "-E"
+    ++ resolverArgs;
 in
 
 {
@@ -35,7 +52,11 @@ in
 
   options = {
     services.dnscrypt-proxy = {
-      enable = mkEnableOption "DNSCrypt client proxy";
+      enable = mkOption {
+        default = false;
+        type = types.bool;
+        description = "Whether to enable the DNSCrypt client proxy";
+      };
 
       localAddress = mkOption {
         default = "127.0.0.1";
@@ -62,24 +83,20 @@ in
         default = "dnscrypt.eu-nl";
         type = types.nullOr types.str;
         description = ''
-          The name of the upstream DNSCrypt resolver to use, taken from the
-          list named in the <literal>resolverList</literal> option.
-          The default resolver is located in Holland, supports DNS security
-          extensions, and claims to not keep logs.
+          The name of the upstream DNSCrypt resolver to use, taken from
+          <filename>${resolverList}</filename>.  The default resolver is
+          located in Holland, supports DNS security extensions, and
+          <emphasis>claims</emphasis> to not keep logs.
         '';
       };
 
       resolverList = mkOption {
+        default = null;
+        type = types.nullOr types.path;
         description = ''
-          The list of upstream DNSCrypt resolvers. By default, we use the most
-          recent list published by upstream.
+          List of DNSCrypt resolvers.  The default is to use the list of
+          public resolvers provided by upstream.
         '';
-        example = literalExample "${pkgs.dnscrypt-proxy}/share/dnscrypt-proxy/dnscrypt-resolvers.csv";
-        default = pkgs.fetchurl {
-          url = https://raw.githubusercontent.com/jedisct1/dnscrypt-proxy/master/dnscrypt-resolvers.csv;
-          sha256 = "1i9wzw4zl052h5nyp28bwl8d66cgj0awvjhw5wgwz0warkjl1g8g";
-        };
-        defaultText = "pkgs.fetchurl { url = ...; sha256 = ...; }";
       };
 
       customResolver = mkOption {
@@ -146,7 +163,7 @@ in
       }
     ];
 
-    security.apparmor.profiles = mkIf apparmorEnabled (singleton (pkgs.writeText "apparmor-dnscrypt-proxy" ''
+    security.apparmor.profiles = optional apparmorEnabled (pkgs.writeText "apparmor-dnscrypt-proxy" ''
       ${dnscrypt-proxy}/bin/dnscrypt-proxy {
         /dev/null rw,
         /dev/urandom r,
@@ -173,9 +190,9 @@ in
         ${getLib pkgs.lz4}/lib/liblz4.so.* mr,
         ${getLib pkgs.attr}/lib/libattr.so.* mr,
 
-        ${cfg.resolverList} r,
+        ${resolverList} r,
       }
-    ''));
+    '');
 
     users.users.dnscrypt-proxy = {
       description = "dnscrypt-proxy daemon user";
@@ -184,11 +201,61 @@ in
     };
     users.groups.dnscrypt-proxy = {};
 
+    systemd.services.init-dnscrypt-proxy-statedir = optionalAttrs useUpstreamResolverList {
+      description = "Initialize dnscrypt-proxy state directory";
+      script = ''
+        mkdir -pv ${stateDirectory}
+        chown -c dnscrypt-proxy:dnscrypt-proxy ${stateDirectory}
+        cp --preserve=timestamps -uv \
+          ${pkgs.dnscrypt-proxy}/share/dnscrypt-proxy/dnscrypt-resolvers.csv \
+          ${stateDirectory}
+      '';
+      serviceConfig = {
+        Type = "oneshot";
+        RemainAfterExit = true;
+      };
+    };
+
+    systemd.services.update-dnscrypt-resolvers = optionalAttrs useUpstreamResolverList {
+      description = "Update list of DNSCrypt resolvers";
+
+      requires = [ "init-dnscrypt-proxy-statedir.service" ];
+      after = [ "init-dnscrypt-proxy-statedir.service" ];
+
+      path = with pkgs; [ curl minisign ];
+      script = ''
+        cd ${stateDirectory}
+        curl -fSsL -o dnscrypt-resolvers.csv.tmp \
+          https://download.dnscrypt.org/dnscrypt-proxy/dnscrypt-resolvers.csv
+        curl -fSsL -o dnscrypt-resolvers.csv.minisig.tmp \
+          https://download.dnscrypt.org/dnscrypt-proxy/dnscrypt-resolvers.csv.minisig
+        mv dnscrypt-resolvers.csv.minisig{.tmp,}
+        minisign -q -V -p ${upstreamResolverListPubKey} \
+          -m dnscrypt-resolvers.csv.tmp -x dnscrypt-resolvers.csv.minisig
+        mv dnscrypt-resolvers.csv{.tmp,}
+      '';
+
+      serviceConfig = {
+        PrivateTmp = true;
+        PrivateDevices = true;
+        ProtectHome = true;
+        ProtectSystem = true;
+      };
+    };
+
+    systemd.timers.update-dnscrypt-resolvers = optionalAttrs useUpstreamResolverList {
+      timerConfig = {
+        OnBootSec = "5min";
+        OnUnitActiveSec = "6h";
+      };
+      wantedBy = [ "timers.target" ];
+    };
+
     systemd.sockets.dnscrypt-proxy = {
       description = "dnscrypt-proxy listening socket";
       socketConfig = {
-        ListenStream = "${localAddress}";
-        ListenDatagram = "${localAddress}";
+        ListenStream = localAddress;
+        ListenDatagram = localAddress;
       };
       wantedBy = [ "sockets.target" ];
     };
@@ -196,8 +263,15 @@ in
     systemd.services.dnscrypt-proxy = {
       description = "dnscrypt-proxy daemon";
 
-      after = [ "network.target" ] ++ optional apparmorEnabled "apparmor.service";
-      requires = [ "dnscrypt-proxy.socket "] ++ optional apparmorEnabled "apparmor.service";
+      before = [ "nss-lookup.target" ];
+
+      after = [ "network.target" ]
+        ++ optional apparmorEnabled "apparmor.service"
+        ++ optional useUpstreamResolverList "init-dnscrypt-proxy-statedir.service";
+
+      requires = [ "dnscrypt-proxy.socket "]
+        ++ optional apparmorEnabled "apparmor.service"
+        ++ optional useUpstreamResolverList "init-dnscrypt-proxy-statedir.service";
 
       serviceConfig = {
         Type = "simple";
diff --git a/nixos/modules/services/networking/dnscrypt-proxy.xml b/nixos/modules/services/networking/dnscrypt-proxy.xml
index e212a8d3e2c..982961833ad 100644
--- a/nixos/modules/services/networking/dnscrypt-proxy.xml
+++ b/nixos/modules/services/networking/dnscrypt-proxy.xml
@@ -49,8 +49,8 @@
   <para>
     <programlisting>
       {
-      services.dnsmasq.enable = true;
-      services.dnsmasq.servers = [ "127.0.0.1#43" ];
+        services.dnsmasq.enable = true;
+        services.dnsmasq.servers = [ "127.0.0.1#43" ];
       }
     </programlisting>
   </para>
@@ -60,12 +60,9 @@
   <para>
     <programlisting>
       {
-      networking.nameservers = [ "127.0.0.1" ];
-      services.unbound.enable = true;
-      services.unbound.forwardAddresses = [ "127.0.0.1@43" ];
-      services.unbound.extraConfig = ''
-        do-not-query-localhost: no
-      '';
+        networking.nameservers = [ "127.0.0.1" ];
+        services.unbound.enable = true;
+        services.unbound.forwardAddresses = [ "127.0.0.1@43" ];
       }
     </programlisting>
   </para>
diff --git a/nixos/modules/services/networking/docker-registry-server.nix b/nixos/modules/services/networking/docker-registry-server.nix
deleted file mode 100644
index d21bbb6a86c..00000000000
--- a/nixos/modules/services/networking/docker-registry-server.nix
+++ /dev/null
@@ -1,98 +0,0 @@
-{ config, lib, pkgs, ... }:
-
-with lib;
-
-let
-  cfg = config.services.nodeDockerRegistry;
-
-in {
-  options.services.nodeDockerRegistry = {
-    enable = mkEnableOption "docker registry service";
-
-    port = mkOption {
-      description = "Docker registry listening port.";
-      default = 8080;
-      type = types.int;
-    };
-
-    users = mkOption {
-      description = "Docker registry list of users.";
-      default = [];
-      options = [{
-        user = mkOption {
-          description = "Docker registry user username.";
-          type = types.str;
-        };
-
-        pass = mkOption {
-          description = "Docker registry user password.";
-          type = types.str;
-        };
-      }];
-      type = types.listOf types.optionSet;
-    };
-
-    onTag = mkOption {
-      description = "Docker registry hook triggered when an image is tagged.";
-      default = "";
-      type = types.str;
-    };
-
-    onImage = mkOption {
-      description = "Docker registry hook triggered when an image metadata is uploaded.";
-      default = "";
-      type = types.str;
-    };
-
-    onLayer = mkOption {
-      description = "Docker registry hook triggered when an when an image layer is uploaded.";
-      default = "";
-      type = types.str;
-    };
-
-    onVerify = mkOption {
-      description = "Docker registry hook triggered when an image layer+metadata has been verified.";
-      default = "";
-      type = types.str;
-    };
-
-    onIndex = mkOption {
-      description = "Docker registry hook triggered when an when an image file system data has been indexed.";
-      default = "";
-      type = types.str;
-    };
-
-    dataDir = mkOption {
-      description = "Docker registry data directory";
-      default = "/var/lib/docker-registry";
-      type = types.path;
-    };
-  };
-
-  config = mkIf cfg.enable {
-    systemd.services.docker-registry-server = {
-      description = "Docker Registry Service.";
-      wantedBy = ["multi-user.target"];
-      after = ["network.target"];
-      script = ''
-        ${pkgs.nodePackages.docker-registry-server}/bin/docker-registry-server \
-          --dir ${cfg.dataDir} \
-          --port ${toString cfg.port} \
-          ${concatMapStringsSep " " (u: "--user ${u.user}:${u.pass}") cfg.users} \
-          ${optionalString (cfg.onTag != "") "--on-tag '${cfg.onTag}'"} \
-          ${optionalString (cfg.onImage != "") "--on-image '${cfg.onImage}'"} \
-          ${optionalString (cfg.onVerify != "") "--on-verify '${cfg.onVerify}'"} \
-          ${optionalString (cfg.onIndex != "") "--on-index '${cfg.onIndex}'"}
-      '';
-
-      serviceConfig.User = "docker-registry";
-    };
-
-    users.extraUsers.docker-registry = {
-      uid = config.ids.uids.docker-registry;
-      description = "Docker registry user";
-      createHome = true;
-      home = cfg.dataDir;
-    };
-  };
-}
diff --git a/nixos/modules/services/networking/fakeroute.nix b/nixos/modules/services/networking/fakeroute.nix
new file mode 100644
index 00000000000..82a9fb729d8
--- /dev/null
+++ b/nixos/modules/services/networking/fakeroute.nix
@@ -0,0 +1,63 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.fakeroute;
+  routeConf = pkgs.writeText "route.conf" (concatStringsSep "\n" cfg.route);
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.fakeroute = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to enable the fakeroute service.
+        '';
+      };
+
+      route = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        example = [
+          "216.102.187.130"
+          "4.0.1.122"
+          "198.116.142.34"
+          "63.199.8.242"
+        ];
+        description = ''
+         Fake route that will appear after the real
+         one to any host running a traceroute.
+        '';
+      };
+
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+    systemd.services.fakeroute = {
+      description = "Fakeroute Daemon";
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        Type = "forking";
+        User = "root";
+        ExecStart = "${pkgs.fakeroute}/bin/fakeroute -f ${routeConf}";
+      };
+    };
+
+  };
+
+}
diff --git a/nixos/modules/services/networking/ferm.nix b/nixos/modules/services/networking/ferm.nix
index 6271e82541f..8933e166f59 100644
--- a/nixos/modules/services/networking/ferm.nix
+++ b/nixos/modules/services/networking/ferm.nix
@@ -51,6 +51,7 @@ in {
       before = [ "network-pre.target" ];
       wants = [ "network-pre.target" ];
       wantedBy = [ "multi-user.target" ];
+      reloadIfChanged = true;
       serviceConfig = {
         Type="oneshot";
         RemainAfterExit = "yes";
diff --git a/nixos/modules/services/networking/firewall.nix b/nixos/modules/services/networking/firewall.nix
index 138153306dd..1c0ea5034df 100644
--- a/nixos/modules/services/networking/firewall.nix
+++ b/nixos/modules/services/networking/firewall.nix
@@ -100,13 +100,13 @@ let
 
     # Perform a reverse-path test to refuse spoofers
     # For now, we just drop, as the raw table doesn't have a log-refuse yet
-    ${optionalString (kernelHasRPFilter && cfg.checkReversePath) ''
+    ${optionalString (kernelHasRPFilter && (cfg.checkReversePath != false)) ''
       # Clean up rpfilter rules
       ip46tables -t raw -D PREROUTING -j nixos-fw-rpfilter 2> /dev/null || true
       ip46tables -t raw -F nixos-fw-rpfilter 2> /dev/null || true
       ip46tables -t raw -N nixos-fw-rpfilter 2> /dev/null || true
 
-      ip46tables -t raw -A nixos-fw-rpfilter -m rpfilter -j RETURN
+      ip46tables -t raw -A nixos-fw-rpfilter -m rpfilter ${optionalString (cfg.checkReversePath == "loose") "--loose"} -j RETURN
 
       # Allows this host to act as a DHCPv4 server
       iptables -t raw -A nixos-fw-rpfilter -s 0.0.0.0 -d 255.255.255.255 -p udp --sport 68 --dport 67 -j RETURN
@@ -200,7 +200,7 @@ let
     # Clean up after added ruleset
     ip46tables -D INPUT -j nixos-fw 2>/dev/null || true
 
-    ${optionalString (kernelHasRPFilter && cfg.checkReversePath) ''
+    ${optionalString (kernelHasRPFilter && (cfg.checkReversePath != false)) ''
       ip46tables -t raw -D PREROUTING -j nixos-fw-rpfilter 2>/dev/null || true
     ''}
 
@@ -373,7 +373,7 @@ in
 
     networking.firewall.checkReversePath = mkOption {
       default = kernelHasRPFilter;
-      type = types.bool;
+      type = types.either types.bool (types.enum ["strict" "loose"]);
       description =
         ''
           Performs a reverse path filter test on a packet.
@@ -381,7 +381,8 @@ in
           that the packet arrived on, it is refused.
 
           If using asymmetric routing or other complicated routing,
-          disable this setting and setup your own counter-measures.
+          set this option to loose mode or disable it and setup your
+          own counter-measures.
 
           (needs kernel 3.3+)
         '';
@@ -482,7 +483,7 @@ in
       options nf_conntrack nf_conntrack_helper=0
     '';
 
-    assertions = [ { assertion = ! cfg.checkReversePath || kernelHasRPFilter;
+    assertions = [ { assertion = (cfg.checkReversePath != false) || kernelHasRPFilter;
                      message = "This kernel does not support rpfilter"; }
                    { assertion = cfg.autoLoadConntrackHelpers || kernelCanDisableHelpers;
                      message = "This kernel does not support disabling conntrack helpers"; }
@@ -490,7 +491,8 @@ in
 
     systemd.services.firewall = {
       description = "Firewall";
-      wantedBy = [ "network-pre.target" ];
+      wantedBy = [ "sysinit.target" ];
+      wants = [ "network-pre.target" ];
       before = [ "network-pre.target" ];
       after = [ "systemd-modules-load.service" ];
 
@@ -500,6 +502,7 @@ in
       # containers don't have CAP_SYS_MODULE. So the host system had
       # better have all necessary modules already loaded.
       unitConfig.ConditionCapability = "CAP_NET_ADMIN";
+      unitConfig.DefaultDependencies = false;
 
       reloadIfChanged = true;
 
diff --git a/nixos/modules/services/networking/flannel.nix b/nixos/modules/services/networking/flannel.nix
new file mode 100644
index 00000000000..ca47a18bc1f
--- /dev/null
+++ b/nixos/modules/services/networking/flannel.nix
@@ -0,0 +1,154 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.flannel;
+
+  networkConfig = filterAttrs (n: v: v != null) {
+    Network = cfg.network;
+    SubnetLen = cfg.subnetLen;
+    SubnetMin = cfg.subnetMin;
+    SubnetMax = cfg.subnetMax;
+    Backend = cfg.backend;
+  };
+in {
+  options.services.flannel = {
+    enable = mkEnableOption "flannel";
+
+    package = mkOption {
+      description = "Package to use for flannel";
+      type = types.package;
+      default = pkgs.flannel.bin;
+      defaultText = "pkgs.flannel.bin";
+    };
+
+    publicIp = mkOption {
+      description = ''
+        IP accessible by other nodes for inter-host communication.
+        Defaults to the IP of the interface being used for communication.
+      '';
+      type = types.nullOr types.str;
+      default = null;
+    };
+
+    iface = mkOption {
+      description = ''
+        Interface to use (IP or name) for inter-host communication.
+        Defaults to the interface for the default route on the machine.
+      '';
+      type = types.nullOr types.str;
+      default = null;
+    };
+
+    etcd = {
+      endpoints = mkOption {
+        description = "Etcd endpoints";
+        type = types.listOf types.str;
+        default = ["http://127.0.0.1:2379"];
+      };
+
+      prefix = mkOption {
+        description = "Etcd key prefix";
+        type = types.str;
+        default = "/coreos.com/network";
+      };
+
+      caFile = mkOption {
+        description = "Etcd certificate authority file";
+        type = types.nullOr types.path;
+        default = null;
+      };
+
+      certFile = mkOption {
+        description = "Etcd cert file";
+        type = types.nullOr types.path;
+        default = null;
+      };
+
+      keyFile = mkOption {
+        description = "Etcd key file";
+        type = types.nullOr types.path;
+        default = null;
+      };
+    };
+
+    network = mkOption {
+      description = " IPv4 network in CIDR format to use for the entire flannel network.";
+      type = types.str;
+    };
+
+    subnetLen = mkOption {
+      description = ''
+        The size of the subnet allocated to each host. Defaults to 24 (i.e. /24)
+        unless the Network was configured to be smaller than a /24 in which case
+        it is one less than the network.
+      '';
+      type = types.int;
+      default = 24;
+    };
+
+    subnetMin = mkOption {
+      description = ''
+        The beginning of IP range which the subnet allocation should start with.
+        Defaults to the first subnet of Network.
+      '';
+      type = types.nullOr types.str;
+      default = null;
+    };
+
+    subnetMax = mkOption {
+      description = ''
+        The end of IP range which the subnet allocation should start with.
+        Defaults to the last subnet of Network.
+      '';
+      type = types.nullOr types.str;
+      default = null;
+    };
+
+    backend = mkOption {
+      description = "Type of backend to use and specific configurations for that backend.";
+      type = types.attrs;
+      default = {
+        Type = "vxlan";
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.services.flannel = {
+      description = "Flannel Service";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+      environment = {
+        FLANNELD_PUBLIC_IP = cfg.publicIp;
+        FLANNELD_ETCD_ENDPOINTS = concatStringsSep "," cfg.etcd.endpoints;
+        FLANNELD_ETCD_KEYFILE = cfg.etcd.keyFile;
+        FLANNELD_ETCD_CERTFILE = cfg.etcd.certFile;
+        FLANNELD_ETCD_CAFILE = cfg.etcd.caFile;
+        FLANNELD_IFACE = cfg.iface;
+        ETCDCTL_CERT_FILE = cfg.etcd.certFile;
+        ETCDCTL_KEY_FILE = cfg.etcd.keyFile;
+        ETCDCTL_CA_FILE = cfg.etcd.caFile;
+        ETCDCTL_PEERS = concatStringsSep "," cfg.etcd.endpoints;
+      };
+      preStart = ''
+        echo "setting network configuration"
+        until ${pkgs.etcdctl.bin}/bin/etcdctl set /coreos.com/network/config '${builtins.toJSON networkConfig}'
+        do
+          echo "setting network configuration, retry"
+          sleep 1
+        done
+      '';
+      postStart = ''
+        while [ ! -f /run/flannel/subnet.env ]
+        do
+          sleep 1
+        done
+      '';
+      serviceConfig.ExecStart = "${cfg.package}/bin/flannel";
+    };
+
+    services.etcd.enable = mkDefault cfg.etcd.endpoints == ["http://127.0.0.1:2379"];
+  };
+}
diff --git a/nixos/modules/services/networking/git-daemon.nix b/nixos/modules/services/networking/git-daemon.nix
index 215ffe48a56..cd3fcd0f8f6 100644
--- a/nixos/modules/services/networking/git-daemon.nix
+++ b/nixos/modules/services/networking/git-daemon.nix
@@ -116,7 +116,8 @@ in
       };
 
     systemd.services."git-daemon" = {
-      wantedBy = [ "ip-up.target" ];
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
       script = "${pkgs.git}/bin/git daemon --reuseaddr "
         + (optionalString (cfg.basePath != "") "--base-path=${cfg.basePath} ")
         + (optionalString (cfg.listenAddress != "") "--listen=${cfg.listenAddress} ")
diff --git a/nixos/modules/services/networking/gvpe.nix b/nixos/modules/services/networking/gvpe.nix
index 27b64b5bb95..3ef3548e0a0 100644
--- a/nixos/modules/services/networking/gvpe.nix
+++ b/nixos/modules/services/networking/gvpe.nix
@@ -105,7 +105,7 @@ in
   config = mkIf cfg.enable {
     systemd.services.gvpe = {
       description = "GNU Virtual Private Ethernet node";
-      after = [ "network-interfaces.target" ];
+      after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
 
       preStart = ''
diff --git a/nixos/modules/services/networking/hostapd.nix b/nixos/modules/services/networking/hostapd.nix
index 287964aab07..fd4545e88e2 100644
--- a/nixos/modules/services/networking/hostapd.nix
+++ b/nixos/modules/services/networking/hostapd.nix
@@ -86,7 +86,7 @@ in
 
       hwMode = mkOption {
         default = "g";
-        type = types.string;
+        type = types.enum [ "a" "b" "g" ];
         description = ''
           Operation mode.
           (a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g).
@@ -140,7 +140,7 @@ in
           ieee80211n=1
           ht_capab=[HT40-][SHORT-GI-40][DSSS_CCK-40]
           '';
-        type = types.string;
+        type = types.lines;
         description = "Extra configuration options to put in hostapd.conf.";
       };
     };
@@ -152,9 +152,6 @@ in
   config = mkIf cfg.enable {
 
     assertions = [
-      { assertion = (cfg.hwMode == "a" || cfg.hwMode == "b" || cfg.hwMode == "g");
-        message = "hwMode must be a/b/g";
-      }
       { assertion = (cfg.channel >= 1 && cfg.channel <= 13);
         message = "channel must be between 1 and 13";
       }];
diff --git a/nixos/modules/services/networking/htpdate.nix b/nixos/modules/services/networking/htpdate.nix
new file mode 100644
index 00000000000..f5d512c7cd5
--- /dev/null
+++ b/nixos/modules/services/networking/htpdate.nix
@@ -0,0 +1,80 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  inherit (pkgs) htpdate;
+
+  cfg = config.services.htpdate;
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.htpdate = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Enable htpdate daemon.
+        '';
+      };
+
+      extraOptions = mkOption {
+        type = types.str;
+        default = "";
+        description = ''
+          Additional command line arguments to pass to htpdate.
+        '';
+      };
+
+      servers = mkOption {
+        type = types.listOf types.str;
+        default = [ "www.google.com" ];
+        description = ''
+          HTTP servers to use for time synchronization.
+        '';
+      };
+
+      proxy = mkOption {
+        type = types.str;
+        default = "";
+        example = "127.0.0.1:8118";
+        description = ''
+          HTTP proxy used for requests.
+        '';
+      };
+
+    };
+
+  };
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    systemd.services.htpdate = {
+      description = "htpdate daemon";
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        Type = "forking";
+        PIDFile = "/var/run/htpdate.pid";
+        ExecStart = concatStringsSep " " [
+          "${htpdate}/bin/htpdate"
+          "-D -u nobody"
+          "-a -s"
+          "-l"
+          "${optionalString (cfg.proxy != "") "-P ${cfg.proxy}"}"
+          "${cfg.extraOptions}"
+          "${concatStringsSep " " cfg.servers}"
+        ];
+      };
+    };
+
+  };
+
+}
diff --git a/nixos/modules/services/networking/i2pd.nix b/nixos/modules/services/networking/i2pd.nix
index 0cbf57314c4..abb7a4e9137 100644
--- a/nixos/modules/services/networking/i2pd.nix
+++ b/nixos/modules/services/networking/i2pd.nix
@@ -10,7 +10,7 @@ let
 
   extip = "EXTIP=\$(${pkgs.curl.bin}/bin/curl -sf \"http://jsonip.com\" | ${pkgs.gawk}/bin/awk -F'\"' '{print $4}')";
 
-  toYesNo = b: if b then "yes" else "no";
+  toYesNo = b: if b then "true" else "false";
 
   mkEndpointOpt = name: addr: port: {
     enable = mkEnableOption name;
@@ -31,6 +31,17 @@ let
     };
   };
 
+  mkKeyedEndpointOpt = name: addr: port: keyFile:
+  (mkEndpointOpt name addr port) // {
+    keys = mkOption {
+      type = types.str;
+      default = "";
+      description = ''
+        File to persist ${lib.toUpper name} keys.
+      '';
+    };
+  };
+
   commonTunOpts = let
     i2cpOpts = {
       length = mkOption {
@@ -63,19 +74,49 @@ let
     };
   } // mkEndpointOpt name "127.0.0.1" 0;
 
-  i2pdConf = pkgs.writeText "i2pd.conf" ''
-      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)
-        (proto: let portStr = toString proto.port; in ''
-      [${proto.name}]
-      address = ${proto.address}
-      port = ${toString proto.port}
-      enabled = ${toYesNo proto.enable}
-      '')
+  i2pdConf = pkgs.writeText "i2pd.conf"
+  ''
+  ipv4 = ${toYesNo cfg.enableIPv4}
+  ipv6 = ${toYesNo cfg.enableIPv6}
+  notransit = ${toYesNo cfg.notransit}
+  floodfill = ${toYesNo cfg.floodfill}
+  netid = ${toString cfg.netid}
+  ${if isNull cfg.bandwidth then "" else "bandwidth = ${toString cfg.bandwidth}" }
+  ${if isNull cfg.port then "" else "port = ${toString cfg.port}"}
+
+  [limits]
+  transittunnels = ${toString cfg.limits.transittunnels}
+
+  [upnp]
+  enabled = ${toYesNo cfg.upnp.enable}
+  name = ${cfg.upnp.name}
+
+  [precomputation]
+  elgamal = ${toYesNo cfg.precomputation.elgamal}
+
+  [reseed]
+  verify = ${toYesNo cfg.reseed.verify}
+  file = ${cfg.reseed.file}
+  urls = ${builtins.concatStringsSep "," cfg.reseed.urls}
+
+  [addressbook]
+  defaulturl = ${cfg.addressbook.defaulturl}
+  subscriptions = ${builtins.concatStringsSep "," cfg.addressbook.subscriptions}
+  ${flip concatMapStrings
+      (collect (proto: proto ? port && proto ? address && proto ? name) cfg.proto)
+      (proto: let portStr = toString proto.port; in
+        ''
+          [${proto.name}]
+          enabled = ${toYesNo proto.enable}
+          address = ${proto.address}
+          port = ${toString proto.port}
+          ${if proto ? keys then "keys = ${proto.keys}" else ""}
+          ${if proto ? auth then "auth = ${toYesNo proto.auth}" else ""}
+          ${if proto ? user then "user = ${proto.user}" else ""}
+          ${if proto ? pass then "pass = ${proto.pass}" else ""}
+          ${if proto ? outproxy then "outproxy = ${proto.outproxy}" else ""}
+          ${if proto ? outproxyPort then "outproxyport = ${toString proto.outproxyPort}" else ""}
+        '')
       }
   '';
 
@@ -106,7 +147,7 @@ let
   host = ${tun.address}
   port = ${tun.port}
   inport = ${tun.inPort}
-  accesslist = ${concatStringSep "," tun.accessList}
+  accesslist = ${builtins.concatStringsSep "," tun.accessList}
   '')
   }
   '';
@@ -114,7 +155,7 @@ let
   i2pdSh = pkgs.writeScriptBin "i2pd" ''
     #!/bin/sh
     ${if isNull cfg.extIp then extip else ""}
-    ${pkgs.i2pd}/bin/i2pd --log=1 \
+    ${pkgs.i2pd}/bin/i2pd \
       --host=${if isNull cfg.extIp then "$EXTIP" else cfg.extIp} \
       --conf=${i2pdConf} \
       --tunconf=${i2pdTunnelConf}
@@ -135,6 +176,8 @@ in
         default = false;
         description = ''
           Enables I2Pd as a running service upon activation.
+          Please read http://i2pd.readthedocs.io/en/latest/ for further
+          configuration help.
         '';
       };
 
@@ -162,6 +205,22 @@ in
         '';
       };
 
+      netid = mkOption {
+        type = types.int;
+        default = 2;
+        description = ''
+          I2P overlay netid.
+        '';
+      };
+
+      bandwidth = mkOption {
+        type = with types; nullOr int;
+        default = null;
+        description = ''
+           Set a router bandwidth limit integer in kbps or letters: L (32), O (256), P (2048), X (>9000)
+        '';
+      };
+
       port = mkOption {
         type = with types; nullOr int;
         default = null;
@@ -170,6 +229,14 @@ in
         '';
       };
 
+      enableIPv4 = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Enables IPv4 connectivity. Enabled by default.
+        '';
+      };
+
       enableIPv6 = mkOption {
         type = types.bool;
         default = false;
@@ -178,53 +245,177 @@ in
         '';
       };
 
-      proto.http = mkEndpointOpt "http" "127.0.0.1" 7070;
+      upnp = {
+        enable = mkOption {
+          type = types.bool;
+          default = false;
+          description = ''
+            Enables UPnP.
+          '';
+        };
+
+        name = mkOption {
+          type = types.str;
+          default = "I2Pd";
+          description = ''
+            Name i2pd appears in UPnP forwardings list.
+          '';
+        };
+      };
+
+      precomputation.elgamal = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Use ElGamal precomputated tables.
+        '';
+      };
+
+      reseed = {
+        verify = mkOption {
+          type = types.bool;
+          default = false;
+          description = ''
+            Request SU3 signature verification
+          '';
+        };
+
+        file = mkOption {
+          type = types.str;
+          default = "";
+          description = ''
+            Full path to SU3 file to reseed from
+          '';
+        };
+
+        urls = mkOption {
+          type = with types; listOf str;
+          default = [
+            "https://reseed.i2p-project.de/"
+            "https://i2p.mooo.com/netDb/"
+            "https://netdb.i2p2.no/"
+            "https://us.reseed.i2p2.no:444/"
+            "https://uk.reseed.i2p2.no:444/"
+            "https://i2p.manas.ca:8443/"
+          ];
+          description = ''
+            Reseed URLs
+          '';
+        };
+      };
+
+      addressbook = {
+       defaulturl = mkOption {
+          type = types.str;
+          default = "http://joajgazyztfssty4w2on5oaqksz6tqoxbduy553y34mf4byv6gpq.b32.i2p/export/alive-hosts.txt";
+          description = ''
+            AddressBook subscription URL for initial setup
+          '';
+        };
+       subscriptions = mkOption {
+          type = with types; listOf str;
+          default = [
+            "http://inr.i2p/export/alive-hosts.txt"
+            "http://i2p-projekt.i2p/hosts.txt"
+            "http://stats.i2p/cgi-bin/newhosts.txt"
+          ];
+          description = ''
+            AddressBook subscription URLs
+          '';
+        };
+      };
+
+      limits.transittunnels = mkOption {
+        type = types.int;
+        default = 2500;
+        description = ''
+          Maximum number of active transit sessions
+        '';
+      };
+
+      proto.http = (mkEndpointOpt "http" "127.0.0.1" 7070) // {
+        auth = mkOption {
+          type = types.bool;
+          default = false;
+          description = ''
+            Enable authentication for webconsole.
+          '';
+        };
+        user = mkOption {
+          type = types.str;
+          default = "i2pd";
+          description = ''
+            Username for webconsole access
+          '';
+        };
+        pass = mkOption {
+          type = types.str;
+          default = "i2pd";
+          description = ''
+            Password for webconsole access.
+          '';
+        };
+      };
+
+      proto.httpProxy = mkKeyedEndpointOpt "httpproxy" "127.0.0.1" 4446 "";
+      proto.socksProxy = (mkKeyedEndpointOpt "socksproxy" "127.0.0.1" 4447 "")
+      // {
+        outproxy = mkOption {
+          type = types.str;
+          default = "127.0.0.1";
+          description = "Upstream outproxy bind address.";
+        };
+        outproxyPort = mkOption {
+          type = types.int;
+          default = 4444;
+          description = "Upstream outproxy bind port.";
+        };
+      };
+
       proto.sam = mkEndpointOpt "sam" "127.0.0.1" 7656;
       proto.bob = mkEndpointOpt "bob" "127.0.0.1" 2827;
+      proto.i2cp = mkEndpointOpt "i2cp" "127.0.0.1" 7654;
       proto.i2pControl = mkEndpointOpt "i2pcontrol" "127.0.0.1" 7650;
-      proto.httpProxy = mkEndpointOpt "httpproxy" "127.0.0.1" 4446;
-      proto.socksProxy = mkEndpointOpt "socksproxy" "127.0.0.1" 4447;
 
       outTunnels = mkOption {
         default = {};
-        type = with types; loaOf optionSet;
+        type = with types; loaOf (submodule (
+          { name, config, ... }: {
+            options = commonTunOpts name;
+            config = {
+              name = mkDefault name;
+            };
+          }
+        ));
         description = ''
           Connect to someone as a client and establish a local accept endpoint
         '';
-        options = [ ({ name, config, ... }: {
-          options = commonTunOpts name;
-          config = {
-            name = mkDefault name;
-          };
-        }) ];
       };
 
       inTunnels = mkOption {
         default = {};
-        type = with types; loaOf optionSet;
+        type = with types; loaOf (submodule (
+          { name, config, ... }: {
+            options = {
+              inPort = mkOption {
+                type = types.int;
+                default = 0;
+                description = "Service port. Default to the tunnel's listen port.";
+              };
+              accessList = mkOption {
+                type = with types; listOf str;
+                default = [];
+                description = "I2P nodes that are allowed to connect to this service.";
+              };
+            } // commonTunOpts name;
+            config = {
+              name = mkDefault name;
+            };
+          }
+        ));
         description = ''
           Serve something on I2P network at port and delegate requests to address inPort.
         '';
-        options = [ ({ name, config, ... }: {
-
-          options = {
-            inPort = mkOption {
-              type = types.int;
-              default = 0;
-              description = "Service port. Default to the tunnel's listen port.";
-            };
-            accessList = mkOption {
-              type = with types; listOf str;
-              default = [];
-              description = "I2P nodes that are allowed to connect to this service.";
-            };
-          } // commonTunOpts name;
-
-          config = {
-            name = mkDefault name;
-          };
-
-        }) ];
       };
     };
   };
diff --git a/nixos/modules/services/networking/iodine.nix b/nixos/modules/services/networking/iodine.nix
index 1b0d2d9a517..512dbd77ae4 100644
--- a/nixos/modules/services/networking/iodine.nix
+++ b/nixos/modules/services/networking/iodine.nix
@@ -106,7 +106,8 @@ in
       createIodineClientService = name: cfg:
       {
         description = "iodine client - ${name}";
-        wantedBy = [ "ip-up.target" ];
+        after = [ "network.target" ];
+        wantedBy = [ "multi-user.target" ];
         serviceConfig = {
           RestartSec = "30s";
           Restart = "always";
@@ -121,7 +122,8 @@ in
     ) // {
       iodined = mkIf (cfg.server.enable) {
         description = "iodine, ip over dns server daemon";
-        wantedBy = [ "ip-up.target" ];
+        after = [ "network.target" ];
+        wantedBy = [ "multi-user.target" ];
         serviceConfig.ExecStart = "${pkgs.iodine}/bin/iodined -f -u ${iodinedUser} ${cfg.server.extraConfig} ${cfg.server.ip} ${cfg.server.domain}";
       };
     };
diff --git a/nixos/modules/services/networking/ircd-hybrid/builder.sh b/nixos/modules/services/networking/ircd-hybrid/builder.sh
index f2c92878a4d..38312210df2 100644
--- a/nixos/modules/services/networking/ircd-hybrid/builder.sh
+++ b/nixos/modules/services/networking/ircd-hybrid/builder.sh
@@ -12,7 +12,7 @@ for i in $scripts; do
     if test "$(echo $i | cut -c1-2)" = "=>"; then
         subDir=$(echo $i | cut -c3-)
     else
-        dst=$out/$subDir/$((stripHash $i; echo $strippedName) | sed 's/\.in//')
+        dst=$out/$subDir/$(stripHash $i | sed 's/\.in//')
         doSub $i $dst
         chmod +x $dst # !!!
     fi
@@ -23,7 +23,7 @@ for i in $substFiles; do
     if test "$(echo $i | cut -c1-2)" = "=>"; then
         subDir=$(echo $i | cut -c3-)
     else
-        dst=$out/$subDir/$((stripHash $i; echo $strippedName) | sed 's/\.in//')
+        dst=$out/$subDir/$(stripHash $i | sed 's/\.in//')
         doSub $i $dst
     fi
 done
diff --git a/nixos/modules/services/networking/kippo.nix b/nixos/modules/services/networking/kippo.nix
index 5f3efcd133a..834de4fdc09 100644
--- a/nixos/modules/services/networking/kippo.nix
+++ b/nixos/modules/services/networking/kippo.nix
@@ -46,7 +46,7 @@ rec {
       };
       extraConfig = mkOption {
         default = "";
-        type = types.string;
+        type = types.lines;
         description = ''Extra verbatim configuration added to the end of kippo.cfg.'';
       };
     };
@@ -54,7 +54,7 @@ rec {
   };
   config = mkIf cfg.enable {
     environment.systemPackages = with pkgs.pythonPackages; [
-      python twisted_11 pycrypto pyasn1 ];
+      python pkgs.kippo.twisted pycrypto pyasn1 ];
 
     environment.etc."kippo.cfg".text = ''
         # Automatically generated by NixOS.
@@ -84,7 +84,7 @@ rec {
       description = "Kippo Web Server";
       after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
-      environment.PYTHONPATH = "${pkgs.kippo}/src/:${pkgs.pythonPackages.pycrypto}/lib/python2.7/site-packages/:${pkgs.pythonPackages.pyasn1}/lib/python2.7/site-packages/:${pkgs.pythonPackages.python}/lib/python2.7/site-packages/:${pkgs.pythonPackages.twisted_11}/lib/python2.7/site-packages/:.";
+      environment.PYTHONPATH = "${pkgs.kippo}/src/:${pkgs.pythonPackages.pycrypto}/lib/python2.7/site-packages/:${pkgs.pythonPackages.pyasn1}/lib/python2.7/site-packages/:${pkgs.pythonPackages.python}/lib/python2.7/site-packages/:${pkgs.kippo.twisted}/lib/python2.7/site-packages/:.";
       preStart = ''
         if [ ! -d ${cfg.varPath}/ ] ; then
             mkdir -p ${cfg.logPath}/tty
@@ -107,7 +107,7 @@ rec {
         fi
       '';
 
-      serviceConfig.ExecStart = "${pkgs.pythonPackages.twisted_11}/bin/twistd -y ${pkgs.kippo}/src/kippo.tac --syslog --rundir=${cfg.varPath}/ --pidfile=${cfg.pidPath}/kippo.pid --prefix=kippo -n";
+      serviceConfig.ExecStart = "${pkgs.kippo.twisted}/bin/twistd -y ${pkgs.kippo}/src/kippo.tac --syslog --rundir=${cfg.varPath}/ --pidfile=${cfg.pidPath}/kippo.pid --prefix=kippo -n";
       serviceConfig.PermissionsStartOnly = true;
       serviceConfig.User = "kippo"; 
       serviceConfig.Group = "kippo"; 
diff --git a/nixos/modules/services/networking/miredo.nix b/nixos/modules/services/networking/miredo.nix
new file mode 100644
index 00000000000..932d6cf2903
--- /dev/null
+++ b/nixos/modules/services/networking/miredo.nix
@@ -0,0 +1,93 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.miredo;
+  pidFile = "/run/miredo.pid";
+  miredoConf = pkgs.writeText "miredo.conf" ''
+    InterfaceName ${cfg.interfaceName}
+    ServerAddress ${cfg.serverAddress}
+    ${optionalString (cfg.bindAddress != null) "BindAddress ${cfg.bindAddress}"}
+    ${optionalString (cfg.bindPort != null) "BindPort ${cfg.bindPort}"}
+  '';
+in
+{
+
+  ###### interface
+
+  options = {
+
+    services.miredo = {
+
+      enable = mkEnableOption "Whether miredo should be run on startup.";
+
+      package = mkOption {
+        type = types.package;
+        default = pkgs.miredo;
+        defaultText = "pkgs.miredo";
+        description = ''
+          The package to use for the miredo daemon's binary.
+        '';
+      };
+
+      serverAddress = mkOption {
+        default = "teredo.remlab.net";
+        type = types.str;
+        description = ''
+          The hostname or primary IPv4 address of the Teredo server.
+          This setting is required if Miredo runs as a Teredo client.
+          "teredo.remlab.net" is an experimental service for testing only.
+          Please use another server for production and/or large scale deployments.
+        '';
+      };
+
+      interfaceName = mkOption {
+        default = "teredo";
+        type = types.str;
+        description = ''
+          Name of the network tunneling interface.
+        '';
+      };
+
+      bindAddress = mkOption {
+        default = null;
+        type = types.nullOr types.str;
+        description = ''
+          Depending on the local firewall/NAT rules, you might need to force
+          Miredo to use a fixed UDP port and or IPv4 address.
+        '';
+      };
+
+      bindPort = mkOption {
+        default = null;
+        type = types.nullOr types.str;
+        description = ''
+          Depending on the local firewall/NAT rules, you might need to force
+          Miredo to use a fixed UDP port and or IPv4 address.
+        '';
+      };
+    };
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+
+    systemd.services.miredo = {
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+      description = "Teredo IPv6 Tunneling Daemon";
+      serviceConfig = {
+        Restart = "always";
+        RestartSec = "5s";
+        ExecStartPre = "${cfg.package}/bin/miredo-checkconf -f ${miredoConf}";
+        ExecStart = "${cfg.package}/bin/miredo -c ${miredoConf} -p ${pidFile} -f";
+        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+      };
+    };
+
+  };
+
+}
diff --git a/nixos/modules/services/networking/mjpg-streamer.nix b/nixos/modules/services/networking/mjpg-streamer.nix
index 9986f549aec..1286b0c7ef6 100644
--- a/nixos/modules/services/networking/mjpg-streamer.nix
+++ b/nixos/modules/services/networking/mjpg-streamer.nix
@@ -59,8 +59,12 @@ in {
       description = "mjpg-streamer webcam streamer";
       wantedBy = [ "multi-user.target" ];
 
-      serviceConfig.User = cfg.user;
-      serviceConfig.Group = cfg.group;
+      serviceConfig = {
+        User = cfg.user;
+        Group = cfg.group;
+        Restart = "on-failure";
+        RestartSec = 1;
+      };
 
       script = ''
         IPLUGIN="${cfg.inputPlugin}"
diff --git a/nixos/modules/services/networking/murmur.nix b/nixos/modules/services/networking/murmur.nix
index 1cc19a2c9e0..81f968ae9fe 100644
--- a/nixos/modules/services/networking/murmur.nix
+++ b/nixos/modules/services/networking/murmur.nix
@@ -15,7 +15,7 @@ let
     logfile=/var/log/murmur/murmurd.log
     pidfile=${cfg.pidfile}
 
-    welcome="${cfg.welcome}"
+    welcometext="${cfg.welcometext}"
     port=${toString cfg.port}
 
     ${if cfg.hostName == "" then "" else "host="+cfg.hostName}
@@ -84,7 +84,7 @@ in
         description = "Path to PID file for Murmur daemon.";
       };
 
-      welcome = mkOption {
+      welcometext = mkOption {
         type = types.str;
         default = "";
         description = "Welcome message for connected clients.";
@@ -230,7 +230,7 @@ in
       };
 
       extraConfig = mkOption {
-        type = types.str;
+        type = types.lines;
         default = "";
         description = "Extra configuration to put into mumur.ini.";
       };
diff --git a/nixos/modules/services/networking/nat.nix b/nixos/modules/services/networking/nat.nix
index 9d163e60d5e..08ba2fdb164 100644
--- a/nixos/modules/services/networking/nat.nix
+++ b/nixos/modules/services/networking/nat.nix
@@ -122,23 +122,23 @@ in
     };
 
     networking.nat.forwardPorts = mkOption {
-      type = types.listOf types.optionSet;
+      type = with types; listOf (submodule {
+        options = {
+          sourcePort = mkOption {
+            type = types.int;
+            example = 8080;
+            description = "Source port of the external interface";
+          };
+
+          destination = mkOption {
+            type = types.str;
+            example = "10.0.0.1:80";
+            description = "Forward tcp connection to destination ip:port";
+          };
+        };
+      });
       default = [];
       example = [ { sourcePort = 8080; destination = "10.0.0.1:80"; } ];
-      options = {
-        sourcePort = mkOption {
-          type = types.int;
-          example = 8080;
-          description = "Source port of the external interface";
-        };
-
-        destination = mkOption {
-          type = types.str;
-          example = "10.0.0.1:80";
-          description = "Forward tcp connection to destination ip:port";
-        };
-      };
-
       description =
         ''
           List of forwarded ports from the external interface to
@@ -171,7 +171,7 @@ in
     systemd.services = mkIf (!config.networking.firewall.enable) { nat = {
       description = "Network Address Translation";
       wantedBy = [ "network.target" ];
-      after = [ "network-interfaces.target" "systemd-modules-load.service" ];
+      after = [ "network-pre.target" "systemd-modules-load.service" ];
       path = [ pkgs.iptables ];
       unitConfig.ConditionCapability = "CAP_NET_ADMIN";
 
diff --git a/nixos/modules/services/networking/networkmanager.nix b/nixos/modules/services/networking/networkmanager.nix
index d198e3bfc02..8f353979d3f 100644
--- a/nixos/modules/services/networking/networkmanager.nix
+++ b/nixos/modules/services/networking/networkmanager.nix
@@ -52,14 +52,6 @@ let
     });
   '';
 
-  ipUpScript = writeScript "01nixos-ip-up" ''
-    #!/bin/sh
-    if test "$2" = "up"; then
-      ${config.systemd.package}/bin/systemctl start ip-up.target
-      ${config.systemd.package}/bin/systemctl start network-online.target
-    fi
-  '';
-
   ns = xs: writeText "nameservers" (
     concatStrings (map (s: "nameserver ${s}\n") xs)
   );
@@ -188,9 +180,6 @@ in {
     boot.kernelModules = [ "ppp_mppe" ]; # Needed for most (all?) PPTP VPN connections.
 
     environment.etc = with cfg.basePackages; [
-      { source = ipUpScript;
-        target = "NetworkManager/dispatcher.d/01nixos-ip-up";
-      }
       { source = configFile;
         target = "NetworkManager/NetworkManager.conf";
       }
@@ -209,6 +198,9 @@ in {
       { source = "${networkmanager_l2tp}/etc/NetworkManager/VPN/nm-l2tp-service.name";
         target = "NetworkManager/VPN/nm-l2tp-service.name";
       }
+      { source = "${networkmanager_strongswan}/etc/NetworkManager/VPN/nm-strongswan-service.name";
+        target = "NetworkManager/VPN/nm-strongswan-service.name";
+      }
     ] ++ optional (cfg.appendNameservers == [] || cfg.insertNameservers == [])
            { source = overrideNameserversScript;
              target = "NetworkManager/dispatcher.d/02overridedns";
diff --git a/nixos/modules/services/networking/nntp-proxy.nix b/nixos/modules/services/networking/nntp-proxy.nix
index dca8ccac762..7eebecb23b0 100644
--- a/nixos/modules/services/networking/nntp-proxy.nix
+++ b/nixos/modules/services/networking/nntp-proxy.nix
@@ -148,11 +148,11 @@ in
       };
 
       verbosity = mkOption {
-        type = types.str;
+        type = types.enum [ "error" "warning" "notice" "info" "debug" ];
         default = "info";
         example = "error";
         description = ''
-          Verbosity level (error, warning, notice, info, debug)
+          Verbosity level
         '';
       };
 
diff --git a/nixos/modules/services/networking/nsd.nix b/nixos/modules/services/networking/nsd.nix
index 333a3378c4c..481e267f6c3 100644
--- a/nixos/modules/services/networking/nsd.nix
+++ b/nixos/modules/services/networking/nsd.nix
@@ -71,6 +71,7 @@ let
       # interfaces
     ${forEach "  ip-address: " cfg.interfaces}
 
+      ip-freebind:         ${yesOrNo  cfg.ipFreebind}
       hide-version:        ${yesOrNo  cfg.hideVersion}
       identity:            "${cfg.identity}"
       ip-transparent:      ${yesOrNo  cfg.ipTransparent}
@@ -84,7 +85,7 @@ let
       reuseport:           ${yesOrNo  cfg.reuseport}
       round-robin:         ${yesOrNo  cfg.roundRobin}
       server-count:        ${toString cfg.serverCount}
-      ${if cfg.statistics == null then "" else "statistics:          ${toString cfg.statistics}"}
+      ${maybeToString "statistics: " cfg.statistics}
       tcp-count:           ${toString cfg.tcpCount}
       tcp-query-count:     ${toString cfg.tcpQueryCount}
       tcp-timeout:         ${toString cfg.tcpTimeout}
@@ -117,7 +118,8 @@ let
   '';
 
   yesOrNo = b: if b then "yes" else "no";
-  maybeString = pre: s: if s == null then "" else ''${pre} "${s}"'';
+  maybeString = prefix: x: if x == null then "" else ''${prefix} "${x}"'';
+  maybeToString = prefix: x: if x == null then "" else ''${prefix} ${toString x}'';
   forEach = pre: l: concatMapStrings (x: pre + x + "\n") l;
 
 
@@ -146,6 +148,11 @@ let
     ${forEach     "  rrl-whitelist: "      zone.rrlWhitelist}
       ${maybeString "zonestats: "          zone.zoneStats}
 
+      ${maybeToString "max-refresh-time: " zone.maxRefreshSecs}
+      ${maybeToString "min-refresh-time: " zone.minRefreshSecs}
+      ${maybeToString "max-retry-time:   " zone.maxRetrySecs}
+      ${maybeToString "min-retry-time:   " zone.minRetrySecs}
+
       allow-axfr-fallback: ${yesOrNo       zone.allowAXFRFallback}
     ${forEach     "  allow-notify: "       zone.allowNotify}
     ${forEach     "  request-xfr: "        zone.requestXFR}
@@ -241,6 +248,44 @@ let
         '';
       };
 
+      maxRefreshSecs = mkOption {
+        type = types.nullOr types.int;
+        default = null;
+        description = ''
+          Limit refresh time for secondary zones. This is the timer which
+          checks to see if the zone has to be refetched when it expires.
+          Normally the value from the SOA record is used, but this  option
+          restricts that value.
+        '';
+      };
+
+      minRefreshSecs = mkOption {
+        type = types.nullOr types.int;
+        default = null;
+        description = ''
+          Limit refresh time for secondary zones.
+        '';
+      };
+
+      maxRetrySecs = mkOption {
+        type = types.nullOr types.int;
+        default = null;
+        description = ''
+          Limit retry time for secondary zones. This is the timeout after
+          a failed fetch attempt for the zone. Normally the value from
+          the SOA record is used, but this option restricts that value.
+        '';
+      };
+
+      minRetrySecs = mkOption {
+        type = types.nullOr types.int;
+        default = null;
+        description = ''
+          Limit retry time for secondary zones.
+        '';
+      };
+
+
       notify = mkOption {
         type = types.listOf types.str;
         default = [];
@@ -300,12 +345,10 @@ let
       };
 
       rrlWhitelist = mkOption {
-        type = types.listOf types.str;
+        type = with types; listOf (enum [ "nxdomain" "error" "referral" "any" "rrsig" "wildcard" "nodata" "dnskey" "positive" "all" ]);
         default = [];
         description = ''
           Whitelists the given rrl-types.
-          The RRL classification types are:  nxdomain,  error, referral, any,
-          rrsig, wildcard, nodata, dnskey, positive, all
         '';
       };
 
@@ -366,6 +409,15 @@ in
       '';
     };
 
+    ipFreebind = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Whether to bind to nonlocal addresses and interfaces that are down.
+        Similar to ip-transparent.
+      '';
+    };
+
     ipTransparent = mkOption {
       type = types.bool;
       default = false;
diff --git a/nixos/modules/services/networking/ntpd.nix b/nixos/modules/services/networking/ntpd.nix
index c8a08567928..88e6dbf22b9 100644
--- a/nixos/modules/services/networking/ntpd.nix
+++ b/nixos/modules/services/networking/ntpd.nix
@@ -34,7 +34,7 @@ in
     services.ntp = {
 
       enable = mkOption {
-        default = !config.boot.isContainer;
+        default = false;
         description = ''
           Whether to synchronise your machine's time using the NTP
           protocol.
@@ -42,12 +42,7 @@ in
       };
 
       servers = mkOption {
-        default = [
-          "0.nixos.pool.ntp.org"
-          "1.nixos.pool.ntp.org"
-          "2.nixos.pool.ntp.org"
-          "3.nixos.pool.ntp.org"
-        ];
+        default = config.networking.timeServers;
         description = ''
           The set of NTP servers from which to synchronise.
         '';
@@ -70,6 +65,7 @@ in
 
     # Make tools such as ntpq available in the system path.
     environment.systemPackages = [ pkgs.ntp ];
+    services.timesyncd.enable = mkForce false;
 
     users.extraUsers = singleton
       { name = ntpUser;
diff --git a/nixos/modules/services/networking/oidentd.nix b/nixos/modules/services/networking/oidentd.nix
index 651bb8e967c..ba7acd87954 100644
--- a/nixos/modules/services/networking/oidentd.nix
+++ b/nixos/modules/services/networking/oidentd.nix
@@ -25,7 +25,7 @@ with lib;
 
   config = mkIf config.services.oidentd.enable {
     systemd.services.oidentd = {
-      after = [ "network-interfaces.target" ];
+      after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
       serviceConfig.Type = "forking";
       script = "${pkgs.oidentd}/sbin/oidentd -u oidentd -g nogroup" +
diff --git a/nixos/modules/services/networking/openfire.nix b/nixos/modules/services/networking/openfire.nix
index ed91b45ec94..4059eb3db83 100644
--- a/nixos/modules/services/networking/openfire.nix
+++ b/nixos/modules/services/networking/openfire.nix
@@ -34,7 +34,7 @@ with lib;
 
     assertions = singleton
       { assertion = !(config.services.openfire.usePostgreSQL -> config.services.postgresql.enable);
-        message = "OpenFire assertion failed.";
+        message = "OpenFire configured to use PostgreSQL but services.postgresql.enable is not enabled.";
       };
 
     systemd.services.openfire = {
@@ -47,7 +47,7 @@ with lib;
         export HOME=/tmp
         mkdir /var/log/openfire || true
         mkdir /etc/openfire || true
-        for i in ${openfire}/conf.inst/*; do
+        for i in ${pkgs.openfire}/conf.inst/*; do
             if ! test -f /etc/openfire/$(basename $i); then
                 cp $i /etc/openfire/
             fi
diff --git a/nixos/modules/services/networking/openntpd.nix b/nixos/modules/services/networking/openntpd.nix
index a8625fa2fa9..13a1b5258ce 100644
--- a/nixos/modules/services/networking/openntpd.nix
+++ b/nixos/modules/services/networking/openntpd.nix
@@ -49,7 +49,7 @@ in
   ###### implementation
 
   config = mkIf cfg.enable {
-    services.ntp.enable = mkForce false;
+    services.timesyncd.enable = mkForce false;
 
     # Add ntpctl to the environment for status checking
     environment.systemPackages = [ package ];
diff --git a/nixos/modules/services/networking/openvpn.nix b/nixos/modules/services/networking/openvpn.nix
index 82173a841a3..3fbf5a9f022 100644
--- a/nixos/modules/services/networking/openvpn.nix
+++ b/nixos/modules/services/networking/openvpn.nix
@@ -56,7 +56,7 @@ let
       description = "OpenVPN instance ‘${name}’";
 
       wantedBy = optional cfg.autoStart "multi-user.target";
-      after = [ "network-interfaces.target" ];
+      after = [ "network.target" ];
 
       path = [ pkgs.iptables pkgs.iproute pkgs.nettools ];
 
@@ -116,52 +116,54 @@ in
         attribute name.
       '';
 
-      type = types.attrsOf types.optionSet;
+      type = with types; attrsOf (submodule {
 
-      options = {
+        options = {
 
-        config = mkOption {
-          type = types.lines;
-          description = ''
-            Configuration of this OpenVPN instance.  See
-            <citerefentry><refentrytitle>openvpn</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-            for details.
-          '';
-        };
+          config = mkOption {
+            type = types.lines;
+            description = ''
+              Configuration of this OpenVPN instance.  See
+              <citerefentry><refentrytitle>openvpn</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+              for details.
+            '';
+          };
 
-        up = mkOption {
-          default = "";
-          type = types.lines;
-          description = ''
-            Shell commands executed when the instance is starting.
-          '';
-        };
+          up = mkOption {
+            default = "";
+            type = types.lines;
+            description = ''
+              Shell commands executed when the instance is starting.
+            '';
+          };
 
-        down = mkOption {
-          default = "";
-          type = types.lines;
-          description = ''
-            Shell commands executed when the instance is shutting down.
-          '';
-        };
+          down = mkOption {
+            default = "";
+            type = types.lines;
+            description = ''
+              Shell commands executed when the instance is shutting down.
+            '';
+          };
 
-        autoStart = mkOption {
-          default = true;
-          type = types.bool;
-          description = "Whether this OpenVPN instance should be started automatically.";
-        };
+          autoStart = mkOption {
+            default = true;
+            type = types.bool;
+            description = "Whether this OpenVPN instance should be started automatically.";
+          };
+
+          updateResolvConf = mkOption {
+            default = false;
+            type = types.bool;
+            description = ''
+              Use the script from the update-resolv-conf package to automatically
+              update resolv.conf with the DNS information provided by openvpn. The
+              script will be run after the "up" commands and before the "down" commands.
+            '';
+          };
 
-        updateResolvConf = mkOption {
-          default = false;
-          type = types.bool;
-          description = ''
-            Use the script from the update-resolv-conf package to automatically
-            update resolv.conf with the DNS information provided by openvpn. The
-            script will be run after the "up" commands and before the "down" commands.
-          '';
         };
 
-      };
+      });
 
     };
 
diff --git a/nixos/modules/services/networking/powerdns.nix b/nixos/modules/services/networking/powerdns.nix
new file mode 100644
index 00000000000..ba05e15389f
--- /dev/null
+++ b/nixos/modules/services/networking/powerdns.nix
@@ -0,0 +1,49 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.powerdns;
+  configDir = pkgs.writeTextDir "pdns.conf" "${cfg.extraConfig}";
+in {
+  options = {
+    services.powerdns = {
+      enable = mkEnableOption "Powerdns domain name server";
+
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "launch=bind";
+        description = ''
+          Extra lines to be added verbatim to pdns.conf.
+          Powerdns will chroot to /var/lib/powerdns.
+          So any file, powerdns is supposed to be read,
+          should be in /var/lib/powerdns and needs to specified
+          relative to the chroot.
+        '';
+      };
+    };
+  };
+
+  config = mkIf config.services.powerdns.enable {
+    systemd.services.pdns = {
+      unitConfig.Documentation = "man:pdns_server(1) man:pdns_control(1)";
+      description = "Powerdns name server";
+      wantedBy = [ "multi-user.target" ];
+      after = ["network.target" "mysql.service" "postgresql.service" "openldap.service"];
+
+      serviceConfig = {
+        Restart="on-failure";
+        RestartSec="1";
+        StartLimitInterval="0";
+        PrivateDevices=true;
+        CapabilityBoundingSet="CAP_CHOWN CAP_NET_BIND_SERVICE CAP_SETGID CAP_SETUID CAP_SYS_CHROOT";
+        NoNewPrivileges=true;
+        ExecStartPre = "${pkgs.coreutils}/bin/mkdir -p /var/lib/powerdns";
+        ExecStart = "${pkgs.powerdns}/bin/pdns_server --setuid=nobody --setgid=nogroup --chroot=/var/lib/powerdns --socket-dir=/ --daemon=no --guardian=no --disable-syslog --write-pid=no --config-dir=${configDir}";
+        ProtectSystem="full";
+        ProtectHome=true;
+        RestrictAddressFamilies="AF_UNIX AF_INET AF_INET6";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/networking/prayer.nix b/nixos/modules/services/networking/prayer.nix
index 4e1d66bc110..67d8cece611 100644
--- a/nixos/modules/services/networking/prayer.nix
+++ b/nixos/modules/services/networking/prayer.nix
@@ -56,6 +56,7 @@ in
       };
 
       extraConfig = mkOption {
+        type = types.lines;
         default = "" ;
         description = ''
           Extra configuration. Contents will be added verbatim to the configuration file.
diff --git a/nixos/modules/services/networking/privoxy.nix b/nixos/modules/services/networking/privoxy.nix
index 94beb78ef5a..49ca839a2c3 100644
--- a/nixos/modules/services/networking/privoxy.nix
+++ b/nixos/modules/services/networking/privoxy.nix
@@ -6,8 +6,6 @@ let
 
   inherit (pkgs) privoxy;
 
-  privoxyUser = "privoxy";
-
   cfg = config.services.privoxy;
 
   confFile = pkgs.writeText "privoxy.conf" ''
@@ -88,18 +86,25 @@ in
   ###### implementation
 
   config = mkIf cfg.enable {
-  
-    users.extraUsers = singleton
-      { name = privoxyUser;
-        uid = config.ids.uids.privoxy;
-        description = "Privoxy daemon user";
-      };
+
+    users.users.privoxy = {
+      isSystemUser = true;
+      home = "/var/empty";
+      group = "privoxy";
+    };
+
+    users.groups.privoxy = {};
 
     systemd.services.privoxy = {
       description = "Filtering web proxy";
       after = [ "network.target" "nss-lookup.target" ];
       wantedBy = [ "multi-user.target" ];
-      serviceConfig.ExecStart = "${privoxy}/sbin/privoxy --no-daemon --user ${privoxyUser} ${confFile}";
+      serviceConfig.ExecStart = "${privoxy}/bin/privoxy --no-daemon --user privoxy ${confFile}";
+
+      serviceConfig.PrivateDevices = true;
+      serviceConfig.PrivateTmp = true;
+      serviceConfig.ProtectHome = true;
+      serviceConfig.ProtectSystem = "full";
     };
 
   };
diff --git a/nixos/modules/services/networking/prosody.nix b/nixos/modules/services/networking/prosody.nix
index f82f8bfddbb..5682b506344 100644
--- a/nixos/modules/services/networking/prosody.nix
+++ b/nixos/modules/services/networking/prosody.nix
@@ -164,7 +164,7 @@ in
 
         description = "Define the virtual hosts";
 
-        type = types.loaOf types.optionSet;
+        type = with types; loaOf (submodule vHostOpts);
 
         example = {
           myhost = {
@@ -180,7 +180,6 @@ in
           };
         };
 
-        options = [ vHostOpts ];
       };
 
       ssl = mkOption {
@@ -196,6 +195,7 @@ in
       };
 
       extraConfig = mkOption {
+        type = types.lines;
         default = '''';
         description = "Additional prosody configuration";
       };
diff --git a/nixos/modules/services/networking/quagga.nix b/nixos/modules/services/networking/quagga.nix
new file mode 100644
index 00000000000..ac83da92063
--- /dev/null
+++ b/nixos/modules/services/networking/quagga.nix
@@ -0,0 +1,187 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.quagga;
+
+  services = [ "babel" "bgp" "isis" "ospf6" "ospf" "pim" "rip" "ripng" ];
+  allServices = services ++ [ "zebra" ];
+
+  isEnabled = service: cfg.${service}.enable;
+
+  daemonName = service: if service == "zebra" then service else "${service}d";
+
+  configFile = service:
+    let
+      scfg = cfg.${service};
+    in
+      if scfg.configFile != null then scfg.configFile
+      else pkgs.writeText "${daemonName service}.conf"
+        ''
+          ! Quagga ${daemonName service} configuration
+          !
+          hostname ${config.networking.hostName}
+          log syslog
+          service password-encryption
+          !
+          ${scfg.config}
+          !
+          end
+        '';
+
+  serviceOptions = service:
+    {
+      enable = mkEnableOption "the Quagga ${toUpper service} routing protocol";
+
+      configFile = mkOption {
+        type = types.nullOr types.path;
+        default = null;
+        example = "/etc/quagga/${daemonName service}.conf";
+        description = ''
+          Configuration file to use for Quagga ${daemonName service}.
+          By default the NixOS generated files are used.
+        '';
+      };
+
+      config = mkOption {
+        type = types.lines;
+        default = "";
+        example =
+          let
+            examples = {
+              rip = ''
+                router rip
+                  network 10.0.0.0/8
+              '';
+
+              ospf = ''
+                router ospf
+                  network 10.0.0.0/8 area 0
+              '';
+
+              bgp = ''
+                router bgp 65001
+                  neighbor 10.0.0.1 remote-as 65001
+              '';
+            };
+          in
+            examples.${service} or "";
+        description = ''
+          ${daemonName service} configuration statements.
+        '';
+      };
+
+      vtyListenAddress = mkOption {
+        type = types.str;
+        default = "127.0.0.1";
+        description = ''
+          Address to bind to for the VTY interface.
+        '';
+      };
+
+      vtyListenPort = mkOption {
+        type = types.nullOr types.int;
+        default = null;
+        description = ''
+          TCP Port to bind to for the VTY interface.
+        '';
+      };
+    };
+
+in
+
+{
+
+  ###### interface
+
+  options.services.quagga =
+    {
+
+      zebra = (serviceOptions "zebra") // {
+
+        enable = mkOption {
+          type = types.bool;
+          default = any isEnabled services;
+          example = true;
+          description = ''
+            Whether to enable the Zebra routing manager.
+
+            The Zebra routing manager is automatically enabled
+            if any routing protocols are configured.
+          '';
+        };
+
+      };
+
+    } // (genAttrs services serviceOptions);
+
+  ###### implementation
+
+  config = mkIf (any isEnabled allServices) {
+
+    environment.systemPackages = [
+      pkgs.quagga               # for the vtysh tool
+    ];
+
+    users.users.quagga = {
+      description = "Quagga daemon user";
+      isSystemUser = true;
+      group = "quagga";
+    };
+
+    users.groups = {
+      quagga = {};
+      # Members of the quaggavty group can use vtysh to inspect the Quagga daemons
+      quaggavty = {};
+    };
+
+    systemd.services =
+      let
+        quaggaService = service:
+          let
+            scfg = cfg.${service};
+            daemon = daemonName service;
+          in
+            nameValuePair daemon ({
+              wantedBy = [ "multi-user.target" ];
+              restartTriggers = [ (configFile service) ];
+
+              serviceConfig = {
+                Type = "forking";
+                PIDFile = "/run/quagga/${daemon}.pid";
+                ExecStart = "@${pkgs.quagga}/libexec/quagga/${daemon} ${daemon} -d -f ${configFile service}"
+                  + optionalString (scfg.vtyListenAddress != "") " -A ${scfg.vtyListenAddress}"
+                  + optionalString (scfg.vtyListenPort != null) " -P ${toString scfg.vtyListenPort}";
+                ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+                Restart = "on-abort";
+              };
+            } // (
+              if service == "zebra" then
+                {
+                  description = "Quagga Zebra routing manager";
+                  unitConfig.Documentation = "man:zebra(8)";
+                  after = [ "network.target" ];
+                  preStart = ''
+                    install -m 0755 -o quagga -g quagga -d /run/quagga
+
+                    ${pkgs.iproute}/bin/ip route flush proto zebra
+                  '';
+                }
+              else
+                {
+                  description = "Quagga ${toUpper service} routing daemon";
+                  unitConfig.Documentation = "man:${daemon}(8) man:zebra(8)";
+                  bindsTo = [ "zebra.service" ];
+                  after = [ "network.target" "zebra.service" ];
+                }
+            ));
+       in
+         listToAttrs (map quaggaService (filter isEnabled allServices));
+
+  };
+
+  meta.maintainers = with lib.maintainers; [ tavyc ];
+
+}
diff --git a/nixos/modules/services/networking/quassel.nix b/nixos/modules/services/networking/quassel.nix
index 99269c49e8f..edcc12170b2 100644
--- a/nixos/modules/services/networking/quassel.nix
+++ b/nixos/modules/services/networking/quassel.nix
@@ -3,8 +3,8 @@
 with lib;
 
 let
-  quassel = pkgs.kde4.quasselDaemon;
   cfg = config.services.quassel;
+  quassel = cfg.package;
   user = if cfg.user != null then cfg.user else "quassel";
 in
 
@@ -23,6 +23,16 @@ in
         '';
       };
 
+      package = mkOption {
+        type = types.package;
+        default = pkgs.kde4.quasselDaemon;
+        defaultText = "pkgs.kde4.quasselDaemon";
+        description = ''
+          The package of the quassel daemon.
+        '';
+        example = literalExample "pkgs.quasselDaemon";
+      };
+
       interfaces = mkOption {
         default = [ "127.0.0.1" ];
         description = ''
diff --git a/nixos/modules/services/networking/radicale.nix b/nixos/modules/services/networking/radicale.nix
index 19762f4e570..f9300fdabc5 100644
--- a/nixos/modules/services/networking/radicale.nix
+++ b/nixos/modules/services/networking/radicale.nix
@@ -33,7 +33,7 @@ in
   };
 
   config = mkIf cfg.enable {
-    environment.systemPackages = [ pkgs.pythonPackages.radicale ];
+    environment.systemPackages = [ pkgs.radicale ];
 
     users.extraUsers = singleton
       { name = "radicale";
@@ -50,10 +50,9 @@ in
 
     systemd.services.radicale = {
       description = "A Simple Calendar and Contact Server";
-      after = [ "network-interfaces.target" ];
+      after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
-      script = "${pkgs.pythonPackages.radicale}/bin/radicale -C ${confFile} -d";
-      serviceConfig.Type = "forking";
+      script = "${pkgs.radicale}/bin/radicale -C ${confFile} -f";
       serviceConfig.User = "radicale";
       serviceConfig.Group = "radicale";
     };
diff --git a/nixos/modules/services/networking/skydns.nix b/nixos/modules/services/networking/skydns.nix
index ba913482e3c..6ad18bb2240 100644
--- a/nixos/modules/services/networking/skydns.nix
+++ b/nixos/modules/services/networking/skydns.nix
@@ -11,7 +11,7 @@ in {
 
     etcd = {
       machines = mkOption {
-        default = [ "http://localhost:4001" ];
+        default = [ "http://127.0.0.1:2379" ];
         type = types.listOf types.str;
         description = "Skydns list of etcd endpoints to connect to.";
       };
diff --git a/nixos/modules/services/networking/smokeping.nix b/nixos/modules/services/networking/smokeping.nix
index f7a5926dc64..04312c39062 100644
--- a/nixos/modules/services/networking/smokeping.nix
+++ b/nixos/modules/services/networking/smokeping.nix
@@ -6,31 +6,39 @@ let
   cfg = config.services.smokeping;
   smokepingHome = "/var/lib/smokeping";
   smokepingPidDir = "/run";
-  configFile = ''
-    *** General ***
-    owner = ${cfg.owner}
-    contact = ${cfg.ownerEmail}
-    mailhost = ${cfg.mailHost}
-    #sendmail = /var/setuid-wrappers/sendmail
-    imgcache = ${smokepingHome}/cache
-    imgurl   = http://${cfg.hostName}:${builtins.toString cfg.port}/cache
-    datadir  = ${smokepingHome}/data
-    piddir  = ${smokepingPidDir}
-    cgiurl   = http://${cfg.hostName}:${builtins.toString cfg.port}/smokeping.cgi
-    smokemail = ${cfg.smokeMailTemplate}
-    *** Presentation ***
-    template = ${cfg.presentationTemplate}
-    ${cfg.presentationConfig}
-    #*** Alerts ***
-    #${cfg.alertConfig}
-    *** Database ***
-    ${cfg.databaseConfig}
-    *** Probes ***
-    ${cfg.probeConfig}
-    *** Targets ***
-    ${cfg.targetConfig}
-    ${cfg.extraConfig}
-  '';
+  configFile =
+    if cfg.config == null
+      then
+        ''
+          *** General ***
+          cgiurl   = ${cfg.cgiUrl}
+          contact = ${cfg.ownerEmail}
+          datadir  = ${smokepingHome}/data
+          imgcache = ${smokepingHome}/cache
+          imgurl   = ${cfg.imgUrl}
+          linkstyle = ${cfg.linkStyle}
+          ${lib.optionalString (cfg.mailHost != "") "mailhost = ${cfg.mailHost}"}
+          owner = ${cfg.owner}
+          pagedir = ${smokepingHome}/cache
+          piddir  = ${smokepingPidDir}
+          ${lib.optionalString (cfg.sendmail != null) "sendmail = ${cfg.sendmail}"}
+          smokemail = ${cfg.smokeMailTemplate}
+          *** Presentation ***
+          template = ${cfg.presentationTemplate}
+          ${cfg.presentationConfig}
+          *** Alerts ***
+          ${cfg.alertConfig}
+          *** Database ***
+          ${cfg.databaseConfig}
+          *** Probes ***
+          ${cfg.probeConfig}
+          *** Targets ***
+          ${cfg.targetConfig}
+          ${cfg.extraConfig}
+        ''
+      else
+        cfg.config;
+
   configPath = pkgs.writeText "smokeping.conf" configFile;
   cgiHome = pkgs.writeScript "smokeping.fcgi" ''
     #!${pkgs.bash}/bin/bash
@@ -46,58 +54,36 @@ in
         default = false;
         description = "Enable the smokeping service";
       };
-      webService = mkOption {
-        type = types.bool;
-        default = true;
-        description = "Enable a smokeping web interface";
-      };
-
-      user = mkOption {
-        type = types.string;
-        default = "smokeping";
-        description = "User that runs smokeping and (optionally) thttpd";
-      };
-      mailHost = mkOption {
-        type = types.string;
-        default = "127.0.0.1";
-        description = "Use this SMTP server rather than localhost";
-      };
-      smokeMailTemplate = mkOption {
+      alertConfig = mkOption {
         type = types.string;
-        default = "${cfg.package}/etc/smokemail.dist";
-        description = "Specify the smokemail template for alerts.";
-      };
+        default = ''
+          to = root@localhost
+          from = smokeping@localhost
+        '';
+        example = literalExample ''
+          to = alertee@address.somewhere
+          from = smokealert@company.xy
 
-      package = mkOption {
-        type = types.package;
-        default = pkgs.smokeping;
-        description = "Specify a custom smokeping package";
-      };
-      owner = mkOption {
-        type = types.string;
-        default = "nobody";
-        example = "Joe Admin";
-        description = "Real name of the owner of the instance";
+          +someloss
+          type = loss
+          # in percent
+          pattern = >0%,*12*,>0%,*12*,>0%
+          comment = loss 3 times  in a row;
+        '';
+        description = "Configuration for alerts.";
       };
-      hostName = mkOption {
+      cgiUrl = mkOption {
         type = types.string;
-        default = config.networking.hostName;
-        example = "somewhere.example.com";
-        description = "DNS name for the urls generated in the cgi.";
-      };
-      port = mkOption {
-        type = types.int;
-        default = 8081;
-        example = 8081;
-        description = "TCP port to use for the web server.";
+        default = "http://${cfg.hostName}:${builtins.toString cfg.port}/smokeping.cgi";
+        example = "https://somewhere.example.com/smokeping.cgi";
+        description = "URL to the smokeping cgi.";
       };
-      ownerEmail = mkOption {
-        type = types.string;
-        default = "no-reply@${cfg.hostName}";
-        example = "no-reply@yourdomain.com";
-        description = "Email contact for owner";
+      config = mkOption {
+        type = types.nullOr types.string;
+        default = null;
+        description = "Full smokeping config supplied by the user. Overrides " +
+          "and replaces any other configuration supplied.";
       };
-
       databaseConfig = mkOption {
         type = types.string;
         default = ''
@@ -130,27 +116,59 @@ in
           Once set, changing the interval will require deletion or migration of all
           the collected data.'';
       };
-      alertConfig = mkOption {
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = "Any additional customization not already included.";
+      };
+      hostName = mkOption {
+        type = types.string;
+        default = config.networking.hostName;
+        example = "somewhere.example.com";
+        description = "DNS name for the urls generated in the cgi.";
+      };
+      imgUrl = mkOption {
+        type = types.string;
+        default = "http://${cfg.hostName}:${builtins.toString cfg.port}/cache";
+        example = "https://somewhere.example.com/cache";
+        description = "Base url for images generated in the cgi.";
+      };
+      linkStyle = mkOption {
+        type = types.enum ["original" "absolute" "relative"];
+        default = "relative";
+        example = "absolute";
+        description = "DNS name for the urls generated in the cgi.";
+      };
+      mailHost = mkOption {
         type = types.string;
         default = "";
-        example = literalExample ''
-          to = alertee@address.somewhere
-          from = smokealert@company.xy
-
-          +someloss
-          type = loss
-          # in percent
-          pattern = >0%,*12*,>0%,*12*,>0%
-          comment = loss 3 times  in a row;
-        '';
-        description = "Configuration for alerts.";
+        example = "localhost";
+        description = "Use this SMTP server to send alerts";
       };
-      presentationTemplate = mkOption {
+      owner = mkOption {
         type = types.string;
-        default = "${pkgs.smokeping}/etc/basepage.html.dist";
-        description = "Default page layout for the web UI.";
+        default = "nobody";
+        example = "Joe Admin";
+        description = "Real name of the owner of the instance";
+      };
+      ownerEmail = mkOption {
+        type = types.string;
+        default = "no-reply@${cfg.hostName}";
+        example = "no-reply@yourdomain.com";
+        description = "Email contact for owner";
+      };
+      package = mkOption {
+        type = types.package;
+        default = pkgs.smokeping;
+        defaultText = "pkgs.smokeping";
+        description = "Specify a custom smokeping package";
+      };
+      port = mkOption {
+        type = types.int;
+        default = 8081;
+        example = 8081;
+        description = "TCP port to use for the web server.";
       };
-
       presentationConfig = mkOption {
         type = types.string;
         default = ''
@@ -192,14 +210,30 @@ in
         '';
         description = "presentation graph style";
       };
+      presentationTemplate = mkOption {
+        type = types.string;
+        default = "${pkgs.smokeping}/etc/basepage.html.dist";
+        description = "Default page layout for the web UI.";
+      };
       probeConfig = mkOption {
         type = types.string;
         default = ''
           + FPing
-          binary = ${pkgs.fping}/bin/fping
+          binary = ${config.security.wrapperDir}/fping
         '';
         description = "Probe configuration";
       };
+      sendmail = mkOption {
+        type = types.nullOr types.path;
+        default = null;
+        example = "/var/setuid-wrappers/sendmail";
+        description = "Use this sendmail compatible script to deliver alerts";
+      };
+      smokeMailTemplate = mkOption {
+        type = types.string;
+        default = "${cfg.package}/etc/smokemail.dist";
+        description = "Specify the smokemail template for alerts.";
+      };
       targetConfig = mkOption {
         type = types.string;
         default = ''
@@ -218,17 +252,29 @@ in
         '';
         description = "Target configuration";
       };
-      extraConfig = mkOption {
+      user = mkOption {
         type = types.string;
-        default = "";
-        description = "Any additional customization not already included.";
+        default = "smokeping";
+        description = "User that runs smokeping and (optionally) thttpd";
+      };
+      webService = mkOption {
+        type = types.bool;
+        default = true;
+        description = "Enable a smokeping web interface";
       };
-
     };
 
   };
 
   config = mkIf cfg.enable {
+    assertions = [
+      {
+        assertion = !(cfg.sendmail != null && cfg.mailHost != "");
+        message = "services.smokeping: sendmail and Mailhost cannot both be enabled.";
+      }
+    ];
+    security.setuidPrograms = [ "fping" ];
+    environment.systemPackages = [ pkgs.fping ];
     users.extraUsers = singleton {
       name = cfg.user;
       isNormalUser = false;
@@ -243,9 +289,12 @@ in
       serviceConfig.PermissionsStartOnly = true;
       preStart = ''
         mkdir -m 0755 -p ${smokepingHome}/cache ${smokepingHome}/data
-        chown -R ${cfg.user} ${smokepingHome}
+        rm -f ${smokepingHome}/cropper
+        ln -s ${cfg.package}/htdocs/cropper ${smokepingHome}/cropper
         cp ${cgiHome} ${smokepingHome}/smokeping.fcgi
         ${cfg.package}/bin/smokeping --check --config=${configPath}
+        ${cfg.package}/bin/smokeping --static --config=${configPath}
+        chown -R ${cfg.user} ${smokepingHome}
       '';
       script = ''${cfg.package}/bin/smokeping --config=${configPath} --nodaemon'';
     };
@@ -253,8 +302,9 @@ in
       wantedBy = [ "multi-user.target"];
       requires = [ "smokeping.service"];
       partOf = [ "smokeping.service"];
-      path = with pkgs; [ bash rrdtool smokeping ];
-      script = ''${pkgs.thttpd}/bin/thttpd -u ${cfg.user} -c "**.fcgi" -d ${smokepingHome} -p ${builtins.toString cfg.port} -D'';
+      path = with pkgs; [ bash rrdtool smokeping thttpd ];
+      script = ''thttpd -u ${cfg.user} -c "**.fcgi" -d ${smokepingHome} -p ${builtins.toString cfg.port} -D -nos'';
+      serviceConfig.Restart = "always";
     };
   };
 }
diff --git a/nixos/modules/services/networking/softether.nix b/nixos/modules/services/networking/softether.nix
index 5e49efc3aa3..16530078b97 100644
--- a/nixos/modules/services/networking/softether.nix
+++ b/nixos/modules/services/networking/softether.nix
@@ -63,7 +63,6 @@ in
         ];
       systemd.services."softether-init" = {
         description = "SoftEther VPN services initial task";
-        wantedBy = [ "network-interfaces.target" ];
         serviceConfig = {
           Type = "oneshot";
           RemainAfterExit = false;
@@ -84,8 +83,9 @@ in
     (mkIf (cfg.vpnserver.enable) {
       systemd.services.vpnserver = {
         description = "SoftEther VPN Server";
-        after = [ "softether-init.service" ];
-        wantedBy = [ "network-interfaces.target" ];
+        after = [ "softether-init.service" "network.target" ];
+        wants = [ "softether-init.service" ];
+        wantedBy = [ "multi-user.target" ];
         serviceConfig = {
           Type = "forking";
           ExecStart = "${pkg}/bin/vpnserver start";
@@ -104,8 +104,9 @@ in
     (mkIf (cfg.vpnbridge.enable) {
       systemd.services.vpnbridge = {
         description = "SoftEther VPN Bridge";
-        after = [ "softether-init.service" ];
-        wantedBy = [ "network-interfaces.target" ];
+        after = [ "softether-init.service" "network.target" ];
+        wants = [ "softether-init.service" ];
+        wantedBy = [ "multi-user.target" ];
         serviceConfig = {
           Type = "forking";
           ExecStart = "${pkg}/bin/vpnbridge start";
@@ -124,8 +125,9 @@ in
     (mkIf (cfg.vpnclient.enable) {
       systemd.services.vpnclient = {
         description = "SoftEther VPN Client";
-        after = [ "softether-init.service" ];
-        wantedBy = [ "network-interfaces.target" ];
+        after = [ "softether-init.service" "network.target" ];
+        wants = [ "softether-init.service" ];
+        wantedBy = [ "multi-user.target" ];
         serviceConfig = {
           Type = "forking";
           ExecStart = "${pkg}/bin/vpnclient start";
diff --git a/nixos/modules/services/networking/ssh/lshd.nix b/nixos/modules/services/networking/ssh/lshd.nix
index 661a6a52463..eca599afb33 100644
--- a/nixos/modules/services/networking/ssh/lshd.nix
+++ b/nixos/modules/services/networking/ssh/lshd.nix
@@ -120,7 +120,7 @@ in
     systemd.services.lshd = {
       description = "GNU lshd SSH2 daemon";
 
-      after = [ "network-interfaces.target" ];
+      after = [ "network.target" ];
 
       wantedBy = [ "multi-user.target" ];
 
diff --git a/nixos/modules/services/networking/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix
index f900ef494ab..80659f19c59 100644
--- a/nixos/modules/services/networking/ssh/sshd.nix
+++ b/nixos/modules/services/networking/ssh/sshd.nix
@@ -85,7 +85,7 @@ in
 
       forwardX11 = mkOption {
         type = types.bool;
-        default = cfgc.setXAuthLocation;
+        default = false;
         description = ''
           Whether to allow X11 connections to be forwarded.
         '';
@@ -102,8 +102,8 @@ in
       };
 
       permitRootLogin = mkOption {
-        default = "without-password";
-        type = types.enum ["yes" "without-password" "forced-commands-only" "no"];
+        default = "prohibit-password";
+        type = types.enum ["yes" "without-password" "prohibit-password" "forced-commands-only" "no"];
         description = ''
           Whether the root user can login using ssh.
         '';
@@ -129,7 +129,24 @@ in
       };
 
       listenAddresses = mkOption {
-        type = types.listOf types.optionSet;
+        type = with types; listOf (submodule {
+          options = {
+            addr = mkOption {
+              type = types.nullOr types.str;
+              default = null;
+              description = ''
+                Host, IPv4 or IPv6 address to listen to.
+              '';
+            };
+            port = mkOption {
+              type = types.nullOr types.int;
+              default = null;
+              description = ''
+                Port to listen to.
+              '';
+            };
+          };
+        });
         default = [];
         example = [ { addr = "192.168.3.1"; port = 22; } { addr = "0.0.0.0"; port = 64022; } ];
         description = ''
@@ -140,22 +157,6 @@ in
           NOTE: setting this option won't automatically enable given ports
           in firewall configuration.
         '';
-        options = {
-          addr = mkOption {
-            type = types.nullOr types.str;
-            default = null;
-            description = ''
-              Host, IPv4 or IPv6 address to listen to.
-            '';
-          };
-          port = mkOption {
-            type = types.nullOr types.int;
-            default = null;
-            description = ''
-              Port to listen to.
-            '';
-          };
-        };
       };
 
       passwordAuthentication = mkOption {
@@ -239,7 +240,7 @@ in
 
     systemd =
       let
-        service =
+        sshd-service =
           { description = "SSH Daemon";
 
             wantedBy = optional (!cfg.startWhenNeeded) "multi-user.target";
@@ -250,16 +251,8 @@ in
 
             environment.LD_LIBRARY_PATH = nssModulesPath;
 
-            preStart =
-              ''
-                mkdir -m 0755 -p /etc/ssh
-
-                ${flip concatMapStrings cfg.hostKeys (k: ''
-                  if ! [ -f "${k.path}" ]; then
-                      ssh-keygen -t "${k.type}" ${if k ? bits then "-b ${toString k.bits}" else ""} -f "${k.path}" -N ""
-                  fi
-                '')}
-              '';
+            wants = [ "sshd-keygen.service" ];
+            after = [ "sshd-keygen.service" ];
 
             serviceConfig =
               { ExecStart =
@@ -271,10 +264,29 @@ in
                 StandardInput = "socket";
               } else {
                 Restart = "always";
-                Type = "forking";
-                PIDFile = "/run/sshd.pid";
+                Type = "simple";
               });
           };
+
+        sshd-keygen-service =
+          { description = "SSH Host Key Generation";
+            path = [ cfgc.package ];
+            script =
+            ''
+              mkdir -m 0755 -p /etc/ssh
+              ${flip concatMapStrings cfg.hostKeys (k: ''
+                if ! [ -f "${k.path}" ]; then
+                  ssh-keygen -t "${k.type}" ${if k ? bits then "-b ${toString k.bits}" else ""} -f "${k.path}" -N ""
+                fi
+              '')}
+            '';
+
+            serviceConfig = {
+              Type = "oneshot";
+              RemainAfterExit = "yes";
+            };
+          };
+
       in
 
       if cfg.startWhenNeeded then {
@@ -286,11 +298,13 @@ in
             socketConfig.Accept = true;
           };
 
-        services."sshd@" = service;
+        services.sshd-keygen = sshd-keygen-service;
+        services."sshd@" = sshd-service;
 
       } else {
 
-        services.sshd = service;
+        services.sshd-keygen = sshd-keygen-service;
+        services.sshd = sshd-service;
 
       };
 
@@ -307,8 +321,6 @@ in
 
     services.openssh.extraConfig = mkOrder 0
       ''
-        PidFile /run/sshd.pid
-
         Protocol 2
 
         UsePAM yes
diff --git a/nixos/modules/services/networking/supplicant.nix b/nixos/modules/services/networking/supplicant.nix
index 16c4ee7e33b..0c459fb1dd0 100644
--- a/nixos/modules/services/networking/supplicant.nix
+++ b/nixos/modules/services/networking/supplicant.nix
@@ -34,7 +34,8 @@ let
       '';
     in
       { description = "Supplicant ${iface}${optionalString (iface=="WLAN"||iface=="LAN") " %I"}";
-        wantedBy = [ "network.target" ];
+        wantedBy = [ "multi-user.target" ] ++ deps;
+        wants = [ "network.target" ];
         bindsTo = deps;
         after = deps;
         before = [ "network.target" ];
@@ -75,7 +76,107 @@ in
   options = {
 
     networking.supplicant = mkOption {
-      type = types.attrsOf types.optionSet;
+      type = with types; attrsOf (submodule {
+        options = {
+  
+          configFile = {
+  
+            path = mkOption {
+              type = types.path;
+              example = literalExample "/etc/wpa_supplicant.conf";
+              description = ''
+                External <literal>wpa_supplicant.conf</literal> configuration file.
+                The configuration options defined declaratively within <literal>networking.supplicant</literal> have
+                precedence over options defined in <literal>configFile</literal>.
+              '';
+            };
+  
+            writable = mkOption {
+              type = types.bool;
+              default = false;
+              description = ''
+                Whether the configuration file at <literal>configFile.path</literal> should be written to by
+                <literal>wpa_supplicant</literal>.
+              '';
+            };
+  
+          };
+  
+          extraConf = mkOption {
+            type = types.lines;
+            default = "";
+            example = ''
+              ap_scan=1
+              device_name=My-NixOS-Device
+              device_type=1-0050F204-1
+              driver_param=use_p2p_group_interface=1
+              disable_scan_offload=1
+              p2p_listen_reg_class=81
+              p2p_listen_channel=1
+              p2p_oper_reg_class=81
+              p2p_oper_channel=1
+              manufacturer=NixOS
+              model_name=NixOS_Unstable
+              model_number=2015
+            '';
+            description = ''
+              Configuration options for <literal>wpa_supplicant.conf</literal>.
+              Options defined here have precedence over options in <literal>configFile</literal>.
+              NOTE: Do not write sensitive data into <literal>extraConf</literal> as it will
+              be world-readable in the <literal>nix-store</literal>. For sensitive information
+              use the <literal>configFile</literal> instead.
+            '';
+          };
+  
+          extraCmdArgs = mkOption {
+            type = types.str;
+            default = "";
+            example = "-e/var/run/wpa_supplicant/entropy.bin";
+            description =
+              "Command line arguments to add when executing <literal>wpa_supplicant</literal>.";
+          };
+  
+          driver = mkOption {
+            type = types.nullOr types.str;
+            default = "nl80211,wext";
+            description = "Force a specific wpa_supplicant driver.";
+          };
+  
+          bridge = mkOption {
+            type = types.str;
+            default = "";
+            description = "Name of the bridge interface that wpa_supplicant should listen at.";
+          };
+  
+          userControlled = {
+  
+            enable = mkOption {
+              type = types.bool;
+              default = false;
+              description = ''
+                Allow normal users to control wpa_supplicant through wpa_gui or wpa_cli.
+                This is useful for laptop users that switch networks a lot and don't want
+                to depend on a large package such as NetworkManager just to pick nearby
+                access points.
+              '';
+            };
+  
+            socketDir = mkOption {
+              type = types.str;
+              default = "/var/run/wpa_supplicant";
+              description = "Directory of sockets for controlling wpa_supplicant.";
+            };
+  
+            group = mkOption {
+              type = types.str;
+              default = "wheel";
+              example = "network";
+              description = "Members of this group can control wpa_supplicant.";
+            };
+  
+          };
+        };
+      });
 
       default = { };
 
@@ -109,107 +210,6 @@ in
         service that can be accessed through <literal>D-Bus</literal>.
       '';
 
-      options = {
-
-        configFile = {
-
-          path = mkOption {
-            type = types.path;
-            example = literalExample "/etc/wpa_supplicant.conf";
-            description = ''
-              External <literal>wpa_supplicant.conf</literal> configuration file.
-              The configuration options defined declaratively within <literal>networking.supplicant</literal> have
-              precedence over options defined in <literal>configFile</literal>.
-            '';
-          };
-
-          writable = mkOption {
-            type = types.bool;
-            default = false;
-            description = ''
-              Whether the configuration file at <literal>configFile.path</literal> should be written to by
-              <literal>wpa_supplicant</literal>.
-            '';
-          };
-
-        };
-
-        extraConf = mkOption {
-          type = types.lines;
-          default = "";
-          example = ''
-            ap_scan=1
-            device_name=My-NixOS-Device
-            device_type=1-0050F204-1
-            driver_param=use_p2p_group_interface=1
-            disable_scan_offload=1
-            p2p_listen_reg_class=81
-            p2p_listen_channel=1
-            p2p_oper_reg_class=81
-            p2p_oper_channel=1
-            manufacturer=NixOS
-            model_name=NixOS_Unstable
-            model_number=2015
-          '';
-          description = ''
-            Configuration options for <literal>wpa_supplicant.conf</literal>.
-            Options defined here have precedence over options in <literal>configFile</literal>.
-            NOTE: Do not write sensitive data into <literal>extraConf</literal> as it will
-            be world-readable in the <literal>nix-store</literal>. For sensitive information
-            use the <literal>configFile</literal> instead.
-          '';
-        };
-
-        extraCmdArgs = mkOption {
-          type = types.str;
-          default = "";
-          example = "-e/var/run/wpa_supplicant/entropy.bin";
-          description =
-            "Command line arguments to add when executing <literal>wpa_supplicant</literal>.";
-        };
-
-        driver = mkOption {
-          type = types.nullOr types.str;
-          default = "nl80211,wext";
-          description = "Force a specific wpa_supplicant driver.";
-        };
-
-        bridge = mkOption {
-          type = types.str;
-          default = "";
-          description = "Name of the bridge interface that wpa_supplicant should listen at.";
-        };
-
-        userControlled = {
-
-          enable = mkOption {
-            type = types.bool;
-            default = false;
-            description = ''
-              Allow normal users to control wpa_supplicant through wpa_gui or wpa_cli.
-              This is useful for laptop users that switch networks a lot and don't want
-              to depend on a large package such as NetworkManager just to pick nearby
-              access points.
-            '';
-          };
-
-          socketDir = mkOption {
-            type = types.str;
-            default = "/var/run/wpa_supplicant";
-            description = "Directory of sockets for controlling wpa_supplicant.";
-          };
-
-          group = mkOption {
-            type = types.str;
-            default = "wheel";
-            example = "network";
-            description = "Members of this group can control wpa_supplicant.";
-          };
-
-        };
-
-      };
-
     };
 
   };
diff --git a/nixos/modules/services/networking/syncthing.nix b/nixos/modules/services/networking/syncthing.nix
index 8a430734319..dcdc203bdc6 100644
--- a/nixos/modules/services/networking/syncthing.nix
+++ b/nixos/modules/services/networking/syncthing.nix
@@ -3,46 +3,11 @@
 with lib;
 
 let
-
   cfg = config.services.syncthing;
   defaultUser = "syncthing";
-
-  header = {
-    description = "Syncthing service";
-    after = [ "network.target" ];
-    environment = {
-      STNORESTART = "yes";
-      STNOUPGRADE = "yes";
-      inherit (cfg) all_proxy;
-    } // config.networking.proxy.envVars;
-  };
-
-  service = {
-    Restart = "on-failure";
-    SuccessExitStatus = "2 3 4";
-    RestartForceExitStatus="3 4";
-  };
-
-  iNotifyHeader = {
-    description = "Syncthing Inotify File Watcher service";
-    after = [ "network.target" "syncthing.service" ];
-    requires = [ "syncthing.service" ];
-  };
-
-  iNotifyService = {
-    SuccessExitStatus = "2";
-    RestartForceExitStatus = "3";
-    Restart = "on-failure";
-  };
-
-in
-
-{
-
+in {
   ###### interface
-
   options = {
-
     services.syncthing = {
 
       enable = mkEnableOption ''
@@ -100,6 +65,19 @@ in
         '';
       };
 
+      openDefaultPorts = mkOption {
+        type = types.bool;
+        default = false;
+        example = literalExample "true";
+        description = ''
+          Open the default ports in the firewall:
+            - TCP 22000 for transfers
+            - UDP 21027 for discovery
+          If multiple users are running syncthing on this machine, you will need to manually open a set of ports for each instance and leave this disabled.
+          Alternatively, if are running only a single instance on this machine using the default ports, enable this.
+        '';
+      };
+
       package = mkOption {
         type = types.package;
         default = pkgs.syncthing;
@@ -117,6 +95,14 @@ in
 
   config = mkIf cfg.enable {
 
+    networking.firewall = mkIf cfg.openDefaultPorts {
+      allowedTCPPorts = [ 22000 ];
+      allowedUDPPorts = [ 21027 ];
+    };
+
+    systemd.packages = [ pkgs.syncthing ]
+                       ++ lib.optional cfg.useInotify pkgs.syncthing-inotify;
+
     users = mkIf (cfg.user == defaultUser) {
       extraUsers."${defaultUser}" =
         { group = cfg.group;
@@ -131,39 +117,44 @@ in
     };
 
     systemd.services = {
-      syncthing = mkIf cfg.systemService (header // {
-          wants = mkIf cfg.useInotify [ "syncthing-inotify.service" ];
-          wantedBy = [ "multi-user.target" ];
-          serviceConfig = service // {
-            User = cfg.user;
-            Group = cfg.group;
-            PermissionsStartOnly = true;
-            ExecStart = "${cfg.package}/bin/syncthing -no-browser -home=${cfg.dataDir}";
-          };
-      });
-
-      syncthing-inotify = mkIf (cfg.systemService && cfg.useInotify) (iNotifyHeader // {
+      syncthing = mkIf cfg.systemService {
+        description = "Syncthing service";
+        after = [ "network.target" ];
+        environment = {
+          STNORESTART = "yes";
+          STNOUPGRADE = "yes";
+          inherit (cfg) all_proxy;
+        } // config.networking.proxy.envVars;
+        wants = mkIf cfg.useInotify [ "syncthing-inotify.service" ];
         wantedBy = [ "multi-user.target" ];
-        serviceConfig = iNotifyService // {
+        serviceConfig = {
+          Restart = "on-failure";
+          SuccessExitStatus = "2 3 4";
+          RestartForceExitStatus="3 4";
           User = cfg.user;
-          ExecStart = "${pkgs.syncthing-inotify.bin}/bin/syncthing-inotify -home=${cfg.dataDir} -logflags=0";
+          Group = cfg.group;
+          PermissionsStartOnly = true;
+          ExecStart = "${cfg.package}/bin/syncthing -no-browser -home=${cfg.dataDir}";
         };
-      });
-    };
+      };
 
-    systemd.user.services = {
-      syncthing = header // {
-        serviceConfig = service // {
-          ExecStart = "${cfg.package}/bin/syncthing -no-browser";
-        };
+      syncthing-resume = {
+        wantedBy = [ "suspend.target" ];
       };
 
-      syncthing-inotify = mkIf cfg.useInotify (iNotifyHeader // {
-        serviceConfig = iNotifyService // {
-          ExecStart = "${pkgs.syncthing-inotify.bin}/bin/syncthing-inotify -logflags=0";
+      syncthing-inotify = mkIf (cfg.systemService && cfg.useInotify) {
+        description = "Syncthing Inotify File Watcher service";
+        after = [ "network.target" "syncthing.service" ];
+        requires = [ "syncthing.service" ];
+        wantedBy = [ "multi-user.target" ];
+        serviceConfig = {
+          SuccessExitStatus = "2";
+          RestartForceExitStatus = "3";
+          Restart = "on-failure";
+          User = cfg.user;
+          ExecStart = "${pkgs.syncthing-inotify.bin}/bin/syncthing-inotify -home=${cfg.dataDir} -logflags=0";
         };
-      });
+      };
     };
-
   };
 }
diff --git a/nixos/modules/services/networking/tcpcrypt.nix b/nixos/modules/services/networking/tcpcrypt.nix
index 267653abce0..2f304165eb4 100644
--- a/nixos/modules/services/networking/tcpcrypt.nix
+++ b/nixos/modules/services/networking/tcpcrypt.nix
@@ -39,7 +39,7 @@ in
       description = "tcpcrypt";
 
       wantedBy = [ "multi-user.target" ];
-      after = [ "network-interfaces.target" ];
+      after = [ "network.target" ];
 
       path = [ pkgs.iptables pkgs.tcpcrypt pkgs.procps ];
 
diff --git a/nixos/modules/services/networking/tftpd.nix b/nixos/modules/services/networking/tftpd.nix
index 9b3cc6b8ec4..c9c0a2b321d 100644
--- a/nixos/modules/services/networking/tftpd.nix
+++ b/nixos/modules/services/networking/tftpd.nix
@@ -13,12 +13,13 @@ with lib;
       default = false;
       description = ''
         Whether to enable tftpd, a Trivial File Transfer Protocol server.
+        The server will be run as an xinetd service.
       '';
     };
 
     services.tftpd.path = mkOption {
       type = types.path;
-      default = "/home/tftp";
+      default = "/srv/tftp";
       description = ''
         Where the tftp server files are stored.
       '';
diff --git a/nixos/modules/services/networking/tinc.nix b/nixos/modules/services/networking/tinc.nix
index 8da0f817ae2..f8e68fda7fc 100644
--- a/nixos/modules/services/networking/tinc.nix
+++ b/nixos/modules/services/networking/tinc.nix
@@ -18,94 +18,96 @@ in
 
       networks = mkOption {
         default = { };
-        type = types.loaOf types.optionSet;
+        type = with types; loaOf (submodule {
+          options = {
+
+            extraConfig = mkOption {
+              default = "";
+              type = types.lines;
+              description = ''
+                Extra lines to add to the tinc service configuration file.
+              '';
+            };
+
+            name = mkOption {
+              default = null;
+              type = types.nullOr types.str;
+              description = ''
+                The name of the node which is used as an identifier when communicating
+                with the remote nodes in the mesh. If null then the hostname of the system
+                is used.
+              '';
+            };
+
+            ed25519PrivateKeyFile = mkOption {
+              default = null;
+              type = types.nullOr types.path;
+              description = ''
+                Path of the private ed25519 keyfile.
+              '';
+            };
+
+            debugLevel = mkOption {
+              default = 0;
+              type = types.addCheck types.int (l: l >= 0 && l <= 5);
+              description = ''
+                The amount of debugging information to add to the log. 0 means little
+                logging while 5 is the most logging. <command>man tincd</command> for
+                more details.
+              '';
+            };
+
+            hosts = mkOption {
+              default = { };
+              type = types.loaOf types.lines;
+              description = ''
+                The name of the host in the network as well as the configuration for that host.
+                This name should only contain alphanumerics and underscores.
+              '';
+            };
+
+            interfaceType = mkOption {
+              default = "tun";
+              type = types.enum [ "tun" "tap" ];
+              description = ''
+                The type of virtual interface used for the network connection
+              '';
+            };
+
+            listenAddress = mkOption {
+              default = null;
+              type = types.nullOr types.str;
+              description = ''
+                The ip adress to bind to.
+              '';
+            };
+
+            package = mkOption {
+              type = types.package;
+              default = pkgs.tinc_pre;
+              defaultText = "pkgs.tinc_pre";
+              description = ''
+                The package to use for the tinc daemon's binary.
+              '';
+            };
+
+            chroot = mkOption {
+              default = true;
+              type = types.bool;
+              description = ''
+                Change process root directory to the directory where the config file is located (/etc/tinc/netname/), for added security.
+                The chroot is performed after all the initialization is done, after writing pid files and opening network sockets.
+
+                Note that tinc can't run scripts anymore (such as tinc-down or host-up), unless it is setup to be runnable inside chroot environment.
+              '';
+            };
+          };
+        });
+
         description = ''
           Defines the tinc networks which will be started.
           Each network invokes a different daemon.
         '';
-        options = {
-
-          extraConfig = mkOption {
-            default = "";
-            type = types.lines;
-            description = ''
-              Extra lines to add to the tinc service configuration file.
-            '';
-          };
-
-          name = mkOption {
-            default = null;
-            type = types.nullOr types.str;
-            description = ''
-              The name of the node which is used as an identifier when communicating
-              with the remote nodes in the mesh. If null then the hostname of the system
-              is used.
-            '';
-          };
-
-          ed25519PrivateKeyFile = mkOption {
-            default = null;
-            type = types.nullOr types.path;
-            description = ''
-              Path of the private ed25519 keyfile.
-            '';
-          };
-
-          debugLevel = mkOption {
-            default = 0;
-            type = types.addCheck types.int (l: l >= 0 && l <= 5);
-            description = ''
-              The amount of debugging information to add to the log. 0 means little
-              logging while 5 is the most logging. <command>man tincd</command> for
-              more details.
-            '';
-          };
-
-          hosts = mkOption {
-            default = { };
-            type = types.loaOf types.lines;
-            description = ''
-              The name of the host in the network as well as the configuration for that host.
-              This name should only contain alphanumerics and underscores.
-            '';
-          };
-
-          interfaceType = mkOption {
-            default = "tun";
-            type = types.addCheck types.str (n: n == "tun" || n == "tap");
-            description = ''
-              The type of virtual interface used for the network connection
-            '';
-          };
-
-          listenAddress = mkOption {
-            default = null;
-            type = types.nullOr types.str;
-            description = ''
-              The ip adress to bind to.
-            '';
-          };
-
-          package = mkOption {
-            type = types.package;
-            default = pkgs.tinc_pre;
-            defaultText = "pkgs.tinc_pre";
-            description = ''
-              The package to use for the tinc daemon's binary.
-            '';
-          };
-
-          chroot = mkOption {
-            default = true;
-            type = types.bool;
-            description = ''
-              Change process root directory to the directory where the config file is located (/etc/tinc/netname/), for added security.
-              The chroot is performed after all the initialization is done, after writing pid files and opening network sockets.
-
-              Note that tinc can't run scripts anymore (such as tinc-down or host-up), unless it is setup to be runnable inside chroot environment.
-            '';
-          };
-        };
       };
     };
 
@@ -149,8 +151,8 @@ in
       ("tinc.${network}")
       ({
         description = "Tinc Daemon - ${network}";
-        wantedBy = [ "network.target" ];
-        after = [ "network-interfaces.target" ];
+        wantedBy = [ "multi-user.target" ];
+        after = [ "network.target" ];
         path = [ data.package ];
         restartTriggers = [ config.environment.etc."tinc/${network}/tinc.conf".source ]
           ++ mapAttrsToList (host: _ : config.environment.etc."tinc/${network}/hosts/${host}".source) data.hosts;
diff --git a/nixos/modules/services/networking/toxvpn.nix b/nixos/modules/services/networking/toxvpn.nix
index c38424c8e27..911836fdee4 100644
--- a/nixos/modules/services/networking/toxvpn.nix
+++ b/nixos/modules/services/networking/toxvpn.nix
@@ -25,8 +25,8 @@ with lib;
     systemd.services.toxvpn = {
       description = "toxvpn daemon";
 
-      requires = [ "network-online.target" ]; # consider replacing by NetworkManager-wait-online.service
       wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
 
       preStart = ''
         mkdir -p /run/toxvpn || true
diff --git a/nixos/modules/services/networking/unbound.nix b/nixos/modules/services/networking/unbound.nix
index ed0744c44cc..f3a04d97c98 100644
--- a/nixos/modules/services/networking/unbound.nix
+++ b/nixos/modules/services/networking/unbound.nix
@@ -12,9 +12,17 @@ let
 
   interfaces = concatMapStrings (x: "  interface: ${x}\n") cfg.interfaces;
 
-  forward = optionalString (length cfg.forwardAddresses != 0)
-    "forward-zone:\n  name: .\n" +
-    concatMapStrings (x: "  forward-addr: ${x}\n") cfg.forwardAddresses;
+  isLocalAddress = x: substring 0 3 x == "::1" || substring 0 9 x == "127.0.0.1";
+
+  forward =
+    optionalString (any isLocalAddress cfg.forwardAddresses) ''
+      do-not-query-localhost: no
+    '' +
+    optionalString (cfg.forwardAddresses != []) ''
+      forward-zone:
+        name: .
+    '' +
+    concatMapStringsSep "\n" (x: "    forward-addr: ${x}") cfg.forwardAddresses;
 
   rootTrustAnchorFile = "${stateDir}/root.key";
 
@@ -71,8 +79,12 @@ in
 
       extraConfig = mkOption {
         default = "";
-        type = types.str;
-        description = "Extra lines of unbound config.";
+        type = types.lines;
+        description = ''
+          Extra unbound config. See
+          <citerefentry><refentrytitle>unbound.conf</refentrytitle><manvolnum>8
+          </manvolnum></citerefentry>.
+        '';
       };
 
     };
@@ -84,12 +96,9 @@ in
 
     environment.systemPackages = [ pkgs.unbound ];
 
-    users.extraUsers = singleton {
-      name = "unbound";
-      uid = config.ids.uids.unbound;
+    users.users.unbound = {
       description = "unbound daemon user";
-      home = stateDir;
-      createHome = true;
+      isSystemUser = true;
     };
 
     systemd.services.unbound = {
@@ -107,12 +116,16 @@ in
         chown unbound ${stateDir} ${rootTrustAnchorFile}
         ''}
         touch ${stateDir}/dev/random
-        ${pkgs.utillinux}/bin/mount --bind -n /dev/random ${stateDir}/dev/random
+        ${pkgs.utillinux}/bin/mount --bind -n /dev/urandom ${stateDir}/dev/random
       '';
 
       serviceConfig = {
         ExecStart = "${pkgs.unbound}/bin/unbound -d -c ${stateDir}/unbound.conf";
         ExecStopPost="${pkgs.utillinux}/bin/umount ${stateDir}/dev/random";
+
+        ProtectSystem = true;
+        ProtectHome = true;
+        PrivateDevices = true;
       };
     };
 
diff --git a/nixos/modules/services/networking/vsftpd.nix b/nixos/modules/services/networking/vsftpd.nix
index 7ec484941ed..deff645d9bf 100644
--- a/nixos/modules/services/networking/vsftpd.nix
+++ b/nixos/modules/services/networking/vsftpd.nix
@@ -100,6 +100,10 @@ let
         seccomp_sandbox=NO
       ''}
       anon_umask=${cfg.anonymousUmask}
+      ${optionalString cfg.anonymousUser ''
+        anon_root=${cfg.anonymousUserHome}
+      ''}
+      ${cfg.extraConfig}
     '';
 
 in
@@ -163,6 +167,13 @@ in
         description = "Anonymous write umask.";
       };
 
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        example = "ftpd_banner=Hello";
+        description = "Extra configuration to add at the bottom of the generated configuration file.";
+      };
+
     } // (listToAttrs (catAttrs "nixosOption" optionDescription));
 
   };
diff --git a/nixos/modules/services/networking/wicd.nix b/nixos/modules/services/networking/wicd.nix
index 9e5a437b485..03c6bd28aab 100644
--- a/nixos/modules/services/networking/wicd.nix
+++ b/nixos/modules/services/networking/wicd.nix
@@ -26,7 +26,9 @@ with lib;
     environment.systemPackages = [pkgs.wicd];
 
     systemd.services.wicd = {
-      after = [ "network-interfaces.target" ];
+      after = [ "network-pre.target" ];
+      before = [ "network.target" ];
+      wants = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
       script = "${pkgs.wicd}/sbin/wicd -f";
     };
diff --git a/nixos/modules/services/networking/wireguard.nix b/nixos/modules/services/networking/wireguard.nix
new file mode 100644
index 00000000000..368d89e2e32
--- /dev/null
+++ b/nixos/modules/services/networking/wireguard.nix
@@ -0,0 +1,231 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.networking.wireguard;
+
+  kernel = config.boot.kernelPackages;
+
+  # interface options
+
+  interfaceOpts = { name, ... }: {
+
+    options = {
+
+      ips = mkOption {
+        example = [ "192.168.2.1/24" ];
+        default = [];
+        type = with types; listOf str;
+        description = "The IP addresses of the interface.";
+      };
+
+      privateKey = mkOption {
+        example = "yAnz5TF+lXXJte14tji3zlMNq+hd2rYUIgJBgB3fBmk=";
+        type = types.str;
+        description = "Base64 private key generated by wg genkey.";
+      };
+
+      presharedKey = mkOption {
+        default = null;
+        example = "rVXs/Ni9tu3oDBLS4hOyAUAa1qTWVA3loR8eL20os3I=";
+        type = with types; nullOr str;
+        description = ''
+          base64 preshared key generated by wg genpsk. Optional,
+          and may be omitted. This option adds an additional layer of
+          symmetric-key cryptography to be mixed into the already existing
+          public-key  cryptography, for post-quantum resistance.
+        '';
+      };
+
+      listenPort = mkOption {
+        default = null;
+        type = with types; nullOr int;
+        example = 51820;
+        description = ''
+          16-bit port for listening. Optional; if not specified,
+          automatically generated based on interface name.
+        '';
+      };
+
+      preSetup = mkOption {
+        example = literalExample [''
+          ${pkgs.iproute}/bin/ip netns add foo
+        ''];
+        default = [];
+        type = with types; listOf str;
+        description = ''
+          A list of commands called at the start of the interface setup.
+        '';
+      };
+
+      postSetup = mkOption {
+        example = literalExample [''
+          ${pkgs.bash} -c 'printf "nameserver 10.200.100.1" | ${pkgs.openresolv}/bin/resolvconf -a wg0 -m 0'
+        ''];
+        default = [];
+        type = with types; listOf str;
+        description = "A list of commands called at the end of the interface setup.";
+      };
+
+      postShutdown = mkOption {
+        example = literalExample ["${pkgs.openresolv}/bin/resolvconf -d wg0"];
+        default = [];
+        type = with types; listOf str;
+        description = "A list of commands called after shutting down the interface.";
+      };
+
+      peers = mkOption {
+        default = [];
+        description = "Peers linked to the interface.";
+        type = with types; listOf (submodule peerOpts);
+      };
+
+    };
+
+  };
+
+  # peer options
+
+  peerOpts = {
+
+    options = {
+
+      publicKey = mkOption {
+        example = "xTIBA5rboUvnH4htodjb6e697QjLERt1NAB4mZqp8Dg=";
+        type = types.str;
+        description = "The base64 public key the peer.";
+      };
+
+      allowedIPs = mkOption {
+        example = [ "10.192.122.3/32" "10.192.124.1/24" ];
+        type = with types; listOf str;
+        description = ''List of IP (v4 or v6) addresses with CIDR masks from
+        which this peer is allowed to send incoming traffic and to which
+        outgoing traffic for this peer is directed. The catch-all 0.0.0.0/0 may
+        be specified for matching all IPv4 addresses, and ::/0 may be specified
+        for matching all IPv6 addresses.'';
+      };
+
+      endpoint = mkOption {
+        default = null;
+        example = "demo.wireguard.io:12913";
+        type = with types; nullOr str;
+        description = ''Endpoint IP or hostname of the peer, followed by a colon,
+        and then a port number of the peer.'';
+      };
+
+      persistentKeepalive = mkOption {
+        default = null;
+        type = with types; nullOr int;
+        example = 25;
+        description = ''This is optional and is by default off, because most
+        users will not need it. It represents, in seconds, between 1 and 65535
+        inclusive, how often to send an authenticated empty packet to the peer,
+        for the purpose of keeping a stateful firewall or NAT mapping valid
+        persistently. For example, if the interface very rarely sends traffic,
+        but it might at anytime receive traffic from a peer, and it is behind
+        NAT, the interface might benefit from having a persistent keepalive
+        interval of 25 seconds; however, most users will not need this.'';
+      };
+
+    };
+
+  };
+
+  generateConf = name: values: pkgs.writeText "wireguard-${name}.conf" ''
+    [Interface]
+    PrivateKey = ${values.privateKey}
+    ${optionalString (values.presharedKey != null) "PresharedKey = ${values.presharedKey}"}
+    ${optionalString (values.listenPort != null)   "ListenPort = ${toString values.listenPort}"}
+
+    ${concatStringsSep "\n\n" (map (peer: ''
+    [Peer]
+    PublicKey = ${peer.publicKey}
+    ${optionalString (peer.allowedIPs != []) "AllowedIPs = ${concatStringsSep ", " peer.allowedIPs}"}
+    ${optionalString (peer.endpoint != null) "Endpoint = ${peer.endpoint}"}
+    ${optionalString (peer.persistentKeepalive != null) "PersistentKeepalive = ${toString peer.persistentKeepalive}"}
+    '') values.peers)}
+  '';
+
+  ipCommand = "${pkgs.iproute}/bin/ip";
+  wgCommand = "${pkgs.wireguard}/bin/wg";
+
+  generateUnit = name: values:
+    nameValuePair "wireguard-${name}"
+      {
+        description = "WireGuard Tunnel - ${name}";
+        after = [ "network.target" ];
+        wantedBy = [ "multi-user.target" ];
+        serviceConfig = {
+          Type = "oneshot";
+          RemainAfterExit = true;
+          ExecStart = lib.flatten([
+            values.preSetup
+
+            "-${ipCommand} link del dev ${name}"
+            "${ipCommand} link add dev ${name} type wireguard"
+            "${wgCommand} setconf ${name} ${generateConf name values}"
+
+            (map (ip:
+            ''${ipCommand} address add ${ip} dev ${name}''
+            ) values.ips)
+
+            "${ipCommand} link set up dev ${name}"
+
+            (flatten (map (peer: (map (ip:
+            "${ipCommand} route add ${ip} dev ${name}"
+            ) peer.allowedIPs)) values.peers))
+
+            values.postSetup
+          ]);
+
+          ExecStop = [ ''${ipCommand} link del dev "${name}"'' ] ++ values.postShutdown;
+        };
+      };
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    networking.wireguard = {
+
+      interfaces = mkOption {
+        description = "Wireguard interfaces.";
+        default = {};
+        example = {
+          wg0 = {
+            ips = [ "192.168.20.4/24" ];
+            privateKey = "yAnz5TF+lXXJte14tji3zlMNq+hd2rYUIgJBgB3fBmk=";
+            peers = [
+              { allowedIPs = [ "192.168.20.1/32" ];
+                publicKey  = "xTIBA5rboUvnH4htodjb6e697QjLERt1NAB4mZqp8Dg=";
+                endpoint   = "demo.wireguard.io:12913"; }
+            ];
+          };
+        };
+        type = with types; attrsOf (submodule interfaceOpts);
+      };
+
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf (cfg.interfaces != {}) {
+
+    boot.extraModulePackages = [ kernel.wireguard ];
+    environment.systemPackages = [ pkgs.wireguard ];
+
+    systemd.services = mapAttrs' generateUnit cfg.interfaces;
+
+  };
+
+}
diff --git a/nixos/modules/services/networking/wpa_supplicant.nix b/nixos/modules/services/networking/wpa_supplicant.nix
index de99ce4f026..c91ba91fcb4 100644
--- a/nixos/modules/services/networking/wpa_supplicant.nix
+++ b/nixos/modules/services/networking/wpa_supplicant.nix
@@ -12,11 +12,13 @@ let
       psk = if networkConfig.psk != null
         then ''"${networkConfig.psk}"''
         else networkConfig.pskRaw;
+      priority = networkConfig.priority;
     in ''
       network={
         ssid="${ssid}"
         ${optionalString (psk != null) ''psk=${psk}''}
         ${optionalString (psk == null) ''key_mgmt=NONE''}
+        ${optionalString (priority != null) ''priority=${toString priority}''}
       }
     '') cfg.networks)}
   '' else "/etc/wpa_supplicant.conf";
@@ -68,6 +70,19 @@ in {
                 Mutually exclusive with <varname>psk</varname>.
               '';
             };
+            priority = mkOption {
+              type = types.nullOr types.int;
+              default = null;
+              description = ''
+                By default, all networks will get same priority group (0). If some of the
+                networks are more desirable, this field can be used to change the order in
+                which wpa_supplicant goes through the networks when selecting a BSS. The
+                priority groups will be iterated in decreasing priority (i.e., the larger the
+                priority value, the sooner the network is matched against the scan results).
+                Within each priority group, networks will be selected based on security
+                policy, signal strength, etc.
+              '';
+            };
           };
         });
         description = ''
@@ -128,9 +143,11 @@ in {
     in {
       description = "WPA Supplicant";
 
-      after = [ "network-interfaces.target" ] ++ lib.concatMap deviceUnit ifaces;
+      after = lib.concatMap deviceUnit ifaces;
+      before = [ "network.target" ];
+      wants = [ "network.target" ];
       requires = lib.concatMap deviceUnit ifaces;
-      wantedBy = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
 
       path = [ pkgs.wpa_supplicant ];
 
diff --git a/nixos/modules/services/networking/xinetd.nix b/nixos/modules/services/networking/xinetd.nix
index 08680b51780..00224502780 100644
--- a/nixos/modules/services/networking/xinetd.nix
+++ b/nixos/modules/services/networking/xinetd.nix
@@ -65,71 +65,73 @@ in
         A list of services provided by xinetd.
       '';
 
-      type = types.listOf types.optionSet;
+      type = with types; listOf (submodule ({
+
+        options = {
+
+          name = mkOption {
+            type = types.string;
+            example = "login";
+            description = "Name of the service.";
+          };
+
+          protocol = mkOption {
+            type = types.string;
+            default = "tcp";
+            description =
+              "Protocol of the service.  Usually <literal>tcp</literal> or <literal>udp</literal>.";
+          };
+
+          port = mkOption {
+            type = types.int;
+            default = 0;
+            example = 123;
+            description = "Port number of the service.";
+          };
+
+          user = mkOption {
+            type = types.string;
+            default = "nobody";
+            description = "User account for the service";
+          };
+
+          server = mkOption {
+            type = types.string;
+            example = "/foo/bin/ftpd";
+            description = "Path of the program that implements the service.";
+          };
+
+          serverArgs = mkOption {
+            type = types.string;
+            default = "";
+            description = "Command-line arguments for the server program.";
+          };
+
+          flags = mkOption {
+            type = types.string;
+            default = "";
+            description = "";
+          };
+
+          unlisted = mkOption {
+            type = types.bool;
+            default = false;
+            description = ''
+              Whether this server is listed in
+              <filename>/etc/services</filename>.  If so, the port
+              number can be omitted.
+            '';
+          };
+
+          extraConfig = mkOption {
+            type = types.lines;
+            default = "";
+            description = "Extra configuration-lines added to the section of the service.";
+          };
 
-      options = {
-
-        name = mkOption {
-          type = types.string;
-          example = "login";
-          description = "Name of the service.";
-        };
-
-        protocol = mkOption {
-          type = types.string;
-          default = "tcp";
-          description =
-            "Protocol of the service.  Usually <literal>tcp</literal> or <literal>udp</literal>.";
-        };
-
-        port = mkOption {
-          type = types.int;
-          default = 0;
-          example = 123;
-          description = "Port number of the service.";
-        };
-
-        user = mkOption {
-          type = types.string;
-          default = "nobody";
-          description = "User account for the service";
-        };
-
-        server = mkOption {
-          type = types.string;
-          example = "/foo/bin/ftpd";
-          description = "Path of the program that implements the service.";
-        };
-
-        serverArgs = mkOption {
-          type = types.string;
-          default = "";
-          description = "Command-line arguments for the server program.";
-        };
-
-        flags = mkOption {
-          type = types.string;
-          default = "";
-          description = "";
-        };
-
-        unlisted = mkOption {
-          type = types.bool;
-          default = false;
-          description = ''
-            Whether this server is listed in
-            <filename>/etc/services</filename>.  If so, the port
-            number can be omitted.
-          '';
-        };
-
-        extraConfig = mkOption {
-          type = types.string;
-          default = "";
-          description = "Extra configuration-lines added to the section of the service.";
         };
 
-      };
+      }));
 
     };
 
@@ -141,7 +143,7 @@ in
   config = mkIf cfg.enable {
     systemd.services.xinetd = {
       description = "xinetd server";
-      after = [ "network-interfaces.target" ];
+      after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
       path = [ pkgs.xinetd ];
       script = "xinetd -syslog daemon -dontfork -stayalive -f ${configFile}";
diff --git a/nixos/modules/services/networking/zerobin.nix b/nixos/modules/services/networking/zerobin.nix
index 1c524602f8e..274bbca53fa 100644
--- a/nixos/modules/services/networking/zerobin.nix
+++ b/nixos/modules/services/networking/zerobin.nix
@@ -86,15 +86,15 @@ in
 
       systemd.services.zerobin = {
         enable = true;
-        after = [ "network-interfaces.target" ];
+        after = [ "network.target" ];
         wantedBy = [ "multi-user.target" ];
         serviceConfig.ExecStart = "${pkgs.pythonPackages.zerobin}/bin/zerobin ${cfg.listenAddress} ${toString cfg.listenPort} false ${cfg.user} ${cfg.group} ${zerobin_config}";
         serviceConfig.PrivateTmp="yes";
         serviceConfig.User = cfg.user;
         serviceConfig.Group = cfg.group;
         preStart = ''
-        mkdir -p ${cfg.dataDir}
-        chown ${cfg.user} ${cfg.dataDir}
+          mkdir -p ${cfg.dataDir}
+          chown ${cfg.user} ${cfg.dataDir}
         '';
       };
     };
diff --git a/nixos/modules/services/networking/znc.nix b/nixos/modules/services/networking/znc.nix
index 196a14dd40e..76ba78ff366 100644
--- a/nixos/modules/services/networking/znc.nix
+++ b/nixos/modules/services/networking/znc.nix
@@ -26,53 +26,35 @@ let
   };
 
   # Keep znc.conf in nix store, then symlink or copy into `dataDir`, depending on `mutable`.
+  notNull = a: ! isNull a;
   mkZncConf = confOpts: ''
-    // Also check http://en.znc.in/wiki/Configuration
-    
-    AnonIPLimit = 10
-    ConnectDelay = 5
-    # Add `LoadModule = x` for each module...
+    Version = 1.6.3
     ${concatMapStrings (n: "LoadModule = ${n}\n") confOpts.modules}
-    MaxBufferSize = 500
-    ProtectWebSessions = true
-    SSLCertFile = ${cfg.dataDir}/znc.pem
-    ServerThrottle = 30
-    Skin = dark-clouds
-    StatusPrefix = *
-    Version = 1.2
-
-    <Listener listener0>
-            AllowIRC = true
-            AllowWeb = true
+
+    <Listener l>
+            Port = ${toString confOpts.port}
             IPv4 = true
-            IPv6 = false
-            Port = ${if confOpts.useSSL then "+" else ""}${toString confOpts.port}
+            IPv6 = true
             SSL = ${if confOpts.useSSL then "true" else "false"}
     </Listener>
     
     <User ${confOpts.userName}>
+            ${confOpts.passBlock}
             Admin = true
-            Allow = *
-            AltNick = ${confOpts.nick}_
-            AppendTimestamp = false
-            AutoClearChanBuffer = false
-            Buffer = 150
-            ChanModes = +stn
-            DenyLoadMod = false
-            DenySetBindHost = false
-            Ident = ident
-            JoinTries = 10
-            MaxJoins = 0
-            MaxNetworks = 1
-            MultiClients = true
             Nick = ${confOpts.nick}
-            PrependTimestamp = true
-            QuitMsg = Quit
+            AltNick = ${confOpts.nick}_
+            Ident = ${confOpts.nick}
             RealName = ${confOpts.nick}
-            TimestampFormat = [%H:%M:%S]
             ${concatMapStrings (n: "LoadModule = ${n}\n") confOpts.userModules}
-            
-            ${confOpts.passBlock}
+
+            ${ lib.concatStringsSep "\n" (lib.mapAttrsToList (name: net: ''
+              <Network ${name}>
+                  ${concatMapStrings (m: "LoadModule = ${m}\n") net.modules}
+                  Server = ${net.server} ${if net.useSSL then "+" else ""}${toString net.port}
+
+                  ${concatMapStrings (c: "<Chan #${c}>\n</Chan>\n") net.channels}
+              </Network>
+              '') confOpts.networks) }
     </User>
     ${confOpts.extraZncConf}
   '';
@@ -84,6 +66,62 @@ let
       else mkZncConf cfg.confOptions;
   };
 
+  networkOpts = { ... }: {
+    options = {
+      server = mkOption {
+        type = types.str;
+        example = "chat.freenode.net";
+        description = ''
+          IRC server address.
+        '';
+      };
+
+      port = mkOption {
+        type = types.int;
+        default = 6697;
+        example = 6697;
+        description = ''
+          IRC server port.
+        '';
+      };
+
+      useSSL = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Whether to use SSL to connect to the IRC server.
+        '';
+      };
+
+      modulePackages = mkOption {
+        type = types.listOf types.package;
+        default = [];
+        example = [ "pkgs.zncModules.push" "pkgs.zncModules.fish" ];
+        description = ''
+          External ZNC modules to build.
+        '';
+      };
+
+      modules = mkOption {
+        type = types.listOf types.str;
+        default = [ "simple_away" ];
+        example = literalExample "[ simple_away sasl ]";
+        description = ''
+          ZNC modules to load.
+        '';
+      };
+
+      channels = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        example = [ "nixos" ];
+        description = ''
+          IRC channels to join.
+        '';
+      };
+    };
+  };
+
 in
 
 {
@@ -111,6 +149,15 @@ in
         '';
       };
 
+      group = mkOption {
+        default = "";
+        example = "users";
+        type = types.string;
+        description = ''
+          Group to own the ZNCserver process.
+        '';
+      };
+
       dataDir = mkOption {
         default = "/var/lib/znc/";
         example = "/home/john/.znc/";
@@ -125,27 +172,16 @@ in
         example = "See: http://wiki.znc.in/Configuration";
         type = types.lines;
         description = ''
-          The contents of the `znc.conf` file to use when creating it.
+          Config file as generated with `znc --makeconf` to use for the whole ZNC configuration.
           If specified, `confOptions` will be ignored, and this value, as-is, will be used.
           If left empty, a conf file with default values will be used.
-          Recommended to generate with `znc --makeconf` command.
         '';
       };
 
-      /* TODO: add to the documentation of the current module:
-
-         Values to use when creating a `znc.conf` file.
-
-           confOptions = {
-             modules = [ "log" ];
-             userName = "john";
-             nick = "johntron";
-           };
-      */
       confOptions = {
         modules = mkOption {
           type = types.listOf types.str;
-          default = [ "partyline" "webadmin" "adminlog" "log" ];
+          default = [ "webadmin" "adminlog" ];
           example = [ "partyline" "webadmin" "adminlog" "log" ];
           description = ''
             A list of modules to include in the `znc.conf` file.
@@ -154,8 +190,8 @@ in
 
         userModules = mkOption {
           type = types.listOf types.str;
-          default = [ ];
-          example = [ "fish" "push" ];
+          default = [ "chansaver" "controlpanel" ];
+          example = [ "chansaver" "controlpanel" "fish" "push" ];
           description = ''
             A list of user modules to include in the `znc.conf` file.
           '';
@@ -166,9 +202,24 @@ in
           example = "johntron";
           type = types.string;
           description = ''
-            The user name to use when generating the `znc.conf` file.
-            This is the user name used by the user logging into the ZNC web admin.
+            The user name used to log in to the ZNC web admin interface.
+          '';
+        };
+
+        networks = mkOption {
+          default = { };
+          type = with types; loaOf (submodule networkOpts);
+          description = ''
+            IRC networks to connect the user to.
           '';
+          example = {
+            "freenode" = {
+              server = "chat.freenode.net";
+              port = 6697;
+              ssl = true;
+              modules = [ "simple_away" ];
+            };
+          };
         };
 
         nick = mkOption {
@@ -176,19 +227,16 @@ in
           example = "john";
           type = types.string;
           description = ''
-            The IRC nick to use when generating the `znc.conf` file.
+            The IRC nick.
           '';
         };
 
         passBlock = mkOption {
-          default = defaultPassBlock;
-          example = "Must be the block generated by the `znc --makepass` command.";
+          example = defaultPassBlock;
           type = types.string;
           description = ''
-            The pass block to use when generating the `znc.conf` file.
-            This is the password used by the user logging into the ZNC web admin.
-            This is the block generated by the `znc --makepass` command.
-            !!! If not specified, please change this after starting the service. !!!
+            Generate with znc --makepass.
+            This is the password used to log in to the ZNC web admin interface.
           '';
         };
 
@@ -206,7 +254,7 @@ in
           example = true;
           type = types.bool;
           description = ''
-            Indicates whether the ZNC server should use SSL when listening on the specified port.
+            Indicates whether the ZNC server should use SSL when listening on the specified port. A self-signed certificate will be generated.
           '';
         };
 
@@ -214,7 +262,7 @@ in
           default = "";
           type = types.lines;
           description = ''
-            Extra config to `znc.conf` file
+            Extra config to `znc.conf` file.
           '';
         };
       };
@@ -265,6 +313,7 @@ in
       after = [ "network.service" ];
       serviceConfig = {
         User = cfg.user;
+        Group = cfg.group;
         Restart = "always";
         ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
         ExecStop   = "${pkgs.coreutils}/bin/kill -INT $MAINPID";
diff --git a/nixos/modules/services/printing/cupsd.nix b/nixos/modules/services/printing/cupsd.nix
index 368d7ac761a..3041dccfd15 100644
--- a/nixos/modules/services/printing/cupsd.nix
+++ b/nixos/modules/services/printing/cupsd.nix
@@ -75,7 +75,7 @@ let
     '') cfg.listenAddresses}
     Listen /var/run/cups/cups.sock
 
-    SetEnv PATH ${bindir}/lib/cups/filter:${bindir}/bin
+    SetEnv PATH /var/lib/cups/path/lib/cups/filter:/var/lib/cups/path/bin
 
     DefaultShared ${if cfg.defaultShared then "Yes" else "No"}
 
@@ -310,6 +310,13 @@ in
             for i in *; do
               [ ! -e "/var/lib/cups/$i" ] && ln -s "${rootdir}/etc/cups/$i" "/var/lib/cups/$i"
             done
+
+            #update path reference
+            [ -L /var/lib/cups/path ] && \
+              rm /var/lib/cups/path
+            [ ! -e /var/lib/cups/path ] && \
+              ln -s ${bindir} /var/lib/cups/path
+
             ${optionalString cfg.gutenprint ''
               if [ -d /var/lib/cups/ppd ]; then
                 ${gutenprint}/bin/cups-genppdupdate -p /var/lib/cups/ppd
diff --git a/nixos/modules/services/scheduling/chronos.nix b/nixos/modules/services/scheduling/chronos.nix
index db1f0f5f00c..6c39997fec8 100644
--- a/nixos/modules/services/scheduling/chronos.nix
+++ b/nixos/modules/services/scheduling/chronos.nix
@@ -41,7 +41,7 @@ in {
     systemd.services.chronos = {
       description = "Chronos Service";
       wantedBy = [ "multi-user.target" ];
-      after = [ "network-interfaces.target" "zookeeper.service" ];
+      after = [ "network.target" "zookeeper.service" ];
 
       serviceConfig = {
         ExecStart = "${pkgs.chronos}/bin/chronos --master ${cfg.master} --zk_hosts ${concatStringsSep "," cfg.zookeeperHosts} --http_port ${toString cfg.httpPort}";
diff --git a/nixos/modules/services/scheduling/marathon.nix b/nixos/modules/services/scheduling/marathon.nix
index 4e837c62dc1..19c9a708f21 100644
--- a/nixos/modules/services/scheduling/marathon.nix
+++ b/nixos/modules/services/scheduling/marathon.nix
@@ -83,7 +83,7 @@ in {
       description = "Marathon Service";
       environment = cfg.environment;
       wantedBy = [ "multi-user.target" ];
-      after = [ "network-interfaces.target" "zookeeper.service" "mesos-master.service" "mesos-slave.service" ];
+      after = [ "network.target" "zookeeper.service" "mesos-master.service" "mesos-slave.service" ];
 
       serviceConfig = {
         ExecStart = "${pkgs.marathon}/bin/marathon --master ${cfg.master} --zk zk://${concatStringsSep "," cfg.zookeeperHosts}/marathon --http_port ${toString cfg.httpPort} ${concatStringsSep " " cfg.extraCmdLineOptions}";
diff --git a/nixos/modules/services/search/elasticsearch.nix b/nixos/modules/services/search/elasticsearch.nix
index 9299aaac2f7..574f74d547a 100644
--- a/nixos/modules/services/search/elasticsearch.nix
+++ b/nixos/modules/services/search/elasticsearch.nix
@@ -129,7 +129,7 @@ in {
     systemd.services.elasticsearch = {
       description = "Elasticsearch Daemon";
       wantedBy = [ "multi-user.target" ];
-      after = [ "network-interfaces.target" ];
+      after = [ "network.target" ];
       path = [ pkgs.inetutils ];
       environment = {
         ES_HOME = cfg.dataDir;
diff --git a/nixos/modules/services/search/hound.nix b/nixos/modules/services/search/hound.nix
new file mode 100644
index 00000000000..a94a851e80e
--- /dev/null
+++ b/nixos/modules/services/search/hound.nix
@@ -0,0 +1,125 @@
+{ config, lib, pkgs, ... }:
+with lib;
+let
+  cfg = config.services.hound;
+in {
+  options = {
+    services.hound = {
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to enable the hound code search daemon.
+        '';
+      };
+
+      user = mkOption {
+        default = "hound";
+        type = types.str;
+        description = ''
+          User the hound daemon should execute under.
+        '';
+      };
+
+      group = mkOption {
+        default = "hound";
+        type = types.str;
+        description = ''
+          Group the hound daemon should execute under.
+        '';
+      };
+
+      extraGroups = mkOption {
+        type = types.listOf types.str;
+        default = [ ];
+        example = [ "dialout" ];
+        description = ''
+          List of extra groups that the "hound" user should be a part of.
+        '';
+      };
+
+      home = mkOption {
+        default = "/var/lib/hound";
+        type = types.path;
+        description = ''
+          The path to use as hound's $HOME. If the default user
+          "hound" is configured then this is the home of the "hound"
+          user.
+        '';
+      };
+
+      package = mkOption {
+        default = pkgs.hound;
+        defaultText = "pkgs.hound";
+        type = types.package;
+        description = ''
+          Package for running hound.
+        '';
+      };
+
+      config = mkOption {
+        type = types.str;
+        description = ''
+          The full configuration of the Hound daemon. Note the dbpath
+          should be an absolute path to a writable location on disk.
+        '';
+        example = ''
+          {
+             "max-concurrent-indexers" : 2,
+             "dbpath" : "''${services.hound.home}/data",
+             "repos" : {
+                "nixpkgs": {
+                   "url" : "https://www.github.com/NixOS/nixpkgs.git"
+                }
+             }
+          }
+        '';
+      };
+
+      listen = mkOption {
+        type = types.str;
+        default = "0.0.0.0:6080";
+        example = "127.0.0.1:6080 or just :6080";
+        description = ''
+          Listen on this IP:port / :port
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    users.extraGroups = optional (cfg.group == "hound") {
+      name = "hound";
+      gid = config.ids.gids.hound;
+    };
+
+    users.extraUsers = optional (cfg.user == "hound") {
+      name = "hound";
+      description = "hound code search";
+      createHome = true;
+      home = cfg.home;
+      group = cfg.group;
+      extraGroups = cfg.extraGroups;
+      uid = config.ids.uids.hound;
+    };
+
+    systemd.services.hound = {
+      description = "Hound Code Search";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+
+      serviceConfig = {
+        User = cfg.user;
+        Group = cfg.group;
+        WorkingDirectory = cfg.home;
+        ExecStartPre = "${pkgs.git}/bin/git config --global --replace-all http.sslCAinfo /etc/ssl/certs/ca-certificates.crt";
+        ExecStart = "${cfg.package}/bin/houndd" +
+                    " -addr ${cfg.listen}" +
+                    " -conf ${pkgs.writeText "hound.json" cfg.config}";
+
+      };
+      path = [ pkgs.git pkgs.mercurial pkgs.openssh ];
+    };
+  };
+
+}
diff --git a/nixos/modules/services/search/kibana.nix b/nixos/modules/services/search/kibana.nix
index 033b8139d34..d377a6feeb8 100644
--- a/nixos/modules/services/search/kibana.nix
+++ b/nixos/modules/services/search/kibana.nix
@@ -138,7 +138,7 @@ in {
     systemd.services.kibana = {
       description = "Kibana Service";
       wantedBy = [ "multi-user.target" ];
-      after = [ "network-interfaces.target" "elasticsearch.service" ];
+      after = [ "network.target" "elasticsearch.service" ];
       environment = { BABEL_CACHE_PATH = "${cfg.dataDir}/.babelcache.json"; };
       serviceConfig = {
         ExecStart = "${cfg.package}/bin/kibana --config ${cfgFile}";
diff --git a/nixos/modules/services/security/clamav.nix b/nixos/modules/services/security/clamav.nix
index e4e5c1253b7..b045e140546 100644
--- a/nixos/modules/services/security/clamav.nix
+++ b/nixos/modules/services/security/clamav.nix
@@ -3,26 +3,37 @@ with lib;
 let
   clamavUser = "clamav";
   stateDir = "/var/lib/clamav";
-  runDir = "/var/run/clamav";
-  logDir = "/var/log/clamav";
+  runDir = "/run/clamav";
   clamavGroup = clamavUser;
   cfg = config.services.clamav;
+  pkg = pkgs.clamav;
+
   clamdConfigFile = pkgs.writeText "clamd.conf" ''
     DatabaseDirectory ${stateDir}
     LocalSocket ${runDir}/clamd.ctl
-    LogFile ${logDir}/clamav.log
     PidFile ${runDir}/clamd.pid
+    TemporaryDirectory /tmp
     User clamav
+    Foreground yes
 
     ${cfg.daemon.extraConfig}
   '';
-  pkg = pkgs.clamav.override { freshclamConf = cfg.updater.config; };
+
+  freshclamConfigFile = pkgs.writeText "freshclam.conf" ''
+    DatabaseDirectory ${stateDir}
+    Foreground yes
+    Checks ${toString cfg.updater.frequency}
+
+    ${cfg.updater.extraConfig}
+
+    DatabaseMirror database.clamav.net
+  '';
 in
 {
   options = {
     services.clamav = {
       daemon = {
-        enable = mkEnableOption "clamd daemon";
+        enable = mkEnableOption "ClamAV clamd daemon";
 
         extraConfig = mkOption {
           type = types.lines;
@@ -34,16 +45,27 @@ in
         };
       };
       updater = {
-        enable = mkEnableOption "freshclam updater";
+        enable = mkEnableOption "ClamAV freshclam updater";
 
         frequency = mkOption {
+          type = types.int;
           default = 12;
           description = ''
             Number of database checks per day.
           '';
         };
 
-        config = mkOption {
+        interval = mkOption {
+          type = types.str;
+          default = "hourly";
+          description = ''
+            How often freshclam is invoked. See systemd.time(7) for more
+            information about the format.
+          '';
+        };
+
+        extraConfig = mkOption {
+          type = types.lines;
           default = "";
           description = ''
             Extra configuration for freshclam. Contents will be added verbatim to the
@@ -68,50 +90,53 @@ in
       gid = config.ids.gids.clamav;
     };
 
-    services.clamav.updater.config = mkIf cfg.updater.enable ''
-      DatabaseDirectory ${stateDir}
-      Foreground yes
-      Checks ${toString cfg.updater.frequency}
-      DatabaseMirror database.clamav.net
-    '';
+    environment.etc."clamav/freshclam.conf".source = freshclamConfigFile;
+    environment.etc."clamav/clamd.conf".source = clamdConfigFile;
 
-    systemd.services.clamd = mkIf cfg.daemon.enable {
+    systemd.services.clamav-daemon = mkIf cfg.daemon.enable {
       description = "ClamAV daemon (clamd)";
-      path = [ pkg ];
-      after = [ "network.target" "freshclam.service" ];
-      requires = [ "freshclam.service" ];
+      after = mkIf cfg.updater.enable [ "clamav-freshclam.service" ];
+      requires = mkIf cfg.updater.enable [ "clamav-freshclam.service" ];
       wantedBy = [ "multi-user.target" ];
+      restartTriggers = [ clamdConfigFile ];
+
       preStart = ''
-        mkdir -m 0755 -p ${logDir}
         mkdir -m 0755 -p ${runDir}
-        chown ${clamavUser}:${clamavGroup} ${logDir}
         chown ${clamavUser}:${clamavGroup} ${runDir}
       '';
+
       serviceConfig = {
-        ExecStart = "${pkg}/bin/clamd --config-file=${clamdConfigFile}";
-        Type = "forking";
-        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
-        Restart = "on-failure";
-        RestartSec = "10s";
-        StartLimitInterval = "1min";
+        ExecStart = "${pkg}/bin/clamd";
+        ExecReload = "${pkgs.coreutils}/bin/kill -USR2 $MAINPID";
+        PrivateTmp = "yes";
+        PrivateDevices = "yes";
+        PrivateNetwork = "yes";
       };
     };
 
-    systemd.services.freshclam = mkIf cfg.updater.enable {
-      description = "ClamAV updater (freshclam)";
-      after = [ "network.target" ];
-      wantedBy = [ "multi-user.target" ];
-      path = [ pkg ];
+    systemd.timers.clamav-freshclam = mkIf cfg.updater.enable {
+      description = "Timer for ClamAV virus database updater (freshclam)";
+      wantedBy = [ "timers.target" ];
+      timerConfig = {
+        OnCalendar = cfg.updater.interval;
+        Unit = "clamav-freshclam.service";
+      };
+    };
+
+    systemd.services.clamav-freshclam = mkIf cfg.updater.enable {
+      description = "ClamAV virus database updater (freshclam)";
+      restartTriggers = [ freshclamConfigFile ];
+
       preStart = ''
         mkdir -m 0755 -p ${stateDir}
         chown ${clamavUser}:${clamavGroup} ${stateDir}
       '';
+
       serviceConfig = {
-        ExecStart = "${pkg}/bin/freshclam --daemon --config-file=${pkgs.writeText "freshclam.conf" cfg.updater.config}";
-        ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
-        Restart = "on-failure";
-        RestartSec = "10s";
-        StartLimitInterval = "1min";
+        Type = "oneshot";
+        ExecStart = "${pkg}/bin/freshclam";
+        PrivateTmp = "yes";
+        PrivateDevices = "yes";
       };
     };
   };
diff --git a/nixos/modules/services/security/fail2ban.nix b/nixos/modules/services/security/fail2ban.nix
index 22e3bb0066c..716ae7a2d2f 100644
--- a/nixos/modules/services/security/fail2ban.nix
+++ b/nixos/modules/services/security/fail2ban.nix
@@ -143,7 +143,7 @@ in
     services.fail2ban.jails.ssh-iptables =
       ''
         filter   = sshd
-        action   = iptables[name=SSH, port=ssh, protocol=tcp]
+        action   = iptables-multiport[name=SSH, port="${concatMapStringsSep "," (p: toString p) config.services.openssh.ports}", protocol=tcp]
         maxretry = 5
       '';
 
diff --git a/nixos/modules/services/security/haveged.nix b/nixos/modules/services/security/haveged.nix
index 2aa523bf70a..eca52918881 100644
--- a/nixos/modules/services/security/haveged.nix
+++ b/nixos/modules/services/security/haveged.nix
@@ -48,14 +48,18 @@ in
       { description = "Entropy Harvesting Daemon";
         unitConfig.Documentation = "man:haveged(8)";
         wantedBy = [ "multi-user.target" ];
-        
+
         path = [ pkgs.haveged ];
-        
-        serviceConfig = 
-          { Type = "forking";
-            ExecStart = "${pkgs.haveged}/sbin/haveged -w ${toString cfg.refill_threshold} -v 1";
-            PIDFile = "/run/haveged.pid";
-          };
+
+        serviceConfig = {
+          ExecStart = "${pkgs.haveged}/bin/haveged -F -w ${toString cfg.refill_threshold} -v 1";
+          SuccessExitStatus = 143;
+          PrivateTmp = true;
+          PrivateDevices = true;
+          PrivateNetwork = true;
+          ProtectSystem = "full";
+          ProtectHome = true;
+        };
       };
 
   };
diff --git a/nixos/modules/services/security/oauth2_proxy.nix b/nixos/modules/services/security/oauth2_proxy.nix
index 4c20392214f..caa7d9d5081 100644
--- a/nixos/modules/services/security/oauth2_proxy.nix
+++ b/nixos/modules/services/security/oauth2_proxy.nix
@@ -510,7 +510,7 @@ in
       description = "OAuth2 Proxy";
       path = [ cfg.package ];
       wantedBy = [ "multi-user.target" ];
-      after = [ "network-interfaces.target" ];
+      after = [ "network.target" ];
 
       serviceConfig = {
         User = "oauth2_proxy";
diff --git a/nixos/modules/services/system/cgmanager.nix b/nixos/modules/services/system/cgmanager.nix
new file mode 100644
index 00000000000..59d3deced86
--- /dev/null
+++ b/nixos/modules/services/system/cgmanager.nix
@@ -0,0 +1,27 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.cgmanager;
+in {
+  meta.maintainers = [ maintainers.mic92 ];
+
+  ###### interface
+  options.services.cgmanager.enable = mkEnableOption "cgmanager";
+
+  ###### implementation
+  config = mkIf cfg.enable {
+    systemd.services.cgmanager = {
+      wantedBy = [ "multi-user.target" ];
+      after = [ "local-fs.target" ];
+      description = "Cgroup management daemon";
+      restartIfChanged = false;
+      serviceConfig = {
+        ExecStart = "${pkgs.cgmanager}/bin/cgmanager -m name=systemd";
+        KillMode = "process";
+        Restart = "on-failure";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/system/dbus.nix b/nixos/modules/services/system/dbus.nix
index df93fcd2bdb..d15d5551e34 100644
--- a/nixos/modules/services/system/dbus.nix
+++ b/nixos/modules/services/system/dbus.nix
@@ -8,7 +8,7 @@ let
 
   cfg = config.services.dbus;
 
-  homeDir = "/var/run/dbus";
+  homeDir = "/run/dbus";
 
   systemExtraxml = concatStrings (flip concatMap cfg.packages (d: [
     "<servicedir>${d}/share/dbus-1/system-services</servicedir>"
@@ -20,15 +20,23 @@ let
     "<includedir>${d}/etc/dbus-1/session.d</includedir>"
   ]));
 
-  configDir = pkgs.stdenv.mkDerivation {
-    name = "dbus-conf";
+  daemonArgs = "--address=systemd: --nofork --nopidfile --systemd-activation";
 
-    preferLocalBuild = true;
-    allowSubstitutes = false;
-
-    buildCommand = ''
+  configDir = pkgs.runCommand "dbus-conf"
+    { preferLocalBuild = true;
+      allowSubstitutes = false;
+    }
+    ''
       mkdir -p $out
 
+      cp ${pkgs.dbus.out}/share/dbus-1/{system,session}.conf $out
+
+      # avoid circular includes
+      sed -ri 's@(<include ignore_missing="yes">/etc/dbus-1/(system|session)\.conf</include>)@<!-- \1 -->@g' $out/{system,session}.conf
+
+      # include by full path
+      sed -ri "s@/etc/dbus-1/(system|session)-@$out/\1-@" $out/{system,session}.conf
+
       sed '${./dbus-system-local.conf.in}' \
         -e 's,@servicehelper@,${config.security.permissionsWrapperDir}/dbus-daemon-launch-helper,g' \
         -e 's,@extra@,${systemExtraxml},' \
@@ -38,7 +46,6 @@ let
         -e 's,@extra@,${sessionExtraxml},' \
         > "$out/session-local.conf"
     '';
-  };
 
 in
 
@@ -75,16 +82,21 @@ in
         '';
       };
 
+      socketActivated = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Make the user instance socket activated.
+        '';
+      };
     };
-
   };
 
-
   ###### implementation
 
   config = mkIf cfg.enable {
 
-    environment.systemPackages = [ pkgs.dbus.daemon pkgs.dbus_tools ];
+    environment.systemPackages = [ pkgs.dbus.daemon pkgs.dbus ];
 
     environment.etc = singleton
       { source = configDir;
@@ -104,7 +116,7 @@ in
 
     security.permissionsWrappers.setuid = singleton
       { program = "dbus-daemon-launch-helper";
-        source = "${pkgs.dbus_daemon}/libexec/dbus-daemon-launch-helper";
+        source = "${pkgs.dbus.daemon}/libexec/dbus-daemon-launch-helper";
         owner = "root";
         group = "messagebus";
         setuid = true;
@@ -117,13 +129,29 @@ in
       config.system.path
     ];
 
-    # Don't restart dbus-daemon. Bad things tend to happen if we do.
-    systemd.services.dbus.reloadIfChanged = true;
+    systemd.services.dbus = {
+      # Don't restart dbus-daemon. Bad things tend to happen if we do.
+      reloadIfChanged = true;
+      restartTriggers = [ configDir ];
+      serviceConfig.ExecStart = [
+        ""
+        "${lib.getBin pkgs.dbus}/bin/dbus-daemon --config-file=${configDir}/system.conf ${daemonArgs}"
+      ];
+    };
 
-    systemd.services.dbus.restartTriggers = [ configDir ];
+    systemd.user = {
+      services.dbus = {
+        # Don't restart dbus-daemon. Bad things tend to happen if we do.
+        reloadIfChanged = true;
+        restartTriggers = [ configDir ];
+        serviceConfig.ExecStart = [
+          ""
+          "${lib.getBin pkgs.dbus}/bin/dbus-daemon --config-file=${configDir}/session.conf ${daemonArgs}"
+        ];
+      };
+      sockets.dbus.wantedBy = mkIf cfg.socketActivated [ "sockets.target" ];
+    };
 
     environment.pathsToLink = [ "/etc/dbus-1" "/share/dbus-1" ];
-
   };
-
 }
diff --git a/nixos/modules/services/system/nscd.nix b/nixos/modules/services/system/nscd.nix
index d98ef8a306d..eb4b5281c7c 100644
--- a/nixos/modules/services/system/nscd.nix
+++ b/nixos/modules/services/system/nscd.nix
@@ -9,8 +9,6 @@ let
 
   inherit (lib) singleton;
 
-  cfgFile = pkgs.writeText "nscd.conf" cfg.config;
-
 in
 
 {
@@ -41,6 +39,7 @@ in
   ###### implementation
 
   config = mkIf cfg.enable {
+    environment.etc."nscd.conf".text = cfg.config;
 
     users.extraUsers.nscd =
       { isSystemUser = true;
@@ -61,10 +60,14 @@ in
             mkdir -m 0755 -p /var/db/nscd
           '';
 
-        restartTriggers = [ config.environment.etc.hosts.source config.environment.etc."nsswitch.conf".source ];
+        restartTriggers = [
+          config.environment.etc.hosts.source
+          config.environment.etc."nsswitch.conf".source
+          config.environment.etc."nscd.conf".source
+        ];
 
         serviceConfig =
-          { ExecStart = "@${pkgs.glibc.bin}/sbin/nscd nscd -f ${cfgFile}";
+          { ExecStart = "@${pkgs.glibc.bin}/sbin/nscd nscd";
             Type = "forking";
             PIDFile = "/run/nscd/nscd.pid";
             Restart = "always";
@@ -79,7 +82,7 @@ in
         # its pid. So wait until it's ready.
         postStart =
           ''
-            while ! ${pkgs.glibc.bin}/sbin/nscd -g -f ${cfgFile} > /dev/null; do
+            while ! ${pkgs.glibc.bin}/sbin/nscd -g > /dev/null; do
               sleep 0.2
             done
           '';
diff --git a/nixos/modules/services/torrent/deluge.nix b/nixos/modules/services/torrent/deluge.nix
index becd57055d4..a9c08b66eb8 100644
--- a/nixos/modules/services/torrent/deluge.nix
+++ b/nixos/modules/services/torrent/deluge.nix
@@ -5,26 +5,36 @@ with lib;
 let
   cfg = config.services.deluge;
   cfg_web = config.services.deluge.web;
+  openFilesLimit = 4096;
+
 in {
   options = {
-    services.deluge = {
-      enable = mkOption {
-        default = false;
-        example = true;
-        description = ''
-          Start Deluge daemon.
-        ''; 
-      };  
-    };
+    services = {
+      deluge = {
+        enable = mkOption {
+          default = false;
+          example = true;
+          description = "Start the Deluge daemon";
+        };
+
+        openFilesLimit = mkOption {
+          default = openFilesLimit;
+          example = 8192;
+          description = ''
+            Number of files to allow deluged to open.
+          '';
+        };
+      };
 
-    services.deluge.web = {
-      enable = mkOption {
-        default = false;
-        example = true;
-        description = ''
-          Start Deluge Web daemon.
-        ''; 
-      };  
+      deluge.web = {
+        enable = mkOption {
+          default = false;
+          example = true;
+          description = ''
+            Start Deluge Web daemon.
+          '';
+        };
+      };
     };
   };
 
@@ -35,11 +45,14 @@ in {
       description = "Deluge BitTorrent Daemon";
       wantedBy = [ "multi-user.target" ];
       path = [ pkgs.pythonPackages.deluge ];
-      serviceConfig.ExecStart = "${pkgs.pythonPackages.deluge}/bin/deluged -d";
-      # To prevent "Quit & shutdown daemon" from working; we want systemd to manage it!
-      serviceConfig.Restart = "on-success";
-      serviceConfig.User = "deluge";
-      serviceConfig.Group = "deluge";
+      serviceConfig = {
+        ExecStart = "${pkgs.pythonPackages.deluge}/bin/deluged -d";
+        # To prevent "Quit & shutdown daemon" from working; we want systemd to manage it!
+        Restart = "on-success";
+        User = "deluge";
+        Group = "deluge";
+        LimitNOFILE = cfg.openFilesLimit;
+      };
     };
 
     systemd.services.delugeweb = mkIf cfg_web.enable {
diff --git a/nixos/modules/services/torrent/flexget.nix b/nixos/modules/services/torrent/flexget.nix
index 1252aa1c549..4b9038e3e25 100644
--- a/nixos/modules/services/torrent/flexget.nix
+++ b/nixos/modules/services/torrent/flexget.nix
@@ -4,7 +4,7 @@ with lib;
 
 let
   cfg = config.services.flexget;
-  pkg = pkgs.python27Packages.flexget;
+  pkg = pkgs.flexget;
   ymlFile = pkgs.writeText "flexget.yml" ''
     ${cfg.config}
 
@@ -54,12 +54,12 @@ in {
 
   config = mkIf cfg.enable {
 
-    environment.systemPackages = [ pkgs.python27Packages.flexget ];
+    environment.systemPackages = [ pkg ];
 
     systemd.services = {
       flexget = {
         description = "FlexGet Daemon";
-        path = [ pkgs.pythonPackages.flexget ];
+        path = [ pkg ];
         serviceConfig = {
           User = cfg.user;
           Environment = "TZ=${config.time.timeZone}";
diff --git a/nixos/modules/services/torrent/opentracker.nix b/nixos/modules/services/torrent/opentracker.nix
new file mode 100644
index 00000000000..74f443381d9
--- /dev/null
+++ b/nixos/modules/services/torrent/opentracker.nix
@@ -0,0 +1,45 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+let
+  cfg = config.services.opentracker;
+in {
+  options.services.opentracker = {
+    enable = mkEnableOption "opentracker";
+
+    package = mkOption {
+      type = types.package;
+      description = ''
+        opentracker package to use
+      '';
+      default = pkgs.opentracker;
+      defaultText = "pkgs.opentracker";
+    };
+
+    extraOptions = mkOption {
+      type = types.separatedString " ";
+      description = ''
+        Configuration Arguments for opentracker
+        See https://erdgeist.org/arts/software/opentracker/ for all params
+      '';
+      default = "";
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+
+    systemd.services.opentracker = {
+      description = "opentracker server";
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+      restartIfChanged = true;
+      serviceConfig = {
+        ExecStart = "${cfg.package}/bin/opentracker ${cfg.extraOptions}";
+        PrivateTmp = true;
+        WorkingDirectory = "/var/empty";
+        # By default opentracker drops all privileges and runs in chroot after starting up as root.
+      };
+    };
+  };
+}
+
diff --git a/nixos/modules/services/torrent/peerflix.nix b/nixos/modules/services/torrent/peerflix.nix
index 38fbd3b226c..2e3dd9902d7 100644
--- a/nixos/modules/services/torrent/peerflix.nix
+++ b/nixos/modules/services/torrent/peerflix.nix
@@ -42,7 +42,7 @@ in {
     systemd.services.peerflix = {
       description = "Peerflix Daemon";
       wantedBy = [ "multi-user.target" ];
-      after = [ "network-interfaces.target" ];
+      after = [ "network.target" ];
       environment.HOME = cfg.stateDir;
 
       preStart = ''
diff --git a/nixos/modules/services/ttys/agetty.nix b/nixos/modules/services/ttys/agetty.nix
index ea7196fc873..051d54e932f 100644
--- a/nixos/modules/services/ttys/agetty.nix
+++ b/nixos/modules/services/ttys/agetty.nix
@@ -80,8 +80,7 @@ in
       };
 
     systemd.services."container-getty@" =
-      { unitConfig.ConditionPathExists = "/dev/pts/%I"; # Work around being respawned when "machinectl login" exits.
-        serviceConfig.ExecStart = gettyCmd "--noclear --keep-baud pts/%I 115200,38400,9600 $TERM";
+      { serviceConfig.ExecStart = gettyCmd "--noclear --keep-baud pts/%I 115200,38400,9600 $TERM";
         restartIfChanged = false;
       };
 
diff --git a/nixos/modules/services/web-apps/atlassian/confluence.nix b/nixos/modules/services/web-apps/atlassian/confluence.nix
new file mode 100644
index 00000000000..2d9287577de
--- /dev/null
+++ b/nixos/modules/services/web-apps/atlassian/confluence.nix
@@ -0,0 +1,141 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.confluence;
+
+  pkg = pkgs.atlassian-confluence;
+
+in
+
+{
+  options = {
+    services.confluence = {
+      enable = mkEnableOption "Atlassian Confluence service";
+
+      user = mkOption {
+        type = types.str;
+        default = "confluence";
+        description = "User which runs confluence.";
+      };
+
+      group = mkOption {
+        type = types.str;
+        default = "confluence";
+        description = "Group which runs confluence.";
+      };
+
+      home = mkOption {
+        type = types.str;
+        default = "/var/lib/confluence";
+        description = "Home directory of the confluence instance.";
+      };
+
+      listenAddress = mkOption {
+        type = types.str;
+        default = "127.0.0.1";
+        description = "Address to listen on.";
+      };
+
+      listenPort = mkOption {
+        type = types.int;
+        default = 8090;
+        description = "Port to listen on.";
+      };
+
+      catalinaOptions = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        example = [ "-Xms1024m" "-Xmx2048m" "-Dconfluence.disable.peopledirectory.all=true" ];
+        description = "Java options to pass to catalina/tomcat.";
+      };
+
+      proxy = {
+        enable = mkEnableOption "proxy support";
+
+        name = mkOption {
+          type = types.str;
+          example = "confluence.example.com";
+          description = "Virtual hostname at the proxy";
+        };
+
+        port = mkOption {
+          type = types.int;
+          default = 443;
+          example = 80;
+          description = "Port used at the proxy";
+        };
+
+        scheme = mkOption {
+          type = types.str;
+          default = "https";
+          example = "http";
+          description = "Protocol used at the proxy.";
+        };
+      };
+
+      jrePackage = let
+        jreSwitch = unfree: free: if config.nixpkgs.config.allowUnfree or false then unfree else free;
+      in mkOption {
+        type = types.package;
+        default = jreSwitch pkgs.oraclejre8 pkgs.openjdk8.jre;
+        defaultText = jreSwitch "pkgs.oraclejre8" "pkgs.openjdk8.jre";
+        example = literalExample "pkgs.openjdk8.jre";
+        description = "Java Runtime to use for Confluence. Note that Atlassian recommends the Oracle JRE.";
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    users.extraUsers."${cfg.user}" = {
+      isSystemUser = true;
+      group = cfg.group;
+    };
+
+    users.extraGroups."${cfg.group}" = {};
+
+    systemd.services.confluence = {
+      description = "Atlassian Confluence";
+
+      wantedBy = [ "multi-user.target" ];
+      requires = [ "postgresql.service" ];
+      after = [ "postgresql.service" ];
+
+      path = [ cfg.jrePackage ];
+
+      environment = {
+        CONF_USER = cfg.user;
+        JAVA_HOME = "${cfg.jrePackage}";
+        CATALINA_OPTS = concatStringsSep " " cfg.catalinaOptions;
+      };
+
+      preStart = ''
+        mkdir -p ${cfg.home}/{logs,work,temp,deploy}
+
+        mkdir -p /run/confluence
+        ln -sf ${cfg.home}/{logs,work,temp,server.xml} /run/confluence
+        ln -sf ${cfg.home} /run/confluence/home
+
+        chown -R ${cfg.user} ${cfg.home}
+
+        sed -e 's,port="8090",port="${toString cfg.listenPort}" address="${cfg.listenAddress}",' \
+        '' + (lib.optionalString cfg.proxy.enable ''
+          -e 's,protocol="org.apache.coyote.http11.Http11NioProtocol",protocol="org.apache.coyote.http11.Http11NioProtocol" proxyName="${cfg.proxy.name}" proxyPort="${toString cfg.proxy.port}" scheme="${cfg.proxy.scheme}",' \
+        '') + ''
+          ${pkg}/conf/server.xml.dist > ${cfg.home}/server.xml
+      '';
+
+      script = "${pkg}/bin/start-confluence.sh -fg";
+      stopScript  = "${pkg}/bin/stop-confluence.sh";
+
+      serviceConfig = {
+        User = cfg.user;
+        Group = cfg.group;
+        PrivateTmp = true;
+        PermissionsStartOnly = true;
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/web-apps/atlassian/crowd.nix b/nixos/modules/services/web-apps/atlassian/crowd.nix
new file mode 100644
index 00000000000..ada26f8057b
--- /dev/null
+++ b/nixos/modules/services/web-apps/atlassian/crowd.nix
@@ -0,0 +1,156 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.crowd;
+
+  pkg = pkgs.atlassian-crowd.override {
+    home = cfg.home;
+    port = cfg.listenPort;
+    proxyUrl = "${cfg.proxy.scheme}://${cfg.proxy.name}:${toString cfg.proxy.port}";
+    openidPassword = cfg.openidPassword;
+  };
+
+in
+
+{
+  options = {
+    services.crowd = {
+      enable = mkEnableOption "Atlassian Crowd service";
+
+      user = mkOption {
+        type = types.str;
+        default = "crowd";
+        description = "User which runs Crowd.";
+      };
+
+      group = mkOption {
+        type = types.str;
+        default = "crowd";
+        description = "Group which runs Crowd.";
+      };
+
+      home = mkOption {
+        type = types.str;
+        default = "/var/lib/crowd";
+        description = "Home directory of the Crowd instance.";
+      };
+
+      listenAddress = mkOption {
+        type = types.str;
+        default = "127.0.0.1";
+        description = "Address to listen on.";
+      };
+
+      listenPort = mkOption {
+        type = types.int;
+        default = 8092;
+        description = "Port to listen on.";
+      };
+
+      openidPassword = mkOption {
+        type = types.str;
+        description = "Application password for OpenID server.";
+      };
+
+      catalinaOptions = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        example = [ "-Xms1024m" "-Xmx2048m" ];
+        description = "Java options to pass to catalina/tomcat.";
+      };
+
+      proxy = {
+        enable = mkEnableOption "reverse proxy support";
+
+        name = mkOption {
+          type = types.str;
+          example = "crowd.example.com";
+          description = "Virtual hostname at the proxy";
+        };
+
+        port = mkOption {
+          type = types.int;
+          default = 443;
+          example = 80;
+          description = "Port used at the proxy";
+        };
+
+        scheme = mkOption {
+          type = types.str;
+          default = "https";
+          example = "http";
+          description = "Protocol used at the proxy.";
+        };
+
+        secure = mkOption {
+          type = types.bool;
+          default = true;
+          example = false;
+          description = "Whether the connections to the proxy should be considered secure.";
+        };
+      };
+
+      jrePackage = let
+        jreSwitch = unfree: free: if config.nixpkgs.config.allowUnfree or false then unfree else free;
+      in mkOption {
+        type = types.package;
+        default = jreSwitch pkgs.oraclejre8 pkgs.openjdk8.jre;
+        defaultText = jreSwitch "pkgs.oraclejre8" "pkgs.openjdk8.jre";
+        example = literalExample "pkgs.openjdk8.jre";
+        description = "Java Runtime to use for Crowd. Note that Atlassian recommends the Oracle JRE.";
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    users.extraUsers."${cfg.user}" = {
+      isSystemUser = true;
+      group = cfg.group;
+    };
+
+    users.extraGroups."${cfg.group}" = {};
+
+    systemd.services.atlassian-crowd = {
+      description = "Atlassian Crowd";
+
+      wantedBy = [ "multi-user.target" ];
+      requires = [ "postgresql.service" ];
+      after = [ "postgresql.service" ];
+
+      path = [ cfg.jrePackage ];
+
+      environment = {
+        JAVA_HOME = "${cfg.jrePackage}";
+        CATALINA_OPTS = concatStringsSep " " cfg.catalinaOptions;
+        CATALINA_TMPDIR = "/tmp";
+      };
+
+      preStart = ''
+        mkdir -p ${cfg.home}/{logs,work,database}
+
+        mkdir -p /run/atlassian-crowd
+        ln -sf ${cfg.home}/{database,work,server.xml} /run/atlassian-crowd
+
+        chown -R ${cfg.user} ${cfg.home}
+
+        sed -e 's,port="8095",port="${toString cfg.listenPort}" address="${cfg.listenAddress}",' \
+        '' + (lib.optionalString cfg.proxy.enable ''
+          -e 's,compression="on",compression="off" protocol="HTTP/1.1" proxyName="${cfg.proxy.name}" proxyPort="${toString cfg.proxy.port}" scheme="${cfg.proxy.scheme}" secure="${toString cfg.proxy.secure}",' \
+        '') + ''
+          ${pkg}/apache-tomcat/conf/server.xml.dist > ${cfg.home}/server.xml
+      '';
+
+      script = "${pkg}/start_crowd.sh";
+
+      serviceConfig = {
+        User = cfg.user;
+        Group = cfg.group;
+        PrivateTmp = true;
+        PermissionsStartOnly = true;
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/web-apps/atlassian/jira.nix b/nixos/modules/services/web-apps/atlassian/jira.nix
new file mode 100644
index 00000000000..6e31d20d068
--- /dev/null
+++ b/nixos/modules/services/web-apps/atlassian/jira.nix
@@ -0,0 +1,149 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.jira;
+
+  pkg = pkgs.atlassian-jira;
+
+in
+
+{
+  options = {
+    services.jira = {
+      enable = mkEnableOption "Atlassian JIRA service";
+
+      user = mkOption {
+        type = types.str;
+        default = "jira";
+        description = "User which runs JIRA.";
+      };
+
+      group = mkOption {
+        type = types.str;
+        default = "jira";
+        description = "Group which runs JIRA.";
+      };
+
+      home = mkOption {
+        type = types.str;
+        default = "/var/lib/jira";
+        description = "Home directory of the JIRA instance.";
+      };
+
+      listenAddress = mkOption {
+        type = types.str;
+        default = "127.0.0.1";
+        description = "Address to listen on.";
+      };
+
+      listenPort = mkOption {
+        type = types.int;
+        default = 8091;
+        description = "Port to listen on.";
+      };
+
+      catalinaOptions = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        example = [ "-Xms1024m" "-Xmx2048m" ];
+        description = "Java options to pass to catalina/tomcat.";
+      };
+
+      proxy = {
+        enable = mkEnableOption "reverse proxy support";
+
+        name = mkOption {
+          type = types.str;
+          example = "jira.example.com";
+          description = "Virtual hostname at the proxy";
+        };
+
+        port = mkOption {
+          type = types.int;
+          default = 443;
+          example = 80;
+          description = "Port used at the proxy";
+        };
+
+        scheme = mkOption {
+          type = types.str;
+          default = "https";
+          example = "http";
+          description = "Protocol used at the proxy.";
+        };
+
+        secure = mkOption {
+          type = types.bool;
+          default = true;
+          example = false;
+          description = "Whether the connections to the proxy should be considered secure.";
+        };
+      };
+
+      jrePackage = let
+        jreSwitch = unfree: free: if config.nixpkgs.config.allowUnfree or false then unfree else free;
+      in mkOption {
+        type = types.package;
+        default = jreSwitch pkgs.oraclejre8 pkgs.openjdk8.jre;
+        defaultText = jreSwitch "pkgs.oraclejre8" "pkgs.openjdk8.jre";
+        example = literalExample "pkgs.openjdk8.jre";
+        description = "Java Runtime to use for JIRA. Note that Atlassian recommends the Oracle JRE.";
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    users.extraUsers."${cfg.user}" = {
+      isSystemUser = true;
+      group = cfg.group;
+    };
+
+    users.extraGroups."${cfg.group}" = {};
+
+    systemd.services.atlassian-jira = {
+      description = "Atlassian JIRA";
+
+      wantedBy = [ "multi-user.target" ];
+      requires = [ "postgresql.service" ];
+      after = [ "postgresql.service" ];
+
+      path = [ cfg.jrePackage ];
+
+      environment = {
+        JIRA_USER = cfg.user;
+        JIRA_HOME = cfg.home;
+        JAVA_HOME = "${cfg.jrePackage}";
+        CATALINA_OPTS = concatStringsSep " " cfg.catalinaOptions;
+      };
+
+      preStart = ''
+        mkdir -p ${cfg.home}/{logs,work,temp,deploy}
+
+        mkdir -p /run/atlassian-jira
+        ln -sf ${cfg.home}/{logs,work,temp,server.xml} /run/atlassian-jira
+        ln -sf ${cfg.home} /run/atlassian-jira/home
+
+        chown -R ${cfg.user} ${cfg.home}
+
+        sed -e 's,port="8080",port="${toString cfg.listenPort}" address="${cfg.listenAddress}",' \
+        '' + (lib.optionalString cfg.proxy.enable ''
+          -e 's,protocol="HTTP/1.1",protocol="HTTP/1.1" proxyName="${cfg.proxy.name}" proxyPort="${toString cfg.proxy.port}" scheme="${cfg.proxy.scheme}" secure="${toString cfg.proxy.secure}",' \
+        '') + ''
+          ${pkg}/conf/server.xml.dist > ${cfg.home}/server.xml
+      '';
+
+      script = "${pkg}/bin/start-jira.sh -fg";
+      stopScript  = "${pkg}/bin/stop-jira.sh";
+
+      serviceConfig = {
+        User = cfg.user;
+        Group = cfg.group;
+        PrivateTmp = true;
+        PermissionsStartOnly = true;
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/web-apps/nixbot.nix b/nixos/modules/services/web-apps/nixbot.nix
new file mode 100644
index 00000000000..0592d01bf36
--- /dev/null
+++ b/nixos/modules/services/web-apps/nixbot.nix
@@ -0,0 +1,149 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.nixbot;
+  pyramidIni = ''
+    ###
+    # app configuration
+    # http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/environment.html
+    ###
+
+    [app:main]
+    use = egg:nixbot
+
+    nixbot.github_token = ${cfg.githubToken}
+    nixbot.bot_name = ${cfg.botName}
+    nixbot.repo = ${cfg.repo}
+    nixbot.pr_repo = ${cfg.prRepo}
+    nixbot.hydra_jobsets_repo = ${cfg.hydraJobsetsRepo}
+    nixbot.github_secret = justnotsorandom
+    nixbot.public_url = ${cfg.publicUrl}
+    nixbot.repo_dir = ${cfg.repoDir}
+
+    pyramid.reload_templates = false
+    pyramid.debug_authorization = false
+    pyramid.debug_notfound = false
+    pyramid.debug_routematch = false
+    pyramid.default_locale_name = en
+
+    # By default, the toolbar only appears for clients from IP addresses
+    # '127.0.0.1' and '::1'.
+    # debugtoolbar.hosts = 127.0.0.1 ::1
+
+    ###
+    # wsgi server configuration
+    ###
+
+    [server:main]
+    use = egg:waitress#main
+    host = 0.0.0.0
+    port = 6543
+
+    ###
+    # logging configuration
+    # http://docs.pylonsproject.org/projects/pyramid/en/1.7-branch/narr/logging.html
+    ###
+
+    [loggers]
+    keys = root, nixbot
+
+    [handlers]
+    keys = console
+
+    [formatters]
+    keys = generic
+
+    [logger_root]
+    level = INFO
+    handlers = console
+
+    [logger_nixbot]
+    level = INFO
+    handlers =
+    qualname = nixbot
+
+    [handler_console]
+    class = StreamHandler
+    args = (sys.stderr,)
+    level = NOTSET
+    formatter = generic
+
+    [formatter_generic]
+    format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] %(message)s
+  '';
+in {
+  options = {
+    services.nixbot = {
+      enable = mkEnableOption "nixbot";
+
+      botName = mkOption {
+        type = types.str;
+        description = "The bot's github user account name.";
+        default = "nixbot";
+      };
+
+      githubToken = mkOption {
+        type = types.str;
+        description = "The bot's github user account token.";
+        example = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
+      };
+
+      repo = mkOption {
+        type = types.str;
+        description = "The github repository to check for PRs.";
+        example = "nixos/nixpkgs";
+      };
+
+      prRepo = mkOption {
+        type = types.str;
+        description = "The github repository to push the testing branches to.";
+        example = "nixos/nixpkgs-pr";
+      };
+
+      hydraJobsetsRepo = mkOption {
+        type = types.str;
+        description = "The github repository to push the hydra jobset definitions to.";
+        example = "nixos/hydra-jobsets";
+      };
+
+      publicUrl = mkOption {
+        type = types.str;
+        description = "The public URL the bot is reachable at (Github hook endpoint).";
+        example = "https://nixbot.nixos.org";
+      };
+
+      repoDir = mkOption {
+        type = types.path;
+        description = "The directory the repositories are stored in.";
+        default = "/var/lib/nixbot";
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    users.extraUsers.nixbot = {
+      createHome = true;
+      home = cfg.repoDir;
+    };
+
+    systemd.services.nixbot = let
+      env = pkgs.python3.buildEnv.override {
+        extraLibs = [ pkgs.nixbot ];
+      };
+    in {
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+      script = ''
+        ${env}/bin/pserve ${pkgs.writeText "production.ini" pyramidIni}
+      '';
+
+      serviceConfig = {
+        User = "nixbot";
+        Group = "nogroup";
+        PermissionsStartOnly = true;
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/web-apps/quassel-webserver.nix b/nixos/modules/services/web-apps/quassel-webserver.nix
new file mode 100644
index 00000000000..d19e4bc5827
--- /dev/null
+++ b/nixos/modules/services/web-apps/quassel-webserver.nix
@@ -0,0 +1,101 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.quassel-webserver;
+  quassel-webserver = cfg.pkg;
+  settings = ''
+    module.exports = {
+      default: {
+        host: '${cfg.quasselCoreHost}',  // quasselcore host
+        port: ${toString cfg.quasselCorePort},  // quasselcore port
+        initialBacklogLimit: ${toString cfg.initialBacklogLimit},  // Amount of backlogs to fetch per buffer on connection
+        backlogLimit: ${toString cfg.backlogLimit},  // Amount of backlogs to fetch per buffer after first retrieval
+        securecore: ${if cfg.secureCore then "true" else "false"},  // Connect to the core using SSL
+        theme: '${cfg.theme}'  // Default UI theme
+      },
+      themes: ['default', 'darksolarized'],  //  Available themes
+      forcedefault: ${if cfg.forceHostAndPort then "true" else "false"},  // Will force default host and port to be used, and will hide the corresponding fields in the UI
+      prefixpath: '${cfg.prefixPath}'  // Configure this if you use a reverse proxy
+    };
+  '';
+  settingsFile = pkgs.writeText "settings-user.js" settings;
+in {
+  options = {
+    services.quassel-webserver = {
+      enable = mkOption {
+        default = false;
+        type = types.bool;
+        description = "Whether to enable the quassel webclient service";
+      };
+      pkg = mkOption {
+        default = pkgs.quassel-webserver;
+        defaultText = "pkgs.quassel-webserver";
+        type = types.package;
+        description = "The quassel-webserver package";
+      };
+      quasselCoreHost = mkOption {
+        default = "";
+        type = types.str;
+        description = "The default host of the quassel core";
+      };
+      quasselCorePort = mkOption {
+        default = 4242;
+        type = types.int;
+        description = "The default quassel core port";
+      };
+      initialBacklogLimit = mkOption {
+        default = 20;
+        type = types.int;
+        description = "Amount of backlogs to fetch per buffer on connection";
+      };
+      backlogLimit = mkOption {
+        default = 100;
+        type = types.int;
+        description = "Amount of backlogs to fetch per buffer after first retrieval";
+      };
+      secureCore = mkOption {
+        default = true;
+        type = types.bool;
+        description = "Connect to the core using SSL";
+      };
+      theme = mkOption {
+        default = "default";
+        type = types.str;
+        description = "default or darksolarized";
+      };
+      prefixPath = mkOption {
+        default = "";
+        type = types.str;
+        description = "Configure this if you use a reverse proxy. Must start with a '/'";
+        example = "/quassel";
+      };
+      port = mkOption {
+        default = 60443;
+        type = types.int;
+        description = "The port the quassel webserver should listen on";
+      };
+      useHttps = mkOption {
+        default = true;
+        type = types.bool;
+        description = "Whether the quassel webserver connection should be a https connection";
+      };
+      forceHostAndPort = mkOption {
+        default = false;
+        type = types.bool;
+        description = "Force the users to use the quasselCoreHost and quasselCorePort defaults";
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.services.quassel-webserver = {
+      description = "A web server/client for Quassel";
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        ExecStart = "${quassel-webserver}/lib/node_modules/quassel-webserver/bin/www -p ${toString cfg.port} -m ${if cfg.useHttps == true then "https" else "http"} -c ${settingsFile}";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/web-apps/selfoss.nix b/nixos/modules/services/web-apps/selfoss.nix
new file mode 100644
index 00000000000..5571f77334c
--- /dev/null
+++ b/nixos/modules/services/web-apps/selfoss.nix
@@ -0,0 +1,166 @@
+{ config, lib, pkgs, ... }:
+with lib;
+let
+  cfg = config.services.selfoss;
+
+  poolName = "selfoss_pool";
+  phpfpmSocketName = "/var/run/phpfpm/${poolName}.sock";
+
+  dataDir = "/var/lib/selfoss";
+
+  selfoss-config =
+  let
+    db_type = cfg.database.type;
+    default_port = if (db_type == "mysql") then 3306 else 5342;
+  in
+  pkgs.writeText "selfoss-config.ini" ''
+    [globals]
+    ${lib.optionalString (db_type != "sqlite") ''
+      db_type=${db_type}
+      db_host=${cfg.database.host}
+      db_database=${cfg.database.name}
+      db_username=${cfg.database.user}
+      db_password=${cfg.database.password}
+      db_port=${if (cfg.database.port != null) then cfg.database.port
+                    else default_port}
+    ''
+    }
+    ${cfg.extraConfig}
+  '';
+in
+  {
+    options = {
+      services.selfoss = {
+        enable = mkEnableOption "selfoss";
+
+        user = mkOption {
+          type = types.str;
+          default = "nginx";
+          example = "nginx";
+          description = ''
+            User account under which both the service and the web-application run.
+          '';
+        };
+
+        pool = mkOption {
+          type = types.str;
+          default = "${poolName}";
+          description = ''
+            Name of existing phpfpm pool that is used to run web-application.
+            If not specified a pool will be created automatically with
+            default values.
+          '';
+        };
+
+      database = {
+        type = mkOption {
+          type = types.enum ["pgsql" "mysql" "sqlite"];
+          default = "sqlite";
+          description = ''
+            Database to store feeds. Supported are sqlite, pgsql and mysql.
+          '';
+        };
+
+        host = mkOption {
+          type = types.str;
+          default = "localhost";
+          description = ''
+            Host of the database (has no effect if type is "sqlite").
+          '';
+        };
+
+        name = mkOption {
+          type = types.str;
+          default = "tt_rss";
+          description = ''
+            Name of the existing database (has no effect if type is "sqlite").
+          '';
+        };
+
+        user = mkOption {
+          type = types.str;
+          default = "tt_rss";
+          description = ''
+            The database user. The user must exist and has access to
+            the specified database (has no effect if type is "sqlite").
+          '';
+        };
+
+        password = mkOption {
+          type = types.nullOr types.str;
+          default = null;
+          description = ''
+            The database user's password (has no effect if type is "sqlite").
+          '';
+        };
+
+        port = mkOption {
+          type = types.nullOr types.int;
+          default = null;
+          description = ''
+            The database's port. If not set, the default ports will be
+            provided (5432 and 3306 for pgsql and mysql respectively)
+            (has no effect if type is "sqlite").
+          '';
+        };
+      };
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Extra configuration added to config.ini
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+
+    services.phpfpm.poolConfigs = mkIf (cfg.pool == "${poolName}") {
+      "${poolName}" = ''
+        listen = "${phpfpmSocketName}";
+        listen.owner = nginx
+        listen.group = nginx
+        listen.mode = 0600
+        user = nginx
+        pm = dynamic
+        pm.max_children = 75
+        pm.start_servers = 10
+        pm.min_spare_servers = 5
+        pm.max_spare_servers = 20
+        pm.max_requests = 500
+        catch_workers_output = 1
+      '';
+    };
+
+    systemd.services.selfoss-config = {
+      serviceConfig.Type = "oneshot";
+      script = ''
+        mkdir -m 755 -p ${dataDir}
+        cd ${dataDir}
+
+        # Delete all but the "data" folder
+        ls | grep -v data | while read line; do rm -rf $line; done || true
+
+        # Create the files
+        cp -r "${pkgs.selfoss}/"* "${dataDir}"
+        ln -sf "${selfoss-config}" "${dataDir}/config.ini"
+        chown -R "${cfg.user}" "${dataDir}"
+        chmod -R 755 "${dataDir}"
+      '';
+      wantedBy = [ "multi-user.target" ];
+    };
+
+    systemd.services.selfoss-update = {
+      serviceConfig = {
+        ExecStart = "${pkgs.php}/bin/php ${dataDir}/cliupdate.php";
+        User = "${cfg.user}";
+      };
+      startAt = "hourly";
+      after = [ "selfoss-config.service" ];
+      wantedBy = [ "multi-user.target" ];
+
+    };
+
+  };
+}
diff --git a/nixos/modules/services/web-apps/tt-rss.nix b/nixos/modules/services/web-apps/tt-rss.nix
index b08070f1e36..5193814da72 100644
--- a/nixos/modules/services/web-apps/tt-rss.nix
+++ b/nixos/modules/services/web-apps/tt-rss.nix
@@ -18,7 +18,6 @@ let
 
   poolName = "tt-rss";
   phpfpmSocketName = "/var/run/phpfpm/${poolName}.sock";
-  virtualHostName = "tt-rss";
 
   tt-rss-config = pkgs.writeText "config.php" ''
     <?php
@@ -34,10 +33,10 @@ let
       define('MYSQL_CHARSET', 'UTF8');
 
       define('DB_TYPE', '${cfg.database.type}');
-      define('DB_HOST', '${cfg.database.host}');
+      define('DB_HOST', '${optionalString (cfg.database.host != null) cfg.database.host}');
       define('DB_USER', '${cfg.database.user}');
       define('DB_NAME', '${cfg.database.name}');
-      define('DB_PASS', '${escape ["'" "\\"] cfg.database.password}');
+      define('DB_PASS', '${optionalString (cfg.database.password != null) (escape ["'" "\\"] cfg.database.password)}');
       define('DB_PORT', '${toString dbPort}');
 
       define('AUTH_AUTO_CREATE', ${boolToString cfg.auth.autoCreate});
@@ -91,12 +90,21 @@ let
 
       enable = mkEnableOption "tt-rss";
 
+      root = mkOption {
+        type = types.path;
+        default = "/var/lib/tt-rss";
+        example = "/var/lib/tt-rss";
+        description = ''
+          Root of the application.
+        '';
+      };
+
       user = mkOption {
         type = types.str;
         default = "nginx";
         example = "nginx";
         description = ''
-          User account under which both the service and the web-application run.
+          User account under which both the update daemon and the web-application run.
         '';
       };
 
@@ -110,17 +118,13 @@ let
         '';
       };
 
-      # TODO: Re-enable after https://github.com/NixOS/nixpkgs/pull/15862 is merged
-
-      # virtualHost = mkOption {
-      #   type = types.str;
-      #   default = "${virtualHostName}";
-      #   description = ''
-      #     Name of existing nginx virtual host that is used to run web-application.
-      #     If not specified a host will be created automatically with
-      #     default values.
-      #   '';
-      # };
+      virtualHost = mkOption {
+        type = types.nullOr types.str;
+        default = "tt-rss";
+        description = ''
+          Name of the nginx virtualhost to use and setup. If null, do not setup any virtualhost.
+        '';
+      };
 
       database = {
         type = mkOption {
@@ -132,10 +136,10 @@ let
         };
 
         host = mkOption {
-          type = types.str;
-          default = "localhost";
+          type = types.nullOr types.str;
+          default = null;
           description = ''
-            Host of the database.
+            Host of the database. Leave null to use Unix domain socket.
           '';
         };
 
@@ -362,7 +366,7 @@ let
 
       singleUserMode = mkOption {
         type = types.bool;
-        default = true;
+        default = false;
 
         description = ''
           Operate in single user mode, disables all functionality related to
@@ -445,17 +449,15 @@ let
 
   ###### implementation
 
-  config = let
-    root = "/var/lib/tt-rss";
-  in mkIf cfg.enable {
+  config = mkIf cfg.enable {
 
-    services.phpfpm.poolConfigs = if cfg.pool == "${poolName}" then {
+    services.phpfpm.poolConfigs = mkIf (cfg.pool == "${poolName}") {
       "${poolName}" = ''
         listen = "${phpfpmSocketName}";
         listen.owner = nginx
         listen.group = nginx
         listen.mode = 0600
-        user = nginx
+        user = ${cfg.user}
         pm = dynamic
         pm.max_children = 75
         pm.start_servers = 10
@@ -464,36 +466,26 @@ let
         pm.max_requests = 500
         catch_workers_output = 1
       '';
-    } else {};
-
-    # TODO: Re-enable after https://github.com/NixOS/nixpkgs/pull/15862 is merged
-
-    # services.nginx.virtualHosts = if cfg.virtualHost == "${virtualHostName}" then {
-    #   "${virtualHostName}" = {
-    #     root = "${root}";
-    #     extraConfig = ''
-    #       access_log  /var/log/nginx-${virtualHostName}-access.log;
-    #       error_log   /var/log/nginx-${virtualHostName}-error.log;
-    #     '';
-
-    #     locations."/" = {
-    #       extraConfig = ''
-    #         index index.php;
-    #       '';
-    #     };
-
-    #     locations."~ \.php$" = {
-    #       extraConfig = ''
-    #         fastcgi_split_path_info ^(.+\.php)(/.+)$;
-    #         fastcgi_pass unix:${phpfpmSocketName};
-    #         fastcgi_index index.php;
-    #         fastcgi_param SCRIPT_FILENAME ${root}/$fastcgi_script_name;
-
-    #         include ${pkgs.nginx}/conf/fastcgi_params;
-    #       '';
-    #     };
-    #   };
-    # } else {};
+    };
+
+    services.nginx.virtualHosts = mkIf (cfg.virtualHost != null) {
+      "${cfg.virtualHost}" = {
+        root = "${cfg.root}";
+
+        locations."/" = {
+          index = "index.php";
+        };
+
+        locations."~ \.php$" = {
+          extraConfig = ''
+            fastcgi_split_path_info ^(.+\.php)(/.+)$;
+            fastcgi_pass unix:${phpfpmSocketName};
+            fastcgi_index index.php;
+            fastcgi_param SCRIPT_FILENAME ${cfg.root}/$fastcgi_script_name;
+          '';
+        };
+      };
+    };
 
 
     systemd.services.tt-rss = let
@@ -503,35 +495,34 @@ let
         description = "Tiny Tiny RSS feeds update daemon";
 
         preStart = let
-          callSql = if cfg.database.type == "pgsql" then (e: ''
-                 ${optionalString (cfg.database.password != null)
-                   "PGPASSWORD=${cfg.database.password}"} ${pkgs.postgresql95}/bin/psql \
-                     -U ${cfg.database.user}                                            \
-                     -h ${cfg.database.host}                                            \
-                     --port ${toString dbPort}                                          \
-                     -c '${e}'                                                          \
-                     ${cfg.database.name}'')
-
-               else if cfg.database.type == "mysql" then (e: ''
-                 echo '${e}' | ${pkgs.mysql}/bin/mysql                  \
-                   ${optionalString (cfg.database.password != null)
-                     "-p${cfg.database.password}"}                      \
-                   -u ${cfg.database.user}                              \
-                   -h ${cfg.database.host}                              \
-                   -P ${toString dbPort}                                \
-                   ${cfg.database.name}'')
-
-               else "";
+          callSql = e:
+              if cfg.database.type == "pgsql" then ''
+                  ${optionalString (cfg.database.password != null) "PGPASSWORD=${cfg.database.password}"} \
+                  ${pkgs.postgresql95}/bin/psql \
+                    -U ${cfg.database.user} \
+                    ${optionalString (cfg.database.host != null) "-h ${cfg.database.host} --port ${toString dbPort}"} \
+                    -c '${e}' \
+                    ${cfg.database.name}''
+
+              else if cfg.database.type == "mysql" then ''
+                  echo '${e}' | ${pkgs.mysql}/bin/mysql \
+                    -u ${cfg.database.user} \
+                    ${optionalString (cfg.database.password != null) "-p${cfg.database.password}"} \
+                    ${optionalString (cfg.database.host != null) "-h ${cfg.database.host} -P ${toString dbPort}"} \
+                    ${cfg.database.name}''
+
+              else "";
 
         in ''
-          rm -rf "${root}/*"
-          mkdir -m 755 -p "${root}"
-          cp -r "${pkgs.tt-rss}/"* "${root}"
-          ln -sf "${tt-rss-config}" "${root}/config.php"
-          chown -R "${cfg.user}" "${root}"
-          chmod -R 755 "${root}"
-        '' + (optionalString (cfg.database.type == "pgsql") ''
-
+          rm -rf "${cfg.root}/*"
+          mkdir -m 755 -p "${cfg.root}"
+          cp -r "${pkgs.tt-rss}/"* "${cfg.root}"
+          ln -sf "${tt-rss-config}" "${cfg.root}/config.php"
+          chown -R "${cfg.user}" "${cfg.root}"
+          chmod -R 755 "${cfg.root}"
+        ''
+
+        + (optionalString (cfg.database.type == "pgsql") ''
           exists=$(${callSql "select count(*) > 0 from pg_tables where tableowner = user"} \
           | tail -n+3 | head -n-2 | sed -e 's/[ \n\t]*//')
 
@@ -540,8 +531,9 @@ let
           else
             echo 'The database contains some data. Leaving it as it is.'
           fi;
-        '') + (optionalString (cfg.database.type == "mysql") ''
+        '')
 
+        + (optionalString (cfg.database.type == "mysql") ''
           exists=$(${callSql "select count(*) > 0 from information_schema.tables where table_schema = schema()"} \
           | tail -n+2 | sed -e 's/[ \n\t]*//')
 
@@ -554,7 +546,7 @@ let
 
         serviceConfig = {
           User = "${cfg.user}";
-          ExecStart = "${pkgs.php}/bin/php /var/lib/tt-rss/update.php --daemon";
+          ExecStart = "${pkgs.php}/bin/php ${cfg.root}/update.php --daemon";
           StandardOutput = "syslog";
           StandardError = "syslog";
           PermissionsStartOnly = true;
diff --git a/nixos/modules/services/web-servers/apache-httpd/default.nix b/nixos/modules/services/web-servers/apache-httpd/default.nix
index 397857ea085..dc0ca501a48 100644
--- a/nixos/modules/services/web-servers/apache-httpd/default.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/default.nix
@@ -16,7 +16,19 @@ let
 
   phpMajorVersion = head (splitString "." php.version);
 
-  getPort = cfg: if cfg.port != 0 then cfg.port else if cfg.enableSSL then 443 else 80;
+  mod_perl = pkgs.mod_perl.override { apacheHttpd = httpd; };
+
+  defaultListen = cfg: if cfg.enableSSL
+    then [{ip = "*"; port = 443;}]
+    else [{ip = "*"; port = 80;}];
+
+  getListen = cfg:
+    let list = (lib.optional (cfg.port != 0) {ip = "*"; port = cfg.port;}) ++ cfg.listen;
+    in if list == []
+        then defaultListen cfg
+        else list;
+
+  listenToString = l: "${l.ip}:${toString l.port}";
 
   extraModules = attrByPath ["extraModules"] [] mainCfg;
   extraForeignModules = filter isAttrs extraModules;
@@ -25,10 +37,13 @@ let
 
   makeServerInfo = cfg: {
     # Canonical name must not include a trailing slash.
-    canonicalName =
-      (if cfg.enableSSL then "https" else "http") + "://" +
-      cfg.hostName +
-      (if getPort cfg != (if cfg.enableSSL then 443 else 80) then ":${toString (getPort cfg)}" else "");
+    canonicalNames =
+      let defaultPort = (head (defaultListen cfg)).port; in
+      map (port:
+        (if cfg.enableSSL then "https" else "http") + "://" +
+        cfg.hostName +
+        (if port != defaultPort then ":${toString port}" else "")
+        ) (map (x: x.port) (getListen cfg));
 
     # Admin address: inherit from the main server if not specified for
     # a virtual host.
@@ -63,6 +78,7 @@ let
           robotsEntries = "";
           startupScript = "";
           enablePHP = false;
+          enablePerl = false;
           phpOptions = "";
           options = {};
           documentRoot = null;
@@ -224,7 +240,7 @@ let
         ++ (map (svc: svc.robotsEntries) subservices)));
 
   in ''
-    ServerName ${serverInfo.canonicalName}
+    ${concatStringsSep "\n" (map (n: "ServerName ${n}") serverInfo.canonicalNames)}
 
     ${concatMapStrings (alias: "ServerAlias ${alias}\n") cfg.serverAliases}
 
@@ -326,9 +342,10 @@ let
     </IfModule>
 
     ${let
-        ports = map getPort allHosts;
-        uniquePorts = uniqList {inputList = ports;};
-      in concatMapStrings (port: "Listen ${toString port}\n") uniquePorts
+        listen = concatMap getListen allHosts;
+        toStr = listen: "Listen ${listenToString listen}\n";
+        uniqueListen = uniqList {inputList = map toStr listen;};
+      in concatStrings uniqueListen
     }
 
     User ${mainCfg.user}
@@ -341,6 +358,7 @@ let
           ++ map (name: {inherit name; path = "${httpd}/modules/mod_${name}.so";}) apacheModules
           ++ optional mainCfg.enableMellon { name = "auth_mellon"; path = "${pkgs.apacheHttpdPackages.mod_auth_mellon}/modules/mod_auth_mellon.so"; }
           ++ optional enablePHP { name = "php${phpMajorVersion}"; path = "${php}/modules/libphp${phpMajorVersion}.so"; }
+          ++ optional enablePerl { name = "perl"; path = "${mod_perl}/modules/mod_perl.so"; }
           ++ concatMap (svc: svc.extraModules) allSubservices
           ++ extraForeignModules;
       in concatMapStrings load allModules
@@ -382,15 +400,15 @@ let
 
     # Always enable virtual hosts; it doesn't seem to hurt.
     ${let
-        ports = map getPort allHosts;
-        uniquePorts = uniqList {inputList = ports;};
-        directives = concatMapStrings (port: "NameVirtualHost *:${toString port}\n") uniquePorts;
+        listen = concatMap getListen allHosts;
+        uniqueListen = uniqList {inputList = listen;};
+        directives = concatMapStrings (listen: "NameVirtualHost ${listenToString listen}\n") uniqueListen;
       in optionalString (!version24) directives
     }
 
     ${let
         makeVirtualHost = vhost: ''
-          <VirtualHost *:${toString (getPort vhost)}>
+          <VirtualHost ${concatStringsSep " " (map listenToString (getListen vhost))}>
               ${perServerConf false vhost}
           </VirtualHost>
         '';
@@ -401,6 +419,8 @@ let
 
   enablePHP = mainCfg.enablePHP || any (svc: svc.enablePHP) allSubservices;
 
+  enablePerl = mainCfg.enablePerl || any (svc: svc.enablePerl) allSubservices;
+
 
   # Generate the PHP configuration file.  Should probably be factored
   # out into a separate module.
@@ -565,6 +585,12 @@ in
         '';
       };
 
+      enablePerl = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Whether to enable the Perl module (mod_perl).";
+      };
+
       phpOptions = mkOption {
         type = types.lines;
         default = "";
@@ -628,6 +654,8 @@ in
                      message = "SSL is enabled for httpd, but sslServerCert and/or sslServerKey haven't been specified."; }
                  ];
 
+    warnings = map (cfg: ''apache-httpd's port option is deprecated. Use listen = [{/*ip = "*"; */ port = ${toString cfg.port}";}]; instead'' ) (lib.filter (cfg: cfg.port != 0) allHosts);
+
     users.extraUsers = optionalAttrs (mainCfg.user == "wwwrun") (singleton
       { name = "wwwrun";
         group = mainCfg.group;
@@ -681,13 +709,6 @@ in
             ''}
             mkdir -m 0700 -p ${mainCfg.logDir}
 
-            ${optionalString (mainCfg.documentRoot != null)
-            ''
-              # Create the document root directory if does not exists yet
-              mkdir -p ${mainCfg.documentRoot}
-            ''
-            }
-
             # Get rid of old semaphores.  These tend to accumulate across
             # server restarts, eventually preventing it from restarting
             # successfully.
@@ -712,5 +733,4 @@ in
       };
 
   };
-
 }
diff --git a/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix b/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix
index b4b5a6fdc07..1ed489bcb09 100644
--- a/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix
@@ -83,11 +83,11 @@ let
 
   # Unpack Mediawiki and put the config file in its root directory.
   mediawikiRoot = pkgs.stdenv.mkDerivation rec {
-    name= "mediawiki-1.23.13";
+    name= "mediawiki-1.27.1";
 
     src = pkgs.fetchurl {
-      url = "http://download.wikimedia.org/mediawiki/1.23/${name}.tar.gz";
-      sha256 = "168wpf53n4ksj2g5q5r0hxapx6238dvsfng5ff9ixk6axsn0j5d0";
+      url = "http://download.wikimedia.org/mediawiki/1.27/${name}.tar.gz";
+      sha256 = "0sm3ymz93qragbwhzzbwq7f127mbj29inv0afg2z6p32jb1pd9h8";
     };
 
     skins = config.skins;
@@ -288,6 +288,7 @@ in
     };
 
     extraConfig = mkOption {
+      type = types.lines;
       default = "";
       example =
         ''
diff --git a/nixos/modules/services/web-servers/apache-httpd/moodle.nix b/nixos/modules/services/web-servers/apache-httpd/moodle.nix
index 87b1fba5aa1..d525348d5c7 100644
--- a/nixos/modules/services/web-servers/apache-httpd/moodle.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/moodle.nix
@@ -63,6 +63,10 @@ let
         cp -r * $out
         cp ${moodleConfig} $out/config.php
       '';
+    # Marked as broken due to needing an update for security issues.
+    # See: https://github.com/NixOS/nixpkgs/issues/18856
+    meta.broken = true;
+
   };
 
 in
@@ -160,6 +164,7 @@ in
 
 
     extraConfig = mkOption {
+      type = types.lines;
       default = "";
       example =
         ''
diff --git a/nixos/modules/services/web-servers/apache-httpd/per-server-options.nix b/nixos/modules/services/web-servers/apache-httpd/per-server-options.nix
index 5abcc5e7490..1d53ce65900 100644
--- a/nixos/modules/services/web-servers/apache-httpd/per-server-options.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/per-server-options.nix
@@ -28,9 +28,30 @@ with lib;
     type = types.int;
     default = 0;
     description = ''
-      Port for the server.  0 means use the default port: 80 for http
-      and 443 for https (i.e. when enableSSL is set).
+      Port for the server. Option will be removed, use <option>listen</option> instead.
+  '';
+  };
+
+  listen = mkOption {
+     type = types.listOf (types.submodule (
+          {
+            options = {
+              port = mkOption {
+                type = types.int;
+                description = "port to listen on";
+              };
+              ip = mkOption {
+                type = types.string;
+                default = "*";
+                description = "Ip to listen on. 0.0.0.0 for ipv4 only, * for all.";
+              };
+            };
+          } ));
+    description = ''
+      List of { /* ip: "*"; */ port = 80;} to listen on
     '';
+
+    default = [];
   };
 
   enableSSL = mkOption {
diff --git a/nixos/modules/services/web-servers/apache-httpd/trac.nix b/nixos/modules/services/web-servers/apache-httpd/trac.nix
index 3196edc2838..35b9ab56087 100644
--- a/nixos/modules/services/web-servers/apache-httpd/trac.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/trac.nix
@@ -99,10 +99,9 @@ in
         makeSearchPathOutput "lib" "lib/${pkgs.python.libPrefix}/site-packages"
           [ pkgs.mod_python
             pkgs.pythonPackages.trac
-            pkgs.setuptools
+            pkgs.pythonPackages.setuptools
             pkgs.pythonPackages.genshi
             pkgs.pythonPackages.psycopg2
-            pkgs.python.modules.sqlite3
             subversion
           ];
     };
diff --git a/nixos/modules/services/web-servers/apache-httpd/wordpress.nix b/nixos/modules/services/web-servers/apache-httpd/wordpress.nix
index 937b2698ce9..32dd4439675 100644
--- a/nixos/modules/services/web-servers/apache-httpd/wordpress.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/wordpress.nix
@@ -5,7 +5,8 @@ with lib;
 
 let
 
-  version = "4.3.1";
+  # Upgrading? We have a test! nix-build ./nixos/tests/wordpress.nix
+  version = "4.6.1";
   fullversion = "${version}";
 
   # Our bare-bones wp-config.php file using the above settings
@@ -74,7 +75,7 @@ let
       owner = "WordPress";
       repo = "WordPress";
       rev = "${fullversion}";
-      sha256 = "1rk10vcv4z9p04hfzc0wkbilrgx7m9ssyr6c3w6vw3vl1bcgqxza";
+      sha256 = "0n82xgjg1ry2p73hhgpslnkdzrma5n6hxxq76s7qskkzj0qjfvpn";
     };
     installPhase = ''
       mkdir -p $out
@@ -98,7 +99,7 @@ let
       # symlink additional plugin(s)
       ${concatMapStrings (plugin: "ln -s ${plugin} $out/wp-content/plugins/${plugin.name}\n") (config.plugins) }
 
-      # symlink additional translation(s) 
+      # symlink additional translation(s)
       mkdir -p $out/wp-content/languages
       ${concatMapStrings (language: "ln -s ${language}/*.mo ${language}/*.po $out/wp-content/languages/\n") (selectedLanguages) }
     '';
@@ -123,7 +124,7 @@ in
   options = {
     dbHost = mkOption {
       default = "localhost";
-      description = "The location of the database server.";  
+      description = "The location of the database server.";
       example = "localhost";
     };
     dbName = mkOption {
@@ -211,6 +212,7 @@ in
           example = "[ \"en_GB\" \"de_DE\" ];";
     };
     extraConfig = mkOption {
+      type = types.lines;
       default = "";
       example =
         ''
@@ -244,7 +246,6 @@ in
     chown ${serverInfo.serverConfig.user} ${config.wordpressUploads}
 
     # we should use systemd dependencies here
-    #waitForUnit("network-interfaces.target");
     if [ ! -d ${serverInfo.fullConfig.services.mysql.dataDir}/${config.dbName} ]; then
       echo "Need to create the database '${config.dbName}' and grant permissions to user named '${config.dbUser}'."
       # Wait until MySQL is up
@@ -253,7 +254,7 @@ in
       done
       ${pkgs.mysql}/bin/mysql -e 'CREATE DATABASE ${config.dbName};'
       ${pkgs.mysql}/bin/mysql -e 'GRANT ALL ON ${config.dbName}.* TO ${config.dbUser}@localhost IDENTIFIED BY "${config.dbPassword}";'
-    else 
+    else
       echo "Good, no need to do anything database related."
     fi
   '';
diff --git a/nixos/modules/services/web-servers/fcgiwrap.nix b/nixos/modules/services/web-servers/fcgiwrap.nix
index 2c5e433003c..a64a187255a 100644
--- a/nixos/modules/services/web-servers/fcgiwrap.nix
+++ b/nixos/modules/services/web-servers/fcgiwrap.nix
@@ -21,7 +21,7 @@ in {
       };
 
       socketType = mkOption {
-        type = types.addCheck types.str (t: t == "unix" || t == "tcp" || t == "tcp6");
+        type = types.enum [ "unix" "tcp" "tcp6" ];
         default = "unix";
         description = "Socket type: 'unix', 'tcp' or 'tcp6'.";
       };
diff --git a/nixos/modules/services/web-servers/lighttpd/inginious.nix b/nixos/modules/services/web-servers/lighttpd/inginious.nix
index 43deccb6aef..669e81d0f14 100644
--- a/nixos/modules/services/web-servers/lighttpd/inginious.nix
+++ b/nixos/modules/services/web-servers/lighttpd/inginious.nix
@@ -191,9 +191,8 @@ in
         virtualisation.docker = {
           enable = true;
           # We need docker to listen on port 2375.
-          extraOptions = "-H tcp://127.0.0.1:2375 -H unix:///var/run/docker.sock";
+          listenOptions = ["127.0.0.1:2375" "/var/run/docker.sock"];
           storageDriver = mkDefault "overlay";
-          socketActivation = false;
         };
 
         users.extraUsers."lighttpd".extraGroups = [ "docker" ];
diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix
index 6e62606f323..68a672c42c9 100644
--- a/nixos/modules/services/web-servers/nginx/default.nix
+++ b/nixos/modules/services/web-servers/nginx/default.nix
@@ -10,6 +10,7 @@ let
       sslCertificateKey = "/var/lib/acme/${vhostName}/key.pem";
     })
   ) cfg.virtualHosts;
+  enableIPv6 = config.networking.enableIPv6;
 
   configFile = pkgs.writeText "nginx.conf" ''
     user ${cfg.user} ${cfg.group};
@@ -18,9 +19,13 @@ let
 
     ${cfg.config}
 
-    ${optionalString (cfg.httpConfig == "" && cfg.config == "") ''
-    events {}
+    ${optionalString (cfg.eventsConfig != "" || cfg.config == "") ''
+    events {
+      ${cfg.eventsConfig}
+    }
+    ''}
 
+    ${optionalString (cfg.httpConfig == "" && cfg.config == "") ''
     http {
       include ${cfg.package}/conf/mime.types;
       include ${cfg.package}/conf/fastcgi.conf;
@@ -80,7 +85,7 @@ let
       ${optionalString cfg.statusPage ''
         server {
           listen 80;
-          listen [::]:80;
+          ${optionalString enableIPv6 "listen [::]:80;" }
 
           server_name localhost;
 
@@ -88,7 +93,7 @@ let
             stub_status on;
             access_log off;
             allow 127.0.0.1;
-            allow ::1;
+            ${optionalString enableIPv6 "allow ::1;"}
             deny all;
           }
         }
@@ -98,7 +103,6 @@ let
     }''}
 
     ${optionalString (cfg.httpConfig != "") ''
-    events {}
     http {
       include ${cfg.package}/conf/mime.types;
       include ${cfg.package}/conf/fastcgi.conf;
@@ -113,35 +117,38 @@ let
         ssl = vhost.enableSSL || vhost.forceSSL;
         port = if vhost.port != null then vhost.port else (if ssl then 443 else 80);
         listenString = toString port + optionalString ssl " ssl http2"
-          + optionalString vhost.default " default";
-        acmeLocation = optionalString vhost.enableACME ''
+          + optionalString vhost.default " default_server";
+        acmeLocation = optionalString vhost.enableACME (''
           location /.well-known/acme-challenge {
-            try_files $uri @acme-fallback;
+            ${optionalString (vhost.acmeFallbackHost != null) "try_files $uri @acme-fallback;"}
             root ${vhost.acmeRoot};
             auth_basic off;
           }
+        '' + (optionalString (vhost.acmeFallbackHost != null) ''
           location @acme-fallback {
             auth_basic off;
             proxy_pass http://${vhost.acmeFallbackHost};
           }
-        '';
+        ''));
       in ''
         ${optionalString vhost.forceSSL ''
           server {
-            listen 80 ${optionalString vhost.default "default"};
-            listen [::]:80 ${optionalString vhost.default "default"};
+            listen 80 ${optionalString vhost.default "default_server"};
+            ${optionalString enableIPv6
+              ''listen [::]:80 ${optionalString vhost.default "default_server"};''
+            }
 
             server_name ${serverName} ${concatStringsSep " " vhost.serverAliases};
             ${acmeLocation}
             location / {
-              return 301 https://$host${optionalString (port != 443) ":${port}"}$request_uri;
+              return 301 https://$host${optionalString (port != 443) ":${toString port}"}$request_uri;
             }
           }
         ''}
 
         server {
           listen ${listenString};
-          listen [::]:${listenString};
+          ${optionalString enableIPv6 "listen [::]:${listenString};"}
 
           server_name ${serverName} ${concatStringsSep " " vhost.serverAliases};
           ${acmeLocation}
@@ -271,12 +278,20 @@ in
         ";
       };
 
+      eventsConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Configuration lines to be set inside the events block.
+        '';
+      };
+
       appendHttpConfig = mkOption {
         type = types.lines;
         default = "";
         description = "
           Configuration lines to be appended to the generated http block.
-          This is mutually exclusive with using config and httpConfig for 
+          This is mutually exclusive with using config and httpConfig for
           specifying the whole http block verbatim.
         ";
       };
@@ -380,8 +395,13 @@ in
     security.acme.certs = filterAttrs (n: v: v != {}) (
       mapAttrs (vhostName: vhostConfig:
         optionalAttrs vhostConfig.enableACME {
+          user = cfg.user;
+          group = cfg.group;
           webroot = vhostConfig.acmeRoot;
           extraDomains = genAttrs vhostConfig.serverAliases (alias: null);
+          postRun = ''
+            systemctl reload nginx
+          '';
         }
       ) virtualHosts
     );
diff --git a/nixos/modules/services/web-servers/nginx/vhost-options.nix b/nixos/modules/services/web-servers/nginx/vhost-options.nix
index ee3f68bf805..dcebbc9229f 100644
--- a/nixos/modules/services/web-servers/nginx/vhost-options.nix
+++ b/nixos/modules/services/web-servers/nginx/vhost-options.nix
@@ -39,8 +39,8 @@ with lib;
     };
 
     acmeFallbackHost = mkOption {
-      type = types.str;
-      default = "0.0.0.0";
+      type = types.nullOr types.str;
+      default = null;
       description = ''
         Host which to proxy requests to if acme challenge is not found. Useful
         if you want multiple hosts to be able to verify the same domain name.
diff --git a/nixos/modules/services/web-servers/phpfpm/default.nix b/nixos/modules/services/web-servers/phpfpm/default.nix
index 29cfbb8e9a0..ed537e7122a 100644
--- a/nixos/modules/services/web-servers/phpfpm/default.nix
+++ b/nixos/modules/services/web-servers/phpfpm/default.nix
@@ -7,8 +7,6 @@ let
 
   stateDir = "/run/phpfpm";
 
-  pidFile = "${stateDir}/phpfpm.pid";
-
   mkPool = n: p: ''
     [${n}]
     listen = ${p.listen}
@@ -17,9 +15,8 @@ let
 
   cfgFile = pkgs.writeText "phpfpm.conf" ''
     [global]
-    pid = ${pidFile}
     error_log = syslog
-    daemonize = yes
+    daemonize = no
     ${cfg.extraConfig}
 
     ${concatStringsSep "\n" (mapAttrsToList mkPool cfg.pools)}
@@ -42,8 +39,8 @@ in {
         default = "";
         description = ''
           Extra configuration that should be put in the global section of
-          the PHP FPM configuration file. Do not specify the options
-          <literal>pid</literal>, <literal>error_log</literal> or
+          the PHP-FPM configuration file. Do not specify the options
+          <literal>error_log</literal> or
           <literal>daemonize</literal> here, since they are generated by
           NixOS.
         '';
@@ -54,7 +51,7 @@ in {
         default = pkgs.php;
         defaultText = "pkgs.php";
         description = ''
-          The PHP package to use for running the FPM service.
+          The PHP package to use for running the PHP-FPM service.
         '';
       };
 
@@ -86,7 +83,7 @@ in {
           }
         '';
         description = ''
-          A mapping between PHP FPM pool names and their configurations.
+          A mapping between PHP-FPM pool names and their configurations.
           See the documentation on <literal>php-fpm.conf</literal> for
           details on configuration directives. If no pools are defined,
           the phpfpm service is disabled.
@@ -98,8 +95,24 @@ in {
           inherit lib;
         }));
         default = {};
+        example = literalExample ''
+         {
+           mypool = {
+             listen = "/path/to/unix/socket";
+             extraConfig = '''
+               user = nobody
+               pm = dynamic
+               pm.max_children = 75
+               pm.start_servers = 10
+               pm.min_spare_servers = 5
+               pm.max_spare_servers = 20
+               pm.max_requests = 500
+             ''';
+           }
+         }'';
         description = ''
-          If no pools are defined, the phpfpm service is disabled.
+          PHP-FPM pools. If no pools or poolConfigs are defined, the PHP-FPM
+          service is disabled.
         '';
       };
     };
@@ -113,10 +126,10 @@ in {
         mkdir -p "${stateDir}"
       '';
       serviceConfig = {
+        Type = "notify";
         ExecStart = "${cfg.phpPackage}/bin/php-fpm -y ${cfgFile} -c ${phpIni}";
-        PIDFile = pidFile;
+        ExecReload = "${pkgs.coreutils}/bin/kill -USR2 $MAINPID";
       };
     };
-
   };
 }
diff --git a/nixos/modules/services/web-servers/tomcat.nix b/nixos/modules/services/web-servers/tomcat.nix
index c3be20b41e2..943415e08c6 100644
--- a/nixos/modules/services/web-servers/tomcat.nix
+++ b/nixos/modules/services/web-servers/tomcat.nix
@@ -10,6 +10,10 @@ in
 
 {
 
+  meta = {
+    maintainers = with maintainers; [ danbst ];
+  };
+
   ###### interface
 
   options = {
@@ -23,9 +27,9 @@ in
 
       package = mkOption {
         type = types.package;
-        default = pkgs.tomcat7;
-        defaultText = "pkgs.tomcat7";
-        example = lib.literalExample "pkgs.tomcat8";
+        default = pkgs.tomcat85;
+        defaultText = "pkgs.tomcat85";
+        example = lib.literalExample "pkgs.tomcatUnstable";
         description = ''
           Which tomcat package to use.
         '';
@@ -74,8 +78,8 @@ in
 
       webapps = mkOption {
         type = types.listOf types.package;
-        default = [ tomcat ];
-        defaultText = "[ tomcat ]";
+        default = [ tomcat.webapps ];
+        defaultText = "[ tomcat.webapps ]";
         description = "List containing WAR files or directories with WAR files which are web applications to be deployed on Tomcat";
       };
 
@@ -135,7 +139,7 @@ in
     systemd.services.tomcat = {
       description = "Apache Tomcat server";
       wantedBy = [ "multi-user.target" ];
-      after = [ "network-interfaces.target" ];
+      after = [ "network.target" ];
       serviceConfig.Type = "oneshot";
       serviceConfig.RemainAfterExit = true;
 
@@ -352,7 +356,7 @@ in
           ${pkgs.su}/bin/su -s ${pkgs.bash}/bin/sh ${cfg.user} -c 'CATALINA_BASE=${cfg.baseDir} JAVA_HOME=${cfg.jdk} JAVA_OPTS="${cfg.javaOpts}" CATALINA_OPTS="${cfg.catalinaOpts}" ${tomcat}/bin/startup.sh'
       '';
 
-      postStop = ''
+      preStop = ''
         echo "Stopping tomcat..."
         CATALINA_BASE=${cfg.baseDir} JAVA_HOME=${cfg.jdk} ${pkgs.su}/bin/su -s ${pkgs.bash}/bin/sh ${cfg.user} -c ${tomcat}/bin/shutdown.sh
       '';
diff --git a/nixos/modules/services/web-servers/uwsgi.nix b/nixos/modules/services/web-servers/uwsgi.nix
index 56f077e62a8..14596bb3add 100644
--- a/nixos/modules/services/web-servers/uwsgi.nix
+++ b/nixos/modules/services/web-servers/uwsgi.nix
@@ -29,7 +29,6 @@ let
 
       pythonPackages = pkgs.pythonPackages.override {
         inherit python;
-        self = pythonPackages;
       };
 
       penv = python.buildEnv.override {
diff --git a/nixos/modules/services/web-servers/winstone.nix b/nixos/modules/services/web-servers/winstone.nix
index 6dab467b35e..064ead5ce4b 100644
--- a/nixos/modules/services/web-servers/winstone.nix
+++ b/nixos/modules/services/web-servers/winstone.nix
@@ -113,8 +113,7 @@ in {
   options = {
     services.winstone = mkOption {
       default = {};
-      type = types.attrsOf types.optionSet;
-      options = [ winstoneOpts ];
+      type = with types; attrsOf (submodule winstoneOpts);
       description = ''
         Defines independent Winstone services, each serving one WAR-file.
       '';
diff --git a/nixos/modules/services/web-servers/zope2.nix b/nixos/modules/services/web-servers/zope2.nix
index ef3cffd582e..8a453e01557 100644
--- a/nixos/modules/services/web-servers/zope2.nix
+++ b/nixos/modules/services/web-servers/zope2.nix
@@ -74,7 +74,7 @@ in
 
     services.zope2.instances = mkOption {
       default = {};
-      type = types.loaOf types.optionSet;
+      type = with types; loaOf (submodule zope2Opts);
       example = literalExample ''
         {
           plone01 = {
@@ -96,7 +96,6 @@ in
         }
       '';
       description = "zope2 instances to be created automaticaly by the system.";
-      options = [ zope2Opts ];
     };
   };
 
diff --git a/nixos/modules/services/x11/compton.nix b/nixos/modules/services/x11/compton.nix
index bda4eec0102..7cbca1dcddf 100644
--- a/nixos/modules/services/x11/compton.nix
+++ b/nixos/modules/services/x11/compton.nix
@@ -188,6 +188,7 @@ in {
     package = mkOption {
       type = types.package;
       default = pkgs.compton;
+      defaultText = "pkgs.compton";
       example = literalExample "pkgs.compton";
       description = ''
         Compton derivation to use.
diff --git a/nixos/modules/services/x11/desktop-managers/default.nix b/nixos/modules/services/x11/desktop-managers/default.nix
index 1ea7b5ccf16..144e4aada27 100644
--- a/nixos/modules/services/x11/desktop-managers/default.nix
+++ b/nixos/modules/services/x11/desktop-managers/default.nix
@@ -19,7 +19,8 @@ in
   # E.g., if KDE is enabled, it supersedes xterm.
   imports = [
     ./none.nix ./xterm.nix ./xfce.nix ./kde4.nix ./kde5.nix
-    ./enlightenment.nix ./gnome3.nix ./kodi.nix
+    ./lumina.nix ./lxqt.nix ./enlightenment.nix ./gnome3.nix
+    ./kodi.nix
   ];
 
   options = {
diff --git a/nixos/modules/services/x11/desktop-managers/enlightenment.nix b/nixos/modules/services/x11/desktop-managers/enlightenment.nix
index 90803ede9d9..9d0ff77c2ae 100644
--- a/nixos/modules/services/x11/desktop-managers/enlightenment.nix
+++ b/nixos/modules/services/x11/desktop-managers/enlightenment.nix
@@ -32,10 +32,10 @@ in
       e.efl e.enlightenment
       e.terminology e.econnman
       pkgs.xorg.xauth # used by kdesu
-      pkgs.gtk # To get GTK+'s themes.
+      pkgs.gtk2 # To get GTK+'s themes.
       pkgs.tango-icon-theme
       pkgs.shared_mime_info
-      pkgs.gnome.gnomeicontheme
+      pkgs.gnome2.gnomeicontheme
       pkgs.xorg.xcursorthemes
     ];
 
diff --git a/nixos/modules/services/x11/desktop-managers/gnome3.nix b/nixos/modules/services/x11/desktop-managers/gnome3.nix
index b3da2544802..17e84b1d9a1 100644
--- a/nixos/modules/services/x11/desktop-managers/gnome3.nix
+++ b/nixos/modules/services/x11/desktop-managers/gnome3.nix
@@ -25,9 +25,8 @@ let
     '';
   };
 
-  nixos-gsettings-desktop-schemas = pkgs.stdenv.mkDerivation {
-    name = "nixos-gsettings-desktop-schemas";
-    buildCommand = ''
+  nixos-gsettings-desktop-schemas = pkgs.runCommand "nixos-gsettings-desktop-schemas" {}
+    ''
      mkdir -p $out/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas
      cp -rf ${gnome3.gsettings_desktop_schemas}/share/gsettings-schemas/gsettings-desktop-schemas*/glib-2.0/schemas/*.xml $out/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas
 
@@ -46,7 +45,6 @@ let
 
      ${pkgs.glib.dev}/bin/glib-compile-schemas $out/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas/
     '';
-  };
 
 in {
 
@@ -84,7 +82,7 @@ in {
 
     environment.gnome3.packageSet = mkOption {
       default = null;
-      example = literalExample "pkgs.gnome3_20";
+      example = literalExample "pkgs.gnome3_22";
       description = "Which GNOME 3 package set to use.";
       apply = p: if p == null then pkgs.gnome3 else p;
     };
@@ -110,6 +108,7 @@ in {
     services.gnome3.gnome-documents.enable = mkDefault true;
     services.gnome3.gnome-keyring.enable = true;
     services.gnome3.gnome-online-accounts.enable = mkDefault true;
+    services.gnome3.gnome-terminal-server.enable = mkDefault true;
     services.gnome3.gnome-user-share.enable = mkDefault true;
     services.gnome3.gvfs.enable = true;
     services.gnome3.seahorse.enable = mkDefault true;
@@ -124,6 +123,7 @@ in {
     services.packagekit.enable = mkDefault true;
     hardware.bluetooth.enable = mkDefault true;
     services.xserver.libinput.enable = mkDefault true; # for controlling touchpad settings via gnome control center
+    services.udev.packages = [ pkgs.gnome3.gnome_settings_daemon ];
 
     fonts.fonts = [ pkgs.dejavu_fonts pkgs.cantarell_fonts ];
 
diff --git a/nixos/modules/services/x11/desktop-managers/kde4.nix b/nixos/modules/services/x11/desktop-managers/kde4.nix
index 88b3c3a1016..31d2ebcdf1a 100644
--- a/nixos/modules/services/x11/desktop-managers/kde4.nix
+++ b/nixos/modules/services/x11/desktop-managers/kde4.nix
@@ -14,7 +14,7 @@ let
   # files), segfault sometimes and consume significant resources.
   # They can be re-enabled in the KDE System Settings under "Desktop
   # Search".
-  nepomukConfig = pkgs.writeTextFile
+  disableNepomuk = pkgs.writeTextFile
     { name = "nepomuk-config";
       destination = "/share/config/nepomukserverrc";
       text =
@@ -70,6 +70,18 @@ in
         type = types.package;
         description = "Custom kde-workspace, used for NixOS rebranding.";
       };
+
+      enablePIM = mkOption {
+        type = types.bool;
+        default = true;
+        description = "Whether to enable PIM support. Note that enabling this pulls in Akonadi and MariaDB as dependencies.";
+      };
+
+      enableNepomuk = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Whether to enable Nepomuk (deprecated).";
+      };
     };
   };
 
@@ -138,7 +150,6 @@ in
 
           pkgs.kde4.kde_wallpapers # contains kdm's default background
           pkgs.kde4.oxygen_icons
-          pkgs.virtuoso # to enable Nepomuk to find Virtuoso
 
           # Starts KDE's Polkit authentication agent.
           pkgs.kde4.polkit_kde_agent
@@ -149,20 +160,26 @@ in
           xorg.xmessage # so that startkde can show error messages
           xorg.xset # used by startkde, non-essential
           xorg.xauth # used by kdesu
-          pkgs.shared_desktop_ontologies # used by nepomuk
-          pkgs.strigi # used by nepomuk
+        ]
+      ++ optionals cfg.enablePIM
+        [ pkgs.kde4.kdepim_runtime
           pkgs.kde4.akonadi
           pkgs.mysql # used by akonadi
-          pkgs.kde4.kdepim_runtime
         ]
-      ++ lib.optional config.hardware.pulseaudio.enable pkgs.kde4.kmix  # Perhaps this should always be enabled
-      ++ lib.optional config.hardware.bluetooth.enable pkgs.kde4.bluedevil
-      ++ lib.optional config.networking.networkmanager.enable pkgs.kde4.plasma-nm
-      ++ [ nepomukConfig ] ++ phononBackendPackages;
+      ++ (if cfg.enableNepomuk then
+        [ pkgs.shared_desktop_ontologies # used by nepomuk
+          pkgs.strigi # used by nepomuk
+          pkgs.virtuoso # to enable Nepomuk to find Virtuoso
+        ] else
+        [ disableNepomuk ])
+      ++ optional config.hardware.pulseaudio.enable pkgs.kde4.kmix  # Perhaps this should always be enabled
+      ++ optional config.hardware.bluetooth.enable pkgs.kde4.bluedevil
+      ++ optional config.networking.networkmanager.enable pkgs.kde4.plasma-nm
+      ++ phononBackendPackages;
 
     environment.pathsToLink = [ "/share" ];
 
-    environment.profileRelativeEnvVars = mkIf (lib.elem "gstreamer" cfg.phononBackends) {
+    environment.profileRelativeEnvVars = mkIf (elem "gstreamer" cfg.phononBackends) {
       GST_PLUGIN_SYSTEM_PATH = [ "/lib/gstreamer-0.10" ];
     };
 
diff --git a/nixos/modules/services/x11/desktop-managers/kde5.nix b/nixos/modules/services/x11/desktop-managers/kde5.nix
index 7856ff03f16..3037f949cbf 100644
--- a/nixos/modules/services/x11/desktop-managers/kde5.nix
+++ b/nixos/modules/services/x11/desktop-managers/kde5.nix
@@ -22,207 +22,231 @@ in
         description = "Enable the Plasma 5 (KDE 5) desktop environment.";
       };
 
+      enableQt4Support = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Enable support for Qt 4-based applications. Particularly, install the
+          Qt 4 version of the Breeze theme and a default backend for Phonon.
+        '';
+      };
+
+      extraPackages = mkOption {
+        type = types.listOf types.package;
+        default = [];
+        description = ''
+          KDE packages that need to be installed system-wide.
+        '';
+      };
+
     };
 
   };
 
 
-  config = mkIf (xcfg.enable && cfg.enable) {
+  config = mkMerge [
+    (mkIf (cfg.extraPackages != []) {
+      environment.systemPackages = [ (kde5.kdeWrapper cfg.extraPackages) ];
+    })
 
-    warnings = optional config.services.xserver.desktopManager.kde4.enable
-      "KDE 4 should not be enabled at the same time as KDE 5";
+    (mkIf (xcfg.enable && cfg.enable) {
 
-    services.xserver.desktopManager.session = singleton {
-      name = "kde5";
-      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"
-        ''}
+      warnings = optional config.services.xserver.desktopManager.kde4.enable
+        "KDE 4 should not be enabled at the same time as KDE 5";
 
-        exec "${kde5.startkde}"
+      services.xserver.desktopManager.session = singleton {
+        name = "kde5";
+        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"
+          ''}
 
-      '';
-    };
+          exec "${kde5.startkde}"
+        '';
+      };
 
-    security.permissionsWrappers.setuid = [
-      {
-        program = "kcheckpass";
-        source = "${kde5.plasma-workspace.out}/lib/libexec/kcheckpass";
-        owner = "root";
-        setuid = true;
-      }
-      {
-        program = "start_kdeinit";
-        source = "${kde5.kinit.out}/lib/libexec/kf5/start_kdeinit";
-        owner = "root";
-        setuid = true;
-      }
-    ];
-
-    environment.systemPackages =
-      [
-        kde5.frameworkintegration
-        kde5.kactivities
-        kde5.kauth
-        kde5.kcmutils
-        kde5.kconfig
-        kde5.kconfigwidgets
-        kde5.kcoreaddons
-        kde5.kdbusaddons
-        kde5.kdeclarative
-        kde5.kded
-        kde5.kdesu
-        kde5.kdnssd
-        kde5.kemoticons
-        kde5.kfilemetadata
-        kde5.kglobalaccel
-        kde5.kguiaddons
-        kde5.kiconthemes
-        kde5.kidletime
-        kde5.kimageformats
-        kde5.kinit
-        kde5.kio
-        kde5.kjobwidgets
-        kde5.knewstuff
-        kde5.knotifications
-        kde5.knotifyconfig
-        kde5.kpackage
-        kde5.kparts
-        kde5.kpeople
-        kde5.krunner
-        kde5.kservice
-        kde5.ktextwidgets
-        kde5.kwallet
-        kde5.kwayland
-        kde5.kwidgetsaddons
-        kde5.kxmlgui
-        kde5.kxmlrpcclient
-        kde5.plasma-framework
-        kde5.solid
-        kde5.sonnet
-        kde5.threadweaver
-
-        kde5.breeze
-        kde5.kactivitymanagerd
-        kde5.kde-cli-tools
-        kde5.kdecoration
-        kde5.kdeplasma-addons
-        kde5.kgamma5
-        kde5.khelpcenter
-        kde5.khotkeys
-        kde5.kinfocenter
-        kde5.kmenuedit
-        kde5.kscreen
-        kde5.kscreenlocker
-        kde5.ksysguard
-        kde5.kwayland
-        kde5.kwin
-        kde5.kwrited
-        kde5.libkscreen
-        kde5.libksysguard
-        kde5.milou
-        kde5.oxygen
-        kde5.plasma-integration
-        kde5.polkit-kde-agent
-        kde5.systemsettings
-
-        kde5.plasma-desktop
-        kde5.plasma-workspace
-        kde5.plasma-workspace-wallpapers
-
-        kde5.dolphin
-        kde5.dolphin-plugins
-        kde5.ffmpegthumbs
-        kde5.kdegraphics-thumbnailers
-        kde5.kio-extras
-        kde5.konsole
-        kde5.print-manager
-
-        # Oxygen icons moved to KDE Frameworks 5.16 and later.
-        (kde5.oxygen-icons or kde5.oxygen-icons5)
-        pkgs.hicolor_icon_theme
-
-        kde5.kde-gtk-config
-
-        pkgs.phonon-backend-gstreamer
-        pkgs.qt5.phonon-backend-gstreamer
-      ]
-
-      # Plasma 5.5 and later has a Breeze GTK theme.
-      # If it is not available, Orion is very similar to Breeze.
-      ++ lib.optional (!(lib.hasAttr "breeze-gtk" kde5)) pkgs.orion
-
-      # Install Breeze icons if available
-      ++ lib.optional (lib.hasAttr "breeze-icons" kde5) kde5.breeze-icons
-
-      # Install activity manager if available
-      ++ lib.optional (lib.hasAttr "kactivitymanagerd" kde5) kde5.kactivitymanagerd
-
-      # frameworkintegration was split with plasma-integration in Plasma 5.6
-      ++ lib.optional (lib.hasAttr "plasma-integration" kde5) kde5.plasma-integration
-
-      # Optional hardware support features
-      ++ lib.optional config.hardware.bluetooth.enable kde5.bluedevil
-      ++ 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 pkgs.colord-kde
-      ++ lib.optionals config.services.samba.enable [ kde5.kdenetwork-filesharing pkgs.samba ];
-
-    environment.pathsToLink = [ "/share" ];
-
-    environment.etc = singleton {
-      source = "${pkgs.xkeyboard_config}/etc/X11/xkb";
-      target = "X11/xkb";
-    };
+      security.permissionsWrappers.setuid = [
+        {
+          program = "kcheckpass";
+          source = "${kde5.plasma-workspace.out}/lib/libexec/kcheckpass";
+          owner = "root";
+          setuid = true;
+        }
+        {
+          program = "start_kdeinit";
+          source = "${kde5.kinit.out}/lib/libexec/kf5/start_kdeinit";
+          owner = "root";
+          setuid = true;
+        }
+      ];
+
+      environment.systemPackages =
+        [
+          kde5.frameworkintegration
+          kde5.kactivities
+          kde5.kauth
+          kde5.kcmutils
+          kde5.kconfig
+          kde5.kconfigwidgets
+          kde5.kcoreaddons
+          kde5.kdbusaddons
+          kde5.kdeclarative
+          kde5.kded
+          kde5.kdesu
+          kde5.kdnssd
+          kde5.kemoticons
+          kde5.kfilemetadata
+          kde5.kglobalaccel
+          kde5.kguiaddons
+          kde5.kiconthemes
+          kde5.kidletime
+          kde5.kimageformats
+          kde5.kinit
+          kde5.kio
+          kde5.kjobwidgets
+          kde5.knewstuff
+          kde5.knotifications
+          kde5.knotifyconfig
+          kde5.kpackage
+          kde5.kparts
+          kde5.kpeople
+          kde5.krunner
+          kde5.kservice
+          kde5.ktextwidgets
+          kde5.kwallet
+          kde5.kwayland
+          kde5.kwidgetsaddons
+          kde5.kxmlgui
+          kde5.kxmlrpcclient
+          kde5.plasma-framework
+          kde5.solid
+          kde5.sonnet
+          kde5.threadweaver
+
+          kde5.breeze-qt5
+          kde5.kactivitymanagerd
+          kde5.kde-cli-tools
+          kde5.kdecoration
+          kde5.kdeplasma-addons
+          kde5.kgamma5
+          kde5.khotkeys
+          kde5.kinfocenter
+          kde5.kmenuedit
+          kde5.kscreen
+          kde5.kscreenlocker
+          kde5.ksysguard
+          kde5.kwayland
+          kde5.kwin
+          kde5.kwrited
+          kde5.libkscreen
+          kde5.libksysguard
+          kde5.milou
+          kde5.plasma-integration
+          kde5.polkit-kde-agent
+          kde5.systemsettings
+
+          kde5.plasma-desktop
+          kde5.plasma-workspace
+          kde5.plasma-workspace-wallpapers
+
+          kde5.dolphin-plugins
+          kde5.ffmpegthumbs
+          kde5.kdegraphics-thumbnailers
+          kde5.kio-extras
+          kde5.print-manager
+
+          # Install Breeze icons if available
+          (kde5.breeze-icons or kde5.oxygen-icons5 or kde5.oxygen-icons)
+          pkgs.hicolor_icon_theme
+
+          kde5.kde-gtk-config kde5.breeze-gtk
+
+          pkgs.qt5.phonon-backend-gstreamer
+        ]
+
+        # Plasma 5.5 and later has a Breeze GTK theme.
+        # If it is not available, Orion is very similar to Breeze.
+        ++ lib.optional (!(lib.hasAttr "breeze-gtk" kde5)) pkgs.orion
+
+        # Install activity manager if available
+        ++ lib.optional (lib.hasAttr "kactivitymanagerd" kde5) kde5.kactivitymanagerd
+
+        # frameworkintegration was split with plasma-integration in Plasma 5.6
+        ++ lib.optional (lib.hasAttr "plasma-integration" kde5) kde5.plasma-integration
+
+        ++ lib.optionals cfg.enableQt4Support [ kde5.breeze-qt4 pkgs.phonon-backend-gstreamer ]
+
+        # Optional hardware support features
+        ++ lib.optional config.hardware.bluetooth.enable kde5.bluedevil
+        ++ 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 pkgs.colord-kde
+        ++ lib.optionals config.services.samba.enable [ kde5.kdenetwork-filesharing pkgs.samba ];
+
+      services.xserver.desktopManager.kde5.extraPackages =
+        [
+          kde5.khelpcenter
+          kde5.oxygen
+
+          kde5.dolphin
+          kde5.konsole
+        ];
+
+      environment.pathsToLink = [ "/share" ];
+
+      environment.etc = singleton {
+        source = "${pkgs.xkeyboard_config}/etc/X11/xkb";
+        target = "X11/xkb";
+      };
 
-    # Enable GTK applications to load SVG icons
-    environment.variables =
-      {
-        GST_PLUGIN_SYSTEM_PATH_1_0 =
-          lib.makeSearchPath "/lib/gstreamer-1.0"
-          (builtins.map (pkg: pkg.out) (with pkgs.gst_all_1; [
-            gstreamer
-            gst-plugins-base
-            gst-plugins-good
-            gst-plugins-ugly
-            gst-plugins-bad
-            gst-libav # for mp3 playback
-          ]));
-      }
-      // (if (lib.hasAttr "breeze-icons" kde5)
-          then { GDK_PIXBUF_MODULE_FILE = "${pkgs.librsvg.out}/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache"; }
-          else { });
-
-    fonts.fonts = [ (kde5.oxygen-fonts or pkgs.noto-fonts) ];
-
-    programs.ssh.askPassword = "${kde5.ksshaskpass.out}/bin/ksshaskpass";
-
-    # Enable helpful DBus services.
-    services.udisks2.enable = true;
-    services.upower.enable = config.powerManagement.enable;
-
-    # Extra UDEV rules used by Solid
-    services.udev.packages = [
-      pkgs.libmtp
-      pkgs.media-player-info
-    ];
-
-    services.xserver.displayManager.sddm = {
-      theme = "breeze";
-      themes = [
-        kde5.ecm # for the setup-hook
-        kde5.plasma-workspace
-        kde5.breeze-icons
-        (kde5.oxygen-icons or kde5.oxygen-icons5)
+      environment.variables =
+        {
+          # Enable GTK applications to load SVG icons
+          GST_PLUGIN_SYSTEM_PATH_1_0 =
+            lib.makeSearchPath "/lib/gstreamer-1.0"
+            (builtins.map (pkg: pkg.out) (with pkgs.gst_all_1; [
+              gstreamer
+              gst-plugins-base
+              gst-plugins-good
+              gst-plugins-ugly
+              gst-plugins-bad
+              gst-libav # for mp3 playback
+            ]));
+        }
+        // (if (lib.hasAttr "breeze-icons" kde5)
+            then { GDK_PIXBUF_MODULE_FILE = "${pkgs.librsvg.out}/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache"; }
+            else { });
+
+      fonts.fonts = [ (kde5.oxygen-fonts or pkgs.noto-fonts) ];
+
+      programs.ssh.askPassword = "${kde5.ksshaskpass.out}/bin/ksshaskpass";
+
+      # Enable helpful DBus services.
+      services.udisks2.enable = true;
+      services.upower.enable = config.powerManagement.enable;
+
+      # Extra UDEV rules used by Solid
+      services.udev.packages = [
+        pkgs.libmtp
+        pkgs.media-player-info
       ];
-    };
 
-    security.pam.services.kde = { allowNullPassword = true; };
+      services.xserver.displayManager.sddm = {
+        theme = "breeze";
+        themes = [
+          kde5.ecm # for the setup-hook
+          kde5.plasma-workspace
+          kde5.breeze-icons
+        ];
+      };
 
-  };
+      security.pam.services.kde = { allowNullPassword = true; };
+
+    })
+  ];
 
 }
diff --git a/nixos/modules/services/x11/desktop-managers/lumina.nix b/nixos/modules/services/x11/desktop-managers/lumina.nix
new file mode 100644
index 00000000000..f0b31a2acb0
--- /dev/null
+++ b/nixos/modules/services/x11/desktop-managers/lumina.nix
@@ -0,0 +1,52 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  xcfg = config.services.xserver;
+  cfg = xcfg.desktopManager.lumina;
+
+in
+
+{
+  options = {
+
+    services.xserver.desktopManager.lumina.enable = mkOption {
+      type = types.bool;
+      default = false;
+      description = "Enable the Lumina desktop manager";
+    };
+
+  };
+
+
+  config = mkIf (xcfg.enable && cfg.enable) {
+
+    services.xserver.desktopManager.session = singleton {
+      name = "lumina";
+      start = ''
+        exec ${pkgs.lumina}/bin/start-lumina-desktop
+      '';
+    };
+
+    environment.systemPackages = [
+      pkgs.fluxbox
+      pkgs.kde5.kwindowsystem
+      pkgs.kde5.oxygen-icons5
+      pkgs.lumina
+      pkgs.numlockx
+      pkgs.qt5.qtsvg
+      pkgs.xscreensaver
+    ];
+
+    # Link some extra directories in /run/current-system/software/share
+    environment.pathsToLink = [
+      "/share/desktop-directories"
+      "/share/icons"
+      "/share/lumina"
+      "/share"
+    ];
+
+  };
+}
diff --git a/nixos/modules/services/x11/desktop-managers/lxqt.nix b/nixos/modules/services/x11/desktop-managers/lxqt.nix
new file mode 100644
index 00000000000..89ad2882363
--- /dev/null
+++ b/nixos/modules/services/x11/desktop-managers/lxqt.nix
@@ -0,0 +1,66 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  # Remove packages of ys from xs, based on their names
+  removePackagesByName = xs: ys:
+    let
+      pkgName = drv: (builtins.parseDrvName drv.name).name;
+      ysNames = map pkgName ys;
+    in
+      filter (x: !(builtins.elem (pkgName x) ysNames)) xs;
+
+  xcfg = config.services.xserver;
+  cfg = xcfg.desktopManager.lxqt;
+
+in
+
+{
+  options = {
+
+    services.xserver.desktopManager.lxqt.enable = mkOption {
+      type = types.bool;
+      default = false;
+      description = "Enable the LXQt desktop manager";
+    };
+
+    environment.lxqt.excludePackages = mkOption {
+      default = [];
+      example = literalExample "[ pkgs.lxqt.qterminal ]";
+      type = types.listOf types.package;
+      description = "Which LXQt packages to exclude from the default environment";
+    };
+
+  };
+
+  config = mkIf (xcfg.enable && cfg.enable) {
+
+    services.xserver.desktopManager.session = singleton {
+      name = "lxqt";
+      bgSupport = true;
+      start = ''
+        exec ${pkgs.lxqt.lxqt-common}/bin/startlxqt
+      '';
+    };
+
+    environment.systemPackages =
+      pkgs.lxqt.preRequisitePackages ++
+      pkgs.lxqt.corePackages ++
+      (removePackagesByName
+        pkgs.lxqt.optionalPackages
+        config.environment.lxqt.excludePackages);
+
+    # Link some extra directories in /run/current-system/software/share
+    environment.pathsToLink = [
+      "/share/desktop-directories"
+      "/share/icons"
+      "/share/lxqt"
+    ];
+
+    environment.variables.GIO_EXTRA_MODULES = [ "${pkgs.gvfs}/lib/gio/modules" ];
+
+  };
+
+}
diff --git a/nixos/modules/services/x11/desktop-managers/xfce.nix b/nixos/modules/services/x11/desktop-managers/xfce.nix
index 634d2a39576..530468be5f9 100644
--- a/nixos/modules/services/x11/desktop-managers/xfce.nix
+++ b/nixos/modules/services/x11/desktop-managers/xfce.nix
@@ -69,7 +69,7 @@ in
     services.xserver.updateDbusEnvironment = true;
 
     environment.systemPackages =
-      [ pkgs.gtk # To get GTK+'s themes.
+      [ pkgs.gtk2.out # To get GTK+'s themes and gtk-update-icon-cache
         pkgs.hicolor_icon_theme
         pkgs.tango-icon-theme
         pkgs.shared_mime_info
@@ -100,6 +100,7 @@ in
         pkgs.xfce.tumbler       # found via dbus
       ]
       ++ optional config.powerManagement.enable pkgs.xfce.xfce4_power_manager
+      ++ optional config.networking.networkmanager.enable pkgs.networkmanagerapplet
       ++ optionals (!cfg.noDesktop)
          [ pkgs.xfce.xfce4panel
            pkgs.xfce.xfdesktop
diff --git a/nixos/modules/services/x11/display-managers/default.nix b/nixos/modules/services/x11/display-managers/default.nix
index 75d80609f73..c0daf30d04e 100644
--- a/nixos/modules/services/x11/display-managers/default.nix
+++ b/nixos/modules/services/x11/display-managers/default.nix
@@ -82,12 +82,12 @@ let
 
       # Speed up application start by 50-150ms according to
       # http://kdemonkey.blogspot.nl/2008/04/magic-trick.html
-      rm -rf $HOME/.compose-cache
-      mkdir $HOME/.compose-cache
+      rm -rf "$HOME/.compose-cache"
+      mkdir "$HOME/.compose-cache"
 
       # Work around KDE errors when a user first logs in and
       # .local/share doesn't exist yet.
-      mkdir -p $HOME/.local/share
+      mkdir -p "$HOME/.local/share"
 
       unset _DID_SYSTEMD_CAT
 
@@ -134,13 +134,8 @@ let
         (*) echo "$0: Desktop manager '$desktopManager' not found.";;
       esac
 
-      # FIXME: gdbus should not be in glib.dev!
-      ${optionalString (cfg.startDbusSession && cfg.updateDbusEnvironment) ''
-        ${pkgs.glib.dev}/bin/gdbus call --session \
-          --dest org.freedesktop.DBus --object-path /org/freedesktop/DBus \
-          --method org.freedesktop.DBus.UpdateActivationEnvironment \
-          "{$(env | ${pkgs.gnused}/bin/sed "s/'/\\\\'/g; s/\([^=]*\)=\(.*\)/'\1':'\2'/" \
-                  | ${pkgs.coreutils}/bin/paste -sd,)}"
+      ${optionalString cfg.updateDbusEnvironment ''
+        ${lib.getBin pkgs.dbus}/bin/dbus-update-activation-environment --systemd --all
       ''}
 
       test -n "$waitPID" && wait "$waitPID"
@@ -153,7 +148,7 @@ let
       allowSubstitutes = false;
     }
     ''
-      mkdir -p $out
+      mkdir -p "$out"
       ${concatMapStrings (n: ''
         cat - > "$out/${n}.desktop" << EODESKTOP
         [Desktop Entry]
@@ -192,7 +187,6 @@ in
         default = [];
         example = [ "-ac" "-logverbose" "-verbose" "-nolisten tcp" ];
         description = "List of arguments for the X server.";
-        apply = toString;
       };
 
       sessionCommands = mkOption {
diff --git a/nixos/modules/services/x11/display-managers/gdm.nix b/nixos/modules/services/x11/display-managers/gdm.nix
index 52847d2f8d2..6c63fede857 100644
--- a/nixos/modules/services/x11/display-managers/gdm.nix
+++ b/nixos/modules/services/x11/display-managers/gdm.nix
@@ -92,12 +92,16 @@ in
 
     users.extraGroups.gdm.gid = config.ids.gids.gdm;
 
+    # GDM needs different xserverArgs, presumable because using wayland by default.
+    services.xserver.tty = null;
+    services.xserver.display = null;
+
     services.xserver.displayManager.job =
       {
         environment = {
-          GDM_X_SERVER = "${cfg.xserverBin} ${cfg.xserverArgs}";
+          GDM_X_SERVER_EXTRA_ARGS = toString
+            (filter (arg: arg != "-terminate") cfg.xserverArgs);
           GDM_SESSIONS_DIR = "${cfg.session.desktops}";
-          XDG_CONFIG_DIRS = "${gnome3.gnome_settings_daemon}/etc/xdg";
           # Find the mouse
           XCURSOR_PATH = "~/.icons:${config.system.path}/share/icons";
         };
@@ -108,10 +112,12 @@ in
     systemd.services.display-manager.wants = [ "systemd-machined.service" ];
     systemd.services.display-manager.after = [ "systemd-machined.service" ];
 
-    systemd.services.display-manager.path = [ gnome3.gnome_shell gnome3.caribou pkgs.xorg.xhost pkgs.dbus_tools ];
+    systemd.services.display-manager.path = [ gnome3.gnome_session ];
 
     services.dbus.packages = [ gdm ];
 
+    systemd.user.services.dbus.wantedBy = [ "default.target" ];
+
     programs.dconf.profiles.gdm = "${gdm}/share/dconf/profile/gdm";
 
     # Use AutomaticLogin if delay is zero, because it's immediate.
diff --git a/nixos/modules/services/x11/display-managers/kdm.nix b/nixos/modules/services/x11/display-managers/kdm.nix
index d9f7f8f0dfc..04701a1640c 100644
--- a/nixos/modules/services/x11/display-managers/kdm.nix
+++ b/nixos/modules/services/x11/display-managers/kdm.nix
@@ -25,7 +25,7 @@ let
       FailsafeClient=${pkgs.xterm}/bin/xterm
 
       [X-:*-Core]
-      ServerCmd=${dmcfg.xserverBin} ${dmcfg.xserverArgs}
+      ServerCmd=${dmcfg.xserverBin} ${toString dmcfg.xserverArgs}
       # KDM calls `rm' somewhere to clean up some temporary directory.
       SystemPath=${pkgs.coreutils}/bin
       # The default timeout (15) is too short in a heavily loaded boot process.
@@ -54,19 +54,17 @@ let
       ''}
     '';
 
-  kdmrc = pkgs.stdenv.mkDerivation {
-    name = "kdmrc";
-    config = defaultConfig + cfg.extraConfig;
-    preferLocalBuild = true;
-    buildCommand =
-      ''
-        echo "$config" > $out
+  kdmrc = pkgs.runCommand "kdmrc"
+    { config = defaultConfig + cfg.extraConfig;
+      preferLocalBuild = true;
+    }
+    ''
+      echo "$config" > $out
 
-        # The default kdmrc would add "-nolisten tcp", and we already
-        # have that managed by nixos. Hence the grep.
-        cat ${kdebase_workspace}/share/config/kdm/kdmrc | grep -v nolisten >> $out
-      '';
-  };
+      # The default kdmrc would add "-nolisten tcp", and we already
+      # have that managed by nixos. Hence the grep.
+      cat ${kdebase_workspace}/share/config/kdm/kdmrc | grep -v nolisten >> $out
+    '';
 
 in
 
diff --git a/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix b/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix
index 543dd628ce6..dfda90978b1 100644
--- a/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix
+++ b/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix
@@ -16,11 +16,9 @@ let
   # The default greeter provided with this expression is the GTK greeter.
   # Again, we need a few things in the environment for the greeter to run with
   # fonts/icons.
-  wrappedGtkGreeter = stdenv.mkDerivation {
-    name = "lightdm-gtk-greeter";
-    buildInputs = [ pkgs.makeWrapper ];
-
-    buildCommand = ''
+  wrappedGtkGreeter = pkgs.runCommand "lightdm-gtk-greeter"
+    { buildInputs = [ pkgs.makeWrapper ]; }
+    ''
       # This wrapper ensures that we actually get themes
       makeWrapper ${pkgs.lightdm_gtk_greeter}/sbin/lightdm-gtk-greeter \
         $out/greeter \
@@ -40,7 +38,6 @@ let
       Type=Application
       EOF
     '';
-  };
 
   gtkGreeterConf = writeText "lightdm-gtk-greeter.conf"
     ''
diff --git a/nixos/modules/services/x11/display-managers/lightdm.nix b/nixos/modules/services/x11/display-managers/lightdm.nix
index 47786f0a432..4afef32aaa4 100644
--- a/nixos/modules/services/x11/display-managers/lightdm.nix
+++ b/nixos/modules/services/x11/display-managers/lightdm.nix
@@ -23,7 +23,7 @@ let
       else additionalArgs="-logfile /var/log/X.$display.log"
       fi
 
-      exec ${dmcfg.xserverBin} ${dmcfg.xserverArgs} $additionalArgs "$@"
+      exec ${dmcfg.xserverBin} ${toString dmcfg.xserverArgs} $additionalArgs "$@"
     '';
 
   usersConf = writeText "users.conf"
@@ -46,13 +46,15 @@ let
       [Seat:*]
       xserver-command = ${xserverWrapper}
       session-wrapper = ${dmcfg.session.script}
+      ${optionalString (elem defaultSessionName dmcfg.session.names) ''
+        user-session = ${defaultSessionName}
+      ''}
       ${optionalString cfg.greeter.enable ''
         greeter-session = ${cfg.greeter.name}
       ''}
       ${optionalString cfg.autoLogin.enable ''
         autologin-user = ${cfg.autoLogin.user}
         autologin-user-timeout = ${toString cfg.autoLogin.timeout}
-        autologin-session = ${defaultSessionName}
       ''}
       ${cfg.extraSeatDefaults}
     '';
@@ -205,6 +207,9 @@ in
     services.dbus.enable = true;
     services.dbus.packages = [ lightdm ];
 
+    # lightdm uses the accounts daemon to rember language/window-manager per user
+    services.accounts-daemon.enable = true;
+
     security.pam.services.lightdm = {
       allowNullPassword = true;
       startSession = true;
diff --git a/nixos/modules/services/x11/display-managers/sddm.nix b/nixos/modules/services/x11/display-managers/sddm.nix
index 16d1e89e8d9..6630b8257e4 100644
--- a/nixos/modules/services/x11/display-managers/sddm.nix
+++ b/nixos/modules/services/x11/display-managers/sddm.nix
@@ -14,7 +14,7 @@ let
   xserverWrapper = pkgs.writeScript "xserver-wrapper" ''
     #!/bin/sh
     ${concatMapStrings (n: "export ${n}=\"${getAttr n xEnv}\"\n") (attrNames xEnv)}
-    exec ${dmcfg.xserverBin} ${dmcfg.xserverArgs} "$@"
+    exec systemd-cat ${dmcfg.xserverBin} ${toString dmcfg.xserverArgs} "$@"
   '';
 
   Xsetup = pkgs.writeScript "Xsetup" ''
@@ -27,7 +27,6 @@ let
     ${cfg.stopScript}
   '';
 
-
   cfgFile = pkgs.writeText "sddm.conf" ''
     [General]
     HaltCommand=${pkgs.systemd}/bin/systemctl poweroff
@@ -46,8 +45,8 @@ let
     HideUsers=${concatStringsSep "," dmcfg.hiddenUsers}
     HideShells=/run/current-system/sw/bin/nologin
 
-    [XDisplay]
-    MinimumVT=${toString xcfg.tty}
+    [X11]
+    MinimumVT=${toString (if xcfg.tty != null then xcfg.tty else 7)}
     ServerPath=${xserverWrapper}
     XephyrPath=${pkgs.xorg.xorgserver.out}/bin/Xephyr
     SessionCommand=${dmcfg.session.script}
@@ -86,7 +85,7 @@ in
       };
 
       extraConfig = mkOption {
-        type = types.str;
+        type = types.lines;
         default = "";
         example = ''
           [Autologin]
@@ -100,7 +99,7 @@ in
 
       theme = mkOption {
         type = types.str;
-        default = "maui";
+        default = "";
         description = ''
           Greeter theme to use.
         '';
@@ -254,5 +253,10 @@ in
 
     users.extraGroups.sddm.gid = config.ids.gids.sddm;
 
+    services.dbus.packages = [ sddm.unwrapped ];
+
+    # To enable user switching, allow sddm to allocate TTYs/displays dynamically.
+    services.xserver.tty = null;
+    services.xserver.display = null;
   };
 }
diff --git a/nixos/modules/services/x11/display-managers/slim.nix b/nixos/modules/services/x11/display-managers/slim.nix
index ce44c9f54a3..68acde85b5d 100644
--- a/nixos/modules/services/x11/display-managers/slim.nix
+++ b/nixos/modules/services/x11/display-managers/slim.nix
@@ -12,7 +12,7 @@ let
     ''
       xauth_path ${dmcfg.xauthBin}
       default_xserver ${dmcfg.xserverBin}
-      xserver_arguments ${dmcfg.xserverArgs}
+      xserver_arguments ${toString dmcfg.xserverArgs}
       sessiondir ${dmcfg.session.desktops}
       login_cmd exec ${pkgs.stdenv.shell} ${dmcfg.session.script} "%session"
       halt_cmd ${config.systemd.package}/sbin/shutdown -h now
@@ -26,15 +26,13 @@ let
   # Unpack the SLiM theme, or use the default.
   slimThemesDir =
     let
-      unpackedTheme = pkgs.stdenv.mkDerivation {
-        name = "slim-theme";
-        buildCommand = ''
+      unpackedTheme = pkgs.runCommand "slim-theme" {}
+        ''
           mkdir -p $out
           cd $out
           unpackFile ${cfg.theme}
           ln -s * default
         '';
-      };
     in if cfg.theme == null then "${pkgs.slim}/share/slim/themes" else unpackedTheme;
 
 in
diff --git a/nixos/modules/services/x11/hardware/synaptics.nix b/nixos/modules/services/x11/hardware/synaptics.nix
index 5c068e89dd7..2a7f4e5cbcd 100644
--- a/nixos/modules/services/x11/hardware/synaptics.nix
+++ b/nixos/modules/services/x11/hardware/synaptics.nix
@@ -19,7 +19,7 @@ let cfg = config.services.xserver.synaptics;
       Option "TapButton3" "0"
     '';
   pkg = pkgs.xorg.xf86inputsynaptics;
-  etcFile = "X11/xorg.conf.d/50-synaptics.conf";
+  etcFile = "X11/xorg.conf.d/70-synaptics.conf";
 in {
 
   options = {
@@ -172,7 +172,7 @@ in {
     services.xserver.modules = [ pkg.out ];
 
     environment.etc."${etcFile}".source =
-      "${pkg.out}/share/X11/xorg.conf.d/50-synaptics.conf";
+      "${pkg.out}/share/X11/xorg.conf.d/70-synaptics.conf";
 
     environment.systemPackages = [ pkg ];
 
diff --git a/nixos/modules/services/x11/hardware/wacom.nix b/nixos/modules/services/x11/hardware/wacom.nix
index 540ed168b48..a27889c36a7 100644
--- a/nixos/modules/services/x11/hardware/wacom.nix
+++ b/nixos/modules/services/x11/hardware/wacom.nix
@@ -22,7 +22,7 @@ in
           which will make Xorg reconfigure the device ?
 
           If you're not satisfied by the default behaviour you can override
-          <option>environment.etc."X11/xorg.conf.d/50-wacom.conf"</option> in
+          <option>environment.etc."X11/xorg.conf.d/70-wacom.conf"</option> in
           configuration.nix easily.
         '';
       };
@@ -40,7 +40,7 @@ in
 
     services.udev.packages = [ pkgs.xf86_input_wacom ];
 
-    environment.etc."X11/xorg.conf.d/50-wacom.conf".source = "${pkgs.xf86_input_wacom}/share/X11/xorg.conf.d/50-wacom.conf";
+    environment.etc."X11/xorg.conf.d/70-wacom.conf".source = "${pkgs.xf86_input_wacom}/share/X11/xorg.conf.d/70-wacom.conf";
 
   };
 
diff --git a/nixos/modules/services/x11/unclutter-xfixes.nix b/nixos/modules/services/x11/unclutter-xfixes.nix
new file mode 100644
index 00000000000..bd02c5ed989
--- /dev/null
+++ b/nixos/modules/services/x11/unclutter-xfixes.nix
@@ -0,0 +1,58 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let cfg = config.services.unclutter-xfixes;
+
+in {
+  options.services.unclutter-xfixes = {
+
+    enable = mkOption {
+      description = "Enable unclutter-xfixes to hide your mouse cursor when inactive.";
+      type = types.bool;
+      default = false;
+      example = true;
+    };
+
+    package = mkOption {
+      description = "unclutter-xfixes derivation to use.";
+      type = types.package;
+      default = pkgs.unclutter-xfixes;
+      defaultText = "pkgs.unclutter-xfixes";
+    };
+
+    timeout = mkOption {
+      description = "Number of seconds before the cursor is marked inactive.";
+      type = types.int;
+      default = 1;
+    };
+
+    threshold = mkOption {
+      description = "Minimum number of pixels considered cursor movement.";
+      type = types.int;
+      default = 1;
+    };
+
+    extraOptions = mkOption {
+      description = "More arguments to pass to the unclutter-xfixes command.";
+      type = types.listOf types.str;
+      default = [];
+      example = [ "exclude-root" "ignore-scrolling" "fork" ];
+    };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.user.services.unclutter-xfixes = {
+      description = "unclutter-xfixes";
+      wantedBy = [ "graphical.target" ];
+      serviceConfig.ExecStart = ''
+        ${cfg.package}/bin/unclutter \
+          --timeout ${toString cfg.timeout} \
+          --jitter ${toString (cfg.threshold - 1)} \
+          ${concatMapStrings (x: " --"+x) cfg.extraOptions} \
+      '';
+      serviceConfig.RestartSec = 3;
+      serviceConfig.Restart = "always";
+    };
+  };
+}
diff --git a/nixos/modules/services/x11/urxvtd.nix b/nixos/modules/services/x11/urxvtd.nix
new file mode 100644
index 00000000000..be36efaa589
--- /dev/null
+++ b/nixos/modules/services/x11/urxvtd.nix
@@ -0,0 +1,50 @@
+{ config, lib, pkgs, ... }:
+
+# maintainer: siddharthist
+
+with lib;
+
+let
+  cfg = config.services.urxvtd;
+in {
+
+  options.services.urxvtd.enable = mkOption {
+    type = types.bool;
+    default = false;
+    example = true;
+    description = ''
+      Enable urxvtd, the urxvt terminal daemon. To use urxvtd, run
+      "urxvtc".
+    '';
+  };
+
+  config = mkIf cfg.enable {
+    systemd.user = {
+      sockets.urxvtd = {
+        description = "socket for urxvtd, the urxvt terminal daemon";
+        after = [ "graphical.target" ];
+        wants = [ "graphical.target" ];
+        wantedBy = [ "sockets.target" ];
+        socketConfig = {
+          ListenStream = "%t/urxvtd-socket";
+        };
+      };
+
+      services.urxvtd = {
+        description = "urxvt terminal daemon";
+        path = [ pkgs.xsel ];
+        serviceConfig = {
+          ExecStart = "${pkgs.rxvt_unicode-with-plugins}/bin/urxvtd -o";
+          Environment = "RXVT_SOCKET=%t/urxvtd-socket";
+          Restart = "on-failure";
+          RestartSec = "5s";
+        };
+      };
+
+    };
+
+    environment.systemPackages = [ pkgs.rxvt_unicode-with-plugins ];
+    environment.variables.RXVT_SOCKET = "/run/user/$(id -u)/urxvtd-socket";
+  };
+
+}
diff --git a/nixos/modules/services/x11/window-managers/awesome.nix b/nixos/modules/services/x11/window-managers/awesome.nix
index 455b3568499..eb97449c6bd 100644
--- a/nixos/modules/services/x11/window-managers/awesome.nix
+++ b/nixos/modules/services/x11/window-managers/awesome.nix
@@ -6,7 +6,7 @@ let
 
   cfg = config.services.xserver.windowManager.awesome;
   awesome = cfg.package;
-
+  inherit (pkgs.luaPackages) getLuaPath getLuaCPath;
 in
 
 {
@@ -46,10 +46,8 @@ in
       { name = "awesome";
         start =
           ''
-            ${concatMapStrings (pkg: ''
-              export LUA_CPATH=$LUA_CPATH''${LUA_CPATH:+;}${pkg}/lib/lua/${awesome.lua.luaversion}/?.so
-              export LUA_PATH=$LUA_PATH''${LUA_PATH:+;}${pkg}/lib/lua/${awesome.lua.luaversion}/?.lua
-            '') cfg.luaModules}
+            export LUA_CPATH="${lib.concatStringsSep ";" (map getLuaCPath cfg.luaModules)}"
+            export LUA_PATH="${lib.concatStringsSep ";" (map getLuaPath cfg.luaModules)}"
 
             ${awesome}/bin/awesome &
             waitPID=$!
@@ -59,5 +57,4 @@ in
     environment.systemPackages = [ awesome ];
 
   };
-
 }
diff --git a/nixos/modules/services/x11/window-managers/bspwm.nix b/nixos/modules/services/x11/window-managers/bspwm.nix
index 03a1b7a72e8..6783ac3479e 100644
--- a/nixos/modules/services/x11/window-managers/bspwm.nix
+++ b/nixos/modules/services/x11/window-managers/bspwm.nix
@@ -9,40 +9,69 @@ in
 {
   options = {
     services.xserver.windowManager.bspwm = {
-        enable = mkEnableOption "bspwm";
-        startThroughSession = mkOption {
-            type = with types; bool;
-            default = false;
-            description = "
-                Start the window manager through the script defined in 
-                sessionScript. Defaults to the the bspwm-session script
-                provided by bspwm
-            ";
-        };
-        sessionScript = mkOption {
-            default = "${pkgs.bspwm}/bin/bspwm-session";
-            defaultText = "(pkgs.bspwm)/bin/bspwm-session";
-            description = "
-                The start-session script to use. Defaults to the
-                provided bspwm-session script from the bspwm package.
+      enable = mkEnableOption "bspwm";
+
+      package = mkOption {
+        type        = types.package;
+        default     = pkgs.bspwm;
+        defaultText = "pkgs.bspwm";
+        example     = "pkgs.bspwm-unstable";
+        description = ''
+          bspwm package to use.
+        '';
+      };
+      configFile = mkOption {
+        type        = with types; nullOr path;
+        example     = "${pkgs.bspwm}/share/doc/bspwm/examples/bspwmrc";
+        default     = null;
+        description = ''
+          Path to the bspwm configuration file.
+          If null, $HOME/.config/bspwm/bspwmrc will be used.
+        '';
+      };
 
-                Does nothing unless `bspwm.startThroughSession` is enabled
-            ";
+      sxhkd = {
+        package = mkOption {
+          type        = types.package;
+          default     = pkgs.sxhkd;
+          defaultText = "pkgs.sxhkd";
+          example     = "pkgs.sxhkd-unstable";
+          description = ''
+            sxhkd package to use.
+          '';
         };
+        configFile = mkOption {
+          type        = with types; nullOr path;
+          example     = "${pkgs.bspwm}/share/doc/bspwm/examples/sxhkdrc";
+          default     = null;
+          description = ''
+            Path to the sxhkd configuration file.
+            If null, $HOME/.config/sxhkd/sxhkdrc will be used.
+          '';
+        };
+      };
     };
   };
 
   config = mkIf cfg.enable {
     services.xserver.windowManager.session = singleton {
-      name = "bspwm";
-      start = if cfg.startThroughSession
-        then cfg.sessionScript
-        else ''
-            export _JAVA_AWT_WM_NONREPARENTING=1
-            SXHKD_SHELL=/bin/sh ${pkgs.sxhkd}/bin/sxhkd -f 100 &
-            ${pkgs.bspwm}/bin/bspwm
-        '';
+      name  = "bspwm";
+      start = ''
+        export _JAVA_AWT_WM_NONREPARENTING=1
+        SXHKD_SHELL=/bin/sh ${cfg.sxhkd.package}/bin/sxhkd ${optionalString (cfg.sxhkd.configFile != null) "-c \"${cfg.sxhkd.configFile}\""} &
+        ${cfg.package}/bin/bspwm ${optionalString (cfg.configFile != null) "-c \"${cfg.configFile}\""}
+        waitPID=$!
+      '';
     };
-    environment.systemPackages = [ pkgs.bspwm ];
+    environment.systemPackages = [ cfg.package ];
   };
+
+  imports = [
+   (mkRemovedOptionModule [ "services" "xserver" "windowManager" "bspwm-unstable" "enable" ]
+     "Use services.xserver.windowManager.bspwm.enable and set services.xserver.windowManager.bspwm.package to pkgs.bspwm-unstable to use the unstable version of bspwm.")
+   (mkRemovedOptionModule [ "services" "xserver" "windowManager" "bspwm" "startThroughSession" ]
+     "bspwm package does not provide bspwm-session anymore.")
+   (mkRemovedOptionModule [ "services" "xserver" "windowManager" "bspwm" "sessionScript" ]
+     "bspwm package does not provide bspwm-session anymore.")
+  ];
 }
diff --git a/nixos/modules/services/x11/window-managers/i3.nix b/nixos/modules/services/x11/window-managers/i3.nix
index cfe9439b688..f9c75e80db4 100644
--- a/nixos/modules/services/x11/window-managers/i3.nix
+++ b/nixos/modules/services/x11/window-managers/i3.nix
@@ -3,52 +3,58 @@
 with lib;
 
 let
-  wmCfg = config.services.xserver.windowManager;
+  cfg = config.services.xserver.windowManager.i3;
+in
+
+{
+  options.services.xserver.windowManager.i3 = {
+    enable = mkEnableOption "i3 window manager";
 
-  i3option = name: {
-    enable = mkEnableOption name;
     configFile = mkOption {
-      default = null;
-      type = types.nullOr types.path;
+      default     = null;
+      type        = with types; nullOr path;
       description = ''
         Path to the i3 configuration file.
         If left at the default value, $HOME/.i3/config will be used.
       '';
     };
+
     extraSessionCommands = mkOption {
-      default = "";
-      type = types.lines;
+      default     = "";
+      type        = types.lines;
       description = ''
         Shell commands executed just before i3 is started.
       '';
     };
+
+    package = mkOption {
+      type        = types.package;
+      default     = pkgs.i3;
+      defaultText = "pkgs.i3";
+      example     = "pkgs.i3-gaps";
+      description = ''
+        i3 package to use.
+      '';
+    };
   };
 
-  i3config = name: pkg: cfg: {
+  config = mkIf cfg.enable {
     services.xserver.windowManager.session = [{
-      inherit name;
+      name  = "i3";
       start = ''
         ${cfg.extraSessionCommands}
 
-        ${pkg}/bin/i3 ${optionalString (cfg.configFile != null)
+        ${cfg.package}/bin/i3 ${optionalString (cfg.configFile != null)
           "-c \"${cfg.configFile}\""
         } &
         waitPID=$!
       '';
     }];
-    environment.systemPackages = [ pkg ];
-  };
-
-in
-
-{
-  options.services.xserver.windowManager = {
-    i3 = i3option "i3";
-    i3-gaps = i3option "i3-gaps";
+    environment.systemPackages = [ cfg.package ];
   };
 
-  config = mkMerge [
-    (mkIf wmCfg.i3.enable (i3config "i3" pkgs.i3 wmCfg.i3))
-    (mkIf wmCfg.i3-gaps.enable (i3config "i3-gaps" pkgs.i3-gaps wmCfg.i3-gaps))
+  imports = [
+    (mkRemovedOptionModule [ "services" "xserver" "windowManager" "i3-gaps" "enable" ]
+      "Use services.xserver.windowManager.i3.enable and set services.xserver.windowManager.i3.package to pkgs.i3-gaps to use i3-gaps.")
   ];
 }
diff --git a/nixos/modules/services/x11/xserver.nix b/nixos/modules/services/x11/xserver.nix
index b03f70385b1..f5ed5233818 100644
--- a/nixos/modules/services/x11/xserver.nix
+++ b/nixos/modules/services/x11/xserver.nix
@@ -71,15 +71,11 @@ let
     monitors = reverseList (foldl mkMonitor [] xrandrHeads);
   in concatMapStrings (getAttr "value") monitors;
 
-  configFile = pkgs.stdenv.mkDerivation {
-    name = "xserver.conf";
-
-    xfs = optionalString (cfg.useXFS != false)
-      ''FontPath "${toString cfg.useXFS}"'';
-
-    inherit (cfg) config;
-
-    buildCommand =
+  configFile = pkgs.runCommand "xserver.conf"
+    { xfs = optionalString (cfg.useXFS != false)
+        ''FontPath "${toString cfg.useXFS}"'';
+      inherit (cfg) config;
+    }
       ''
         echo 'Section "Files"' >> $out
         echo $xfs >> $out
@@ -102,7 +98,6 @@ let
 
         echo "$config" >> $out
       ''; # */
-  };
 
 in
 
@@ -154,6 +149,22 @@ in
         '';
       };
 
+      autoRepeatDelay = mkOption {
+        type = types.nullOr types.int;
+        default = null;
+        description = ''
+          Sets the autorepeat delay (length of time in milliseconds that a key must be depressed before autorepeat starts).
+        '';
+      };
+
+      autoRepeatInterval = mkOption {
+        type = types.nullOr types.int;
+        default = null;
+        description = ''
+          Sets the autorepeat interval (length of time in milliseconds that should elapse between autorepeat-generated keystrokes).
+        '';
+      };
+
       inputClassSections = mkOption {
         type = types.listOf types.lines;
         default = [];
@@ -504,12 +515,12 @@ in
       { description = "X11 Server";
 
         after = [ "systemd-udev-settle.service" "local-fs.target" "acpid.service" "systemd-logind.service" ];
+        wants = [ "systemd-udev-settle.service" ];
 
         restartIfChanged = false;
 
         environment =
           {
-            XKB_BINDIR = "${xorg.xkbcomp}/bin"; # Needed for the Xkb extension.
             XORG_DRI_DRIVER_PATH = "/run/opengl-driver/lib/dri"; # !!! Depends on the driver selected at runtime.
             LD_LIBRARY_PATH = concatStringsSep ":" (
               [ "${xorg.libX11.out}/lib" "${xorg.libXext.out}/lib" "/run/opengl-driver/lib" ]
@@ -529,6 +540,10 @@ in
           Restart = "always";
           RestartSec = "200ms";
           SyslogIdentifier = "display-manager";
+          # Stop restarting if the display manager stops (crashes) 2 times
+          # in one minute. Starting X typically takes 3-4s.
+          StartLimitInterval = "30s";
+          StartLimitBurst = "3";
         };
       };
 
@@ -541,7 +556,9 @@ in
       ] ++ optional (cfg.display != null) ":${toString cfg.display}"
         ++ optional (cfg.tty     != null) "vt${toString cfg.tty}"
         ++ optional (cfg.dpi     != null) "-dpi ${toString cfg.dpi}"
-        ++ optional (!cfg.enableTCP) "-nolisten tcp";
+        ++ optional (!cfg.enableTCP) "-nolisten tcp"
+        ++ optional (cfg.autoRepeatDelay != null) "-ardelay ${toString cfg.autoRepeatDelay}"
+        ++ optional (cfg.autoRepeatInterval != null) "-arinterval ${toString cfg.autoRepeatInterval}";
 
     services.xserver.modules =
       concatLists (catAttrs "modules" cfg.drivers) ++
@@ -654,6 +671,8 @@ in
         ${xrandrMonitorSections}
       '';
 
+    fonts.enableDefaultFonts = mkDefault true;
+
   };
 
 }