summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
Diffstat (limited to 'nixos')
-rw-r--r--nixos/doc/manual/Makefile5
-rw-r--r--nixos/doc/manual/administration/boot-problems.xml15
-rw-r--r--nixos/doc/manual/administration/imperative-containers.xml2
-rw-r--r--nixos/doc/manual/configuration/config-file.xml24
-rw-r--r--nixos/doc/manual/configuration/linux-kernel.xml51
-rw-r--r--nixos/doc/manual/configuration/network-manager.xml2
-rw-r--r--nixos/doc/manual/configuration/ssh.xml2
-rw-r--r--nixos/doc/manual/default.nix19
-rw-r--r--nixos/doc/manual/development/building-parts.xml27
-rw-r--r--nixos/doc/manual/development/option-declarations.xml12
-rw-r--r--nixos/doc/manual/development/option-types.xml129
-rw-r--r--nixos/doc/manual/development/writing-nixos-tests.xml81
-rw-r--r--nixos/doc/manual/installation/changing-config.xml2
-rw-r--r--nixos/doc/manual/installation/installing-from-other-distro.xml2
-rw-r--r--nixos/doc/manual/installation/installing.xml20
-rw-r--r--nixos/doc/manual/man-nixos-build-vms.xml27
-rw-r--r--nixos/doc/manual/man-nixos-enter.xml49
-rw-r--r--nixos/doc/manual/man-nixos-generate-config.xml41
-rw-r--r--nixos/doc/manual/man-nixos-install.xml92
-rw-r--r--nixos/doc/manual/man-nixos-option.xml30
-rw-r--r--nixos/doc/manual/man-nixos-rebuild.xml135
-rw-r--r--nixos/doc/manual/man-nixos-version.xml28
-rw-r--r--nixos/doc/manual/release-notes/rl-1509.xml10
-rw-r--r--nixos/doc/manual/release-notes/rl-1809.xml205
-rw-r--r--nixos/doc/manual/shell.nix2
-rwxr-xr-xnixos/doc/varlistentry-fixer.rb124
-rw-r--r--nixos/doc/xmlformat.conf7
-rw-r--r--nixos/lib/make-ext4-fs.nix3
-rw-r--r--nixos/lib/qemu-flags.nix4
-rwxr-xr-xnixos/maintainers/scripts/azure/create-azure.sh2
-rw-r--r--nixos/modules/config/fonts/fontconfig-ultimate.nix4
-rw-r--r--nixos/modules/config/ldap.nix4
-rw-r--r--nixos/modules/config/networking.nix4
-rw-r--r--nixos/modules/config/no-x-libs.nix22
-rw-r--r--nixos/modules/config/pulseaudio.nix4
-rw-r--r--nixos/modules/hardware/all-firmware.nix3
-rw-r--r--nixos/modules/hardware/brightnessctl.nix30
-rw-r--r--nixos/modules/hardware/nitrokey.nix2
-rw-r--r--nixos/modules/hardware/video/uvcvideo/default.nix64
-rw-r--r--nixos/modules/hardware/video/uvcvideo/uvcdynctrl-udev-rules.nix46
-rw-r--r--nixos/modules/i18n/input-method/default.nix2
-rw-r--r--nixos/modules/i18n/input-method/default.xml12
-rw-r--r--nixos/modules/installer/cd-dvd/installation-cd-base.nix2
-rw-r--r--nixos/modules/installer/cd-dvd/sd-image-aarch64.nix2
-rw-r--r--nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix2
-rw-r--r--nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix27
-rw-r--r--nixos/modules/installer/cd-dvd/sd-image.nix24
-rw-r--r--nixos/modules/installer/netboot/netboot-base.nix2
-rw-r--r--nixos/modules/installer/scan/not-detected.nix9
-rw-r--r--nixos/modules/installer/tools/nix-fallback-paths.nix8
-rw-r--r--nixos/modules/installer/tools/nixos-generate-config.pl2
-rw-r--r--nixos/modules/installer/tools/nixos-option.sh12
-rw-r--r--nixos/modules/installer/tools/tools.nix4
-rw-r--r--nixos/modules/installer/virtualbox-demo.nix2
-rw-r--r--nixos/modules/misc/ids.nix24
-rw-r--r--nixos/modules/misc/locate.nix2
-rw-r--r--nixos/modules/module-list.nix21
-rw-r--r--nixos/modules/profiles/base.nix1
-rw-r--r--nixos/modules/profiles/clone-config.nix1
-rw-r--r--nixos/modules/profiles/demo.nix2
-rw-r--r--nixos/modules/programs/adb.nix4
-rw-r--r--nixos/modules/programs/digitalbitbox/default.nix2
-rw-r--r--nixos/modules/programs/environment.nix2
-rw-r--r--nixos/modules/programs/firejail.nix48
-rw-r--r--nixos/modules/programs/gphoto2.nix4
-rw-r--r--nixos/modules/programs/mosh.nix18
-rw-r--r--nixos/modules/programs/npm.nix4
-rw-r--r--nixos/modules/programs/nylas-mail.nix1
-rw-r--r--nixos/modules/programs/screen.nix4
-rw-r--r--nixos/modules/programs/shell.nix42
-rw-r--r--nixos/modules/programs/ssh.nix1
-rw-r--r--nixos/modules/programs/sway.nix2
-rw-r--r--nixos/modules/programs/thefuck.nix4
-rw-r--r--nixos/modules/programs/tmux.nix2
-rw-r--r--nixos/modules/programs/wireshark.nix2
-rw-r--r--nixos/modules/programs/xonsh.nix2
-rw-r--r--nixos/modules/programs/xss-lock.nix26
-rw-r--r--nixos/modules/programs/zsh/zsh-autosuggestions.nix60
-rw-r--r--nixos/modules/programs/zsh/zsh.nix19
-rw-r--r--nixos/modules/rename.nix23
-rw-r--r--nixos/modules/security/acme.nix1
-rw-r--r--nixos/modules/security/pam_mount.nix2
-rw-r--r--nixos/modules/security/pam_usb.nix2
-rw-r--r--nixos/modules/security/polkit.nix2
-rw-r--r--nixos/modules/security/rtkit.nix2
-rw-r--r--nixos/modules/security/sudo.nix3
-rw-r--r--nixos/modules/services/admin/oxidized.nix116
-rw-r--r--nixos/modules/services/amqp/activemq/default.nix4
-rw-r--r--nixos/modules/services/amqp/rabbitmq.nix4
-rw-r--r--nixos/modules/services/audio/liquidsoap.nix4
-rw-r--r--nixos/modules/services/audio/mopidy.nix4
-rw-r--r--nixos/modules/services/audio/mpd.nix13
-rw-r--r--nixos/modules/services/audio/slimserver.nix3
-rw-r--r--nixos/modules/services/audio/squeezelite.nix2
-rw-r--r--nixos/modules/services/backup/bacula.nix15
-rw-r--r--nixos/modules/services/backup/borgbackup.nix50
-rw-r--r--nixos/modules/services/backup/crashplan-small-business.nix1
-rw-r--r--nixos/modules/services/backup/crashplan.nix1
-rw-r--r--nixos/modules/services/backup/duplicati.nix23
-rw-r--r--nixos/modules/services/backup/mysql-backup.nix2
-rw-r--r--nixos/modules/services/backup/postgresql-backup.nix62
-rw-r--r--nixos/modules/services/backup/restic-rest-server.nix4
-rw-r--r--nixos/modules/services/backup/restic.nix11
-rw-r--r--nixos/modules/services/backup/znapzend.nix7
-rw-r--r--nixos/modules/services/cluster/hadoop/conf.nix31
-rw-r--r--nixos/modules/services/cluster/hadoop/default.nix60
-rw-r--r--nixos/modules/services/cluster/hadoop/hdfs.nix73
-rw-r--r--nixos/modules/services/cluster/hadoop/yarn.nix74
-rw-r--r--nixos/modules/services/cluster/kubernetes/dashboard.nix239
-rw-r--r--nixos/modules/services/cluster/kubernetes/default.nix133
-rw-r--r--nixos/modules/services/cluster/kubernetes/dns.nix165
-rw-r--r--nixos/modules/services/computing/slurm/slurm.nix92
-rw-r--r--nixos/modules/services/continuous-integration/buildbot/master.nix4
-rw-r--r--nixos/modules/services/continuous-integration/buildbot/worker.nix4
-rw-r--r--nixos/modules/services/continuous-integration/buildkite-agent.nix2
-rw-r--r--nixos/modules/services/continuous-integration/gitlab-runner.nix4
-rw-r--r--nixos/modules/services/continuous-integration/gocd-agent/default.nix4
-rw-r--r--nixos/modules/services/continuous-integration/gocd-server/default.nix8
-rw-r--r--nixos/modules/services/continuous-integration/hydra/default.nix8
-rw-r--r--nixos/modules/services/continuous-integration/jenkins/default.nix4
-rw-r--r--nixos/modules/services/continuous-integration/jenkins/slave.nix4
-rw-r--r--nixos/modules/services/databases/4store-endpoint.nix2
-rw-r--r--nixos/modules/services/databases/4store.nix2
-rw-r--r--nixos/modules/services/databases/aerospike.nix155
-rw-r--r--nixos/modules/services/databases/cassandra.nix2
-rw-r--r--nixos/modules/services/databases/clickhouse.nix4
-rw-r--r--nixos/modules/services/databases/couchdb.nix4
-rw-r--r--nixos/modules/services/databases/firebird.nix4
-rw-r--r--nixos/modules/services/databases/foundationdb.nix4
-rw-r--r--nixos/modules/services/databases/hbase.nix4
-rw-r--r--nixos/modules/services/databases/influxdb.nix4
-rw-r--r--nixos/modules/services/databases/memcached.nix2
-rw-r--r--nixos/modules/services/databases/mongodb.nix2
-rw-r--r--nixos/modules/services/databases/mysql.nix26
-rw-r--r--nixos/modules/services/databases/neo4j.nix677
-rw-r--r--nixos/modules/services/databases/openldap.nix4
-rw-r--r--nixos/modules/services/databases/opentsdb.nix4
-rw-r--r--nixos/modules/services/databases/pgmanage.nix68
-rw-r--r--nixos/modules/services/databases/postgresql.nix9
-rw-r--r--nixos/modules/services/databases/redis.nix2
-rw-r--r--nixos/modules/services/databases/rethinkdb.nix4
-rw-r--r--nixos/modules/services/databases/riak-cs.nix2
-rw-r--r--nixos/modules/services/databases/riak.nix4
-rw-r--r--nixos/modules/services/databases/stanchion.nix4
-rw-r--r--nixos/modules/services/databases/virtuoso.nix2
-rw-r--r--nixos/modules/services/desktops/bamf.nix23
-rw-r--r--nixos/modules/services/desktops/flatpak.nix10
-rw-r--r--nixos/modules/services/desktops/pipewire.nix22
-rw-r--r--nixos/modules/services/development/bloop.nix37
-rw-r--r--nixos/modules/services/editors/infinoted.nix4
-rw-r--r--nixos/modules/services/games/minecraft-server.nix2
-rw-r--r--nixos/modules/services/games/minetest-server.nix2
-rw-r--r--nixos/modules/services/games/terraria.nix4
-rw-r--r--nixos/modules/services/hardware/fwupd.nix2
-rw-r--r--nixos/modules/services/hardware/pcscd.nix4
-rw-r--r--nixos/modules/services/hardware/sane.nix4
-rw-r--r--nixos/modules/services/hardware/tcsd.nix4
-rw-r--r--nixos/modules/services/hardware/thinkfan.nix55
-rw-r--r--nixos/modules/services/hardware/udev.nix2
-rw-r--r--nixos/modules/services/hardware/udisks2.nix11
-rw-r--r--nixos/modules/services/hardware/usbmuxd.nix6
-rw-r--r--nixos/modules/services/logging/graylog.nix2
-rw-r--r--nixos/modules/services/logging/journaldriver.nix112
-rw-r--r--nixos/modules/services/logging/journalwatch.nix4
-rw-r--r--nixos/modules/services/logging/logcheck.nix2
-rw-r--r--nixos/modules/services/mail/dovecot.nix6
-rw-r--r--nixos/modules/services/mail/dspam.nix4
-rw-r--r--nixos/modules/services/mail/exim.nix5
-rw-r--r--nixos/modules/services/mail/mailhog.nix2
-rw-r--r--nixos/modules/services/mail/mlmmj.nix4
-rw-r--r--nixos/modules/services/mail/nullmailer.nix4
-rw-r--r--nixos/modules/services/mail/opendkim.nix4
-rw-r--r--nixos/modules/services/mail/opensmtpd.nix17
-rw-r--r--nixos/modules/services/mail/postfix.nix4
-rw-r--r--nixos/modules/services/mail/postgrey.nix4
-rw-r--r--nixos/modules/services/mail/postsrsd.nix4
-rw-r--r--nixos/modules/services/mail/rmilter.nix8
-rw-r--r--nixos/modules/services/mail/rspamd.nix4
-rw-r--r--nixos/modules/services/mail/spamassassin.nix4
-rw-r--r--nixos/modules/services/misc/airsonic.nix2
-rw-r--r--nixos/modules/services/misc/apache-kafka.nix2
-rw-r--r--nixos/modules/services/misc/autorandr.nix24
-rw-r--r--nixos/modules/services/misc/bepasty.nix4
-rw-r--r--nixos/modules/services/misc/calibre-server.nix4
-rw-r--r--nixos/modules/services/misc/cfdyndns.nix4
-rw-r--r--nixos/modules/services/misc/cgminer.nix2
-rw-r--r--nixos/modules/services/misc/clipmenu.nix31
-rw-r--r--nixos/modules/services/misc/couchpotato.nix4
-rw-r--r--nixos/modules/services/misc/dictd.nix4
-rw-r--r--nixos/modules/services/misc/disnix.nix12
-rw-r--r--nixos/modules/services/misc/docker-registry.nix44
-rw-r--r--nixos/modules/services/misc/dysnomia.nix3
-rw-r--r--nixos/modules/services/misc/emby.nix5
-rw-r--r--nixos/modules/services/misc/errbot.nix4
-rw-r--r--nixos/modules/services/misc/etcd.nix2
-rw-r--r--nixos/modules/services/misc/exhibitor.nix3
-rw-r--r--nixos/modules/services/misc/felix.nix4
-rw-r--r--nixos/modules/services/misc/folding-at-home.nix2
-rw-r--r--nixos/modules/services/misc/gammu-smsd.nix2
-rw-r--r--nixos/modules/services/misc/geoip-updater.nix2
-rw-r--r--nixos/modules/services/misc/gitea.nix78
-rw-r--r--nixos/modules/services/misc/gitit.nix10
-rw-r--r--nixos/modules/services/misc/gitlab.nix17
-rw-r--r--nixos/modules/services/misc/gitolite.nix4
-rw-r--r--nixos/modules/services/misc/gogs.nix4
-rw-r--r--nixos/modules/services/misc/gollum.nix4
-rw-r--r--nixos/modules/services/misc/gpsd.nix15
-rw-r--r--nixos/modules/services/misc/home-assistant.nix18
-rw-r--r--nixos/modules/services/misc/ihaskell.nix10
-rw-r--r--nixos/modules/services/misc/jackett.nix4
-rw-r--r--nixos/modules/services/misc/leaps.nix2
-rw-r--r--nixos/modules/services/misc/mathics.nix10
-rw-r--r--nixos/modules/services/misc/matrix-synapse.nix4
-rw-r--r--nixos/modules/services/misc/mediatomb.nix5
-rw-r--r--nixos/modules/services/misc/nix-daemon.nix31
-rw-r--r--nixos/modules/services/misc/nix-ssh-serve.nix4
-rw-r--r--nixos/modules/services/misc/nixos-manual.nix2
-rw-r--r--nixos/modules/services/misc/nzbget.nix6
-rw-r--r--nixos/modules/services/misc/octoprint.nix4
-rw-r--r--nixos/modules/services/misc/osrm.nix2
-rw-r--r--nixos/modules/services/misc/plex.nix5
-rw-r--r--nixos/modules/services/misc/plexpy.nix2
-rw-r--r--nixos/modules/services/misc/pykms.nix4
-rw-r--r--nixos/modules/services/misc/radarr.nix4
-rw-r--r--nixos/modules/services/misc/redmine.nix4
-rw-r--r--nixos/modules/services/misc/ripple-data-api.nix2
-rw-r--r--nixos/modules/services/misc/rippled.nix2
-rw-r--r--nixos/modules/services/misc/serviio.nix4
-rw-r--r--nixos/modules/services/misc/siproxd.nix2
-rw-r--r--nixos/modules/services/misc/sonarr.nix4
-rw-r--r--nixos/modules/services/misc/subsonic.nix6
-rw-r--r--nixos/modules/services/misc/taskserver/default.nix10
-rw-r--r--nixos/modules/services/misc/uhub.nix4
-rw-r--r--nixos/modules/services/misc/xmr-stak.nix60
-rw-r--r--nixos/modules/services/misc/zookeeper.nix2
-rw-r--r--nixos/modules/services/monitoring/bosun.nix4
-rw-r--r--nixos/modules/services/monitoring/collectd.nix2
-rw-r--r--nixos/modules/services/monitoring/dd-agent/dd-agent.nix16
-rw-r--r--nixos/modules/services/monitoring/fusion-inventory.nix2
-rw-r--r--nixos/modules/services/monitoring/grafana.nix2
-rw-r--r--nixos/modules/services/monitoring/graphite.nix4
-rw-r--r--nixos/modules/services/monitoring/heapster.nix2
-rw-r--r--nixos/modules/services/monitoring/munin.nix4
-rw-r--r--nixos/modules/services/monitoring/nagios.nix2
-rw-r--r--nixos/modules/services/monitoring/netdata.nix4
-rw-r--r--nixos/modules/services/monitoring/prometheus/default.nix4
-rw-r--r--nixos/modules/services/monitoring/prometheus/exporters.nix1
-rw-r--r--nixos/modules/services/monitoring/prometheus/exporters/dnsmasq.nix39
-rw-r--r--nixos/modules/services/monitoring/prometheus/exporters/node.nix1
-rw-r--r--nixos/modules/services/monitoring/riemann-dash.nix4
-rw-r--r--nixos/modules/services/monitoring/riemann-tools.nix4
-rw-r--r--nixos/modules/services/monitoring/riemann.nix4
-rw-r--r--nixos/modules/services/monitoring/scollector.nix4
-rw-r--r--nixos/modules/services/monitoring/statsd.nix2
-rw-r--r--nixos/modules/services/monitoring/telegraf.nix2
-rw-r--r--nixos/modules/services/monitoring/ups.nix4
-rw-r--r--nixos/modules/services/monitoring/uptime.nix2
-rw-r--r--nixos/modules/services/monitoring/vnstat.nix2
-rw-r--r--nixos/modules/services/monitoring/zabbix-agent.nix2
-rw-r--r--nixos/modules/services/monitoring/zabbix-server.nix2
-rw-r--r--nixos/modules/services/network-filesystems/beegfs.nix2
-rw-r--r--nixos/modules/services/network-filesystems/ceph.nix4
-rw-r--r--nixos/modules/services/network-filesystems/davfs2.nix4
-rw-r--r--nixos/modules/services/network-filesystems/ipfs.nix20
-rw-r--r--nixos/modules/services/network-filesystems/openafs/client.nix26
-rw-r--r--nixos/modules/services/network-filesystems/openafs/lib.nix9
-rw-r--r--nixos/modules/services/network-filesystems/openafs/server.nix36
-rw-r--r--nixos/modules/services/network-filesystems/tahoe.nix4
-rw-r--r--nixos/modules/services/network-filesystems/xtreemfs.nix4
-rw-r--r--nixos/modules/services/network-filesystems/yandex-disk.nix2
-rw-r--r--nixos/modules/services/networking/amuled.nix4
-rw-r--r--nixos/modules/services/networking/aria2.nix4
-rw-r--r--nixos/modules/services/networking/asterisk.nix4
-rw-r--r--nixos/modules/services/networking/avahi-daemon.nix4
-rw-r--r--nixos/modules/services/networking/bind.nix12
-rw-r--r--nixos/modules/services/networking/bird.nix4
-rw-r--r--nixos/modules/services/networking/bitlbee.nix4
-rw-r--r--nixos/modules/services/networking/btsync.nix4
-rw-r--r--nixos/modules/services/networking/charybdis.nix4
-rw-r--r--nixos/modules/services/networking/chrony.nix8
-rw-r--r--nixos/modules/services/networking/cjdns.nix3
-rw-r--r--nixos/modules/services/networking/cntlm.nix2
-rw-r--r--nixos/modules/services/networking/consul.nix2
-rw-r--r--nixos/modules/services/networking/coturn.nix4
-rw-r--r--nixos/modules/services/networking/dhcpd.nix2
-rw-r--r--nixos/modules/services/networking/dnscache.nix2
-rw-r--r--nixos/modules/services/networking/dnschain.nix2
-rw-r--r--nixos/modules/services/networking/dnscrypt-proxy.nix7
-rw-r--r--nixos/modules/services/networking/dnsdist.nix61
-rw-r--r--nixos/modules/services/networking/dnsmasq.nix2
-rw-r--r--nixos/modules/services/networking/ejabberd.nix4
-rw-r--r--nixos/modules/services/networking/firewall.nix439
-rw-r--r--nixos/modules/services/networking/freenet.nix4
-rw-r--r--nixos/modules/services/networking/freeradius.nix2
-rw-r--r--nixos/modules/services/networking/gale.nix4
-rw-r--r--nixos/modules/services/networking/gateone.nix4
-rw-r--r--nixos/modules/services/networking/gdomap.nix3
-rw-r--r--nixos/modules/services/networking/git-daemon.nix4
-rw-r--r--nixos/modules/services/networking/gnunet.nix4
-rw-r--r--nixos/modules/services/networking/hans.nix2
-rw-r--r--nixos/modules/services/networking/haproxy.nix4
-rw-r--r--nixos/modules/services/networking/hostapd.nix2
-rw-r--r--nixos/modules/services/networking/i2p.nix4
-rw-r--r--nixos/modules/services/networking/i2pd.nix8
-rw-r--r--nixos/modules/services/networking/iodine.nix4
-rw-r--r--nixos/modules/services/networking/ircd-hybrid/default.nix4
-rw-r--r--nixos/modules/services/networking/iwd.nix4
-rw-r--r--nixos/modules/services/networking/kippo.nix4
-rw-r--r--nixos/modules/services/networking/kresd.nix4
-rw-r--r--nixos/modules/services/networking/lambdabot.nix4
-rw-r--r--nixos/modules/services/networking/lldpd.nix4
-rw-r--r--nixos/modules/services/networking/mailpile.nix4
-rw-r--r--nixos/modules/services/networking/matterbridge.nix4
-rw-r--r--nixos/modules/services/networking/minidlna.nix4
-rw-r--r--nixos/modules/services/networking/mjpg-streamer.nix2
-rw-r--r--nixos/modules/services/networking/monero.nix4
-rw-r--r--nixos/modules/services/networking/morty.nix96
-rw-r--r--nixos/modules/services/networking/mosquitto.nix4
-rw-r--r--nixos/modules/services/networking/murmur.nix4
-rw-r--r--nixos/modules/services/networking/namecoind.nix4
-rw-r--r--nixos/modules/services/networking/nat.nix20
-rw-r--r--nixos/modules/services/networking/networkmanager.nix186
-rw-r--r--nixos/modules/services/networking/ngircd.nix2
-rw-r--r--nixos/modules/services/networking/nix-serve.nix2
-rw-r--r--nixos/modules/services/networking/nntp-proxy.nix2
-rw-r--r--nixos/modules/services/networking/nsd.nix4
-rw-r--r--nixos/modules/services/networking/ntpd.nix2
-rw-r--r--nixos/modules/services/networking/nylon.nix4
-rw-r--r--nixos/modules/services/networking/oidentd.nix4
-rw-r--r--nixos/modules/services/networking/openntpd.nix12
-rw-r--r--nixos/modules/services/networking/openvpn.nix3
-rw-r--r--nixos/modules/services/networking/owamp.nix47
-rw-r--r--nixos/modules/services/networking/pdns-recursor.nix2
-rw-r--r--nixos/modules/services/networking/pdnsd.nix4
-rw-r--r--nixos/modules/services/networking/polipo.nix4
-rw-r--r--nixos/modules/services/networking/prayer.nix4
-rw-r--r--nixos/modules/services/networking/prosody.nix4
-rw-r--r--nixos/modules/services/networking/quagga.nix33
-rw-r--r--nixos/modules/services/networking/quassel.nix4
-rw-r--r--nixos/modules/services/networking/radicale.nix4
-rw-r--r--nixos/modules/services/networking/radvd.nix2
-rw-r--r--nixos/modules/services/networking/rdnssd.nix2
-rw-r--r--nixos/modules/services/networking/resilio.nix4
-rw-r--r--nixos/modules/services/networking/rpcbind.nix2
-rw-r--r--nixos/modules/services/networking/sabnzbd.nix4
-rw-r--r--nixos/modules/services/networking/searx.nix4
-rw-r--r--nixos/modules/services/networking/seeks.nix4
-rw-r--r--nixos/modules/services/networking/shairport-sync.nix2
-rw-r--r--nixos/modules/services/networking/shout.nix2
-rw-r--r--nixos/modules/services/networking/smokeping.nix2
-rw-r--r--nixos/modules/services/networking/sniproxy.nix4
-rw-r--r--nixos/modules/services/networking/spiped.nix4
-rw-r--r--nixos/modules/services/networking/ssh/sshd.nix62
-rw-r--r--nixos/modules/services/networking/sslh.nix114
-rw-r--r--nixos/modules/services/networking/strongswan-swanctl/swanctl-params.nix7
-rw-r--r--nixos/modules/services/networking/supplicant.nix2
-rw-r--r--nixos/modules/services/networking/supybot.nix4
-rw-r--r--nixos/modules/services/networking/syncthing.nix4
-rw-r--r--nixos/modules/services/networking/tcpcrypt.nix2
-rw-r--r--nixos/modules/services/networking/tinc.nix12
-rw-r--r--nixos/modules/services/networking/tinydns.nix2
-rw-r--r--nixos/modules/services/networking/tox-bootstrapd.nix2
-rw-r--r--nixos/modules/services/networking/toxvpn.nix2
-rw-r--r--nixos/modules/services/networking/tvheadend.nix4
-rw-r--r--nixos/modules/services/networking/unbound.nix11
-rw-r--r--nixos/modules/services/networking/unifi.nix2
-rw-r--r--nixos/modules/services/networking/vsftpd.nix4
-rw-r--r--nixos/modules/services/networking/wireguard.nix4
-rw-r--r--nixos/modules/services/networking/xrdp.nix1
-rw-r--r--nixos/modules/services/networking/zerotierone.nix2
-rw-r--r--nixos/modules/services/networking/znc.nix16
-rw-r--r--nixos/modules/services/printing/cupsd.nix19
-rw-r--r--nixos/modules/services/scheduling/atd.nix4
-rw-r--r--nixos/modules/services/scheduling/chronos.nix2
-rw-r--r--nixos/modules/services/scheduling/fcron.nix3
-rw-r--r--nixos/modules/services/scheduling/marathon.nix2
-rw-r--r--nixos/modules/services/search/hound.nix4
-rw-r--r--nixos/modules/services/search/kibana.nix2
-rw-r--r--nixos/modules/services/security/clamav.nix4
-rw-r--r--nixos/modules/services/security/fprot.nix4
-rw-r--r--nixos/modules/services/security/munge.nix16
-rw-r--r--nixos/modules/services/security/oauth2_proxy.nix3
-rw-r--r--nixos/modules/services/security/oauth2_proxy_nginx.nix64
-rw-r--r--nixos/modules/services/security/tor.nix55
-rw-r--r--nixos/modules/services/security/vault.nix4
-rw-r--r--nixos/modules/services/system/dbus.nix5
-rw-r--r--nixos/modules/services/system/kerberos.nix10
-rw-r--r--nixos/modules/services/system/nscd.nix4
-rw-r--r--nixos/modules/services/system/saslauthd.nix1
-rw-r--r--nixos/modules/services/system/uptimed.nix2
-rw-r--r--nixos/modules/services/torrent/deluge.nix4
-rw-r--r--nixos/modules/services/torrent/peerflix.nix2
-rw-r--r--nixos/modules/services/torrent/transmission.nix10
-rw-r--r--nixos/modules/services/ttys/kmscon.nix2
-rw-r--r--nixos/modules/services/web-apps/atlassian/confluence.nix4
-rw-r--r--nixos/modules/services/web-apps/atlassian/crowd.nix9
-rw-r--r--nixos/modules/services/web-apps/atlassian/jira.nix4
-rw-r--r--nixos/modules/services/web-apps/frab.nix5
-rw-r--r--nixos/modules/services/web-apps/matomo.nix6
-rw-r--r--nixos/modules/services/web-apps/mattermost.nix12
-rw-r--r--nixos/modules/services/web-apps/nexus.nix22
-rw-r--r--nixos/modules/services/web-apps/restya-board.nix4
-rw-r--r--nixos/modules/services/web-apps/tt-rss.nix44
-rw-r--r--nixos/modules/services/web-apps/virtlyst.nix72
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/default.nix11
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/owncloud.nix11
-rw-r--r--nixos/modules/services/web-servers/apache-httpd/trac.nix2
-rw-r--r--nixos/modules/services/web-servers/caddy.nix4
-rw-r--r--nixos/modules/services/web-servers/hitch/default.nix4
-rw-r--r--nixos/modules/services/web-servers/hydron.nix105
-rw-r--r--nixos/modules/services/web-servers/lighttpd/cgit.nix28
-rw-r--r--nixos/modules/services/web-servers/lighttpd/default.nix4
-rw-r--r--nixos/modules/services/web-servers/lighttpd/inginious.nix261
-rw-r--r--nixos/modules/services/web-servers/meguca.nix159
-rw-r--r--nixos/modules/services/web-servers/mighttpd2.nix4
-rw-r--r--nixos/modules/services/web-servers/minio.nix6
-rw-r--r--nixos/modules/services/web-servers/nginx/default.nix4
-rw-r--r--nixos/modules/services/web-servers/nginx/vhost-options.nix1
-rw-r--r--nixos/modules/services/web-servers/tomcat.nix6
-rw-r--r--nixos/modules/services/web-servers/traefik.nix4
-rw-r--r--nixos/modules/services/web-servers/uwsgi.nix16
-rw-r--r--nixos/modules/services/web-servers/varnish/default.nix4
-rw-r--r--nixos/modules/services/web-servers/zope2.nix2
-rw-r--r--nixos/modules/services/x11/desktop-managers/gnome3.nix1
-rw-r--r--nixos/modules/services/x11/desktop-managers/plasma5.nix7
-rw-r--r--nixos/modules/services/x11/desktop-managers/xfce.nix8
-rw-r--r--nixos/modules/services/x11/display-managers/gdm.nix4
-rw-r--r--nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix2
-rw-r--r--nixos/modules/services/x11/display-managers/lightdm-greeters/mini.nix100
-rw-r--r--nixos/modules/services/x11/display-managers/lightdm.nix9
-rw-r--r--nixos/modules/services/x11/display-managers/sddm.nix45
-rw-r--r--nixos/modules/services/x11/hardware/libinput.nix2
-rw-r--r--nixos/modules/services/x11/window-managers/awesome.nix7
-rw-r--r--nixos/modules/services/x11/window-managers/openbox.nix1
-rw-r--r--nixos/modules/services/x11/window-managers/wmii.nix1
-rw-r--r--nixos/modules/services/x11/xserver.nix7
-rw-r--r--nixos/modules/system/boot/initrd-network.nix1
-rw-r--r--nixos/modules/system/boot/initrd-ssh.nix2
-rw-r--r--nixos/modules/system/boot/loader/grub/grub.nix28
-rw-r--r--nixos/modules/system/boot/loader/grub/install-grub.pl42
-rw-r--r--nixos/modules/system/boot/resolved.nix2
-rw-r--r--nixos/modules/system/boot/stage-1-init.sh3
-rw-r--r--nixos/modules/system/boot/stage-1.nix9
-rw-r--r--nixos/modules/system/boot/stage-2.nix3
-rw-r--r--nixos/modules/system/boot/systemd-lib.nix14
-rw-r--r--nixos/modules/system/boot/systemd-nspawn.nix3
-rw-r--r--nixos/modules/system/boot/systemd.nix20
-rw-r--r--nixos/modules/system/boot/timesyncd.nix6
-rw-r--r--nixos/modules/tasks/encrypted-devices.nix1
-rw-r--r--nixos/modules/tasks/filesystems/zfs.nix115
-rw-r--r--nixos/modules/tasks/network-interfaces-scripted.nix3
-rw-r--r--nixos/modules/tasks/network-interfaces.nix18
-rw-r--r--nixos/modules/tasks/scsi-link-power-management.nix26
-rw-r--r--nixos/modules/tasks/swraid.nix2
-rw-r--r--nixos/modules/testing/test-instrumentation.nix6
-rw-r--r--nixos/modules/virtualisation/azure-image.nix4
-rw-r--r--nixos/modules/virtualisation/azure-qemu-220-no-etc-install.patch14
-rw-r--r--nixos/modules/virtualisation/docker.nix2
-rw-r--r--nixos/modules/virtualisation/gce-images.nix3
-rw-r--r--nixos/modules/virtualisation/google-compute-image.nix2
-rw-r--r--nixos/modules/virtualisation/kvmgt.nix64
-rw-r--r--nixos/modules/virtualisation/libvirtd.nix2
-rw-r--r--nixos/modules/virtualisation/lxc-container.nix2
-rw-r--r--nixos/modules/virtualisation/lxd.nix4
-rw-r--r--nixos/modules/virtualisation/openvswitch.nix3
-rw-r--r--nixos/modules/virtualisation/rkt.nix2
-rw-r--r--nixos/modules/virtualisation/virtualbox-guest.nix2
-rw-r--r--nixos/modules/virtualisation/virtualbox-host.nix2
-rw-r--r--nixos/modules/virtualisation/virtualbox-image.nix36
-rw-r--r--nixos/release-combined.nix14
-rw-r--r--nixos/release.nix14
-rw-r--r--nixos/tests/acme.nix2
-rw-r--r--nixos/tests/atd.nix2
-rw-r--r--nixos/tests/bind.nix27
-rw-r--r--nixos/tests/cjdns.nix10
-rw-r--r--nixos/tests/common/letsencrypt/default.nix (renamed from nixos/tests/common/letsencrypt.nix)75
-rw-r--r--nixos/tests/common/letsencrypt/mkcerts.nix69
-rwxr-xr-xnixos/tests/common/letsencrypt/mkcerts.sh6
-rw-r--r--nixos/tests/common/letsencrypt/snakeoil-certs.nix253
-rw-r--r--nixos/tests/common/resolver.nix2
-rw-r--r--nixos/tests/common/user-account.nix4
-rw-r--r--nixos/tests/containers-imperative.nix7
-rw-r--r--nixos/tests/containers-reloadable.nix1
-rw-r--r--nixos/tests/dnscrypt-proxy.nix3
-rw-r--r--nixos/tests/docker-tools.nix6
-rw-r--r--nixos/tests/flatpak.nix1
-rw-r--r--nixos/tests/gdk-pixbuf.nix19
-rw-r--r--nixos/tests/gitolite.nix4
-rw-r--r--nixos/tests/gnome3.nix9
-rw-r--r--nixos/tests/hadoop/hdfs.nix54
-rw-r--r--nixos/tests/hadoop/yarn.nix46
-rw-r--r--nixos/tests/haproxy.nix41
-rw-r--r--nixos/tests/hardened.nix8
-rw-r--r--nixos/tests/home-assistant.nix3
-rw-r--r--nixos/tests/hydra.nix32
-rwxr-xr-xnixos/tests/hydra/create-trivial-project.sh56
-rw-r--r--nixos/tests/hydra/default.nix78
-rw-r--r--nixos/tests/iftop.nix14
-rw-r--r--nixos/tests/installer.nix11
-rw-r--r--nixos/tests/jenkins.nix4
-rw-r--r--nixos/tests/kubernetes/base.nix2
-rw-r--r--nixos/tests/kubernetes/kubernetes-common.nix1
-rw-r--r--nixos/tests/lightdm.nix2
-rw-r--r--nixos/tests/memcached.nix28
-rw-r--r--nixos/tests/morty.nix32
-rw-r--r--nixos/tests/mpd.nix119
-rw-r--r--nixos/tests/mysql-replication.nix11
-rw-r--r--nixos/tests/mysql.nix1
-rw-r--r--nixos/tests/nexus.nix2
-rw-r--r--nixos/tests/opensmtpd.nix115
-rw-r--r--nixos/tests/openssh.nix4
-rw-r--r--nixos/tests/ostree.nix21
-rw-r--r--nixos/tests/pam-oath-login.nix4
-rw-r--r--nixos/tests/plasma5.nix20
-rw-r--r--nixos/tests/postgresql.nix7
-rw-r--r--nixos/tests/sddm.nix2
-rw-r--r--nixos/tests/slim.nix2
-rw-r--r--nixos/tests/slurm.nix26
-rw-r--r--nixos/tests/sudo.nix2
-rw-r--r--nixos/tests/taskserver.nix7
-rw-r--r--nixos/tests/tor.nix28
-rw-r--r--nixos/tests/virtualbox.nix2
-rw-r--r--nixos/tests/xss-lock.nix25
523 files changed, 7193 insertions, 2387 deletions
diff --git a/nixos/doc/manual/Makefile b/nixos/doc/manual/Makefile
index 2e2322d5fb51..5cbbf140869a 100644
--- a/nixos/doc/manual/Makefile
+++ b/nixos/doc/manual/Makefile
@@ -14,6 +14,11 @@ format:
 	find . -iname '*.xml' -type f -print0 | xargs -0 -I{} -n1 \
 		xmlformat --config-file "../xmlformat.conf" -i {}
 
+.PHONY: fix-misc-xml
+fix-misc-xml:
+	find . -iname '*.xml' -type f \
+		-exec ../varlistentry-fixer.rb {} ';'
+
 .PHONY: clean
 clean:
 	rm -f manual-combined.xml generated
diff --git a/nixos/doc/manual/administration/boot-problems.xml b/nixos/doc/manual/administration/boot-problems.xml
index 5f05ad261ef3..de3d8ac21aeb 100644
--- a/nixos/doc/manual/administration/boot-problems.xml
+++ b/nixos/doc/manual/administration/boot-problems.xml
@@ -14,7 +14,8 @@
   NixOS boot scripts or by systemd:
   <variablelist>
    <varlistentry>
-    <term><literal>boot.shell_on_fail</literal>
+    <term>
+     <literal>boot.shell_on_fail</literal>
     </term>
     <listitem>
      <para>
@@ -25,7 +26,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><literal>boot.debug1</literal>
+    <term>
+     <literal>boot.debug1</literal>
     </term>
     <listitem>
      <para>
@@ -37,7 +39,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><literal>boot.trace</literal>
+    <term>
+     <literal>boot.trace</literal>
     </term>
     <listitem>
      <para>
@@ -46,7 +49,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><literal>single</literal>
+    <term>
+     <literal>single</literal>
     </term>
     <listitem>
      <para>
@@ -59,7 +63,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><literal>systemd.log_level=debug systemd.log_target=console</literal>
+    <term>
+     <literal>systemd.log_level=debug systemd.log_target=console</literal>
     </term>
     <listitem>
      <para>
diff --git a/nixos/doc/manual/administration/imperative-containers.xml b/nixos/doc/manual/administration/imperative-containers.xml
index 9cc7ca3e672a..9bb62bc2ece9 100644
--- a/nixos/doc/manual/administration/imperative-containers.xml
+++ b/nixos/doc/manual/administration/imperative-containers.xml
@@ -27,7 +27,7 @@
 <screen>
 # nixos-container create foo --config '
   <xref linkend="opt-services.openssh.enable"/> = true;
-  <link linkend="opt-users.users._name__.openssh.authorizedKeys.keys">users.extraUsers.root.openssh.authorizedKeys.keys</link> = ["ssh-dss AAAAB3N…"];
+  <link linkend="opt-users.users._name__.openssh.authorizedKeys.keys">users.users.root.openssh.authorizedKeys.keys</link> = ["ssh-dss AAAAB3N…"];
 '
 </screen>
  </para>
diff --git a/nixos/doc/manual/configuration/config-file.xml b/nixos/doc/manual/configuration/config-file.xml
index a9420b3fc921..8a1a39c98c10 100644
--- a/nixos/doc/manual/configuration/config-file.xml
+++ b/nixos/doc/manual/configuration/config-file.xml
@@ -80,7 +80,9 @@ The option value `services.httpd.enable' in `/etc/nixos/configuration.nix' is no
   Options have various types of values. The most important are:
   <variablelist>
    <varlistentry>
-    <term>Strings</term>
+    <term>
+     Strings
+    </term>
     <listitem>
      <para>
       Strings are enclosed in double quotes, e.g.
@@ -112,7 +114,9 @@ The option value `services.httpd.enable' in `/etc/nixos/configuration.nix' is no
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term>Booleans</term>
+    <term>
+     Booleans
+    </term>
     <listitem>
      <para>
       These can be <literal>true</literal> or <literal>false</literal>, e.g.
@@ -124,7 +128,9 @@ The option value `services.httpd.enable' in `/etc/nixos/configuration.nix' is no
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term>Integers</term>
+    <term>
+     Integers
+    </term>
     <listitem>
      <para>
       For example,
@@ -141,7 +147,9 @@ The option value `services.httpd.enable' in `/etc/nixos/configuration.nix' is no
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term>Sets</term>
+    <term>
+     Sets
+    </term>
     <listitem>
      <para>
       Sets were introduced above. They are name/value pairs enclosed in braces,
@@ -157,7 +165,9 @@ The option value `services.httpd.enable' in `/etc/nixos/configuration.nix' is no
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term>Lists</term>
+    <term>
+     Lists
+    </term>
     <listitem>
      <para>
       The important thing to note about lists is that list elements are
@@ -173,7 +183,9 @@ swapDevices = [ { device = "/dev/disk/by-label/swap"; } ];
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term>Packages</term>
+    <term>
+     Packages
+    </term>
     <listitem>
      <para>
       Usually, the packages you need are already part of the Nix Packages
diff --git a/nixos/doc/manual/configuration/linux-kernel.xml b/nixos/doc/manual/configuration/linux-kernel.xml
index 6502aaec83e5..f4d697c42dbd 100644
--- a/nixos/doc/manual/configuration/linux-kernel.xml
+++ b/nixos/doc/manual/configuration/linux-kernel.xml
@@ -67,6 +67,57 @@ nixpkgs.config.packageOverrides = pkgs:
   parameters, run <command>sysctl -a</command>.
  </para>
  <section>
+  <title>Customize your kernel</title>
+
+  <para>
+   The first step before compiling the kernel is to generate an appropriate
+   <literal>.config</literal> configuration. Either you pass your own config via
+   the <literal>configfile</literal> setting of <literal>linuxManualConfig</literal>:
+  <screen><![CDATA[
+  custom-kernel = super.linuxManualConfig {
+    inherit (super) stdenv hostPlatform;
+    inherit (linux_4_9) src;
+    version = "${linux_4_9.version}-custom";
+
+    configfile = /home/me/my_kernel_config;
+    allowImportFromDerivation = true;
+  };
+  ]]></screen>
+
+You can edit the config with this snippet (by default <command>make menuconfig</command> won't work
+  out of the box on nixos):
+  <screen><![CDATA[
+      nix-shell -E 'with import <nixpkgs> {}; kernelToOverride.overrideAttrs (o: {nativeBuildInputs=o.nativeBuildInputs ++ [ pkgconfig ncurses ];})'
+  ]]></screen>
+
+
+  or you can let nixpkgs generate the configuration.
+  Nixpkgs generates it via answering the interactive kernel utility <command>make config</command>.
+  The answers depend on parameters passed to <filename>pkgs/os-specific/linux/kernel/generic.nix</filename>
+  (which you can influence by overriding <literal>extraConfig, autoModules, modDirVersion, preferBuiltin, extraConfig</literal>).
+<screen><![CDATA[
+
+  mptcp93.override ({
+      name="mptcp-local";
+
+      ignoreConfigErrors = true;
+      autoModules = false;
+      kernelPreferBuiltin = true;
+
+      enableParallelBuilding = true;
+
+      extraConfig = ''
+        DEBUG_KERNEL y
+        FRAME_POINTER y
+        KGDB y
+        KGDB_SERIAL_CONSOLE y
+        DEBUG_INFO y
+      '';
+    });
+  ]]></screen>
+  </para>
+ </section>
+ <section>
   <title>Developing kernel modules</title>
 
   <para>
diff --git a/nixos/doc/manual/configuration/network-manager.xml b/nixos/doc/manual/configuration/network-manager.xml
index e217a99148b9..d103ee249783 100644
--- a/nixos/doc/manual/configuration/network-manager.xml
+++ b/nixos/doc/manual/configuration/network-manager.xml
@@ -19,7 +19,7 @@
   All users that should have permission to change network settings must belong
   to the <code>networkmanager</code> group:
 <programlisting>
-<link linkend="opt-users.users._name__.extraGroups">users.extraUsers.youruser.extraGroups</link> = [ "networkmanager" ];
+<link linkend="opt-users.users._name__.extraGroups">users.users.alice.extraGroups</link> = [ "networkmanager" ];
 </programlisting>
  </para>
 
diff --git a/nixos/doc/manual/configuration/ssh.xml b/nixos/doc/manual/configuration/ssh.xml
index 6e883e3fbbc1..a4af1b96583d 100644
--- a/nixos/doc/manual/configuration/ssh.xml
+++ b/nixos/doc/manual/configuration/ssh.xml
@@ -20,7 +20,7 @@
   follows:
 <!-- FIXME: this might not work if the user is unmanaged. -->
 <programlisting>
-<link linkend="opt-users.users._name__.openssh.authorizedKeys.keys">users.extraUsers.alice.openssh.authorizedKeys.keys</link> =
+<link linkend="opt-users.users._name__.openssh.authorizedKeys.keys">users.users.alice.openssh.authorizedKeys.keys</link> =
   [ "ssh-dss AAAAB3NzaC1kc3MAAACBAPIkGWVEt4..." ];
 </programlisting>
  </para>
diff --git a/nixos/doc/manual/default.nix b/nixos/doc/manual/default.nix
index 2c6309474b37..be28c2c17afd 100644
--- a/nixos/doc/manual/default.nix
+++ b/nixos/doc/manual/default.nix
@@ -31,11 +31,12 @@ let
                   else p;
       describe = args:
         let
+          title = args.title or null;
           name = args.name or (lib.concatStringsSep "." args.path);
           path = args.path or [ args.name ];
           package = args.package or (lib.attrByPath path (throw "Invalid package attribute path `${toString path}'") pkgs);
         in "<listitem>"
-        + "<para><literal>pkgs.${name} (${package.meta.name})</literal>"
+        + "<para><literal>${lib.optionalString (title != null) "${title} aka "}pkgs.${name} (${package.meta.name})</literal>"
         + lib.optionalString (!package.meta.available) " <emphasis>[UNAVAILABLE]</emphasis>"
         + ": ${package.meta.description or "???"}.</para>"
         + lib.optionalString (args ? comment) "\n<para>${args.comment}</para>"
@@ -51,7 +52,7 @@ let
   // lib.optionalAttrs (opt ? example) { example = substFunction opt.example; }
   // lib.optionalAttrs (opt ? default) { default = substFunction opt.default; }
   // lib.optionalAttrs (opt ? type) { type = substFunction opt.type; }
-  // lib.optionalAttrs (opt ? relatedPackages) { relatedPackages = genRelatedPackages opt.relatedPackages; });
+  // lib.optionalAttrs (opt ? relatedPackages && opt.relatedPackages != []) { relatedPackages = genRelatedPackages opt.relatedPackages; });
 
   # We need to strip references to /nix/store/* from options,
   # including any `extraSources` if some modules came from elsewhere,
@@ -208,13 +209,13 @@ let
         --stringparam collect.xref.targets only \
         --stringparam targets.filename "$out/manual.db" \
         --nonet \
-        ${docbook5_xsl}/xml/xsl/docbook/xhtml/chunktoc.xsl \
+        ${docbook_xsl_ns}/xml/xsl/docbook/xhtml/chunktoc.xsl \
         ${manual-combined}/manual-combined.xml
 
       cat > "$out/olinkdb.xml" <<EOF
       <?xml version="1.0" encoding="utf-8"?>
       <!DOCTYPE targetset SYSTEM
-        "file://${docbook5_xsl}/xml/xsl/docbook/common/targetdatabase.dtd" [
+        "file://${docbook_xsl_ns}/xml/xsl/docbook/common/targetdatabase.dtd" [
         <!ENTITY manualtargets SYSTEM "file://$out/manual.db">
       ]>
       <targetset>
@@ -263,11 +264,11 @@ in rec {
         ${manualXsltprocOptions} \
         --stringparam target.database.document "${olinkDB}/olinkdb.xml" \
         --nonet --output $dst/ \
-        ${docbook5_xsl}/xml/xsl/docbook/xhtml/chunktoc.xsl \
+        ${docbook_xsl_ns}/xml/xsl/docbook/xhtml/chunktoc.xsl \
         ${manual-combined}/manual-combined.xml
 
       mkdir -p $dst/images/callouts
-      cp ${docbook5_xsl}/xml/xsl/docbook/images/callouts/*.svg $dst/images/callouts/
+      cp ${docbook_xsl_ns}/xml/xsl/docbook/images/callouts/*.svg $dst/images/callouts/
 
       cp ${../../../doc/style.css} $dst/style.css
       cp ${../../../doc/overrides.css} $dst/overrides.css
@@ -291,11 +292,11 @@ in rec {
         ${manualXsltprocOptions} \
         --stringparam target.database.document "${olinkDB}/olinkdb.xml" \
         --nonet --xinclude --output $dst/epub/ \
-        ${docbook5_xsl}/xml/xsl/docbook/epub/docbook.xsl \
+        ${docbook_xsl_ns}/xml/xsl/docbook/epub/docbook.xsl \
         ${manual-combined}/manual-combined.xml
 
       mkdir -p $dst/epub/OEBPS/images/callouts
-      cp -r ${docbook5_xsl}/xml/xsl/docbook/images/callouts/*.svg $dst/epub/OEBPS/images/callouts # */
+      cp -r ${docbook_xsl_ns}/xml/xsl/docbook/images/callouts/*.svg $dst/epub/OEBPS/images/callouts # */
       echo "application/epub+zip" > mimetype
       manual="$dst/nixos-manual.epub"
       zip -0Xq "$manual" mimetype
@@ -323,7 +324,7 @@ in rec {
         --param man.endnotes.are.numbered 0 \
         --param man.break.after.slash 1 \
         --stringparam target.database.document "${olinkDB}/olinkdb.xml" \
-        ${docbook5_xsl}/xml/xsl/docbook/manpages/docbook.xsl \
+        ${docbook_xsl_ns}/xml/xsl/docbook/manpages/docbook.xsl \
         ${manual-combined}/man-pages-combined.xml
     '';
 
diff --git a/nixos/doc/manual/development/building-parts.xml b/nixos/doc/manual/development/building-parts.xml
index 031048aaa377..eaffc0ef47c2 100644
--- a/nixos/doc/manual/development/building-parts.xml
+++ b/nixos/doc/manual/development/building-parts.xml
@@ -15,7 +15,8 @@ $ nix-build -A config.<replaceable>option</replaceable></screen>
   include:
   <variablelist>
    <varlistentry>
-    <term><varname>system.build.toplevel</varname>
+    <term>
+     <varname>system.build.toplevel</varname>
     </term>
     <listitem>
      <para>
@@ -32,7 +33,8 @@ $ nix-build -A system</screen>
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>system.build.manual.manual</varname>
+    <term>
+     <varname>system.build.manual.manual</varname>
     </term>
     <listitem>
      <para>
@@ -41,7 +43,8 @@ $ nix-build -A system</screen>
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>system.build.etc</varname>
+    <term>
+     <varname>system.build.etc</varname>
     </term>
     <listitem>
      <para>
@@ -51,9 +54,11 @@ $ nix-build -A system</screen>
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>system.build.initialRamdisk</varname>
+    <term>
+     <varname>system.build.initialRamdisk</varname>
     </term>
-    <term><varname>system.build.kernel</varname>
+    <term>
+     <varname>system.build.kernel</varname>
     </term>
     <listitem>
      <para>
@@ -69,11 +74,14 @@ $ qemu-system-x86_64 -kernel ./kernel/bzImage -initrd ./initrd/initrd -hda /dev/
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>system.build.nixos-rebuild</varname>
+    <term>
+     <varname>system.build.nixos-rebuild</varname>
     </term>
-    <term><varname>system.build.nixos-install</varname>
+    <term>
+     <varname>system.build.nixos-install</varname>
     </term>
-    <term><varname>system.build.nixos-generate-config</varname>
+    <term>
+     <varname>system.build.nixos-generate-config</varname>
     </term>
     <listitem>
      <para>
@@ -82,7 +90,8 @@ $ qemu-system-x86_64 -kernel ./kernel/bzImage -initrd ./initrd/initrd -hda /dev/
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>systemd.units.<replaceable>unit-name</replaceable>.unit</varname>
+    <term>
+     <varname>systemd.units.<replaceable>unit-name</replaceable>.unit</varname>
     </term>
     <listitem>
      <para>
diff --git a/nixos/doc/manual/development/option-declarations.xml b/nixos/doc/manual/development/option-declarations.xml
index a8f528a0a804..eee81bf64263 100644
--- a/nixos/doc/manual/development/option-declarations.xml
+++ b/nixos/doc/manual/development/option-declarations.xml
@@ -32,7 +32,8 @@ xlink:href="https://nixos.org/nixpkgs/manual/#sec-package-naming">
   The function <varname>mkOption</varname> accepts the following arguments.
   <variablelist>
    <varlistentry>
-    <term><varname>type</varname>
+    <term>
+     <varname>type</varname>
     </term>
     <listitem>
      <para>
@@ -43,7 +44,8 @@ xlink:href="https://nixos.org/nixpkgs/manual/#sec-package-naming">
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>default</varname>
+    <term>
+     <varname>default</varname>
     </term>
     <listitem>
      <para>
@@ -55,7 +57,8 @@ xlink:href="https://nixos.org/nixpkgs/manual/#sec-package-naming">
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>example</varname>
+    <term>
+     <varname>example</varname>
     </term>
     <listitem>
      <para>
@@ -64,7 +67,8 @@ xlink:href="https://nixos.org/nixpkgs/manual/#sec-package-naming">
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>description</varname>
+    <term>
+     <varname>description</varname>
     </term>
     <listitem>
      <para>
diff --git a/nixos/doc/manual/development/option-types.xml b/nixos/doc/manual/development/option-types.xml
index 5cb747e6d9f1..47dd09158e91 100644
--- a/nixos/doc/manual/development/option-types.xml
+++ b/nixos/doc/manual/development/option-types.xml
@@ -22,7 +22,8 @@
 
   <variablelist>
    <varlistentry>
-    <term><varname>types.attrs</varname>
+    <term>
+     <varname>types.attrs</varname>
     </term>
     <listitem>
      <para>
@@ -31,7 +32,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>types.bool</varname>
+    <term>
+     <varname>types.bool</varname>
     </term>
     <listitem>
      <para>
@@ -41,7 +43,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>types.path</varname>
+    <term>
+     <varname>types.path</varname>
     </term>
     <listitem>
      <para>
@@ -52,7 +55,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>types.package</varname>
+    <term>
+     <varname>types.package</varname>
     </term>
     <listitem>
      <para>
@@ -68,7 +72,8 @@
 
   <variablelist>
    <varlistentry>
-    <term><varname>types.int</varname>
+    <term>
+     <varname>types.int</varname>
     </term>
     <listitem>
      <para>
@@ -77,7 +82,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>types.ints.{s8, s16, s32}</varname>
+    <term>
+     <varname>types.ints.{s8, s16, s32}</varname>
     </term>
     <listitem>
      <para>
@@ -91,7 +97,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>types.ints.unsigned</varname>
+    <term>
+     <varname>types.ints.unsigned</varname>
     </term>
     <listitem>
      <para>
@@ -100,7 +107,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>types.ints.{u8, u16, u32}</varname>
+    <term>
+     <varname>types.ints.{u8, u16, u32}</varname>
     </term>
     <listitem>
      <para>
@@ -114,7 +122,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>types.ints.positive</varname>
+    <term>
+     <varname>types.ints.positive</varname>
     </term>
     <listitem>
      <para>
@@ -130,7 +139,8 @@
 
   <variablelist>
    <varlistentry>
-    <term><varname>types.str</varname>
+    <term>
+     <varname>types.str</varname>
     </term>
     <listitem>
      <para>
@@ -139,7 +149,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>types.lines</varname>
+    <term>
+     <varname>types.lines</varname>
     </term>
     <listitem>
      <para>
@@ -149,7 +160,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>types.commas</varname>
+    <term>
+     <varname>types.commas</varname>
     </term>
     <listitem>
      <para>
@@ -159,7 +171,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>types.envVar</varname>
+    <term>
+     <varname>types.envVar</varname>
     </term>
     <listitem>
      <para>
@@ -169,7 +182,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>types.strMatching</varname>
+    <term>
+     <varname>types.strMatching</varname>
     </term>
     <listitem>
      <para>
@@ -191,7 +205,8 @@
 
   <variablelist>
    <varlistentry>
-    <term><varname>types.enum</varname><replaceable>l</replaceable>
+    <term>
+     <varname>types.enum</varname> <replaceable>l</replaceable>
     </term>
     <listitem>
      <para>
@@ -202,7 +217,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>types.separatedString</varname><replaceable>sep</replaceable>
+    <term>
+     <varname>types.separatedString</varname> <replaceable>sep</replaceable>
     </term>
     <listitem>
      <para>
@@ -212,7 +228,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>types.ints.between</varname><replaceable>lowest</replaceable><replaceable>highest</replaceable>
+    <term>
+     <varname>types.ints.between</varname> <replaceable>lowest</replaceable> <replaceable>highest</replaceable>
     </term>
     <listitem>
      <para>
@@ -223,7 +240,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>types.submodule</varname><replaceable>o</replaceable>
+    <term>
+     <varname>types.submodule</varname> <replaceable>o</replaceable>
     </term>
     <listitem>
      <para>
@@ -250,7 +268,8 @@
 
   <variablelist>
    <varlistentry>
-    <term><varname>types.listOf</varname><replaceable>t</replaceable>
+    <term>
+     <varname>types.listOf</varname> <replaceable>t</replaceable>
     </term>
     <listitem>
      <para>
@@ -260,7 +279,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>types.attrsOf</varname><replaceable>t</replaceable>
+    <term>
+     <varname>types.attrsOf</varname> <replaceable>t</replaceable>
     </term>
     <listitem>
      <para>
@@ -271,7 +291,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>types.loaOf</varname><replaceable>t</replaceable>
+    <term>
+     <varname>types.loaOf</varname> <replaceable>t</replaceable>
     </term>
     <listitem>
      <para>
@@ -281,7 +302,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>types.nullOr</varname><replaceable>t</replaceable>
+    <term>
+     <varname>types.nullOr</varname> <replaceable>t</replaceable>
     </term>
     <listitem>
      <para>
@@ -291,7 +313,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>types.uniq</varname><replaceable>t</replaceable>
+    <term>
+     <varname>types.uniq</varname> <replaceable>t</replaceable>
     </term>
     <listitem>
      <para>
@@ -301,7 +324,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>types.either</varname><replaceable>t1</replaceable><replaceable>t2</replaceable>
+    <term>
+     <varname>types.either</varname> <replaceable>t1</replaceable> <replaceable>t2</replaceable>
     </term>
     <listitem>
      <para>
@@ -312,7 +336,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>types.coercedTo</varname><replaceable>from</replaceable><replaceable>f</replaceable><replaceable>to</replaceable>
+    <term>
+     <varname>types.coercedTo</varname> <replaceable>from</replaceable> <replaceable>f</replaceable> <replaceable>to</replaceable>
     </term>
     <listitem>
      <para>
@@ -468,7 +493,8 @@ config.mod.two = { foo = 2; bar = "two"; };</screen>
 
   <variablelist>
    <varlistentry>
-    <term><varname>check</varname>
+    <term>
+     <varname>check</varname>
     </term>
     <listitem>
      <para>
@@ -501,7 +527,8 @@ nixThings = mkOption {
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>merge</varname>
+    <term>
+     <varname>merge</varname>
     </term>
     <listitem>
      <para>
@@ -534,7 +561,8 @@ nixThings = mkOption {
 
   <variablelist>
    <varlistentry>
-    <term><varname>name</varname>
+    <term>
+     <varname>name</varname>
     </term>
     <listitem>
      <para>
@@ -543,7 +571,8 @@ nixThings = mkOption {
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>definition</varname>
+    <term>
+     <varname>definition</varname>
     </term>
     <listitem>
      <para>
@@ -553,7 +582,8 @@ nixThings = mkOption {
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>check</varname>
+    <term>
+     <varname>check</varname>
     </term>
     <listitem>
      <para>
@@ -565,7 +595,8 @@ nixThings = mkOption {
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>merge</varname>
+    <term>
+     <varname>merge</varname>
     </term>
     <listitem>
      <para>
@@ -573,7 +604,8 @@ nixThings = mkOption {
      </para>
      <variablelist>
       <varlistentry>
-       <term><replaceable>loc</replaceable>
+       <term>
+        <replaceable>loc</replaceable>
        </term>
        <listitem>
         <para>
@@ -583,7 +615,8 @@ nixThings = mkOption {
        </listitem>
       </varlistentry>
       <varlistentry>
-       <term><replaceable>defs</replaceable>
+       <term>
+        <replaceable>defs</replaceable>
        </term>
        <listitem>
         <para>
@@ -600,7 +633,8 @@ nixThings = mkOption {
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>getSubOptions</varname>
+    <term>
+     <varname>getSubOptions</varname>
     </term>
     <listitem>
      <para>
@@ -615,7 +649,8 @@ nixThings = mkOption {
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>getSubModules</varname>
+    <term>
+     <varname>getSubModules</varname>
     </term>
     <listitem>
      <para>
@@ -628,7 +663,8 @@ nixThings = mkOption {
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>substSubModules</varname>
+    <term>
+     <varname>substSubModules</varname>
     </term>
     <listitem>
      <para>
@@ -644,7 +680,8 @@ nixThings = mkOption {
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>typeMerge</varname>
+    <term>
+     <varname>typeMerge</varname>
     </term>
     <listitem>
      <para>
@@ -654,7 +691,8 @@ nixThings = mkOption {
      </para>
      <variablelist>
       <varlistentry>
-       <term><replaceable>f</replaceable>
+       <term>
+        <replaceable>f</replaceable>
        </term>
        <listitem>
         <para>
@@ -670,7 +708,8 @@ nixThings = mkOption {
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><varname>functor</varname>
+    <term>
+     <varname>functor</varname>
     </term>
     <listitem>
      <para>
@@ -679,7 +718,8 @@ nixThings = mkOption {
      </para>
      <variablelist>
       <varlistentry>
-       <term><varname>type</varname>
+       <term>
+        <varname>type</varname>
        </term>
        <listitem>
         <para>
@@ -688,7 +728,8 @@ nixThings = mkOption {
        </listitem>
       </varlistentry>
       <varlistentry>
-       <term><varname>wrapped</varname>
+       <term>
+        <varname>wrapped</varname>
        </term>
        <listitem>
         <para>
@@ -697,7 +738,8 @@ nixThings = mkOption {
        </listitem>
       </varlistentry>
       <varlistentry>
-       <term><varname>payload</varname>
+       <term>
+        <varname>payload</varname>
        </term>
        <listitem>
         <para>
@@ -709,7 +751,8 @@ nixThings = mkOption {
        </listitem>
       </varlistentry>
       <varlistentry>
-       <term><varname>binOp</varname>
+       <term>
+        <varname>binOp</varname>
        </term>
        <listitem>
         <para>
diff --git a/nixos/doc/manual/development/writing-nixos-tests.xml b/nixos/doc/manual/development/writing-nixos-tests.xml
index 89a6a4423627..5935fbc049bd 100644
--- a/nixos/doc/manual/development/writing-nixos-tests.xml
+++ b/nixos/doc/manual/development/writing-nixos-tests.xml
@@ -54,7 +54,8 @@ xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/nfs.nix">nf
 <!-- FIXME: would be nice to generate this automatically. -->
   <variablelist>
    <varlistentry>
-    <term><option>virtualisation.memorySize</option>
+    <term>
+     <option>virtualisation.memorySize</option>
     </term>
     <listitem>
      <para>
@@ -63,7 +64,8 @@ xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/nfs.nix">nf
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><option>virtualisation.vlans</option>
+    <term>
+     <option>virtualisation.vlans</option>
     </term>
     <listitem>
      <para>
@@ -75,7 +77,8 @@ xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/nfs.nix">nf
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><option>virtualisation.writableStore</option>
+    <term>
+     <option>virtualisation.writableStore</option>
     </term>
     <listitem>
      <para>
@@ -120,7 +123,8 @@ startAll;
   The following methods are available on machine objects:
   <variablelist>
    <varlistentry>
-    <term><methodname>start</methodname>
+    <term>
+     <methodname>start</methodname>
     </term>
     <listitem>
      <para>
@@ -130,7 +134,8 @@ startAll;
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><methodname>shutdown</methodname>
+    <term>
+     <methodname>shutdown</methodname>
     </term>
     <listitem>
      <para>
@@ -139,7 +144,8 @@ startAll;
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><methodname>crash</methodname>
+    <term>
+     <methodname>crash</methodname>
     </term>
     <listitem>
      <para>
@@ -148,7 +154,8 @@ startAll;
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><methodname>block</methodname>
+    <term>
+     <methodname>block</methodname>
     </term>
     <listitem>
      <para>
@@ -158,7 +165,8 @@ startAll;
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><methodname>unblock</methodname>
+    <term>
+     <methodname>unblock</methodname>
     </term>
     <listitem>
      <para>
@@ -167,7 +175,8 @@ startAll;
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><methodname>screenshot</methodname>
+    <term>
+     <methodname>screenshot</methodname>
     </term>
     <listitem>
      <para>
@@ -177,7 +186,8 @@ startAll;
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><methodname>getScreenText</methodname>
+    <term>
+     <methodname>getScreenText</methodname>
     </term>
     <listitem>
      <para>
@@ -193,7 +203,8 @@ startAll;
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><methodname>sendMonitorCommand</methodname>
+    <term>
+     <methodname>sendMonitorCommand</methodname>
     </term>
     <listitem>
      <para>
@@ -203,7 +214,8 @@ startAll;
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><methodname>sendKeys</methodname>
+    <term>
+     <methodname>sendKeys</methodname>
     </term>
     <listitem>
      <para>
@@ -213,7 +225,8 @@ startAll;
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><methodname>sendChars</methodname>
+    <term>
+     <methodname>sendChars</methodname>
     </term>
     <listitem>
      <para>
@@ -224,7 +237,8 @@ startAll;
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><methodname>execute</methodname>
+    <term>
+     <methodname>execute</methodname>
     </term>
     <listitem>
      <para>
@@ -235,7 +249,8 @@ startAll;
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><methodname>succeed</methodname>
+    <term>
+     <methodname>succeed</methodname>
     </term>
     <listitem>
      <para>
@@ -245,7 +260,8 @@ startAll;
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><methodname>fail</methodname>
+    <term>
+     <methodname>fail</methodname>
     </term>
     <listitem>
      <para>
@@ -255,7 +271,8 @@ startAll;
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><methodname>waitUntilSucceeds</methodname>
+    <term>
+     <methodname>waitUntilSucceeds</methodname>
     </term>
     <listitem>
      <para>
@@ -264,7 +281,8 @@ startAll;
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><methodname>waitUntilFails</methodname>
+    <term>
+     <methodname>waitUntilFails</methodname>
     </term>
     <listitem>
      <para>
@@ -273,7 +291,8 @@ startAll;
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><methodname>waitForUnit</methodname>
+    <term>
+     <methodname>waitForUnit</methodname>
     </term>
     <listitem>
      <para>
@@ -282,7 +301,8 @@ startAll;
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><methodname>waitForFile</methodname>
+    <term>
+     <methodname>waitForFile</methodname>
     </term>
     <listitem>
      <para>
@@ -291,7 +311,8 @@ startAll;
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><methodname>waitForOpenPort</methodname>
+    <term>
+     <methodname>waitForOpenPort</methodname>
     </term>
     <listitem>
      <para>
@@ -301,7 +322,8 @@ startAll;
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><methodname>waitForClosedPort</methodname>
+    <term>
+     <methodname>waitForClosedPort</methodname>
     </term>
     <listitem>
      <para>
@@ -310,7 +332,8 @@ startAll;
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><methodname>waitForX</methodname>
+    <term>
+     <methodname>waitForX</methodname>
     </term>
     <listitem>
      <para>
@@ -319,7 +342,8 @@ startAll;
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><methodname>waitForText</methodname>
+    <term>
+     <methodname>waitForText</methodname>
     </term>
     <listitem>
      <para>
@@ -336,7 +360,8 @@ startAll;
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><methodname>waitForWindow</methodname>
+    <term>
+     <methodname>waitForWindow</methodname>
     </term>
     <listitem>
      <para>
@@ -346,7 +371,8 @@ startAll;
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><methodname>copyFileFromHost</methodname>
+    <term>
+     <methodname>copyFileFromHost</methodname>
     </term>
     <listitem>
      <para>
@@ -361,7 +387,8 @@ startAll;
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><methodname>systemctl</methodname>
+    <term>
+     <methodname>systemctl</methodname>
     </term>
     <listitem>
      <para>
diff --git a/nixos/doc/manual/installation/changing-config.xml b/nixos/doc/manual/installation/changing-config.xml
index 680160a3cb7e..1a116ec0b655 100644
--- a/nixos/doc/manual/installation/changing-config.xml
+++ b/nixos/doc/manual/installation/changing-config.xml
@@ -66,7 +66,7 @@ $ ./result/bin/run-*-vm
   <literal>mutableUsers = false</literal>. Another way is to temporarily add
   the following to your configuration:
 <screen>
-<link linkend="opt-users.users._name__.initialHashedPassword">users.extraUsers.your-user.initialHashedPassword</link> = "test";
+<link linkend="opt-users.users._name__.initialHashedPassword">users.users.your-user.initialHashedPassword</link> = "test";
 </screen>
   <emphasis>Important:</emphasis> delete the $hostname.qcow2 file if you have
   started the virtual machine at least once without the right users, otherwise
diff --git a/nixos/doc/manual/installation/installing-from-other-distro.xml b/nixos/doc/manual/installation/installing-from-other-distro.xml
index c55aa90267fb..d1e49a2a1597 100644
--- a/nixos/doc/manual/installation/installing-from-other-distro.xml
+++ b/nixos/doc/manual/installation/installing-from-other-distro.xml
@@ -211,7 +211,7 @@ $ sudo groupdel nixbld</screen>
     use <literal>sudo</literal>)
    </para>
 <programlisting>
-<link linkend="opt-users.users._name__.initialHashedPassword">users.extraUsers.root.initialHashedPassword</link> = "";
+<link linkend="opt-users.users._name__.initialHashedPassword">users.users.root.initialHashedPassword</link> = "";
               </programlisting>
   </listitem>
   <listitem>
diff --git a/nixos/doc/manual/installation/installing.xml b/nixos/doc/manual/installation/installing.xml
index 4e1fde662d6e..6066d025adbf 100644
--- a/nixos/doc/manual/installation/installing.xml
+++ b/nixos/doc/manual/installation/installing.xml
@@ -16,7 +16,9 @@
    </para>
    <variablelist>
     <varlistentry>
-     <term>UEFI systems</term>
+     <term>
+      UEFI systems
+     </term>
      <listitem>
       <para>
        You should boot the live CD in UEFI mode (consult your specific
@@ -138,7 +140,9 @@
      <listitem>
       <variablelist>
        <varlistentry>
-        <term>UEFI systems</term>
+        <term>
+         UEFI systems
+        </term>
         <listitem>
          <para>
           For creating boot partitions: <command>mkfs.fat</command>. Again
@@ -178,7 +182,9 @@
   <listitem>
    <variablelist>
     <varlistentry>
-     <term>UEFI systems</term>
+     <term>
+      UEFI systems
+     </term>
      <listitem>
       <para>
        Mount the boot file system on <filename>/mnt/boot</filename>, e.g.
@@ -234,7 +240,9 @@
    </para>
    <variablelist>
     <varlistentry>
-     <term>BIOS systems</term>
+     <term>
+      BIOS systems
+     </term>
      <listitem>
       <para>
        You <emphasis>must</emphasis> set the option
@@ -244,7 +252,9 @@
      </listitem>
     </varlistentry>
     <varlistentry>
-     <term>UEFI systems</term>
+     <term>
+      UEFI systems
+     </term>
      <listitem>
       <para>
        You <emphasis>must</emphasis> set the option
diff --git a/nixos/doc/manual/man-nixos-build-vms.xml b/nixos/doc/manual/man-nixos-build-vms.xml
index 02dad4c548b8..87e4f3dae869 100644
--- a/nixos/doc/manual/man-nixos-build-vms.xml
+++ b/nixos/doc/manual/man-nixos-build-vms.xml
@@ -12,14 +12,22 @@
   </refname><refpurpose>build a network of virtual machines from a network of NixOS configurations</refpurpose>
  </refnamediv>
  <refsynopsisdiv>
-  <cmdsynopsis><command>nixos-build-vms</command>
-   <arg><option>--show-trace</option>
+  <cmdsynopsis>
+   <command>nixos-build-vms</command> 
+   <arg>
+    <option>--show-trace</option>
    </arg>
-   <arg><option>--no-out-link</option>
+    
+   <arg>
+    <option>--no-out-link</option>
    </arg>
-   <arg><option>--help</option>
+    
+   <arg>
+    <option>--help</option>
    </arg>
-   <arg choice="plain"><replaceable>network.nix</replaceable>
+    
+   <arg choice="plain">
+    <replaceable>network.nix</replaceable>
    </arg>
   </cmdsynopsis>
  </refsynopsisdiv>
@@ -78,7 +86,8 @@
   </para>
   <variablelist>
    <varlistentry>
-    <term><option>--show-trace</option>
+    <term>
+     <option>--show-trace</option>
     </term>
     <listitem>
      <para>
@@ -87,7 +96,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><option>--no-out-link</option>
+    <term>
+     <option>--no-out-link</option>
     </term>
     <listitem>
      <para>
@@ -96,7 +106,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><option>-h</option>, <option>--help</option>
+    <term>
+     <option>-h</option>, <option>--help</option>
     </term>
     <listitem>
      <para>
diff --git a/nixos/doc/manual/man-nixos-enter.xml b/nixos/doc/manual/man-nixos-enter.xml
index 7db4b72ee36e..42edaa1ae5b6 100644
--- a/nixos/doc/manual/man-nixos-enter.xml
+++ b/nixos/doc/manual/man-nixos-enter.xml
@@ -12,26 +12,40 @@
   </refname><refpurpose>run a command in a NixOS chroot environment</refpurpose>
  </refnamediv>
  <refsynopsisdiv>
-  <cmdsynopsis><command>nixos-enter</command>
+  <cmdsynopsis>
+   <command>nixos-enter</command> 
    <arg>
-    <arg choice='plain'><option>--root</option>
-    </arg><replaceable>root</replaceable>
+    <arg choice='plain'>
+     <option>--root</option>
+    </arg>
+     <replaceable>root</replaceable>
    </arg>
+    
    <arg>
-    <arg choice='plain'><option>--system</option>
-    </arg><replaceable>system</replaceable>
+    <arg choice='plain'>
+     <option>--system</option>
+    </arg>
+     <replaceable>system</replaceable>
    </arg>
+    
    <arg>
-    <arg choice='plain'><option>-c</option>
-    </arg><replaceable>shell-command</replaceable>
+    <arg choice='plain'>
+     <option>-c</option>
+    </arg>
+     <replaceable>shell-command</replaceable>
    </arg>
+    
    <arg>
-    <arg choice='plain'><option>--help</option>
+    <arg choice='plain'>
+     <option>--help</option>
     </arg>
    </arg>
+    
    <arg>
-    <arg choice='plain'><option>--</option>
-    </arg><replaceable>arguments</replaceable>
+    <arg choice='plain'>
+     <option>--</option>
+    </arg>
+     <replaceable>arguments</replaceable>
    </arg>
   </cmdsynopsis>
  </refsynopsisdiv>
@@ -50,7 +64,8 @@
   </para>
   <variablelist>
    <varlistentry>
-    <term><option>--root</option>
+    <term>
+     <option>--root</option>
     </term>
     <listitem>
      <para>
@@ -60,7 +75,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><option>--system</option>
+    <term>
+     <option>--system</option>
     </term>
     <listitem>
      <para>
@@ -72,9 +88,11 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><option>--command</option>
+    <term>
+     <option>--command</option>
     </term>
-    <term><option>-c</option>
+    <term>
+     <option>-c</option>
     </term>
     <listitem>
      <para>
@@ -83,7 +101,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><option>--</option>
+    <term>
+     <option>--</option>
     </term>
     <listitem>
      <para>
diff --git a/nixos/doc/manual/man-nixos-generate-config.xml b/nixos/doc/manual/man-nixos-generate-config.xml
index 8bf90f452db6..1227873f5780 100644
--- a/nixos/doc/manual/man-nixos-generate-config.xml
+++ b/nixos/doc/manual/man-nixos-generate-config.xml
@@ -12,16 +12,24 @@
   </refname><refpurpose>generate NixOS configuration modules</refpurpose>
  </refnamediv>
  <refsynopsisdiv>
-  <cmdsynopsis><command>nixos-generate-config</command>
-   <arg><option>--force</option>
+  <cmdsynopsis>
+   <command>nixos-generate-config</command> 
+   <arg>
+    <option>--force</option>
    </arg>
+    
    <arg>
-    <arg choice='plain'><option>--root</option>
-    </arg><replaceable>root</replaceable>
+    <arg choice='plain'>
+     <option>--root</option>
+    </arg>
+     <replaceable>root</replaceable>
    </arg>
+    
    <arg>
-    <arg choice='plain'><option>--dir</option>
-    </arg><replaceable>dir</replaceable>
+    <arg choice='plain'>
+     <option>--dir</option>
+    </arg>
+     <replaceable>dir</replaceable>
    </arg>
   </cmdsynopsis>
  </refsynopsisdiv>
@@ -31,7 +39,8 @@
    This command writes two NixOS configuration modules:
    <variablelist>
     <varlistentry>
-     <term><option>/etc/nixos/hardware-configuration.nix</option>
+     <term>
+      <option>/etc/nixos/hardware-configuration.nix</option>
      </term>
      <listitem>
       <para>
@@ -53,7 +62,8 @@
      </listitem>
     </varlistentry>
     <varlistentry>
-     <term><option>/etc/nixos/configuration.nix</option>
+     <term>
+      <option>/etc/nixos/configuration.nix</option>
      </term>
      <listitem>
       <para>
@@ -74,7 +84,8 @@
   </para>
   <variablelist>
    <varlistentry>
-    <term><option>--root</option>
+    <term>
+     <option>--root</option>
     </term>
     <listitem>
      <para>
@@ -88,7 +99,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><option>--dir</option>
+    <term>
+     <option>--dir</option>
     </term>
     <listitem>
      <para>
@@ -99,7 +111,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><option>--force</option>
+    <term>
+     <option>--force</option>
     </term>
     <listitem>
      <para>
@@ -109,7 +122,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><option>--no-filesystems</option>
+    <term>
+     <option>--no-filesystems</option>
     </term>
     <listitem>
      <para>
@@ -119,7 +133,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><option>--show-hardware-config</option>
+    <term>
+     <option>--show-hardware-config</option>
     </term>
     <listitem>
      <para>
diff --git a/nixos/doc/manual/man-nixos-install.xml b/nixos/doc/manual/man-nixos-install.xml
index 2d45e83a863f..25f4f40613ac 100644
--- a/nixos/doc/manual/man-nixos-install.xml
+++ b/nixos/doc/manual/man-nixos-install.xml
@@ -12,47 +12,76 @@
   </refname><refpurpose>install bootloader and NixOS</refpurpose>
  </refnamediv>
  <refsynopsisdiv>
-  <cmdsynopsis><command>nixos-install</command>
+  <cmdsynopsis>
+   <command>nixos-install</command> 
    <arg>
-    <arg choice='plain'><option>-I</option>
-    </arg><replaceable>path</replaceable>
+    <arg choice='plain'>
+     <option>-I</option>
+    </arg>
+     <replaceable>path</replaceable>
    </arg>
+    
    <arg>
-    <arg choice='plain'><option>--root</option>
-    </arg><replaceable>root</replaceable>
+    <arg choice='plain'>
+     <option>--root</option>
+    </arg>
+     <replaceable>root</replaceable>
    </arg>
+    
    <arg>
-    <arg choice='plain'><option>--system</option>
-    </arg><replaceable>path</replaceable>
+    <arg choice='plain'>
+     <option>--system</option>
+    </arg>
+     <replaceable>path</replaceable>
    </arg>
+    
    <arg>
-    <arg choice='plain'><option>--no-channel-copy</option>
+    <arg choice='plain'>
+     <option>--no-channel-copy</option>
     </arg>
    </arg>
+    
    <arg>
-    <arg choice='plain'><option>--no-root-passwd</option>
+    <arg choice='plain'>
+     <option>--no-root-passwd</option>
     </arg>
    </arg>
+    
    <arg>
-    <arg choice='plain'><option>--no-bootloader</option>
+    <arg choice='plain'>
+     <option>--no-bootloader</option>
     </arg>
    </arg>
-   <arg><group choice='req'>
-    <arg choice='plain'><option>--max-jobs</option>
+    
+   <arg>
+    <group choice='req'> 
+    <arg choice='plain'>
+     <option>--max-jobs</option>
     </arg>
-    <arg choice='plain'><option>-j</option>
-    </arg></group><replaceable>number</replaceable>
+     
+    <arg choice='plain'>
+     <option>-j</option>
+    </arg>
+     </group> <replaceable>number</replaceable>
    </arg>
-   <arg><option>--cores</option><replaceable>number</replaceable>
+    
+   <arg>
+    <option>--cores</option> <replaceable>number</replaceable>
    </arg>
-   <arg><option>--option</option><replaceable>name</replaceable><replaceable>value</replaceable>
+    
+   <arg>
+    <option>--option</option> <replaceable>name</replaceable> <replaceable>value</replaceable>
    </arg>
+    
    <arg>
-    <arg choice='plain'><option>--show-trace</option>
+    <arg choice='plain'>
+     <option>--show-trace</option>
     </arg>
    </arg>
+    
    <arg>
-    <arg choice='plain'><option>--help</option>
+    <arg choice='plain'>
+     <option>--help</option>
     </arg>
    </arg>
   </cmdsynopsis>
@@ -106,7 +135,8 @@
   </para>
   <variablelist>
    <varlistentry>
-    <term><option>--root</option>
+    <term>
+     <option>--root</option>
     </term>
     <listitem>
      <para>
@@ -117,7 +147,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><option>--system</option>
+    <term>
+     <option>--system</option>
     </term>
     <listitem>
      <para>
@@ -135,7 +166,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><option>-I</option>
+    <term>
+     <option>-I</option>
     </term>
     <listitem>
      <para>
@@ -147,9 +179,11 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><option>--max-jobs</option>
+    <term>
+     <option>--max-jobs</option>
     </term>
-    <term><option>-j</option>
+    <term>
+     <option>-j</option>
     </term>
     <listitem>
      <para>
@@ -160,7 +194,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><option>--cores</option>
+    <term>
+     <option>--cores</option>
     </term>
     <listitem>
      <para>
@@ -177,7 +212,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><option>--option</option><replaceable>name</replaceable><replaceable>value</replaceable>
+    <term>
+     <option>--option</option> <replaceable>name</replaceable> <replaceable>value</replaceable>
     </term>
     <listitem>
      <para>
@@ -187,7 +223,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><option>--show-trace</option>
+    <term>
+     <option>--show-trace</option>
     </term>
     <listitem>
      <para>
@@ -197,7 +234,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><option>--help</option>
+    <term>
+     <option>--help</option>
     </term>
     <listitem>
      <para>
diff --git a/nixos/doc/manual/man-nixos-option.xml b/nixos/doc/manual/man-nixos-option.xml
index c22c3811dedf..d436cce742a2 100644
--- a/nixos/doc/manual/man-nixos-option.xml
+++ b/nixos/doc/manual/man-nixos-option.xml
@@ -12,14 +12,22 @@
   </refname><refpurpose>inspect a NixOS configuration</refpurpose>
  </refnamediv>
  <refsynopsisdiv>
-  <cmdsynopsis><command>nixos-option</command>
-   <arg><option>-I</option><replaceable>path</replaceable>
+  <cmdsynopsis>
+   <command>nixos-option</command> 
+   <arg>
+    <option>-I</option> <replaceable>path</replaceable>
    </arg>
-   <arg><option>--verbose</option>
+    
+   <arg>
+    <option>--verbose</option>
    </arg>
-   <arg><option>--xml</option>
+    
+   <arg>
+    <option>--xml</option>
    </arg>
-   <arg choice="plain"><replaceable>option.name</replaceable>
+    
+   <arg choice="plain">
+    <replaceable>option.name</replaceable>
    </arg>
   </cmdsynopsis>
  </refsynopsisdiv>
@@ -42,7 +50,8 @@
   </para>
   <variablelist>
    <varlistentry>
-    <term><option>-I</option><replaceable>path</replaceable>
+    <term>
+     <option>-I</option> <replaceable>path</replaceable>
     </term>
     <listitem>
      <para>
@@ -52,7 +61,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><option>--verbose</option>
+    <term>
+     <option>--verbose</option>
     </term>
     <listitem>
      <para>
@@ -62,7 +72,8 @@
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><option>--xml</option>
+    <term>
+     <option>--xml</option>
     </term>
     <listitem>
      <para>
@@ -76,7 +87,8 @@
   <title>Environment</title>
   <variablelist>
    <varlistentry>
-    <term><envar>NIXOS_CONFIG</envar>
+    <term>
+     <envar>NIXOS_CONFIG</envar>
     </term>
     <listitem>
      <para>
diff --git a/nixos/doc/manual/man-nixos-rebuild.xml b/nixos/doc/manual/man-nixos-rebuild.xml
index e1a2c7108d18..551a65f5e96b 100644
--- a/nixos/doc/manual/man-nixos-rebuild.xml
+++ b/nixos/doc/manual/man-nixos-rebuild.xml
@@ -12,43 +12,75 @@
   </refname><refpurpose>reconfigure a NixOS machine</refpurpose>
  </refnamediv>
  <refsynopsisdiv>
-  <cmdsynopsis><command>nixos-rebuild</command><group choice='req'>
-   <arg choice='plain'><option>switch</option>
+  <cmdsynopsis>
+   <command>nixos-rebuild</command><group choice='req'> 
+   <arg choice='plain'>
+    <option>switch</option>
    </arg>
-   <arg choice='plain'><option>boot</option>
+    
+   <arg choice='plain'>
+    <option>boot</option>
    </arg>
-   <arg choice='plain'><option>test</option>
+    
+   <arg choice='plain'>
+    <option>test</option>
    </arg>
-   <arg choice='plain'><option>build</option>
+    
+   <arg choice='plain'>
+    <option>build</option>
    </arg>
-   <arg choice='plain'><option>dry-build</option>
+    
+   <arg choice='plain'>
+    <option>dry-build</option>
    </arg>
-   <arg choice='plain'><option>dry-activate</option>
+    
+   <arg choice='plain'>
+    <option>dry-activate</option>
    </arg>
-   <arg choice='plain'><option>build-vm</option>
+    
+   <arg choice='plain'>
+    <option>build-vm</option>
    </arg>
-   <arg choice='plain'><option>build-vm-with-bootloader</option>
-   </arg></group>
+    
+   <arg choice='plain'>
+    <option>build-vm-with-bootloader</option>
+   </arg>
+    </group>
    <sbr />
-   <arg><option>--upgrade</option>
+   <arg>
+    <option>--upgrade</option>
    </arg>
-   <arg><option>--install-bootloader</option>
+    
+   <arg>
+    <option>--install-bootloader</option>
    </arg>
-   <arg><option>--no-build-nix</option>
+    
+   <arg>
+    <option>--no-build-nix</option>
    </arg>
-   <arg><option>--fast</option>
+    
+   <arg>
+    <option>--fast</option>
    </arg>
-   <arg><option>--rollback</option>
+    
+   <arg>
+    <option>--rollback</option>
    </arg>
    <sbr />
-   <arg><group choice='req'>
-    <arg choice='plain'><option>--profile-name</option>
+   <arg>
+    <group choice='req'> 
+    <arg choice='plain'>
+     <option>--profile-name</option>
+    </arg>
+     
+    <arg choice='plain'>
+     <option>-p</option>
     </arg>
-    <arg choice='plain'><option>-p</option>
-    </arg></group><replaceable>name</replaceable>
+     </group> <replaceable>name</replaceable>
    </arg>
    <sbr />
-   <arg><option>--show-trace</option>
+   <arg>
+    <option>--show-trace</option>
    </arg>
   </cmdsynopsis>
  </refsynopsisdiv>
@@ -68,7 +100,8 @@
    operation. It must be one of the following:
    <variablelist>
     <varlistentry>
-     <term><option>switch</option>
+     <term>
+      <option>switch</option>
      </term>
      <listitem>
       <para>
@@ -82,7 +115,8 @@
      </listitem>
     </varlistentry>
     <varlistentry>
-     <term><option>boot</option>
+     <term>
+      <option>boot</option>
      </term>
      <listitem>
       <para>
@@ -94,7 +128,8 @@
      </listitem>
     </varlistentry>
     <varlistentry>
-     <term><option>test</option>
+     <term>
+      <option>test</option>
      </term>
      <listitem>
       <para>
@@ -107,7 +142,8 @@
      </listitem>
     </varlistentry>
     <varlistentry>
-     <term><option>build</option>
+     <term>
+      <option>build</option>
      </term>
      <listitem>
       <para>
@@ -124,7 +160,8 @@ $ nix-build /path/to/nixpkgs/nixos -A system
      </listitem>
     </varlistentry>
     <varlistentry>
-     <term><option>dry-build</option>
+     <term>
+      <option>dry-build</option>
      </term>
      <listitem>
       <para>
@@ -134,7 +171,8 @@ $ nix-build /path/to/nixpkgs/nixos -A system
      </listitem>
     </varlistentry>
     <varlistentry>
-     <term><option>dry-activate</option>
+     <term>
+      <option>dry-activate</option>
      </term>
      <listitem>
       <para>
@@ -147,7 +185,8 @@ $ nix-build /path/to/nixpkgs/nixos -A system
      </listitem>
     </varlistentry>
     <varlistentry>
-     <term><option>build-vm</option>
+     <term>
+      <option>build-vm</option>
      </term>
      <listitem>
       <para>
@@ -186,7 +225,8 @@ $ ./result/bin/run-*-vm
      </listitem>
     </varlistentry>
     <varlistentry>
-     <term><option>build-vm-with-bootloader</option>
+     <term>
+      <option>build-vm-with-bootloader</option>
      </term>
      <listitem>
       <para>
@@ -213,7 +253,8 @@ $ ./result/bin/run-*-vm
   </para>
   <variablelist>
    <varlistentry>
-    <term><option>--upgrade</option>
+    <term>
+     <option>--upgrade</option>
     </term>
     <listitem>
      <para>
@@ -222,7 +263,8 @@ $ ./result/bin/run-*-vm
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><option>--install-bootloader</option>
+    <term>
+     <option>--install-bootloader</option>
     </term>
     <listitem>
      <para>
@@ -232,7 +274,8 @@ $ ./result/bin/run-*-vm
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><option>--no-build-nix</option>
+    <term>
+     <option>--no-build-nix</option>
     </term>
     <listitem>
      <para>
@@ -246,7 +289,8 @@ $ ./result/bin/run-*-vm
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><option>--fast</option>
+    <term>
+     <option>--fast</option>
     </term>
     <listitem>
      <para>
@@ -258,7 +302,8 @@ $ ./result/bin/run-*-vm
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><option>--rollback</option>
+    <term>
+     <option>--rollback</option>
     </term>
     <listitem>
      <para>
@@ -271,9 +316,11 @@ $ ./result/bin/run-*-vm
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><option>--profile-name</option>
+    <term>
+     <option>--profile-name</option>
     </term>
-    <term><option>-p</option>
+    <term>
+     <option>-p</option>
     </term>
     <listitem>
      <para>
@@ -299,7 +346,8 @@ $ nixos-rebuild switch -p test -I nixos-config=./test.nix
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><option>--build-host</option>
+    <term>
+     <option>--build-host</option>
     </term>
     <listitem>
      <para>
@@ -323,7 +371,8 @@ $ nixos-rebuild switch -p test -I nixos-config=./test.nix
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><option>--target-host</option>
+    <term>
+     <option>--target-host</option>
     </term>
     <listitem>
      <para>
@@ -361,7 +410,8 @@ $ nixos-rebuild switch -p test -I nixos-config=./test.nix
   <title>Environment</title>
   <variablelist>
    <varlistentry>
-    <term><envar>NIXOS_CONFIG</envar>
+    <term>
+     <envar>NIXOS_CONFIG</envar>
     </term>
     <listitem>
      <para>
@@ -371,7 +421,8 @@ $ nixos-rebuild switch -p test -I nixos-config=./test.nix
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><envar>NIX_SSHOPTS</envar>
+    <term>
+     <envar>NIX_SSHOPTS</envar>
     </term>
     <listitem>
      <para>
@@ -386,7 +437,8 @@ $ nixos-rebuild switch -p test -I nixos-config=./test.nix
   <title>Files</title>
   <variablelist>
    <varlistentry>
-    <term><filename>/run/current-system</filename>
+    <term>
+     <filename>/run/current-system</filename>
     </term>
     <listitem>
      <para>
@@ -395,7 +447,8 @@ $ nixos-rebuild switch -p test -I nixos-config=./test.nix
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><filename>/nix/var/nix/profiles/system</filename>
+    <term>
+     <filename>/nix/var/nix/profiles/system</filename>
     </term>
     <listitem>
      <para>
diff --git a/nixos/doc/manual/man-nixos-version.xml b/nixos/doc/manual/man-nixos-version.xml
index c173bce19136..931c4a5ad029 100644
--- a/nixos/doc/manual/man-nixos-version.xml
+++ b/nixos/doc/manual/man-nixos-version.xml
@@ -11,10 +11,14 @@
   </refname><refpurpose>show the NixOS version</refpurpose>
  </refnamediv>
  <refsynopsisdiv>
-  <cmdsynopsis><command>nixos-version</command>
-   <arg><option>--hash</option>
+  <cmdsynopsis>
+   <command>nixos-version</command> 
+   <arg>
+    <option>--hash</option>
    </arg>
-   <arg><option>--revision</option>
+    
+   <arg>
+    <option>--revision</option>
    </arg>
   </cmdsynopsis>
  </refsynopsisdiv>
@@ -29,7 +33,8 @@
    The version consists of the following elements:
    <variablelist>
     <varlistentry>
-     <term><literal>16.03</literal>
+     <term>
+      <literal>16.03</literal>
      </term>
      <listitem>
       <para>
@@ -39,7 +44,8 @@
      </listitem>
     </varlistentry>
     <varlistentry>
-     <term><literal>1011</literal>
+     <term>
+      <literal>1011</literal>
      </term>
      <listitem>
       <para>
@@ -53,7 +59,8 @@
      </listitem>
     </varlistentry>
     <varlistentry>
-     <term><literal>6317da4</literal>
+     <term>
+      <literal>6317da4</literal>
      </term>
      <listitem>
       <para>
@@ -63,7 +70,8 @@
      </listitem>
     </varlistentry>
     <varlistentry>
-     <term><literal>Emu</literal>
+     <term>
+      <literal>Emu</literal>
      </term>
      <listitem>
       <para>
@@ -83,9 +91,11 @@
   </para>
   <variablelist>
    <varlistentry>
-    <term><option>--hash</option>
+    <term>
+     <option>--hash</option>
     </term>
-    <term><option>--revision</option>
+    <term>
+     <option>--revision</option>
     </term>
     <listitem>
      <para>
diff --git a/nixos/doc/manual/release-notes/rl-1509.xml b/nixos/doc/manual/release-notes/rl-1509.xml
index 734bc076b852..2465f370cf13 100644
--- a/nixos/doc/manual/release-notes/rl-1509.xml
+++ b/nixos/doc/manual/release-notes/rl-1509.xml
@@ -435,11 +435,11 @@ system.autoUpgrade.enable = true;
 <programlisting>
 system.nixos.stateVersion = "14.12";
 </programlisting>
-     The new option <option>system.nixos.stateVersion</option> ensures that certain
-     configuration changes that could break existing systems (such as the
-     <command>sshd</command> host key setting) will maintain compatibility with
-     the specified NixOS release. NixOps sets the state version of existing
-     deployments automatically.
+     The new option <option>system.nixos.stateVersion</option> ensures that
+     certain configuration changes that could break existing systems (such as
+     the <command>sshd</command> host key setting) will maintain compatibility
+     with the specified NixOS release. NixOps sets the state version of
+     existing deployments automatically.
     </para>
    </listitem>
    <listitem>
diff --git a/nixos/doc/manual/release-notes/rl-1809.xml b/nixos/doc/manual/release-notes/rl-1809.xml
index 0ae630945db2..7fd6483bca1a 100644
--- a/nixos/doc/manual/release-notes/rl-1809.xml
+++ b/nixos/doc/manual/release-notes/rl-1809.xml
@@ -19,6 +19,27 @@
 
   <itemizedlist>
    <listitem>
+     <para>
+       Support for wrapping binaries using <literal>firejail</literal> has been
+       added through <varname>programs.firejail.wrappedBinaries</varname>.
+     </para>
+     <para>
+       For example
+     </para>
+<programlisting>
+programs.firejail = {
+  enable = true;
+  wrappedBinaries = {
+    firefox = "${lib.getBin pkgs.firefox}/bin/firefox";
+    mpv = "${lib.getBin pkgs.mpv}/bin/mpv";
+  };
+};
+</programlisting>
+      <para>
+        This will place <literal>firefox</literal> and <literal>mpv</literal> binaries in the global path wrapped by firejail.
+      </para>
+   </listitem>
+   <listitem>
     <para>
      User channels are now in the default <literal>NIX_PATH</literal>, allowing
      users to use their personal <command>nix-channel</command> defined
@@ -53,10 +74,12 @@ $ nix-instantiate -E '(import &lt;nixpkgsunstable&gt; {}).gitFull'
 
   <itemizedlist>
    <listitem>
-     <para>When enabled the <literal>iproute2</literal> will copy the files
-       expected by ip route (e.g., <filename>rt_tables</filename>) in
-       <filename>/run/iproute2</filename>. This allows to write aliases for
-       routing tables for instance.</para>
+    <para>
+     When enabled the <literal>iproute2</literal> will copy the files expected
+     by ip route (e.g., <filename>rt_tables</filename>) in
+     <filename>/run/iproute2</filename>. This allows to write aliases for
+     routing tables for instance.
+    </para>
    </listitem>
   </itemizedlist>
  </section>
@@ -99,20 +122,36 @@ $ nix-instantiate -E '(import &lt;nixpkgsunstable&gt; {}).gitFull'
    </listitem>
    <listitem>
     <para>
-     The <varname>services.docker-registry.extraConfig</varname> object doesn't contain
-     environment variables anymore. Instead it needs to provide an object structure
-     that can be mapped onto the YAML configuration defined in <link xlink:href="https://github.com/docker/distribution/blob/v2.6.2/docs/configuration.md">the <varname>docker/distribution</varname> docs</link>.
+     The <varname>services.docker-registry.extraConfig</varname> object doesn't
+     contain environment variables anymore. Instead it needs to provide an
+     object structure that can be mapped onto the YAML configuration defined in
+     <link xlink:href="https://github.com/docker/distribution/blob/v2.6.2/docs/configuration.md">the
+     <varname>docker/distribution</varname> docs</link>.
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     <literal>gnucash</literal> has changed from version 2.4 to 3.x. If you've
+     been using <literal>gnucash</literal> (version 2.4) instead of
+     <literal>gnucash26</literal> (version 2.6) you must open your Gnucash data
+     file(s) with <literal>gnucash26</literal> and then save them to upgrade
+     the file format. Then you may use your data file(s) with Gnucash 3.x. See
+     the upgrade
+     <link xlink:href="https://wiki.gnucash.org/wiki/FAQ#Using_Different_Versions.2C_Up_And_Downgrade">documentation</link>.
+     Gnucash 2.4 is still available under the attribute
+     <literal>gnucash24</literal>.
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     <varname>services.munge</varname> now runs as user (and group) <literal>munge</literal> instead of root.
+     Make sure the key file is accessible to the daemon.
     </para>
    </listitem>
    <listitem>
     <para>
-     <literal>gnucash</literal> has changed from version 2.4 to 3.x.
-     If you've been using <literal>gnucash</literal> (version 2.4) instead of
-     <literal>gnucash26</literal> (version 2.6) you must open your Gnucash 
-     data file(s) with <literal>gnucash26</literal> and then save them to
-     upgrade the file format. Then you may use your data file(s) with
-     Gnucash 3.x. See the upgrade <link xlink:href="https://wiki.gnucash.org/wiki/FAQ#Using_Different_Versions.2C_Up_And_Downgrade">documentation</link>.
-     Gnucash 2.4 is still available under the attribute <literal>gnucash24</literal>.
+      <varname>dockerTools.buildImage</varname> now uses <literal>null</literal> as default value for <varname>tag</varname>,
+      which indicates that the nix output hash will be used as tag.
     </para>
    </listitem>
   </itemizedlist>
@@ -128,9 +167,9 @@ $ nix-instantiate -E '(import &lt;nixpkgsunstable&gt; {}).gitFull'
   <itemizedlist>
    <listitem>
     <para>
-     <literal>dockerTools.pullImage</literal> relies on image digest
-     instead of image tag to download the image. The
-     <literal>sha256</literal> of a pulled image has to be updated.
+     <literal>dockerTools.pullImage</literal> relies on image digest instead of
+     image tag to download the image. The <literal>sha256</literal> of a pulled
+     image has to be updated.
     </para>
    </listitem>
    <listitem>
@@ -166,9 +205,26 @@ $ nix-instantiate -E '(import &lt;nixpkgsunstable&gt; {}).gitFull'
    </listitem>
    <listitem>
     <para>
-     <literal>lib.traceValIfNot</literal> has been deprecated. Use
-     <literal>if/then/else</literal> and <literal>lib.traceValSeq</literal>
-     instead.
+      The <literal>pkgs</literal> argument to NixOS modules can now be set directly using <literal>nixpkgs.pkgs</literal>. Previously, only the <literal>system</literal>, <literal>config</literal> and <literal>overlays</literal> arguments could be used to influence <literal>pkgs</literal>.
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+      A NixOS system can now be constructed more easily based on a preexisting invocation of Nixpkgs. For example:
+      <programlisting>
+inherit (pkgs.nixos {
+  boot.loader.grub.enable = false;
+  fileSystems."/".device = "/dev/xvda1";
+}) toplevel kernel initialRamdisk manual;
+      </programlisting>
+
+      This benefits evaluation performance, lets you write Nixpkgs packages that depend on NixOS images and is consistent with a deployment architecture that would be centered around Nixpkgs overlays.
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+      <literal>lib.traceValIfNot</literal> has been deprecated. Use
+      <literal>if/then/else</literal> and <literal>lib.traceValSeq</literal> instead.
     </para>
    </listitem>
    <listitem>
@@ -187,32 +243,40 @@ $ nix-instantiate -E '(import &lt;nixpkgsunstable&gt; {}).gitFull'
     <para>
      The module for <option>security.dhparams</option> has two new options now:
     </para>
-
     <variablelist>
      <varlistentry>
-      <term><option>security.dhparams.stateless</option></term>
-      <listitem><para>
-       Puts the generated Diffie-Hellman parameters into the Nix store instead
-       of managing them in a stateful manner in
-       <filename class="directory">/var/lib/dhparams</filename>.
-      </para></listitem>
+      <term>
+       <option>security.dhparams.stateless</option>
+      </term>
+      <listitem>
+       <para>
+        Puts the generated Diffie-Hellman parameters into the Nix store instead
+        of managing them in a stateful manner in
+        <filename class="directory">/var/lib/dhparams</filename>.
+       </para>
+      </listitem>
      </varlistentry>
      <varlistentry>
-      <term><option>security.dhparams.defaultBitSize</option></term>
-      <listitem><para>
-       The default bit size to use for the generated Diffie-Hellman parameters.
-      </para></listitem>
+      <term>
+       <option>security.dhparams.defaultBitSize</option>
+      </term>
+      <listitem>
+       <para>
+        The default bit size to use for the generated Diffie-Hellman
+        parameters.
+       </para>
+      </listitem>
      </varlistentry>
     </variablelist>
-
-    <note><para>
-     The path to the actual generated parameter files should now be queried
-     using
-     <literal>config.security.dhparams.params.<replaceable>name</replaceable>.path</literal>
-     because it might be either in the Nix store or in a directory configured
-     by <option>security.dhparams.path</option>.
-    </para></note>
-
+    <note>
+     <para>
+      The path to the actual generated parameter files should now be queried
+      using
+      <literal>config.security.dhparams.params.<replaceable>name</replaceable>.path</literal>
+      because it might be either in the Nix store or in a directory configured
+      by <option>security.dhparams.path</option>.
+     </para>
+    </note>
     <note>
      <title>For developers:</title>
      <para>
@@ -237,8 +301,65 @@ $ nix-instantiate -E '(import &lt;nixpkgsunstable&gt; {}).gitFull'
    </listitem>
    <listitem>
     <para>
-     <literal>networking.networkmanager.useDnsmasq</literal> has been deprecated. Use
-     <literal>networking.networkmanager.dns</literal> instead.
+     <literal>networking.networkmanager.useDnsmasq</literal> has been
+     deprecated. Use <literal>networking.networkmanager.dns</literal> instead.
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     The option
+     <varname>services.kubernetes.apiserver.admissionControl</varname> was
+     renamed to
+     <varname>services.kubernetes.apiserver.enableAdmissionPlugins</varname>.
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     Recommended way to access the Kubernetes Dashboard is via HTTPS (TLS)
+     Therefore; public service port for the dashboard has changed to 443
+     (container port 8443) and scheme to https.
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     The option <varname>services.kubernetes.apiserver.address</varname>
+     was renamed to <varname>services.kubernetes.apiserver.bindAddress</varname>.
+     Note that the default value has changed from 127.0.0.1 to 0.0.0.0.
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     The option <varname>services.kubernetes.apiserver.publicAddress</varname>
+     was not used and thus has been removed.
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     The option <varname>services.kubernetes.addons.dashboard.enableRBAC</varname>
+     was renamed to <varname>services.kubernetes.addons.dashboard.rbac.enable</varname>.
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     The Kubernetes Dashboard now has only minimal RBAC permissions by default.
+     If dashboard cluster-admin rights are desired,
+     set <varname>services.kubernetes.addons.dashboard.rbac.clusterAdmin</varname> to true.
+     On existing clusters, in order for the revocation of privileges to take effect,
+     the current ClusterRoleBinding for kubernetes-dashboard must be manually removed:
+     <literal>kubectl delete clusterrolebinding kubernetes-dashboard</literal>
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     The <varname>programs.screen</varname> module provides allows to configure
+     <literal>/etc/screenrc</literal>, however the module behaved fairly counterintuitive as
+     the config exists, but the package wasn't available. Since 18.09 <literal>pkgs.screen</literal>
+     will be added to <literal>environment.systemPackages</literal>.
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+      The module <option>services.networking.hostapd</option> now uses WPA2 by default.
     </para>
    </listitem>
   </itemizedlist>
diff --git a/nixos/doc/manual/shell.nix b/nixos/doc/manual/shell.nix
index 7f8422b4ec11..cc3609d750e0 100644
--- a/nixos/doc/manual/shell.nix
+++ b/nixos/doc/manual/shell.nix
@@ -4,5 +4,5 @@ in
 pkgs.mkShell {
   name = "nixos-manual";
 
-  buildInputs = with pkgs; [ xmlformat jing xmloscopy ];
+  buildInputs = with pkgs; [ xmlformat jing xmloscopy ruby ];
 }
diff --git a/nixos/doc/varlistentry-fixer.rb b/nixos/doc/varlistentry-fixer.rb
new file mode 100755
index 000000000000..6c7cc1e6439b
--- /dev/null
+++ b/nixos/doc/varlistentry-fixer.rb
@@ -0,0 +1,124 @@
+#!/usr/bin/env ruby
+
+# This script is written intended as a living, evolving tooling
+# to fix oopsies within the docbook documentation.
+#
+# This is *not* a formatter. It, instead, handles some known cases
+# where something bad happened, and fixing it manually is tedious.
+#
+# Read the code to see the different cases it handles.
+#
+# ALWAYS `make format` after fixing with this!
+# ALWAYS read the changes, this tool isn't yet proven to be always right.
+
+require "rexml/document"
+include REXML
+
+if ARGV.length < 1 then
+	$stderr.puts "Needs a filename."
+	exit 1
+end
+
+filename = ARGV.shift
+doc = Document.new(File.open(filename))
+
+$touched = false
+
+# Fixing varnames having a sibling element without spacing.
+# This is to fix an initial `xmlformat` issue where `term`
+# would mangle as spaces.
+#
+#   <varlistentry>
+#    <term><varname>types.separatedString</varname><replaceable>sep</replaceable> <----
+#    </term>
+#    ...
+#
+# Generates: types.separatedStringsep
+#                               ^^^^
+#
+# <varlistentry xml:id='fun-makeWrapper'>
+#  <term>
+#   <function>makeWrapper</function><replaceable>executable</replaceable><replaceable>wrapperfile</replaceable><replaceable>args</replaceable>  <----
+#  </term>
+#
+# Generates: makeWrapperexecutablewrapperfileargs
+#                     ^^^^      ^^^^    ^^  ^^
+#
+#    <term>
+#     <option>--option</option><replaceable>name</replaceable><replaceable>value</replaceable> <-----
+#    </term>
+#
+# Generates: --optionnamevalue
+#                   ^^  ^^
+doc.elements.each("//varlistentry/term") do |term|
+	["varname", "function", "option", "replaceable"].each do |prev_name|
+		term.elements.each(prev_name) do |el|
+			if el.next_element and
+					el.next_element.name == "replaceable" and
+					el.next_sibling_node.class == Element
+				then
+				$touched = true
+				term.insert_after(el, Text.new(" "))
+			end
+		end
+	end
+end
+
+
+
+#  <cmdsynopsis>
+#   <command>nixos-option</command>
+#   <arg>
+#    <option>-I</option><replaceable>path</replaceable>        <------
+#   </arg>
+#
+# Generates: -Ipath
+#             ^^
+doc.elements.each("//cmdsynopsis/arg") do |term|
+	["option", "replaceable"].each do |prev_name|
+		term.elements.each(prev_name) do |el|
+			if el.next_element and
+				el.next_element.name == "replaceable" and
+				el.next_sibling_node.class == Element
+			then
+				$touched = true
+				term.insert_after(el, Text.new(" "))
+			end
+		end
+	end
+end
+
+#  <cmdsynopsis>
+#   <arg>
+#    <group choice='req'>
+#    <arg choice='plain'>
+#     <option>--profile-name</option>
+#    </arg>
+#
+#    <arg choice='plain'>
+#     <option>-p</option>
+#    </arg>
+#     </group><replaceable>name</replaceable>   <----
+#   </arg>
+#
+# Generates: [{--profile-name | -p }name]
+#                                   ^^^^
+doc.elements.each("//cmdsynopsis/arg") do |term|
+	["group"].each do |prev_name|
+		term.elements.each(prev_name) do |el|
+			if el.next_element and
+				el.next_element.name == "replaceable" and
+				el.next_sibling_node.class == Element
+			then
+				$touched = true
+				term.insert_after(el, Text.new(" "))
+			end
+		end
+	end
+end
+
+
+if $touched then
+	doc.context[:attribute_quote] = :quote
+	doc.write(output: File.open(filename, "w"))
+end
diff --git a/nixos/doc/xmlformat.conf b/nixos/doc/xmlformat.conf
index 50255857b24a..4a565c8465bc 100644
--- a/nixos/doc/xmlformat.conf
+++ b/nixos/doc/xmlformat.conf
@@ -67,6 +67,7 @@ programlisting screen
   entry-break = 0
   exit-break = 0
 
-
-#term
-#  format       inline
+# This is needed so that the spacing inside those tags is kept.
+term cmdsynopsis arg
+  normalize yes
+  format    block
diff --git a/nixos/lib/make-ext4-fs.nix b/nixos/lib/make-ext4-fs.nix
index 4095d9c6d00d..35a8afae4a7a 100644
--- a/nixos/lib/make-ext4-fs.nix
+++ b/nixos/lib/make-ext4-fs.nix
@@ -5,6 +5,7 @@
 { pkgs
 , storePaths
 , volumeLabel
+, uuid ? "44444444-4444-4444-8888-888888888888"
 }:
 
 let
@@ -32,7 +33,7 @@ pkgs.stdenv.mkDerivation {
       echo "Creating an EXT4 image of $bytes bytes (numInodes=$numInodes, numDataBlocks=$numDataBlocks)"
 
       truncate -s $bytes $out
-      faketime -f "1970-01-01 00:00:01" mkfs.ext4 -L ${volumeLabel} -U 44444444-4444-4444-8888-888888888888 $out
+      faketime -f "1970-01-01 00:00:01" mkfs.ext4 -L ${volumeLabel} -U ${uuid} $out
 
       # Populate the image contents by piping a bunch of commands to the `debugfs` tool from e2fsprogs.
       # For example, to copy /nix/store/abcd...efg-coreutils-8.23/bin/sleep:
diff --git a/nixos/lib/qemu-flags.nix b/nixos/lib/qemu-flags.nix
index e4c95ebdfb0d..6f61c64a832e 100644
--- a/nixos/lib/qemu-flags.nix
+++ b/nixos/lib/qemu-flags.nix
@@ -13,9 +13,9 @@
         else throw "Unknown QEMU serial device for system '${pkgs.stdenv.system}'";
 
   qemuBinary = qemuPkg: {
-    "i686-linux" = "${qemuPkg}/bin/qemu-kvm";
     "x86_64-linux" = "${qemuPkg}/bin/qemu-kvm -cpu kvm64";
     "armv7l-linux" = "${qemuPkg}/bin/qemu-system-arm -enable-kvm -machine virt -cpu host";
     "aarch64-linux" = "${qemuPkg}/bin/qemu-system-aarch64 -enable-kvm -machine virt,gic-version=host -cpu host";
-  }.${pkgs.stdenv.system} or (throw "Unknown QEMU binary for '${pkgs.stdenv.system}'");
+    "x86_64-darwin" = "${qemuPkg}/bin/qemu-kvm -cpu kvm64";
+  }.${pkgs.stdenv.system} or "${qemuPkg}/bin/qemu-kvm";
 }
diff --git a/nixos/maintainers/scripts/azure/create-azure.sh b/nixos/maintainers/scripts/azure/create-azure.sh
index a834566be8f7..2b22cb536619 100755
--- a/nixos/maintainers/scripts/azure/create-azure.sh
+++ b/nixos/maintainers/scripts/azure/create-azure.sh
@@ -5,4 +5,4 @@ export NIXOS_CONFIG=$(dirname $(readlink -f $0))/../../../modules/virtualisation
 export TIMESTAMP=$(date +%Y%m%d%H%M)
 
 nix-build '<nixpkgs/nixos>' \
-   -A config.system.build.azureImage --argstr system x86_64-linux -o azure --option extra-binary-caches https://hydra.nixos.org -j 10
+   -A config.system.build.azureImage --argstr system x86_64-linux -o azure -j 10
diff --git a/nixos/modules/config/fonts/fontconfig-ultimate.nix b/nixos/modules/config/fonts/fontconfig-ultimate.nix
index c7654ca78c3a..7549dc6c0651 100644
--- a/nixos/modules/config/fonts/fontconfig-ultimate.nix
+++ b/nixos/modules/config/fonts/fontconfig-ultimate.nix
@@ -2,9 +2,7 @@
 
 with lib;
 
-let fcBool = x: if x then "<bool>true</bool>" else "<bool>false</bool>";
-
-    cfg = config.fonts.fontconfig.ultimate;
+let cfg = config.fonts.fontconfig.ultimate;
 
     latestVersion  = pkgs.fontconfig.configVersion;
 
diff --git a/nixos/modules/config/ldap.nix b/nixos/modules/config/ldap.nix
index 710dfdd01af5..0693e896f715 100644
--- a/nixos/modules/config/ldap.nix
+++ b/nixos/modules/config/ldap.nix
@@ -215,11 +215,11 @@ in
     );
 
     users = mkIf cfg.daemon.enable {
-      extraGroups.nslcd = {
+      groups.nslcd = {
         gid = config.ids.gids.nslcd;
       };
 
-      extraUsers.nslcd = {
+      users.nslcd = {
         uid = config.ids.uids.nslcd;
         description = "nslcd user.";
         group = "nslcd";
diff --git a/nixos/modules/config/networking.nix b/nixos/modules/config/networking.nix
index 4101ef82f3e1..48c3b41bc091 100644
--- a/nixos/modules/config/networking.nix
+++ b/nixos/modules/config/networking.nix
@@ -231,10 +231,6 @@ in
               # a collision with an apparently unrelated environment
               # variable with the same name exported by dhcpcd.
               interface_order='lo lo[0-9]*'
-            '' + optionalString config.services.nscd.enable ''
-              # Invalidate the nscd cache whenever resolv.conf is
-              # regenerated.
-              libc_restart='${pkgs.systemd}/bin/systemctl try-restart --no-block nscd.service 2> /dev/null'
             '' + optionalString (length resolvconfOptions > 0) ''
               # Options as described in resolv.conf(5)
               resolv_conf_options='${concatStringsSep " " resolvconfOptions}'
diff --git a/nixos/modules/config/no-x-libs.nix b/nixos/modules/config/no-x-libs.nix
index a20910353f34..c7a6c943bc27 100644
--- a/nixos/modules/config/no-x-libs.nix
+++ b/nixos/modules/config/no-x-libs.nix
@@ -26,16 +26,16 @@ with lib;
 
     fonts.fontconfig.enable = false;
 
-    nixpkgs.config.packageOverrides = pkgs: {
-      dbus = pkgs.dbus.override { x11Support = false; };
-      networkmanager-fortisslvpn = pkgs.networkmanager-fortisslvpn.override { withGnome = false; };
-      networkmanager-l2tp = pkgs.networkmanager-l2tp.override { withGnome = false; };
-      networkmanager-openconnect = pkgs.networkmanager-openconnect.override { withGnome = false; };
-      networkmanager-openvpn = pkgs.networkmanager-openvpn.override { withGnome = false; };
-      networkmanager-vpnc = pkgs.networkmanager-vpnc.override { withGnome = false; };
-      networkmanager-iodine = pkgs.networkmanager-iodine.override { withGnome = false; };
-      pinentry = pkgs.pinentry_ncurses;
-      gobjectIntrospection = pkgs.gobjectIntrospection.override { x11Support = false; };
-    };
+    nixpkgs.overlays = singleton (const (super: {
+      dbus = super.dbus.override { x11Support = false; };
+      networkmanager-fortisslvpn = super.networkmanager-fortisslvpn.override { withGnome = false; };
+      networkmanager-l2tp = super.networkmanager-l2tp.override { withGnome = false; };
+      networkmanager-openconnect = super.networkmanager-openconnect.override { withGnome = false; };
+      networkmanager-openvpn = super.networkmanager-openvpn.override { withGnome = false; };
+      networkmanager-vpnc = super.networkmanager-vpnc.override { withGnome = false; };
+      networkmanager-iodine = super.networkmanager-iodine.override { withGnome = false; };
+      pinentry = super.pinentry_ncurses;
+      gobjectIntrospection = super.gobjectIntrospection.override { x11Support = false; };
+    }));
   };
 }
diff --git a/nixos/modules/config/pulseaudio.nix b/nixos/modules/config/pulseaudio.nix
index 90cea47b70ae..3fd882789af2 100644
--- a/nixos/modules/config/pulseaudio.nix
+++ b/nixos/modules/config/pulseaudio.nix
@@ -264,7 +264,7 @@ in {
     })
 
     (mkIf systemWide {
-      users.extraUsers.pulse = {
+      users.users.pulse = {
         # For some reason, PulseAudio wants UID == GID.
         uid = assert uid == gid; uid;
         group = "pulse";
@@ -274,7 +274,7 @@ in {
         createHome = true;
       };
 
-      users.extraGroups.pulse.gid = gid;
+      users.groups.pulse.gid = gid;
 
       systemd.services.pulseaudio = {
         description = "PulseAudio System-Wide Server";
diff --git a/nixos/modules/hardware/all-firmware.nix b/nixos/modules/hardware/all-firmware.nix
index b61acf1815d9..e978ec6b40ad 100644
--- a/nixos/modules/hardware/all-firmware.nix
+++ b/nixos/modules/hardware/all-firmware.nix
@@ -38,7 +38,8 @@ in {
         firmwareLinuxNonfree
         intel2200BGFirmware
         rtl8192su-firmware
-      ] ++ optionals (versionOlder config.boot.kernelPackages.kernel.version "4.13") [
+      ] ++ optional (pkgs.stdenv.isAarch32 || pkgs.stdenv.isAarch64) raspberrypiWirelessFirmware
+        ++ optionals (versionOlder config.boot.kernelPackages.kernel.version "4.13") [
         rtl8723bs-firmware
       ];
     })
diff --git a/nixos/modules/hardware/brightnessctl.nix b/nixos/modules/hardware/brightnessctl.nix
new file mode 100644
index 000000000000..341e4b791c23
--- /dev/null
+++ b/nixos/modules/hardware/brightnessctl.nix
@@ -0,0 +1,30 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+let
+  cfg = config.hardware.brightnessctl;
+in
+{
+
+  options = {
+
+    hardware.brightnessctl = {
+
+      enable = mkOption {
+        default = false;
+        type = types.bool;
+        description = ''
+          Enable brightnessctl in userspace.
+          This will allow brightness control from users in the video group.
+        '';
+
+      };
+    };
+  };
+
+
+  config = mkIf cfg.enable {
+    services.udev.packages = with pkgs; [ brightnessctl ];
+  };
+
+}
diff --git a/nixos/modules/hardware/nitrokey.nix b/nixos/modules/hardware/nitrokey.nix
index bd440de69722..60fc95a75828 100644
--- a/nixos/modules/hardware/nitrokey.nix
+++ b/nixos/modules/hardware/nitrokey.nix
@@ -36,6 +36,6 @@ in
         { inherit (cfg) group; }
       ))
     ];
-    users.extraGroups."${cfg.group}" = {};
+    users.groups."${cfg.group}" = {};
   };
 }
diff --git a/nixos/modules/hardware/video/uvcvideo/default.nix b/nixos/modules/hardware/video/uvcvideo/default.nix
new file mode 100644
index 000000000000..7e3e94fdf2bd
--- /dev/null
+++ b/nixos/modules/hardware/video/uvcvideo/default.nix
@@ -0,0 +1,64 @@
+
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.uvcvideo;
+
+  uvcdynctrl-udev-rules = packages: pkgs.callPackage ./uvcdynctrl-udev-rules.nix {
+    drivers = packages;
+    udevDebug = false;
+  };
+
+in
+
+{
+
+  options = {
+    services.uvcvideo.dynctrl = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to enable <command>uvcvideo</command> dynamic controls.
+
+          Note that enabling this brings the <command>uvcdynctrl</command> tool
+          into your environement and register all dynamic controls from
+          specified <command>packages</command> to the <command>uvcvideo</command> driver.
+        '';
+      };
+
+      packages = mkOption {
+        type = types.listOf types.path;
+        example = literalExample "[ pkgs.tiscamera ]";
+        description = ''
+          List of packages containing <command>uvcvideo</command> dynamic controls
+          rules. All files found in
+          <filename><replaceable>pkg</replaceable>/share/uvcdynctrl/data</filename>
+          will be included.
+
+          Note that these will serve as input to the <command>libwebcam</command>
+          package which through its own <command>udev</command> rule will register
+          the dynamic controls from specified packages to the <command>uvcvideo</command>
+          driver.
+        '';
+        apply = map getBin;
+      };
+    };
+  };
+
+  config = mkIf cfg.dynctrl.enable {
+
+    services.udev.packages = [
+      (uvcdynctrl-udev-rules cfg.dynctrl.packages)
+    ];
+
+    environment.systemPackages = [
+      pkgs.libwebcam
+    ];
+
+  };
+}
diff --git a/nixos/modules/hardware/video/uvcvideo/uvcdynctrl-udev-rules.nix b/nixos/modules/hardware/video/uvcvideo/uvcdynctrl-udev-rules.nix
new file mode 100644
index 000000000000..832e61966120
--- /dev/null
+++ b/nixos/modules/hardware/video/uvcvideo/uvcdynctrl-udev-rules.nix
@@ -0,0 +1,46 @@
+{ lib
+, stdenv
+, buildEnv
+, libwebcam
+, makeWrapper
+, runCommand
+, drivers ? []
+, udevDebug ? false
+}:
+
+let
+  version = "0.0.0";
+
+  dataPath = buildEnv {
+    name = "uvcdynctrl-with-drivers-data-path";
+    paths = drivers ++ [ libwebcam ];
+    pathsToLink = [ "/share/uvcdynctrl/data" ];
+    ignoreCollisions = false;
+  };
+
+  dataDir = "${dataPath}/share/uvcdynctrl/data";
+  udevDebugVarValue = if udevDebug then "1" else "0";
+in
+
+runCommand "uvcdynctrl-udev-rules-${version}"
+{
+  inherit dataPath;
+  buildInputs = [
+    makeWrapper
+    libwebcam
+  ];
+  dontPatchELF = true;
+  dontStrip = true;
+}
+''
+  mkdir -p "$out/lib/udev"
+  makeWrapper "${libwebcam}/lib/udev/uvcdynctrl" "$out/lib/udev/uvcdynctrl" \
+    --set NIX_UVCDYNCTRL_DATA_DIR "${dataDir}" \
+    --set NIX_UVCDYNCTRL_UDEV_DEBUG "${udevDebugVarValue}"
+
+  mkdir -p "$out/lib/udev/rules.d"
+  cat "${libwebcam}/lib/udev/rules.d/80-uvcdynctrl.rules" | \
+    sed -r "s#RUN\+\=\"([^\"]+)\"#RUN\+\=\"$out/lib/udev/uvcdynctrl\"#g" > \
+    "$out/lib/udev/rules.d/80-uvcdynctrl.rules"
+''
+
diff --git a/nixos/modules/i18n/input-method/default.nix b/nixos/modules/i18n/input-method/default.nix
index 7ed4a584d646..9548a249efa0 100644
--- a/nixos/modules/i18n/input-method/default.nix
+++ b/nixos/modules/i18n/input-method/default.nix
@@ -50,7 +50,7 @@ in
 
       package = mkOption {
         internal = true;
-        type     = types.path;
+        type     = types.nullOr types.path;
         default  = null;
         description = ''
           The input method method package.
diff --git a/nixos/modules/i18n/input-method/default.xml b/nixos/modules/i18n/input-method/default.xml
index 76ffa8cb7e37..eb75b7415c9c 100644
--- a/nixos/modules/i18n/input-method/default.xml
+++ b/nixos/modules/i18n/input-method/default.xml
@@ -68,6 +68,18 @@ ibus.engines = with pkgs.ibus-engines; [ table table-others ];
 <para>To use any input method, the package must be added in the configuration,
   as shown above, and also (after running <literal>nixos-rebuild</literal>) the
   input method must be added from IBus' preference dialog.</para>
+
+<simplesect>
+  <title>Troubleshooting</title>
+  <para>If IBus works in some applications but not others, a likely cause of
+  this is that IBus is depending on a different version of
+  <literal>glib</literal> to what the applications are depending on. This can
+  be checked by running <literal>nix-store -q --requisites &lt;path&gt; | grep
+  glib</literal>, where <literal>&lt;path&gt;</literal> is the path of either
+  IBus or an application in the Nix store. The <literal>glib</literal>
+  packages must match exactly. If they do not, uninstalling and reinstalling
+  the application is a likely fix.</para>
+</simplesect>
 </section>
 
 <section><title>Fcitx</title>
diff --git a/nixos/modules/installer/cd-dvd/installation-cd-base.nix b/nixos/modules/installer/cd-dvd/installation-cd-base.nix
index 1ed56386e6e7..298b8d88bb59 100644
--- a/nixos/modules/installer/cd-dvd/installation-cd-base.nix
+++ b/nixos/modules/installer/cd-dvd/installation-cd-base.nix
@@ -30,7 +30,7 @@ with lib;
   boot.loader.grub.memtest86.enable = true;
 
   # Allow the user to log in as root without a password.
-  users.extraUsers.root.initialHashedPassword = "";
+  users.users.root.initialHashedPassword = "";
 
   system.nixos.stateVersion = mkDefault "18.03";
 }
diff --git a/nixos/modules/installer/cd-dvd/sd-image-aarch64.nix b/nixos/modules/installer/cd-dvd/sd-image-aarch64.nix
index ddf91a5656c7..4eb28434e192 100644
--- a/nixos/modules/installer/cd-dvd/sd-image-aarch64.nix
+++ b/nixos/modules/installer/cd-dvd/sd-image-aarch64.nix
@@ -34,7 +34,7 @@ in
   boot.kernelParams = ["cma=32M" "console=ttyS0,115200n8" "console=ttyAMA0,115200n8" "console=tty0"];
 
   # FIXME: this probably should be in installation-device.nix
-  users.extraUsers.root.initialHashedPassword = "";
+  users.users.root.initialHashedPassword = "";
 
   sdImage = {
     populateBootCommands = let
diff --git a/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix b/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix
index 891923234dda..0d595503f193 100644
--- a/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix
+++ b/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix
@@ -35,7 +35,7 @@ in
   boot.kernelParams = ["console=ttyS0,115200n8" "console=ttymxc0,115200n8" "console=ttyAMA0,115200n8" "console=ttyO0,115200n8" "console=ttySAC2,115200n8" "console=tty0"];
 
   # FIXME: this probably should be in installation-device.nix
-  users.extraUsers.root.initialHashedPassword = "";
+  users.users.root.initialHashedPassword = "";
 
   sdImage = {
     populateBootCommands = let
diff --git a/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix b/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix
index 212013b5e289..aa52844288ca 100644
--- a/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix
+++ b/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix
@@ -28,14 +28,27 @@ in
   boot.kernelPackages = pkgs.linuxPackages_rpi;
 
   # FIXME: this probably should be in installation-device.nix
-  users.extraUsers.root.initialHashedPassword = "";
+  users.users.root.initialHashedPassword = "";
 
   sdImage = {
-    populateBootCommands = ''
-      (cd ${pkgs.raspberrypifw}/share/raspberrypi/boot && cp bootcode.bin fixup*.dat start*.elf $NIX_BUILD_TOP/boot/)
-      cp ${pkgs.ubootRaspberryPi}/u-boot.bin boot/u-boot-rpi.bin
-      echo 'kernel u-boot-rpi.bin' > boot/config.txt
-      ${extlinux-conf-builder} -t 3 -c ${config.system.build.toplevel} -d ./boot
-    '';
+    populateBootCommands = let
+      configTxt = pkgs.writeText "config.txt" ''
+        # Prevent the firmware from smashing the framebuffer setup done by the mainline kernel
+        # when attempting to show low-voltage or overtemperature warnings.
+        avoid_warnings=1
+
+        [pi0]
+        kernel=u-boot-rpi0.bin
+
+        [pi1]
+        kernel=u-boot-rpi1.bin
+      '';
+      in ''
+        (cd ${pkgs.raspberrypifw}/share/raspberrypi/boot && cp bootcode.bin fixup*.dat start*.elf $NIX_BUILD_TOP/boot/)
+        cp ${pkgs.ubootRaspberryPiZero}/u-boot.bin boot/u-boot-rpi0.bin
+        cp ${pkgs.ubootRaspberryPi}/u-boot.bin boot/u-boot-rpi1.bin
+        cp ${configTxt} boot/config.txt
+        ${extlinux-conf-builder} -t 3 -c ${config.system.build.toplevel} -d ./boot
+      '';
   };
 }
diff --git a/nixos/modules/installer/cd-dvd/sd-image.nix b/nixos/modules/installer/cd-dvd/sd-image.nix
index c091923de60f..311a5ff69670 100644
--- a/nixos/modules/installer/cd-dvd/sd-image.nix
+++ b/nixos/modules/installer/cd-dvd/sd-image.nix
@@ -16,6 +16,8 @@ let
     inherit pkgs;
     inherit (config.sdImage) storePaths;
     volumeLabel = "NIXOS_SD";
+  } // optionalAttrs (config.sdImage.rootPartitionUUID != null) {
+    uuid = config.sdImage.rootPartitionUUID;
   };
 in
 {
@@ -42,6 +44,24 @@ in
       '';
     };
 
+    bootPartitionID = mkOption {
+      type = types.string;
+      default = "0x2178694e";
+      description = ''
+        Volume ID for the /boot partition on the SD card. This value must be a
+        32-bit hexadecimal number.
+      '';
+    };
+
+    rootPartitionUUID = mkOption {
+      type = types.nullOr types.string;
+      default = null;
+      example = "14e19a7b-0ae0-484d-9d54-43bd6fdc20c7";
+      description = ''
+        UUID for the main NixOS partition on the SD card.
+      '';
+    };
+
     bootSize = mkOption {
       type = types.int;
       default = 120;
@@ -95,7 +115,7 @@ in
         # type=b is 'W95 FAT32', type=83 is 'Linux'.
         sfdisk $img <<EOF
             label: dos
-            label-id: 0x2178694e
+            label-id: ${config.sdImage.bootPartitionID}
 
             start=8M, size=$bootSizeBlocks, type=b, bootable
             start=${toString (8 + config.sdImage.bootSize)}M, type=83
@@ -108,7 +128,7 @@ in
         # Create a FAT32 /boot partition of suitable size into bootpart.img
         eval $(partx $img -o START,SECTORS --nr 1 --pairs)
         truncate -s $((SECTORS * 512)) bootpart.img
-        faketime "1970-01-01 00:00:00" mkfs.vfat -i 0x2178694e -n NIXOS_BOOT bootpart.img
+        faketime "1970-01-01 00:00:00" mkfs.vfat -i ${config.sdImage.bootPartitionID} -n NIXOS_BOOT bootpart.img
 
         # Populate the files intended for /boot
         mkdir boot
diff --git a/nixos/modules/installer/netboot/netboot-base.nix b/nixos/modules/installer/netboot/netboot-base.nix
index b12eaccf8707..5e8f7f93d92a 100644
--- a/nixos/modules/installer/netboot/netboot-base.nix
+++ b/nixos/modules/installer/netboot/netboot-base.nix
@@ -16,5 +16,5 @@ with lib;
     ];
 
   # Allow the user to log in as root without a password.
-  users.extraUsers.root.initialHashedPassword = "";
+  users.users.root.initialHashedPassword = "";
 }
diff --git a/nixos/modules/installer/scan/not-detected.nix b/nixos/modules/installer/scan/not-detected.nix
index 903933e2df02..baa068c08dbf 100644
--- a/nixos/modules/installer/scan/not-detected.nix
+++ b/nixos/modules/installer/scan/not-detected.nix
@@ -1,9 +1,6 @@
-# List all devices which are _not_ detected by nixos-generate-config.
-# Common devices are enabled by default.
-{ config, lib, pkgs, ... }:
-
-with lib;
+# Enables non-free firmware on devices not recognized by `nixos-generate-config`.
+{ lib, ... }:
 
 {
-  hardware.enableRedistributableFirmware = true;
+  hardware.enableRedistributableFirmware = lib.mkDefault true;
 }
diff --git a/nixos/modules/installer/tools/nix-fallback-paths.nix b/nixos/modules/installer/tools/nix-fallback-paths.nix
index 5ad28ea9499e..7c5414257b46 100644
--- a/nixos/modules/installer/tools/nix-fallback-paths.nix
+++ b/nixos/modules/installer/tools/nix-fallback-paths.nix
@@ -1,6 +1,6 @@
 {
-  x86_64-linux = "/nix/store/z6avpvg24f6d1br2sr6qlphsq3h4d91v-nix-2.0.2";
-  i686-linux = "/nix/store/cdqjyb9srhwkc4gqbknnap7y31lws4yq-nix-2.0.2";
-  aarch64-linux = "/nix/store/fbgaa3fb2am30klwv4lls44njwqh487a-nix-2.0.2";
-  x86_64-darwin = "/nix/store/hs8mxsvdhm95dxgx943d74fws01j2zj3-nix-2.0.2";
+  x86_64-linux = "/nix/store/0d60i73mcv8z1m8d2m74yfn84980gfsa-nix-2.0.4";
+  i686-linux = "/nix/store/6ssafj2s5a2g9x28yld7b70vwd6vw6lb-nix-2.0.4";
+  aarch64-linux = "/nix/store/3wwch7bp7n7xsl8apgy2a4b16yzyij1z-nix-2.0.4";
+  x86_64-darwin = "/nix/store/771l8i0mz4c8kry8cz3sz8rr3alalckg-nix-2.0.4";
 }
diff --git a/nixos/modules/installer/tools/nixos-generate-config.pl b/nixos/modules/installer/tools/nixos-generate-config.pl
index a198c2d49b53..165566912401 100644
--- a/nixos/modules/installer/tools/nixos-generate-config.pl
+++ b/nixos/modules/installer/tools/nixos-generate-config.pl
@@ -619,7 +619,7 @@ $bootLoaderConfig
   # services.xserver.desktopManager.plasma5.enable = true;
 
   # Define a user account. Don't forget to set a password with ‘passwd’.
-  # users.extraUsers.guest = {
+  # users.users.guest = {
   #   isNormalUser = true;
   #   uid = 1000;
   # };
diff --git a/nixos/modules/installer/tools/nixos-option.sh b/nixos/modules/installer/tools/nixos-option.sh
index 5141f3cd51cf..3f1e591b97b0 100644
--- a/nixos/modules/installer/tools/nixos-option.sh
+++ b/nixos/modules/installer/tools/nixos-option.sh
@@ -16,6 +16,7 @@ verbose=false
 nixPath=""
 
 option=""
+exit_code=0
 
 argfun=""
 for arg; do
@@ -74,8 +75,13 @@ fi
 #############################
 
 evalNix(){
+  # disable `-e` flag, it's possible that the evaluation of `nix-instantiate` fails (e.g. due to broken pkgs)
+  set +e
   result=$(nix-instantiate ${nixPath:+$nixPath} - --eval-only "$@" 2>&1)
-  if test $? -eq 0; then
+  exit_code=$?
+  set -e
+
+  if test $exit_code -eq 0; then
       cat <<EOF
 $result
 EOF
@@ -87,7 +93,7 @@ EOF
 ' <<EOF
 $result
 EOF
-      return 1;
+    exit_code=1
   fi
 }
 
@@ -317,3 +323,5 @@ else
     echo $result
   fi
 fi
+
+exit $exit_code
diff --git a/nixos/modules/installer/tools/tools.nix b/nixos/modules/installer/tools/tools.nix
index beac9e29d59c..05029628672b 100644
--- a/nixos/modules/installer/tools/tools.nix
+++ b/nixos/modules/installer/tools/tools.nix
@@ -6,8 +6,6 @@
 with lib;
 
 let
-  cfg = config.installer;
-
   makeProg = args: pkgs.substituteAll (args // {
     dir = "bin";
     isExecutable = true;
@@ -76,7 +74,7 @@ in
       ];
 
     system.build = {
-      inherit nixos-install nixos-prepare-root nixos-generate-config nixos-option nixos-rebuild nixos-enter;
+      inherit nixos-install nixos-generate-config nixos-option nixos-rebuild nixos-enter;
     };
 
   };
diff --git a/nixos/modules/installer/virtualbox-demo.nix b/nixos/modules/installer/virtualbox-demo.nix
index c40e30354206..f58c36587801 100644
--- a/nixos/modules/installer/virtualbox-demo.nix
+++ b/nixos/modules/installer/virtualbox-demo.nix
@@ -14,7 +14,7 @@ with lib;
   boot.loader.grub.fsIdentifier = "provided";
 
   # Allow mounting of shared folders.
-  users.extraUsers.demo.extraGroups = [ "vboxsf" ];
+  users.users.demo.extraGroups = [ "vboxsf" ];
 
   # Add some more video drivers to give X11 a shot at working in
   # VMware and QEMU.
diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix
index cc7d86849824..14c661553c6b 100644
--- a/nixos/modules/misc/ids.nix
+++ b/nixos/modules/misc/ids.nix
@@ -1,6 +1,14 @@
 # This module defines the global list of uids and gids.  We keep a
 # central list to prevent id collisions.
 
+# IMPORTANT!
+# We only add static uids and gids for services where it is not feasible
+# to change uids/gids on service start, in example a service with a lot of
+# files. Please also check if the service is applicable for systemd's
+# DynamicUser option and does not need a uid/gid allocation at all.
+# Systemd can also change ownership of service directories using the
+# RuntimeDirectory/StateDirectory options.
+
 { config, pkgs, lib, ... }:
 
 {
@@ -135,6 +143,7 @@
       jenkins = 109;
       systemd-journal-gateway = 110;
       #notbit = 111; # unused
+      aerospike = 111;
       ngircd = 112;
       btsync = 113;
       minecraft = 114;
@@ -307,6 +316,13 @@
       duplicati = 289;
       monetdb = 290;
       restic = 291;
+      openvpn = 292;
+      meguca = 293;
+      yarn = 294;
+      hdfs = 295;
+      mapred = 296;
+      hadoop = 297;
+      hydron = 298;
 
       # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399!
 
@@ -422,6 +438,7 @@
       jenkins = 109;
       systemd-journal-gateway = 110;
       #notbit = 111; # unused
+      aerospike = 111;
       #ngircd = 112; # unused
       btsync = 113;
       #minecraft = 114; # unused
@@ -582,6 +599,13 @@
       duplicati = 289;
       monetdb = 290;
       restic = 291;
+      openvpn = 292;
+      meguca = 293;
+      yarn = 294;
+      hdfs = 295;
+      mapred = 296;
+      hadoop = 297;
+      hydron = 298;
 
       # When adding a gid, make sure it doesn't match an existing
       # uid. Users and groups with the same name should have equal
diff --git a/nixos/modules/misc/locate.nix b/nixos/modules/misc/locate.nix
index ce5765cf1978..dd6a2f67b30d 100644
--- a/nixos/modules/misc/locate.nix
+++ b/nixos/modules/misc/locate.nix
@@ -101,7 +101,7 @@ in {
   };
 
   config = mkIf cfg.enable {
-    users.extraGroups = mkIf isMLocate { mlocate = {}; };
+    users.groups = mkIf isMLocate { mlocate = {}; };
 
     security.wrappers = mkIf isMLocate {
       locate = {
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 6fe29af3a00d..e5dce84d6ee6 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -29,6 +29,7 @@
   ./config/vpnc.nix
   ./config/zram.nix
   ./hardware/all-firmware.nix
+  ./hardware/brightnessctl.nix
   ./hardware/ckb.nix
   ./hardware/cpu/amd-microcode.nix
   ./hardware/cpu/intel-microcode.nix
@@ -50,6 +51,7 @@
   ./hardware/video/bumblebee.nix
   ./hardware/video/displaylink.nix
   ./hardware/video/nvidia.nix
+  ./hardware/video/uvcvideo/default.nix
   ./hardware/video/webcam/facetimehd.nix
   ./i18n/input-method/default.nix
   ./i18n/input-method/fcitx.nix
@@ -84,6 +86,7 @@
   ./programs/dconf.nix
   ./programs/digitalbitbox/default.nix
   ./programs/environment.nix
+  ./programs/firejail.nix
   ./programs/fish.nix
   ./programs/freetds.nix
   ./programs/gnupg.nix
@@ -122,10 +125,12 @@
   ./programs/wireshark.nix
   ./programs/xfs_quota.nix
   ./programs/xonsh.nix
+  ./programs/xss-lock.nix
   ./programs/yabar.nix
   ./programs/zsh/oh-my-zsh.nix
   ./programs/zsh/zsh.nix
   ./programs/zsh/zsh-autoenv.nix
+  ./programs/zsh/zsh-autosuggestions.nix
   ./programs/zsh/zsh-syntax-highlighting.nix
   ./rename.nix
   ./security/acme.nix
@@ -149,6 +154,7 @@
   ./security/rtkit.nix
   ./security/wrappers/default.nix
   ./security/sudo.nix
+  ./services/admin/oxidized.nix
   ./services/admin/salt/master.nix
   ./services/admin/salt/minion.nix
   ./services/amqp/activemq/default.nix
@@ -173,6 +179,7 @@
   ./services/backup/rsnapshot.nix
   ./services/backup/tarsnap.nix
   ./services/backup/znapzend.nix
+  ./services/cluster/hadoop/default.nix
   ./services/cluster/kubernetes/default.nix
   ./services/cluster/kubernetes/dns.nix
   ./services/cluster/kubernetes/dashboard.nix
@@ -193,6 +200,7 @@
   ./services/continuous-integration/jenkins/slave.nix
   ./services/databases/4store-endpoint.nix
   ./services/databases/4store.nix
+  ./services/databases/aerospike.nix
   ./services/databases/clickhouse.nix
   ./services/databases/couchdb.nix
   ./services/databases/firebird.nix
@@ -214,6 +222,7 @@
   ./services/databases/stanchion.nix
   ./services/databases/virtuoso.nix
   ./services/desktops/accountsservice.nix
+  ./services/desktops/bamf.nix
   ./services/desktops/dleyna-renderer.nix
   ./services/desktops/dleyna-server.nix
   ./services/desktops/flatpak.nix
@@ -237,6 +246,7 @@
   ./services/desktops/gnome3/tracker-miners.nix
   ./services/desktops/profile-sync-daemon.nix
   ./services/desktops/telepathy.nix
+  ./services/development/bloop.nix
   ./services/development/hoogle.nix
   ./services/editors/emacs.nix
   ./services/editors/infinoted.nix
@@ -311,6 +321,7 @@
   ./services/misc/canto-daemon.nix
   ./services/misc/calibre-server.nix
   ./services/misc/cfdyndns.nix
+  ./services/misc/clipmenu.nix
   ./services/misc/cpuminer-cryptonight.nix
   ./services/misc/cgminer.nix
   ./services/misc/confd.nix
@@ -470,6 +481,7 @@
   ./services/networking/dnschain.nix
   ./services/networking/dnscrypt-proxy.nix
   ./services/networking/dnscrypt-wrapper.nix
+  ./services/networking/dnsdist.nix
   ./services/networking/dnsmasq.nix
   ./services/networking/ejabberd.nix
   ./services/networking/fakeroute.nix
@@ -480,6 +492,7 @@
   ./services/networking/flannel.nix
   ./services/networking/flashpolicyd.nix
   ./services/networking/freenet.nix
+  ./services/networking/freeradius.nix
   ./services/networking/gale.nix
   ./services/networking/gateone.nix
   ./services/networking/gdomap.nix
@@ -512,6 +525,7 @@
   ./services/networking/miniupnpd.nix
   ./services/networking/mosquitto.nix
   ./services/networking/monero.nix
+  ./services/networking/morty.nix
   ./services/networking/miredo.nix
   ./services/networking/mstpd.nix
   ./services/networking/murmur.nix
@@ -534,6 +548,7 @@
   ./services/networking/openntpd.nix
   ./services/networking/openvpn.nix
   ./services/networking/ostinato.nix
+  ./services/networking/owamp.nix
   ./services/networking/pdnsd.nix
   ./services/networking/polipo.nix
   ./services/networking/powerdns.nix
@@ -616,6 +631,7 @@
   ./services/security/hologram-agent.nix
   ./services/security/munge.nix
   ./services/security/oauth2_proxy.nix
+  ./services/security/oauth2_proxy_nginx.nix
   ./services/security/physlock.nix
   ./services/security/shibboleth-sp.nix
   ./services/security/sks.nix
@@ -654,17 +670,19 @@
   ./services/web-apps/tt-rss.nix
   ./services/web-apps/selfoss.nix
   ./services/web-apps/quassel-webserver.nix
+  ./services/web-apps/virtlyst.nix
   ./services/web-apps/youtrack.nix
   ./services/web-servers/apache-httpd/default.nix
   ./services/web-servers/caddy.nix
   ./services/web-servers/fcgiwrap.nix
   ./services/web-servers/hitch/default.nix
+  ./services/web-servers/hydron.nix
   ./services/web-servers/jboss/default.nix
   ./services/web-servers/lighttpd/cgit.nix
   ./services/web-servers/lighttpd/collectd.nix
   ./services/web-servers/lighttpd/default.nix
   ./services/web-servers/lighttpd/gitweb.nix
-  ./services/web-servers/lighttpd/inginious.nix
+  ./services/web-servers/meguca.nix
   ./services/web-servers/mighttpd2.nix
   ./services/web-servers/minio.nix
   ./services/web-servers/nginx/default.nix
@@ -784,6 +802,7 @@
   ./virtualisation/lxd.nix
   ./virtualisation/amazon-options.nix
   ./virtualisation/hyperv-guest.nix
+  ./virtualisation/kvmgt.nix
   ./virtualisation/openvswitch.nix
   ./virtualisation/parallels-guest.nix
   ./virtualisation/qemu-guest-agent.nix
diff --git a/nixos/modules/profiles/base.nix b/nixos/modules/profiles/base.nix
index 52481d90eab9..406a69722de6 100644
--- a/nixos/modules/profiles/base.nix
+++ b/nixos/modules/profiles/base.nix
@@ -29,7 +29,6 @@
     # Hardware-related tools.
     pkgs.sdparm
     pkgs.hdparm
-    pkgs.dmraid
     pkgs.smartmontools # for diagnosing hard disks
     pkgs.pciutils
     pkgs.usbutils
diff --git a/nixos/modules/profiles/clone-config.nix b/nixos/modules/profiles/clone-config.nix
index 5b4e68beb6a6..99d4774584f1 100644
--- a/nixos/modules/profiles/clone-config.nix
+++ b/nixos/modules/profiles/clone-config.nix
@@ -31,7 +31,6 @@ let
     let
       relocateNixOS = path:
         "<nixpkgs/nixos" + removePrefix nixosPath (toString path) + ">";
-      relocateOthers = null;
     in
       { nixos = map relocateNixOS partitionedModuleFiles.nixos;
         others = []; # TODO: copy the modules to the install-device repository.
diff --git a/nixos/modules/profiles/demo.nix b/nixos/modules/profiles/demo.nix
index c3ee6e98371e..7477795a94e9 100644
--- a/nixos/modules/profiles/demo.nix
+++ b/nixos/modules/profiles/demo.nix
@@ -3,7 +3,7 @@
 {
   imports = [ ./graphical.nix ];
 
-  users.extraUsers.demo =
+  users.users.demo =
     { isNormalUser = true;
       description = "Demo user account";
       extraGroups = [ "wheel" ];
diff --git a/nixos/modules/programs/adb.nix b/nixos/modules/programs/adb.nix
index f648d70bd9fa..942572cef9d5 100644
--- a/nixos/modules/programs/adb.nix
+++ b/nixos/modules/programs/adb.nix
@@ -14,7 +14,7 @@ with lib;
         description = ''
           Whether to configure system to use Android Debug Bridge (adb).
           To grant access to a user, it must be part of adbusers group:
-          <code>users.extraUsers.alice.extraGroups = ["adbusers"];</code>
+          <code>users.users.alice.extraGroups = ["adbusers"];</code>
         '';
         relatedPackages = [ ["androidenv" "platformTools"] ];
       };
@@ -25,6 +25,6 @@ with lib;
   config = mkIf config.programs.adb.enable {
     services.udev.packages = [ pkgs.android-udev-rules ];
     environment.systemPackages = [ pkgs.androidenv.platformTools ];
-    users.extraGroups.adbusers = {};
+    users.groups.adbusers = {};
   };
 }
diff --git a/nixos/modules/programs/digitalbitbox/default.nix b/nixos/modules/programs/digitalbitbox/default.nix
index 7c727489c6c9..2fe0a14412c5 100644
--- a/nixos/modules/programs/digitalbitbox/default.nix
+++ b/nixos/modules/programs/digitalbitbox/default.nix
@@ -34,6 +34,6 @@ in
 
   meta = {
     doc = ./doc.xml;
-    maintainers = with stdenv.lib.maintainers; [ vidbina ];
+    maintainers = with lib.maintainers; [ vidbina ];
   };
 }
diff --git a/nixos/modules/programs/environment.nix b/nixos/modules/programs/environment.nix
index 401d152941a0..06ebb7bc729b 100644
--- a/nixos/modules/programs/environment.nix
+++ b/nixos/modules/programs/environment.nix
@@ -33,8 +33,6 @@ in
     environment.profileRelativeEnvVars =
       { PATH = [ "/bin" ];
         INFOPATH = [ "/info" "/share/info" ];
-        PKG_CONFIG_PATH = [ "/lib/pkgconfig" ];
-        PERL5LIB = [ "/lib/perl5/site_perl" ];
         KDEDIRS = [ "" ];
         STRIGI_PLUGIN_PATH = [ "/lib/strigi/" ];
         QT_PLUGIN_PATH = [ "/lib/qt4/plugins" "/lib/kde4/plugins" ];
diff --git a/nixos/modules/programs/firejail.nix b/nixos/modules/programs/firejail.nix
new file mode 100644
index 000000000000..46ee4bc0f7a0
--- /dev/null
+++ b/nixos/modules/programs/firejail.nix
@@ -0,0 +1,48 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.programs.firejail;
+
+  wrappedBins = pkgs.stdenv.mkDerivation rec {
+    name = "firejail-wrapped-binaries";
+    nativeBuildInputs = with pkgs; [ makeWrapper ];
+    buildCommand = ''
+      mkdir -p $out/bin
+      ${lib.concatStringsSep "\n" (lib.mapAttrsToList (command: binary: ''
+      cat <<_EOF >$out/bin/${command}
+      #!${pkgs.stdenv.shell} -e
+      /run/wrappers/bin/firejail ${binary} "\$@"
+      _EOF
+      chmod 0755 $out/bin/${command}
+      '') cfg.wrappedBinaries)}
+    '';
+  };
+
+in {
+  options.programs.firejail = {
+    enable = mkEnableOption "firejail";
+
+    wrappedBinaries = mkOption {
+      type = types.attrs;
+      default = {};
+      description = ''
+        Wrap the binaries in firejail and place them in the global path.
+        </para>
+        <para>
+        You will get file collisions if you put the actual application binary in
+        the global environment and applications started via .desktop files are
+        not wrapped if they specify the absolute path to the binary.
+      '';
+    };
+  };
+
+  config = mkIf cfg.enable {
+    security.wrappers.firejail.source = "${lib.getBin pkgs.firejail}/bin/firejail";
+
+    environment.systemPackages = [ wrappedBins ];
+  };
+
+  meta.maintainers = with maintainers; [ peterhoeg ];
+}
diff --git a/nixos/modules/programs/gphoto2.nix b/nixos/modules/programs/gphoto2.nix
index ca7c6fb28f52..93923ff3133c 100644
--- a/nixos/modules/programs/gphoto2.nix
+++ b/nixos/modules/programs/gphoto2.nix
@@ -15,7 +15,7 @@ with lib;
           Whether to configure system to use gphoto2.
           To grant digital camera access to a user, the user must
           be part of the camera group:
-          <code>users.extraUsers.alice.extraGroups = ["camera"];</code>
+          <code>users.users.alice.extraGroups = ["camera"];</code>
         '';
       };
     };
@@ -25,6 +25,6 @@ with lib;
   config = mkIf config.programs.gphoto2.enable {
     services.udev.packages = [ pkgs.libgphoto2 ];
     environment.systemPackages = [ pkgs.gphoto2 ];
-    users.extraGroups.camera = {};
+    users.groups.camera = {};
   };
 }
diff --git a/nixos/modules/programs/mosh.nix b/nixos/modules/programs/mosh.nix
index b3aa55e189a3..359fe23e0ecd 100644
--- a/nixos/modules/programs/mosh.nix
+++ b/nixos/modules/programs/mosh.nix
@@ -16,10 +16,28 @@ in
       default = false;
       type = lib.types.bool;
     };
+    withUtempter = mkOption {
+      description = ''
+        Whether to enable libutempter for mosh.
+        This is required so that mosh can write to /var/run/utmp (which can be queried with `who` to display currently connected user sessions).
+        Note, this will add a guid wrapper for the group utmp!
+      '';
+      default = true;
+      type = lib.types.bool;
+    };
   };
 
   config = mkIf cfg.enable {
     environment.systemPackages = with pkgs; [ mosh ];
     networking.firewall.allowedUDPPortRanges = [ { from = 60000; to = 61000; } ];
+    security.wrappers = mkIf cfg.withUtempter {
+      utempter = {
+        source = "${pkgs.libutempter}/lib/utempter/utempter";
+        owner = "nobody";
+        group = "utmp";
+        setuid = false;
+        setgid = true;
+      };
+    };
   };
 }
diff --git a/nixos/modules/programs/npm.nix b/nixos/modules/programs/npm.nix
index 7ef172355c1f..5fdd4fa841a1 100644
--- a/nixos/modules/programs/npm.nix
+++ b/nixos/modules/programs/npm.nix
@@ -1,4 +1,4 @@
-{ config, lib, ... }:
+{ config, lib, pkgs, ... }:
 
 with lib;
 
@@ -39,6 +39,8 @@ in
     environment.etc."npmrc".text = cfg.npmrc;
 
     environment.variables.NPM_CONFIG_GLOBALCONFIG = "/etc/npmrc";
+
+    environment.systemPackages = [ pkgs.nodePackages.npm ];
   };
 
 }
diff --git a/nixos/modules/programs/nylas-mail.nix b/nixos/modules/programs/nylas-mail.nix
index 9a6cf755f2a2..08a6cd0a6049 100644
--- a/nixos/modules/programs/nylas-mail.nix
+++ b/nixos/modules/programs/nylas-mail.nix
@@ -4,7 +4,6 @@ with lib;
 
 let
   cfg = config.services.nylas-mail;
-  defaultUser = "nylas-mail";
 in {
   ###### interface
   options = {
diff --git a/nixos/modules/programs/screen.nix b/nixos/modules/programs/screen.nix
index f82338a69d25..c1daaa58f16f 100644
--- a/nixos/modules/programs/screen.nix
+++ b/nixos/modules/programs/screen.nix
@@ -1,4 +1,4 @@
-{ config, lib, ... }:
+{ config, lib, pkgs, ... }:
 
 let
   inherit (lib) mkOption mkIf types;
@@ -25,6 +25,8 @@ in
 
   config = mkIf (cfg.screenrc != "") {
     environment.etc."screenrc".text = cfg.screenrc;
+
+    environment.systemPackages = [ pkgs.screen ];
   };
 
 }
diff --git a/nixos/modules/programs/shell.nix b/nixos/modules/programs/shell.nix
index 3504a8a924b0..26ef18759921 100644
--- a/nixos/modules/programs/shell.nix
+++ b/nixos/modules/programs/shell.nix
@@ -4,12 +4,6 @@
 
 with lib;
 
-let
-
-  cfg = config.environment;
-
-in
-
 {
 
   config = {
@@ -23,39 +17,39 @@ in
     environment.shellInit =
       ''
         # Set up the per-user profile.
-        mkdir -m 0755 -p $NIX_USER_PROFILE_DIR
-        if test "$(stat --printf '%u' $NIX_USER_PROFILE_DIR)" != "$(id -u)"; then
-            echo "WARNING: bad ownership on $NIX_USER_PROFILE_DIR" >&2
+        mkdir -m 0755 -p "$NIX_USER_PROFILE_DIR"
+        if [ "$(stat --printf '%u' "$NIX_USER_PROFILE_DIR")" != "$(id -u)" ]; then
+            echo "WARNING: bad ownership on $NIX_USER_PROFILE_DIR, should be $(id -u)" >&2
         fi
 
-        if test -w $HOME; then
-          if ! test -L $HOME/.nix-profile; then
-              if test "$USER" != root; then
-                  ln -s $NIX_USER_PROFILE_DIR/profile $HOME/.nix-profile
+        if [ -w "$HOME" ]; then
+          if ! [ -L "$HOME/.nix-profile" ]; then
+              if [ "$USER" != root ]; then
+                  ln -s "$NIX_USER_PROFILE_DIR/profile" "$HOME/.nix-profile"
               else
                   # Root installs in the system-wide profile by default.
-                  ln -s /nix/var/nix/profiles/default $HOME/.nix-profile
+                  ln -s /nix/var/nix/profiles/default "$HOME/.nix-profile"
               fi
           fi
 
           # Subscribe the root user to the NixOS channel by default.
-          if [ "$USER" = root -a ! -e $HOME/.nix-channels ]; then
-              echo "${config.system.nixos.defaultChannel} nixos" > $HOME/.nix-channels
+          if [ "$USER" = root -a ! -e "$HOME/.nix-channels" ]; then
+              echo "${config.system.nixos.defaultChannel} nixos" > "$HOME/.nix-channels"
           fi
 
           # Create the per-user garbage collector roots directory.
-          NIX_USER_GCROOTS_DIR=/nix/var/nix/gcroots/per-user/$USER
-          mkdir -m 0755 -p $NIX_USER_GCROOTS_DIR
-          if test "$(stat --printf '%u' $NIX_USER_GCROOTS_DIR)" != "$(id -u)"; then
-              echo "WARNING: bad ownership on $NIX_USER_GCROOTS_DIR" >&2
+          NIX_USER_GCROOTS_DIR="/nix/var/nix/gcroots/per-user/$USER"
+          mkdir -m 0755 -p "$NIX_USER_GCROOTS_DIR"
+          if [ "$(stat --printf '%u' "$NIX_USER_GCROOTS_DIR")" != "$(id -u)" ]; then
+              echo "WARNING: bad ownership on $NIX_USER_GCROOTS_DIR, should be $(id -u)" >&2
           fi
 
           # Set up a default Nix expression from which to install stuff.
-          if [ ! -e $HOME/.nix-defexpr -o -L $HOME/.nix-defexpr ]; then
-              rm -f $HOME/.nix-defexpr
-              mkdir -p $HOME/.nix-defexpr
+          if [ ! -e "$HOME/.nix-defexpr" -o -L "$HOME/.nix-defexpr" ]; then
+              rm -f "$HOME/.nix-defexpr"
+              mkdir -p "$HOME/.nix-defexpr"
               if [ "$USER" != root ]; then
-                  ln -s /nix/var/nix/profiles/per-user/root/channels $HOME/.nix-defexpr/channels_root
+                  ln -s /nix/var/nix/profiles/per-user/root/channels "$HOME/.nix-defexpr/channels_root"
               fi
           fi
         fi
diff --git a/nixos/modules/programs/ssh.nix b/nixos/modules/programs/ssh.nix
index 7a48624fd2a2..db44f9040dde 100644
--- a/nixos/modules/programs/ssh.nix
+++ b/nixos/modules/programs/ssh.nix
@@ -7,7 +7,6 @@ with lib;
 let
 
   cfg  = config.programs.ssh;
-  cfgd = config.services.openssh;
 
   askPassword = cfg.askPassword;
 
diff --git a/nixos/modules/programs/sway.nix b/nixos/modules/programs/sway.nix
index d9503d6004ff..0eaaf6b85b99 100644
--- a/nixos/modules/programs/sway.nix
+++ b/nixos/modules/programs/sway.nix
@@ -73,7 +73,7 @@ in {
       permissions = "u+rx,g+rx";
     };
 
-    users.extraGroups.sway = {};
+    users.groups.sway = {};
     security.pam.services.swaylock = {};
 
     hardware.opengl.enable = mkDefault true;
diff --git a/nixos/modules/programs/thefuck.nix b/nixos/modules/programs/thefuck.nix
index eb913477cf05..f4ae52934760 100644
--- a/nixos/modules/programs/thefuck.nix
+++ b/nixos/modules/programs/thefuck.nix
@@ -31,8 +31,8 @@ in
       environment.systemPackages = with pkgs; [ thefuck ];
       environment.shellInit = initScript;
 
-      programs.zsh.shellInit = mkIf prg.zsh.enable initScript;
-      programs.fish.shellInit = mkIf prg.fish.enable ''
+      programs.zsh.interactiveShellInit = mkIf prg.zsh.enable initScript;
+      programs.fish.interactiveShellInit = mkIf prg.fish.enable ''
         ${pkgs.thefuck}/bin/thefuck --alias | source
       '';
     };
diff --git a/nixos/modules/programs/tmux.nix b/nixos/modules/programs/tmux.nix
index 4a60403a2827..3d5a37274ae2 100644
--- a/nixos/modules/programs/tmux.nix
+++ b/nixos/modules/programs/tmux.nix
@@ -1,7 +1,7 @@
 { config, pkgs, lib, ... }:
 
 let
-  inherit (lib) mkOption mkEnableOption mkIf mkMerge types;
+  inherit (lib) mkOption mkIf types;
 
   cfg = config.programs.tmux;
 
diff --git a/nixos/modules/programs/wireshark.nix b/nixos/modules/programs/wireshark.nix
index 710d223b6f59..819f15b98a05 100644
--- a/nixos/modules/programs/wireshark.nix
+++ b/nixos/modules/programs/wireshark.nix
@@ -29,7 +29,7 @@ in {
 
   config = mkIf cfg.enable {
     environment.systemPackages = [ wireshark ];
-    users.extraGroups.wireshark = {};
+    users.groups.wireshark = {};
 
     security.wrappers.dumpcap = {
       source = "${wireshark}/bin/dumpcap";
diff --git a/nixos/modules/programs/xonsh.nix b/nixos/modules/programs/xonsh.nix
index 49cc4906e038..f967ca82ac8c 100644
--- a/nixos/modules/programs/xonsh.nix
+++ b/nixos/modules/programs/xonsh.nix
@@ -6,8 +6,6 @@ with lib;
 
 let
 
-  cfge = config.environment;
-
   cfg = config.programs.xonsh;
 
 in
diff --git a/nixos/modules/programs/xss-lock.nix b/nixos/modules/programs/xss-lock.nix
new file mode 100644
index 000000000000..49d522c604f5
--- /dev/null
+++ b/nixos/modules/programs/xss-lock.nix
@@ -0,0 +1,26 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.programs.xss-lock;
+in
+{
+  options.programs.xss-lock = {
+    enable = mkEnableOption "xss-lock";
+    lockerCommand = mkOption {
+      example = "xlock";
+      type = types.string;
+      description = "Locker to be used with xsslock";
+    };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.user.services.xss-lock = {
+      description = "XSS Lock Daemon";
+      wantedBy = [ "graphical-session.target" ];
+      partOf = [ "graphical-session.target" ];
+      serviceConfig.ExecStart = "${pkgs.xss-lock}/bin/xss-lock ${cfg.lockerCommand}";
+    };
+  };
+}
diff --git a/nixos/modules/programs/zsh/zsh-autosuggestions.nix b/nixos/modules/programs/zsh/zsh-autosuggestions.nix
new file mode 100644
index 000000000000..416f4c9c6751
--- /dev/null
+++ b/nixos/modules/programs/zsh/zsh-autosuggestions.nix
@@ -0,0 +1,60 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.programs.zsh.autosuggestions;
+in
+{
+  options.programs.zsh.autosuggestions = {
+
+    enable = mkEnableOption "zsh-autosuggestions";
+
+    highlightStyle = mkOption {
+      type = types.str;
+      default = "fg=8"; # https://github.com/zsh-users/zsh-autosuggestions/tree/v0.4.3#suggestion-highlight-style
+      description = "Highlight style for suggestions ({fore,back}ground color)";
+      example = "fg=cyan";
+    };
+
+    strategy = mkOption {
+      type = types.enum [ "default" "match_prev_cmd" ];
+      default = "default";
+      description = ''
+        Set ZSH_AUTOSUGGEST_STRATEGY to choose the strategy for generating suggestions.
+        There are currently two to choose from:
+
+          * default: Chooses the most recent match.
+          * match_prev_cmd: Chooses the most recent match whose preceding history item matches
+            the most recently executed command (more info). Note that this strategy won't work as
+            expected with ZSH options that don't preserve the history order such as
+            HIST_IGNORE_ALL_DUPS or HIST_EXPIRE_DUPS_FIRST.
+      '';
+    };
+
+    extraConfig = mkOption {
+      type = with types; attrsOf str;
+      default = {};
+      description = "Attribute set with additional configuration values";
+      example = literalExample ''
+        {
+          "ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE" = "20";
+        }
+      '';
+    };
+
+  };
+
+  config = mkIf cfg.enable {
+
+    programs.zsh.interactiveShellInit = ''
+      source ${pkgs.zsh-autosuggestions}/share/zsh-autosuggestions/zsh-autosuggestions.zsh
+
+      export ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE="${cfg.highlightStyle}"
+      export ZSH_AUTOSUGGEST_STRATEGY="${cfg.strategy}"
+
+      ${concatStringsSep "\n" (mapAttrsToList (key: value: ''export ${key}="${value}"'') cfg.extraConfig)}
+    '';
+
+  };
+}
diff --git a/nixos/modules/programs/zsh/zsh.nix b/nixos/modules/programs/zsh/zsh.nix
index b88f54678ee1..42d4e1d4ada0 100644
--- a/nixos/modules/programs/zsh/zsh.nix
+++ b/nixos/modules/programs/zsh/zsh.nix
@@ -69,7 +69,9 @@ in
 
       promptInit = mkOption {
         default = ''
-          autoload -U promptinit && promptinit && prompt walters
+          if [ "$TERM" != dumb ]; then
+            autoload -U promptinit && promptinit && prompt walters
+          fi
         '';
         description = ''
           Shell script code used to initialise the zsh prompt.
@@ -85,13 +87,6 @@ in
         type = types.bool;
       };
 
-      enableAutosuggestions = mkOption {
-        default = false;
-        description = ''
-          Enable zsh-autosuggestions
-        '';
-        type = types.bool;
-      };
     };
 
   };
@@ -108,6 +103,8 @@ in
         if [ -n "$__ETC_ZSHENV_SOURCED" ]; then return; fi
         export __ETC_ZSHENV_SOURCED=1
 
+        ${config.system.build.setEnvironment.text}
+
         ${cfge.shellInit}
 
         ${cfg.shellInit}
@@ -127,8 +124,6 @@ in
         if [ -n "$__ETC_ZPROFILE_SOURCED" ]; then return; fi
         __ETC_ZPROFILE_SOURCED=1
 
-        ${config.system.build.setEnvironment.text}
-
         ${cfge.loginShellInit}
 
         ${cfg.loginShellInit}
@@ -166,10 +161,6 @@ in
 
         ${optionalString cfg.enableCompletion "autoload -U compinit && compinit"}
 
-        ${optionalString (cfg.enableAutosuggestions)
-          "source ${pkgs.zsh-autosuggestions}/share/zsh-autosuggestions/zsh-autosuggestions.zsh"
-        }
-
         ${cfge.interactiveShellInit}
 
         ${cfg.interactiveShellInit}
diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix
index 8820a6da8c0b..5242444a60b8 100644
--- a/nixos/modules/rename.nix
+++ b/nixos/modules/rename.nix
@@ -31,9 +31,21 @@ with lib;
     (mkRenamedOptionModule [ "services" "graphite" "web" "host" ] [ "services" "graphite" "web" "listenAddress" ])
     (mkRenamedOptionModule [ "services" "i2pd" "extIp" ] [ "services" "i2pd" "address" ])
     (mkRenamedOptionModule [ "services" "kibana" "host" ] [ "services" "kibana" "listenAddress" ])
+    (mkRenamedOptionModule [ "services" "kubernetes" "apiserver" "admissionControl" ] [ "services" "kubernetes" "apiserver" "enableAdmissionPlugins" ])
+    (mkRenamedOptionModule [ "services" "kubernetes" "apiserver" "address" ] ["services" "kubernetes" "apiserver" "bindAddress"])
+    (mkRemovedOptionModule [ "services" "kubernetes" "apiserver" "publicAddress" ] "")
+    (mkRenamedOptionModule [ "services" "kubernetes" "addons" "dashboard" "enableRBAC" ] [ "services" "kubernetes" "addons" "dashboard" "rbac" "enable" ])
     (mkRenamedOptionModule [ "services" "logstash" "address" ] [ "services" "logstash" "listenAddress" ])
     (mkRenamedOptionModule [ "services" "mpd" "network" "host" ] [ "services" "mpd" "network" "listenAddress" ])
-    (mkRenamedOptionModule [ "services" "neo4j" "host" ] [ "services" "neo4j" "listenAddress" ])
+    (mkRenamedOptionModule [ "services" "neo4j" "host" ] [ "services" "neo4j" "defaultListenAddress" ])
+    (mkRenamedOptionModule [ "services" "neo4j" "listenAddress" ] [ "services" "neo4j" "defaultListenAddress" ])
+    (mkRenamedOptionModule [ "services" "neo4j" "enableBolt" ] [ "services" "neo4j" "bolt" "enable" ])
+    (mkRenamedOptionModule [ "services" "neo4j" "enableHttps" ] [ "services" "neo4j" "https" "enable" ])
+    (mkRenamedOptionModule [ "services" "neo4j" "certDir" ] [ "services" "neo4j" "directories" "certificates" ])
+    (mkRenamedOptionModule [ "services" "neo4j" "dataDir" ] [ "services" "neo4j" "directories" "home" ])
+    (mkRemovedOptionModule [ "services" "neo4j" "port" ] "Use services.neo4j.http.listenAddress instead.")
+    (mkRemovedOptionModule [ "services" "neo4j" "boltPort" ] "Use services.neo4j.bolt.listenAddress instead.")
+    (mkRemovedOptionModule [ "services" "neo4j" "httpsPort" ] "Use services.neo4j.https.listenAddress instead.")
     (mkRenamedOptionModule [ "services" "shout" "host" ] [ "services" "shout" "listenAddress" ])
     (mkRenamedOptionModule [ "services" "sslh" "host" ] [ "services" "sslh" "listenAddress" ])
     (mkRenamedOptionModule [ "services" "statsd" "host" ] [ "services" "statsd" "listenAddress" ])
@@ -196,6 +208,12 @@ with lib;
     (mkRenamedOptionModule [ "fonts" "fontconfig" "ultimate" "forceAutohint" ] [ "fonts" "fontconfig" "forceAutohint" ])
     (mkRenamedOptionModule [ "fonts" "fontconfig" "ultimate" "renderMonoTTFAsBitmap" ] [ "fonts" "fontconfig" "renderMonoTTFAsBitmap" ])
 
+    # postgresqlBackup
+    (mkRemovedOptionModule [ "services" "postgresqlBackup" "period" ] ''
+       A systemd timer is now used instead of cron.
+       The starting time can be configured via <literal>services.postgresqlBackup.startAt</literal>.
+    '')
+
     # Profile splitting
     (mkRenamedOptionModule [ "virtualization" "growPartition" ] [ "boot" "growPartition" ])
 
@@ -232,6 +250,7 @@ with lib;
     (mkRemovedOptionModule [ "fonts" "fontconfig" "hinting" "style" ] "")
     (mkRemovedOptionModule [ "services" "xserver" "displayManager" "sddm" "themes" ]
       "Set the option `services.xserver.displayManager.sddm.package' instead.")
+    (mkRemovedOptionModule [ "services" "xserver" "desktopManager" "xfce" "screenLock" ] "")
     (mkRemovedOptionModule [ "fonts" "fontconfig" "forceAutohint" ] "")
     (mkRemovedOptionModule [ "fonts" "fontconfig" "renderMonoTTFAsBitmap" ] "")
     (mkRemovedOptionModule [ "virtualisation" "xen" "qemu" ] "You don't need this option anymore, it will work without it.")
@@ -246,6 +265,8 @@ with lib;
     (mkRenamedOptionModule [ "programs" "zsh" "oh-my-zsh" "custom" ] [ "programs" "zsh" "ohMyZsh" "custom" ])
     (mkRenamedOptionModule [ "programs" "zsh" "oh-my-zsh" "plugins" ] [ "programs" "zsh" "ohMyZsh" "plugins" ])
 
+    (mkRenamedOptionModule [ "programs" "zsh" "enableAutosuggestions" ] [ "programs" "zsh" "autosuggestions" "enable" ])
+
     # Xen
     (mkRenamedOptionModule [ "virtualisation" "xen" "qemu-package" ] [ "virtualisation" "xen" "package-qemu" ])
 
diff --git a/nixos/modules/security/acme.nix b/nixos/modules/security/acme.nix
index 9e5d636241e9..946da92d80e7 100644
--- a/nixos/modules/security/acme.nix
+++ b/nixos/modules/security/acme.nix
@@ -209,7 +209,6 @@ in
           servicesLists = mapAttrsToList certToServices cfg.certs;
           certToServices = cert: data:
               let
-                domain = if data.domain != null then data.domain else cert;
                 cpath = lpath + optionalString (data.activationDelay != null) ".staging";
                 lpath = "${cfg.directory}/${cert}";
                 rights = if data.allowKeysForGroup then "750" else "700";
diff --git a/nixos/modules/security/pam_mount.nix b/nixos/modules/security/pam_mount.nix
index a5299728348d..8b131c54a2a5 100644
--- a/nixos/modules/security/pam_mount.nix
+++ b/nixos/modules/security/pam_mount.nix
@@ -40,7 +40,7 @@ in
       target = "security/pam_mount.conf.xml";
       source =
         let
-          extraUserVolumes = filterAttrs (n: u: u.cryptHomeLuks != null) config.users.extraUsers;
+          extraUserVolumes = filterAttrs (n: u: u.cryptHomeLuks != null) config.users.users;
           userVolumeEntry = user: "<volume user=\"${user.name}\" path=\"${user.cryptHomeLuks}\" mountpoint=\"${user.home}\" />\n";
         in
          pkgs.writeText "pam_mount.conf.xml" ''
diff --git a/nixos/modules/security/pam_usb.nix b/nixos/modules/security/pam_usb.nix
index 9bc73bf0b85c..c695ba075ca9 100644
--- a/nixos/modules/security/pam_usb.nix
+++ b/nixos/modules/security/pam_usb.nix
@@ -4,8 +4,6 @@ with lib;
 
 let
 
-  inherit (pkgs) pam_usb;
-
   cfg = config.security.pam.usb;
 
   anyUsbAuth = any (attrByPath ["usbAuth"] false) (attrValues config.security.pam.services);
diff --git a/nixos/modules/security/polkit.nix b/nixos/modules/security/polkit.nix
index 7e59408a5b0b..04685f2c9ea1 100644
--- a/nixos/modules/security/polkit.nix
+++ b/nixos/modules/security/polkit.nix
@@ -94,7 +94,7 @@ in
         rm -rf /var/lib/{polkit-1,PolicyKit}
       '';
 
-    users.extraUsers.polkituser = {
+    users.users.polkituser = {
       description = "PolKit daemon";
       uid = config.ids.uids.polkituser;
     };
diff --git a/nixos/modules/security/rtkit.nix b/nixos/modules/security/rtkit.nix
index afe93f24273d..f6dda21c6006 100644
--- a/nixos/modules/security/rtkit.nix
+++ b/nixos/modules/security/rtkit.nix
@@ -34,7 +34,7 @@ with lib;
 
     services.dbus.packages = [ pkgs.rtkit ];
 
-    users.extraUsers = singleton
+    users.users = singleton
       { name = "rtkit";
         uid = config.ids.uids.rtkit;
         description = "RealtimeKit daemon";
diff --git a/nixos/modules/security/sudo.nix b/nixos/modules/security/sudo.nix
index 24283e1d6165..361a7e869602 100644
--- a/nixos/modules/security/sudo.nix
+++ b/nixos/modules/security/sudo.nix
@@ -66,6 +66,9 @@ in
     security.sudo.extraRules = mkOption {
       description = ''
         Define specific rules to be in the <filename>sudoers</filename> file.
+        More specific rules should come after more general ones in order to
+        yield the expected behavior. You can use mkBefore/mkAfter to ensure
+        this is the case when configuration options are merged.
       '';
       default = [];
       example = [
diff --git a/nixos/modules/services/admin/oxidized.nix b/nixos/modules/services/admin/oxidized.nix
new file mode 100644
index 000000000000..70f7dd9e3647
--- /dev/null
+++ b/nixos/modules/services/admin/oxidized.nix
@@ -0,0 +1,116 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.services.oxidized;
+in
+{
+  options.services.oxidized = {
+    enable = mkEnableOption "the oxidized configuation backup service.";
+
+    user = mkOption {
+      type = types.str;
+      default = "oxidized";
+      description = ''
+        User under which the oxidized service runs.
+      '';
+    };
+
+    group = mkOption {
+      type = types.str;
+      default = "oxidized";
+      description = ''
+        Group under which the oxidized service runs.
+      '';
+    };
+
+    dataDir = mkOption {
+      type = types.path;
+      default = "/var/lib/oxidized";
+      description = "State directory for the oxidized service.";
+    };
+
+    configFile = mkOption {
+      type = types.path;
+      example = literalExample ''
+        pkgs.writeText "oxidized-config.yml" '''
+          ---
+          debug: true
+          use_syslog: true
+          input:
+            default: ssh
+            ssh:
+              secure: true
+          interval: 3600
+          model_map:
+            dell: powerconnect
+            hp: procurve
+          source:
+            default: csv
+            csv:
+              delimiter: !ruby/regexp /:/
+              file: "/var/lib/oxidized/.config/oxidized/router.db"
+              map:
+                name: 0
+                model: 1
+                username: 2
+                password: 3
+          pid: "/var/lib/oxidized/.config/oxidized/pid"
+          rest: 127.0.0.1:8888
+          retries: 3
+          # ... additional config
+        ''';
+      '';
+      description = ''
+        Path to the oxidized configuration file.
+      '';
+    };
+
+    routerDB = mkOption {
+      type = types.path;
+      example = literalExample ''
+        pkgs.writeText "oxidized-router.db" '''
+          hostname-sw1:powerconnect:username1:password2
+          hostname-sw2:procurve:username2:password2
+          # ... additional hosts
+        '''
+      '';
+      description = ''
+        Path to the file/database which contains the targets for oxidized.
+      '';
+    };
+  };
+
+  config = mkIf cfg.enable {
+    users.groups.${cfg.group} = { };
+    users.users.${cfg.user} = {
+      description = "Oxidized service user";
+      group = cfg.group;
+      home = cfg.dataDir;
+      createHome = true;
+    };
+
+    systemd.services.oxidized = {
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+
+      preStart = ''
+        mkdir -p ${cfg.dataDir}/.config/oxidized
+        cp -v ${cfg.routerDB} ${cfg.dataDir}/.config/oxidized/router.db
+        cp -v ${cfg.configFile} ${cfg.dataDir}/.config/oxidized/config
+      '';
+
+      serviceConfig = {
+        ExecStart = "${pkgs.oxidized}/bin/oxidized";
+        User = cfg.user;
+        Group = cfg.group;
+        UMask = "0077";
+        NoNewPrivileges = true;
+        Restart  = "always";
+        WorkingDirectory = cfg.dataDir;
+        KillSignal = "SIGKILL";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/amqp/activemq/default.nix b/nixos/modules/services/amqp/activemq/default.nix
index 261f97617664..27bfd91cd2d5 100644
--- a/nixos/modules/services/amqp/activemq/default.nix
+++ b/nixos/modules/services/amqp/activemq/default.nix
@@ -93,13 +93,13 @@ in {
   };
 
   config = mkIf cfg.enable {
-    users.extraUsers.activemq = {
+    users.users.activemq = {
       description = "ActiveMQ server user";
       group = "activemq";
       uid = config.ids.uids.activemq;
     };
 
-    users.extraGroups.activemq.gid = config.ids.gids.activemq;
+    users.groups.activemq.gid = config.ids.gids.activemq;
 
     systemd.services.activemq_init = {
       wantedBy = [ "activemq.service" ];
diff --git a/nixos/modules/services/amqp/rabbitmq.nix b/nixos/modules/services/amqp/rabbitmq.nix
index f536d56d7c63..bb6fc0a104df 100644
--- a/nixos/modules/services/amqp/rabbitmq.nix
+++ b/nixos/modules/services/amqp/rabbitmq.nix
@@ -83,7 +83,7 @@ in {
 
     environment.systemPackages = [ pkgs.rabbitmq_server ];
 
-    users.extraUsers.rabbitmq = {
+    users.users.rabbitmq = {
       description = "RabbitMQ server user";
       home = "${cfg.dataDir}";
       createHome = true;
@@ -91,7 +91,7 @@ in {
       uid = config.ids.uids.rabbitmq;
     };
 
-    users.extraGroups.rabbitmq.gid = config.ids.gids.rabbitmq;
+    users.groups.rabbitmq.gid = config.ids.gids.rabbitmq;
 
     systemd.services.rabbitmq = {
       description = "RabbitMQ Server";
diff --git a/nixos/modules/services/audio/liquidsoap.nix b/nixos/modules/services/audio/liquidsoap.nix
index 1c19ed36bdc7..66f84ef20762 100644
--- a/nixos/modules/services/audio/liquidsoap.nix
+++ b/nixos/modules/services/audio/liquidsoap.nix
@@ -57,7 +57,7 @@ in
 
   config = mkIf (builtins.length streams != 0) {
 
-    users.extraUsers.liquidsoap = {
+    users.users.liquidsoap = {
       uid = config.ids.uids.liquidsoap;
       group = "liquidsoap";
       extraGroups = [ "audio" ];
@@ -66,7 +66,7 @@ in
       createHome = true;
     };
 
-    users.extraGroups.liquidsoap.gid = config.ids.gids.liquidsoap;
+    users.groups.liquidsoap.gid = config.ids.gids.liquidsoap;
 
     systemd.services = builtins.listToAttrs ( map streamService streams );
   };
diff --git a/nixos/modules/services/audio/mopidy.nix b/nixos/modules/services/audio/mopidy.nix
index 52613d450b51..e2f4ec39f94c 100644
--- a/nixos/modules/services/audio/mopidy.nix
+++ b/nixos/modules/services/audio/mopidy.nix
@@ -93,7 +93,7 @@ in {
       };
     };
 
-    users.extraUsers.mopidy = {
+    users.users.mopidy = {
       inherit uid;
       group = "mopidy";
       extraGroups = [ "audio" ];
@@ -101,7 +101,7 @@ in {
       home = "${cfg.dataDir}";
     };
 
-    users.extraGroups.mopidy.gid = gid;
+    users.groups.mopidy.gid = gid;
 
   };
 
diff --git a/nixos/modules/services/audio/mpd.nix b/nixos/modules/services/audio/mpd.nix
index 5f379b392ea8..3add6556d0df 100644
--- a/nixos/modules/services/audio/mpd.nix
+++ b/nixos/modules/services/audio/mpd.nix
@@ -13,7 +13,9 @@ let
   mpdConf = pkgs.writeText "mpd.conf" ''
     music_directory     "${cfg.musicDirectory}"
     playlist_directory  "${cfg.playlistDirectory}"
-    db_file             "${cfg.dbFile}"
+    ${lib.optionalString (cfg.dbFile != null) ''
+      db_file             "${cfg.dbFile}"
+    ''}
     state_file          "${cfg.dataDir}/state"
     sticker_file        "${cfg.dataDir}/sticker.sql"
     log_file            "syslog"
@@ -126,11 +128,12 @@ in {
       };
 
       dbFile = mkOption {
-        type = types.str;
+        type = types.nullOr types.str;
         default = "${cfg.dataDir}/tag_cache";
         defaultText = ''''${dataDir}/tag_cache'';
         description = ''
-          The path to MPD's database.
+          The path to MPD's database. If set to <literal>null</literal> the
+          parameter is omitted from the configuration.
         '';
       };
     };
@@ -181,7 +184,7 @@ in {
       };
     };
 
-    users.extraUsers = optionalAttrs (cfg.user == name) (singleton {
+    users.users = optionalAttrs (cfg.user == name) (singleton {
       inherit uid;
       inherit name;
       group = cfg.group;
@@ -190,7 +193,7 @@ in {
       home = "${cfg.dataDir}";
     });
 
-    users.extraGroups = optionalAttrs (cfg.group == name) (singleton {
+    users.groups = optionalAttrs (cfg.group == name) (singleton {
       inherit name;
       gid = gid;
     });
diff --git a/nixos/modules/services/audio/slimserver.nix b/nixos/modules/services/audio/slimserver.nix
index 7d661dd60408..640403d2c97d 100644
--- a/nixos/modules/services/audio/slimserver.nix
+++ b/nixos/modules/services/audio/slimserver.nix
@@ -51,7 +51,8 @@ in {
       serviceConfig = {
         User = "slimserver";
         PermissionsStartOnly = true;
-        ExecStart = "${cfg.package}/slimserver.pl --logdir ${cfg.dataDir}/logs --prefsdir ${cfg.dataDir}/prefs --cachedir ${cfg.dataDir}/cache";
+        # Issue 40589: Disable broken image/video support (audio still works!)
+        ExecStart = "${cfg.package}/slimserver.pl --logdir ${cfg.dataDir}/logs --prefsdir ${cfg.dataDir}/prefs --cachedir ${cfg.dataDir}/cache --noimage --novideo";
       };
     };
 
diff --git a/nixos/modules/services/audio/squeezelite.nix b/nixos/modules/services/audio/squeezelite.nix
index f1a60be992d8..57ae38559939 100644
--- a/nixos/modules/services/audio/squeezelite.nix
+++ b/nixos/modules/services/audio/squeezelite.nix
@@ -54,7 +54,7 @@ in {
       };
     };
 
-    users.extraUsers.squeezelite= {
+    users.users.squeezelite= {
       inherit uid;
       group = "nogroup";
       extraGroups = [ "audio" ];
diff --git a/nixos/modules/services/backup/bacula.nix b/nixos/modules/services/backup/bacula.nix
index 340b0cf07234..be02ba567956 100644
--- a/nixos/modules/services/backup/bacula.nix
+++ b/nixos/modules/services/backup/bacula.nix
@@ -97,17 +97,6 @@ let
     ${dir_cfg.extraConfig}
     '';
 
-  # TODO: by default use this config
-  bconsole_conf = pkgs.writeText "bconsole.conf"
-    ''
-    Director {
-      Name = ${dir_cfg.name};
-      Address = "localhost";
-      DirPort = ${toString dir_cfg.port};
-      Password = "${dir_cfg.password}";
-    }
-    '';
-
   directorOptions = {name, config, ...}:
   {
     options = {
@@ -397,7 +386,7 @@ in {
 
     environment.systemPackages = [ pkgs.bacula ];
 
-    users.extraUsers.bacula = {
+    users.users.bacula = {
       group = "bacula";
       uid = config.ids.uids.bacula;
       home = "${libDir}";
@@ -406,6 +395,6 @@ in {
       shell = "${pkgs.bash}/bin/bash";
     };
 
-    users.extraGroups.bacula.gid = config.ids.gids.bacula;
+    users.groups.bacula.gid = config.ids.gids.bacula;
   };
 }
diff --git a/nixos/modules/services/backup/borgbackup.nix b/nixos/modules/services/backup/borgbackup.nix
index 1b730e0c2b76..0c3fc9af6f88 100644
--- a/nixos/modules/services/backup/borgbackup.nix
+++ b/nixos/modules/services/backup/borgbackup.nix
@@ -35,25 +35,26 @@ let
     ${cfg.preHook}
   '' + optionalString cfg.doInit ''
     # Run borg init if the repo doesn't exist yet
-    if ! borg list > /dev/null; then
-      borg init \
+    if ! borg list $extraArgs > /dev/null; then
+      borg init $extraArgs \
         --encryption ${cfg.encryption.mode} \
         $extraInitArgs
       ${cfg.postInit}
     fi
   '' + ''
-    borg create \
+    borg create $extraArgs \
       --compression ${cfg.compression} \
       --exclude-from ${mkExcludeFile cfg} \
       $extraCreateArgs \
       "::$archiveName$archiveSuffix" \
       ${escapeShellArgs cfg.paths}
   '' + optionalString cfg.appendFailedSuffix ''
-    borg rename "::$archiveName$archiveSuffix" "$archiveName"
+    borg rename $extraArgs \
+      "::$archiveName$archiveSuffix" "$archiveName"
   '' + ''
     ${cfg.postCreate}
   '' + optionalString (cfg.prune.keep != { }) ''
-    borg prune \
+    borg prune $extraArgs \
       ${mkKeepArgs cfg} \
       --prefix ${escapeShellArg cfg.prune.prefix} \
       $extraPruneArgs
@@ -85,13 +86,14 @@ let
         ProtectSystem = "strict";
         ReadWritePaths =
           [ "${userHome}/.config/borg" "${userHome}/.cache/borg" ]
+          ++ cfg.readWritePaths
           # Borg needs write access to repo if it is not remote
           ++ optional (isLocalPath cfg.repo) cfg.repo;
-        PrivateTmp = true;
+        PrivateTmp = cfg.privateTmp;
       };
       environment = {
         BORG_REPO = cfg.repo;
-        inherit (cfg) extraInitArgs extraCreateArgs extraPruneArgs;
+        inherit (cfg) extraArgs extraInitArgs extraCreateArgs extraPruneArgs;
       } // (mkPassEnv cfg) // cfg.environment;
       inherit (cfg) startAt;
     };
@@ -318,6 +320,30 @@ in {
             ];
           };
 
+          readWritePaths = mkOption {
+            type = with types; listOf path;
+            description = ''
+              By default, borg cannot write anywhere on the system but
+              <literal>$HOME/.config/borg</literal> and <literal>$HOME/.cache/borg</literal>.
+              If, for example, your preHook script needs to dump files
+              somewhere, put those directories here.
+            '';
+            default = [ ];
+            example = [
+              "/var/backup/mysqldump"
+            ];
+          };
+
+          privateTmp = mkOption {
+            type = types.bool;
+            description = ''
+              Set the <literal>PrivateTmp</literal> option for
+              the systemd-service. Set to false if you need sockets
+              or other files from global /tmp.
+            '';
+            default = true;
+          };
+
           doInit = mkOption {
             type = types.bool;
             description = ''
@@ -430,6 +456,16 @@ in {
             default = "";
           };
 
+          extraArgs = mkOption {
+            type = types.str;
+            description = ''
+              Additional arguments for all <command>borg</command> calls the
+              service has. Handle with care.
+            '';
+            default = "";
+            example = "--remote-path=/path/to/borg";
+          };
+
           extraInitArgs = mkOption {
             type = types.str;
             description = ''
diff --git a/nixos/modules/services/backup/crashplan-small-business.nix b/nixos/modules/services/backup/crashplan-small-business.nix
index 9497d8c18bb7..790dafefe66f 100644
--- a/nixos/modules/services/backup/crashplan-small-business.nix
+++ b/nixos/modules/services/backup/crashplan-small-business.nix
@@ -3,7 +3,6 @@
 let
   cfg = config.services.crashplansb;
   crashplansb = pkgs.crashplansb.override { maxRam = cfg.maxRam; };
-  varDir = "/var/lib/crashplan";
 in
 
 with lib;
diff --git a/nixos/modules/services/backup/crashplan.nix b/nixos/modules/services/backup/crashplan.nix
index d0af2e416b63..c540cc6e2aee 100644
--- a/nixos/modules/services/backup/crashplan.nix
+++ b/nixos/modules/services/backup/crashplan.nix
@@ -3,7 +3,6 @@
 let
   cfg = config.services.crashplan;
   crashplan = pkgs.crashplan;
-  varDir = "/var/lib/crashplan";
 in
 
 with lib;
diff --git a/nixos/modules/services/backup/duplicati.nix b/nixos/modules/services/backup/duplicati.nix
index 9772ca4d20a7..80287f30b813 100644
--- a/nixos/modules/services/backup/duplicati.nix
+++ b/nixos/modules/services/backup/duplicati.nix
@@ -9,6 +9,23 @@ in
   options = {
     services.duplicati = {
       enable = mkEnableOption "Duplicati";
+
+      port = mkOption {
+        default = 8200;
+        type = types.int;
+        description = ''
+          Port serving the web interface
+        '';
+      };
+
+      interface = mkOption {
+        default = "lo";
+        type = types.str;
+        description = ''
+          Listening interface for the web UI
+          Set it to "any" to listen on all available interfaces
+        '';
+      };
     };
   };
 
@@ -22,18 +39,18 @@ in
       serviceConfig = {
         User = "duplicati";
         Group = "duplicati";
-        ExecStart = "${pkgs.duplicati}/bin/duplicati-server --webservice-interface=any --webservice-port=8200 --server-datafolder=/var/lib/duplicati";
+        ExecStart = "${pkgs.duplicati}/bin/duplicati-server --webservice-interface=${cfg.interface} --webservice-port=${toString cfg.port} --server-datafolder=/var/lib/duplicati";
         Restart = "on-failure";
       };
     };
 
-    users.extraUsers.duplicati = {
+    users.users.duplicati = {
       uid = config.ids.uids.duplicati;
       home = "/var/lib/duplicati";
       createHome = true;
       group = "duplicati";
     };
-    users.extraGroups.duplicati.gid = config.ids.gids.duplicati;
+    users.groups.duplicati.gid = config.ids.gids.duplicati;
 
   };
 }
diff --git a/nixos/modules/services/backup/mysql-backup.nix b/nixos/modules/services/backup/mysql-backup.nix
index 3f533fa457dc..f0c273ffebf1 100644
--- a/nixos/modules/services/backup/mysql-backup.nix
+++ b/nixos/modules/services/backup/mysql-backup.nix
@@ -84,7 +84,7 @@ in
   };
 
   config = mkIf cfg.enable {
-    users.extraUsers = optionalAttrs (cfg.user == defaultUser) (singleton
+    users.users = optionalAttrs (cfg.user == defaultUser) (singleton
       { name = defaultUser;
         isSystemUser = true;
         createHome = false;
diff --git a/nixos/modules/services/backup/postgresql-backup.nix b/nixos/modules/services/backup/postgresql-backup.nix
index 4a5ebebc682e..2ec78ce6f2cf 100644
--- a/nixos/modules/services/backup/postgresql-backup.nix
+++ b/nixos/modules/services/backup/postgresql-backup.nix
@@ -3,18 +3,41 @@
 with lib;
 
 let
-  inherit (pkgs) gzip;
 
-  location = config.services.postgresqlBackup.location;
+  cfg = config.services.postgresqlBackup;
 
-  postgresqlBackupCron = db:
-    ''
-      ${config.services.postgresqlBackup.period} root ${config.services.postgresql.package}/bin/pg_dump ${db} | ${gzip}/bin/gzip -c > ${location}/${db}.gz
-    '';
+  postgresqlBackupService = db :
+    {
+      enable = true;
 
-in
+      description = "Backup of database ${db}";
 
-{
+      requires = [ "postgresql.service" ];
+
+      preStart = ''
+        mkdir -m 0700 -p ${cfg.location}
+        chown postgres ${cfg.location}
+      '';
+
+      script = ''
+        if [ -e ${cfg.location}/${db}.sql.gz ]; then
+          ${pkgs.coreutils}/bin/mv ${cfg.location}/${db}.sql.gz ${cfg.location}/${db}.prev.sql.gz
+        fi
+
+        ${config.services.postgresql.package}/bin/pg_dump ${cfg.pgdumpOptions} ${db} | \
+          ${pkgs.gzip}/bin/gzip -c > ${cfg.location}/${db}.sql.gz
+      '';
+
+      serviceConfig = {
+        Type = "oneshot";
+        PermissionsStartOnly = "true";
+        User = "postgres";
+      };
+
+      startAt = cfg.startAt;
+    };
+
+in {
 
   options = {
 
@@ -27,10 +50,10 @@ in
         '';
       };
 
-      period = mkOption {
-        default = "15 01 * * *";
+      startAt = mkOption {
+        default = "*-*-* 01:15:00";
         description = ''
-          This option defines (in the format used by cron) when the
+          This option defines (see <literal>systemd.time</literal> for format) when the
           databases should be dumped.
           The default is to update at 01:15 (at night) every day.
         '';
@@ -49,18 +72,23 @@ in
           Location to put the gzipped PostgreSQL database dumps.
         '';
       };
+
+      pgdumpOptions = mkOption {
+        type = types.string;
+        default = "-Cbo";
+        description = ''
+          Command line options for pg_dump.
+        '';
+      };
     };
 
   };
 
   config = mkIf config.services.postgresqlBackup.enable {
-    services.cron.systemCronJobs = map postgresqlBackupCron config.services.postgresqlBackup.databases;
 
-    system.activationScripts.postgresqlBackup = stringAfter [ "stdio" "users" ]
-      ''
-        mkdir -m 0700 -p ${config.services.postgresqlBackup.location}
-        chown root ${config.services.postgresqlBackup.location}
-      '';
+    systemd.services = listToAttrs (map (db : {
+          name = "postgresqlBackup-${db}";
+          value = postgresqlBackupService db; } ) cfg.databases);
   };
 
 }
diff --git a/nixos/modules/services/backup/restic-rest-server.nix b/nixos/modules/services/backup/restic-rest-server.nix
index d4b47a099410..d1b775f150dc 100644
--- a/nixos/modules/services/backup/restic-rest-server.nix
+++ b/nixos/modules/services/backup/restic-rest-server.nix
@@ -95,13 +95,13 @@ in
       };
     };
 
-    users.extraUsers.restic = {
+    users.users.restic = {
       group = "restic";
       home = cfg.dataDir;
       createHome = true;
       uid = config.ids.uids.restic;
     };
 
-    users.extraGroups.restic.gid = config.ids.uids.restic;
+    users.groups.restic.gid = config.ids.uids.restic;
   };
 }
diff --git a/nixos/modules/services/backup/restic.nix b/nixos/modules/services/backup/restic.nix
index 21d82469c605..409c05221d03 100644
--- a/nixos/modules/services/backup/restic.nix
+++ b/nixos/modules/services/backup/restic.nix
@@ -14,7 +14,15 @@ with lib;
             Read the repository password from a file.
           '';
           example = "/etc/nixos/restic-password";
+        };
 
+        s3CredentialsFile = mkOption {
+          type = with types; nullOr str;
+          description = ''
+            file containing the AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY
+            for an S3-hosted repository, in the format of an EnvironmentFile
+            as described by systemd.exec(5)
+          '';
         };
 
         repository = mkOption {
@@ -119,7 +127,6 @@ with lib;
       mapAttrs' (name: backup:
         let
           extraOptions = concatMapStrings (arg: " -o ${arg}") backup.extraOptions;
-          connectTo = elemAt (splitString ":" backup.repository) 1;
           resticCmd = "${pkgs.restic}/bin/restic${extraOptions}";
         in nameValuePair "restic-backups-${name}" ({
           environment = {
@@ -134,6 +141,8 @@ with lib;
             Type = "oneshot";
             ExecStart = "${resticCmd} backup ${concatStringsSep " " backup.extraBackupArgs} ${concatStringsSep " " backup.paths}";
             User = backup.user;
+          } // optionalAttrs (backup.s3CredentialsFile != null) {
+            EnvironmentFile = backup.s3CredentialsFile;
           };
         } // optionalAttrs backup.initialize {
           preStart = ''
diff --git a/nixos/modules/services/backup/znapzend.nix b/nixos/modules/services/backup/znapzend.nix
index 3d133f82d204..fc8a424190f7 100644
--- a/nixos/modules/services/backup/znapzend.nix
+++ b/nixos/modules/services/backup/znapzend.nix
@@ -5,13 +5,6 @@ with types;
 
 let
 
-  # Converts a plan like
-  #   { "1d" = "1h"; "1w" = "1d"; }
-  # into
-  #   "1d=>1h,1w=>1d"
-  attrToPlan = attrs: concatStringsSep "," (builtins.attrValues (
-    mapAttrs (n: v: "${n}=>${v}") attrs));
-
   planDescription = ''
       The znapzend backup plan to use for the source.
     </para>
diff --git a/nixos/modules/services/cluster/hadoop/conf.nix b/nixos/modules/services/cluster/hadoop/conf.nix
new file mode 100644
index 000000000000..38db10406b9a
--- /dev/null
+++ b/nixos/modules/services/cluster/hadoop/conf.nix
@@ -0,0 +1,31 @@
+{ hadoop, pkgs }:
+let
+  propertyXml = name: value: ''
+    <property>
+      <name>${name}</name>
+      <value>${builtins.toString value}</value>
+    </property>
+  '';
+  siteXml = fileName: properties: pkgs.writeTextDir fileName ''
+    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
+    <!-- generated by NixOS -->
+    <configuration>
+      ${builtins.concatStringsSep "\n" (pkgs.lib.mapAttrsToList propertyXml properties)}
+    </configuration>
+  '';
+  userFunctions = ''
+    hadoop_verify_logdir() {
+      echo Skipping verification of log directory
+    }
+  '';
+in
+pkgs.buildEnv {
+  name = "hadoop-conf";
+  paths = [
+    (siteXml "core-site.xml" hadoop.coreSite)
+    (siteXml "hdfs-site.xml" hadoop.hdfsSite)
+    (siteXml "mapred-site.xml" hadoop.mapredSite)
+    (siteXml "yarn-site.xml" hadoop.yarnSite)
+    (pkgs.writeTextDir "hadoop-user-functions.sh" userFunctions)
+  ];
+}
diff --git a/nixos/modules/services/cluster/hadoop/default.nix b/nixos/modules/services/cluster/hadoop/default.nix
new file mode 100644
index 000000000000..f0f5a6ecbfc5
--- /dev/null
+++ b/nixos/modules/services/cluster/hadoop/default.nix
@@ -0,0 +1,60 @@
+{ config, lib, pkgs, ...}:
+
+with lib;
+{
+  imports = [ ./yarn.nix ./hdfs.nix ];
+
+  options.services.hadoop = {
+    coreSite = mkOption {
+      default = {};
+      example = {
+        "fs.defaultFS" = "hdfs://localhost";
+      };
+      description = "Hadoop core-site.xml definition";
+    };
+
+    hdfsSite = mkOption {
+      default = {};
+      example = {
+        "dfs.nameservices" = "namenode1";
+      };
+      description = "Hadoop hdfs-site.xml definition";
+    };
+
+    mapredSite = mkOption {
+      default = {};
+      example = {
+        "mapreduce.map.cpu.vcores" = "1";
+      };
+      description = "Hadoop mapred-site.xml definition";
+    };
+
+    yarnSite = mkOption {
+      default = {};
+      example = {
+        "yarn.resourcemanager.ha.id" = "resourcemanager1";
+      };
+      description = "Hadoop yarn-site.xml definition";
+    };
+
+    package = mkOption {
+      type = types.package;
+      default = pkgs.hadoop;
+      defaultText = "pkgs.hadoop";
+      example = literalExample "pkgs.hadoop";
+      description = ''
+      '';
+    };
+  };
+
+
+  config = mkMerge [
+    (mkIf (builtins.hasAttr "yarn" config.users.users ||
+           builtins.hasAttr "hdfs" config.users.users) {
+      users.groups.hadoop = {
+        gid = config.ids.gids.hadoop;
+      };
+    })
+
+  ];
+}
diff --git a/nixos/modules/services/cluster/hadoop/hdfs.nix b/nixos/modules/services/cluster/hadoop/hdfs.nix
new file mode 100644
index 000000000000..a38b6a78d3a5
--- /dev/null
+++ b/nixos/modules/services/cluster/hadoop/hdfs.nix
@@ -0,0 +1,73 @@
+{ config, lib, pkgs, ...}:
+let
+  cfg = config.services.hadoop;
+  hadoopConf = import ./conf.nix { hadoop = cfg; pkgs = pkgs; };
+in
+with lib;
+{
+  options.services.hadoop.hdfs = {
+    namenode.enabled = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Whether to run the Hadoop YARN NameNode
+      '';
+    };
+    datanode.enabled = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Whether to run the Hadoop YARN DataNode
+      '';
+    };
+  };
+
+  config = mkMerge [
+    (mkIf cfg.hdfs.namenode.enabled {
+      systemd.services."hdfs-namenode" = {
+        description = "Hadoop HDFS NameNode";
+        wantedBy = [ "multi-user.target" ];
+
+        environment = {
+          HADOOP_HOME = "${cfg.package}";
+        };
+
+        preStart = ''
+          ${cfg.package}/bin/hdfs --config ${hadoopConf} namenode -format -nonInteractive || true
+        '';
+
+        serviceConfig = {
+          User = "hdfs";
+          SyslogIdentifier = "hdfs-namenode";
+          ExecStart = "${cfg.package}/bin/hdfs --config ${hadoopConf} namenode";
+        };
+      };
+    })
+    (mkIf cfg.hdfs.datanode.enabled {
+      systemd.services."hdfs-datanode" = {
+        description = "Hadoop HDFS DataNode";
+        wantedBy = [ "multi-user.target" ];
+
+        environment = {
+          HADOOP_HOME = "${cfg.package}";
+        };
+
+        serviceConfig = {
+          User = "hdfs";
+          SyslogIdentifier = "hdfs-datanode";
+          ExecStart = "${cfg.package}/bin/hdfs --config ${hadoopConf} datanode";
+        };
+      };
+    })
+    (mkIf (
+        cfg.hdfs.namenode.enabled || cfg.hdfs.datanode.enabled
+    ) {
+      users.users.hdfs = {
+        description = "Hadoop HDFS user";
+        group = "hadoop";
+        uid = config.ids.uids.hdfs;
+      };
+    })
+
+  ];
+}
diff --git a/nixos/modules/services/cluster/hadoop/yarn.nix b/nixos/modules/services/cluster/hadoop/yarn.nix
new file mode 100644
index 000000000000..5345a2732d7e
--- /dev/null
+++ b/nixos/modules/services/cluster/hadoop/yarn.nix
@@ -0,0 +1,74 @@
+{ config, lib, pkgs, ...}:
+let
+  cfg = config.services.hadoop;
+  hadoopConf = import ./conf.nix { hadoop = cfg; pkgs = pkgs; };
+in
+with lib;
+{
+  options.services.hadoop.yarn = {
+    resourcemanager.enabled = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Whether to run the Hadoop YARN ResourceManager
+      '';
+    };
+    nodemanager.enabled = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Whether to run the Hadoop YARN NodeManager
+      '';
+    };
+  };
+
+  config = mkMerge [
+    (mkIf (
+        cfg.yarn.resourcemanager.enabled || cfg.yarn.nodemanager.enabled
+    ) {
+
+      users.users.yarn = {
+        description = "Hadoop YARN user";
+        group = "hadoop";
+        uid = config.ids.uids.yarn;
+      };
+    })
+
+    (mkIf cfg.yarn.resourcemanager.enabled {
+      systemd.services."yarn-resourcemanager" = {
+        description = "Hadoop YARN ResourceManager";
+        wantedBy = [ "multi-user.target" ];
+
+        environment = {
+          HADOOP_HOME = "${cfg.package}";
+        };
+
+        serviceConfig = {
+          User = "yarn";
+          SyslogIdentifier = "yarn-resourcemanager";
+          ExecStart = "${cfg.package}/bin/yarn --config ${hadoopConf} " +
+                      " resourcemanager";
+        };
+      };
+    })
+
+    (mkIf cfg.yarn.nodemanager.enabled {
+      systemd.services."yarn-nodemanager" = {
+        description = "Hadoop YARN NodeManager";
+        wantedBy = [ "multi-user.target" ];
+
+        environment = {
+          HADOOP_HOME = "${cfg.package}";
+        };
+
+        serviceConfig = {
+          User = "yarn";
+          SyslogIdentifier = "yarn-nodemanager";
+          ExecStart = "${cfg.package}/bin/yarn --config ${hadoopConf} " +
+                      " nodemanager";
+        };
+      };
+    })
+
+  ];
+}
diff --git a/nixos/modules/services/cluster/kubernetes/dashboard.nix b/nixos/modules/services/cluster/kubernetes/dashboard.nix
index e331889b9dd5..cbd6e8f7bf73 100644
--- a/nixos/modules/services/cluster/kubernetes/dashboard.nix
+++ b/nixos/modules/services/cluster/kubernetes/dashboard.nix
@@ -4,38 +4,60 @@ with lib;
 
 let
   cfg = config.services.kubernetes.addons.dashboard;
-
-  name = "gcr.io/google_containers/kubernetes-dashboard-amd64";
-	version = "v1.8.2";
-
-  image = pkgs.dockerTools.pullImage {
-    imageName = name;
-    imageTag = version;
-    sha256 = "11h0fz3wxp0f10fsyqaxjm7l2qg7xws50dv5iwlck5gb1fjmajad";
-  };
 in {
   options.services.kubernetes.addons.dashboard = {
     enable = mkEnableOption "kubernetes dashboard addon";
 
-    enableRBAC = mkOption {
-      description = "Whether to enable role based access control is enabled for kubernetes dashboard";
-      type = types.bool;
-      default = elem "RBAC" config.services.kubernetes.apiserver.authorizationMode;
+    rbac = mkOption {
+      description = "Role-based access control (RBAC) options";
+      default = {};
+      type = types.submodule {
+        options = {
+          enable = mkOption {
+            description = "Whether to enable role based access control is enabled for kubernetes dashboard";
+            type = types.bool;
+            default = elem "RBAC" config.services.kubernetes.apiserver.authorizationMode;
+          };
+
+          clusterAdmin = mkOption {
+            description = "Whether to assign cluster admin rights to the kubernetes dashboard";
+            type = types.bool;
+            default = false;
+          };
+        };
+      };
+    };
+
+    version = mkOption {
+      description = "Which version of the kubernetes dashboard to deploy";
+      type = types.str;
+      default = "v1.8.3";
+    };
+
+    image = mkOption {
+      description = "Docker image to seed for the kubernetes dashboard container.";
+      type = types.attrs;
+      default = {
+        imageName = "k8s.gcr.io/kubernetes-dashboard-amd64";
+        imageDigest = "sha256:dc4026c1b595435ef5527ca598e1e9c4343076926d7d62b365c44831395adbd0";
+        finalImageTag = cfg.version;
+        sha256 = "18ajcg0q1vignfjk2sm4xj4wzphfz8wah69ps8dklqfvv0164mc8";
+      };
     };
   };
 
   config = mkIf cfg.enable {
-    services.kubernetes.kubelet.seedDockerImages = [image];
+    services.kubernetes.kubelet.seedDockerImages = [(pkgs.dockerTools.pullImage cfg.image)];
 
     services.kubernetes.addonManager.addons = {
       kubernetes-dashboard-deployment = {
         kind = "Deployment";
-        apiVersion = "apps/v1beta1";
+        apiVersion = "apps/v1";
         metadata = {
           labels = {
             k8s-addon = "kubernetes-dashboard.addons.k8s.io";
             k8s-app = "kubernetes-dashboard";
-            version = version;
+            version = cfg.version;
             "kubernetes.io/cluster-service" = "true";
             "addonmanager.kubernetes.io/mode" = "Reconcile";
           };
@@ -51,45 +73,66 @@ in {
               labels = {
                 k8s-addon = "kubernetes-dashboard.addons.k8s.io";
                 k8s-app = "kubernetes-dashboard";
-                version = version;
+                version = cfg.version;
                 "kubernetes.io/cluster-service" = "true";
               };
               annotations = {
                 "scheduler.alpha.kubernetes.io/critical-pod" = "";
-                #"scheduler.alpha.kubernetes.io/tolerations" = ''[{"key":"CriticalAddonsOnly", "operator":"Exists"}]'';
               };
             };
             spec = {
+              priorityClassName = "system-cluster-critical";
               containers = [{
                 name = "kubernetes-dashboard";
-                image = "${name}:${version}";
+                image = with cfg.image; "${imageName}:${finalImageTag}";
                 ports = [{
-                  containerPort = 9090;
+                  containerPort = 8443;
                   protocol = "TCP";
                 }];
                 resources = {
                   limits = {
                     cpu = "100m";
-                    memory = "50Mi";
+                    memory = "300Mi";
                   };
                   requests = {
                     cpu = "100m";
-                    memory = "50Mi";
+                    memory = "100Mi";
                   };
                 };
+                args = ["--auto-generate-certificates"];
+                volumeMounts = [{
+                  name = "tmp-volume";
+                  mountPath = "/tmp";
+                } {
+                  name = "kubernetes-dashboard-certs";
+                  mountPath = "/certs";
+                }];
                 livenessProbe = {
                   httpGet = {
+                    scheme = "HTTPS";
                     path = "/";
-                    port = 9090;
+                    port = 8443;
                   };
                   initialDelaySeconds = 30;
                   timeoutSeconds = 30;
                 };
               }];
+              volumes = [{
+                name = "kubernetes-dashboard-certs";
+                secret = {
+                  secretName = "kubernetes-dashboard-certs";
+                };
+              } {
+                name = "tmp-volume";
+                emptyDir = {};
+              }];
               serviceAccountName = "kubernetes-dashboard";
               tolerations = [{
                 key = "node-role.kubernetes.io/master";
                 effect = "NoSchedule";
+              } {
+                key = "CriticalAddonsOnly";
+                operator = "Exists";
               }];
             };
           };
@@ -112,8 +155,8 @@ in {
         };
         spec = {
           ports = [{
-            port = 80;
-            targetPort = 9090;
+            port = 443;
+            targetPort = 8443;
           }];
           selector.k8s-app = "kubernetes-dashboard";
         };
@@ -126,35 +169,153 @@ in {
           labels = {
             k8s-app = "kubernetes-dashboard";
             k8s-addon = "kubernetes-dashboard.addons.k8s.io";
-						"addonmanager.kubernetes.io/mode" = "Reconcile";
+            "addonmanager.kubernetes.io/mode" = "Reconcile";
           };
           name = "kubernetes-dashboard";
           namespace = "kube-system";
         };
       };
-    } // (optionalAttrs cfg.enableRBAC {
-      kubernetes-dashboard-crb = {
-        apiVersion = "rbac.authorization.k8s.io/v1beta1";
-        kind = "ClusterRoleBinding";
+      kubernetes-dashboard-sec-certs = {
+        apiVersion = "v1";
+        kind = "Secret";
         metadata = {
-          name = "kubernetes-dashboard";
           labels = {
             k8s-app = "kubernetes-dashboard";
-            k8s-addon = "kubernetes-dashboard.addons.k8s.io";
-            "addonmanager.kubernetes.io/mode" = "Reconcile";
+            # Allows editing resource and makes sure it is created first.
+            "addonmanager.kubernetes.io/mode" = "EnsureExists";
+          };
+          name = "kubernetes-dashboard-certs";
+          namespace = "kube-system";
+        };
+        type = "Opaque";
+      };
+      kubernetes-dashboard-sec-kholder = {
+        apiVersion = "v1";
+        kind = "Secret";
+        metadata = {
+          labels = {
+            k8s-app = "kubernetes-dashboard";
+            # Allows editing resource and makes sure it is created first.
+            "addonmanager.kubernetes.io/mode" = "EnsureExists";
           };
+          name = "kubernetes-dashboard-key-holder";
+          namespace = "kube-system";
         };
-        roleRef = {
-          apiGroup = "rbac.authorization.k8s.io";
-          kind = "ClusterRole";
-          name = "cluster-admin";
+        type = "Opaque";
+      };
+      kubernetes-dashboard-cm = {
+        apiVersion = "v1";
+        kind = "ConfigMap";
+        metadata = {
+          labels = {
+            k8s-app = "kubernetes-dashboard";
+            # Allows editing resource and makes sure it is created first.
+            "addonmanager.kubernetes.io/mode" = "EnsureExists";
+          };
+          name = "kubernetes-dashboard-settings";
+          namespace = "kube-system";
         };
+      };
+    } // (optionalAttrs cfg.rbac.enable
+      (let
         subjects = [{
           kind = "ServiceAccount";
           name = "kubernetes-dashboard";
           namespace = "kube-system";
         }];
-      };
-    });
+        labels = {
+          k8s-app = "kubernetes-dashboard";
+          k8s-addon = "kubernetes-dashboard.addons.k8s.io";
+          "addonmanager.kubernetes.io/mode" = "Reconcile";
+        };
+      in
+        (if cfg.rbac.clusterAdmin then {
+          kubernetes-dashboard-crb = {
+            apiVersion = "rbac.authorization.k8s.io/v1";
+            kind = "ClusterRoleBinding";
+            metadata = {
+              name = "kubernetes-dashboard";
+              inherit labels;
+            };
+            roleRef = {
+              apiGroup = "rbac.authorization.k8s.io";
+              kind = "ClusterRole";
+              name = "cluster-admin";
+            };
+            inherit subjects;
+          };
+        }
+        else
+        {
+          # Upstream role- and rolebinding as per:
+          # https://raw.githubusercontent.com/kubernetes/dashboard/master/src/deploy/alternative/kubernetes-dashboard.yaml
+          kubernetes-dashboard-role = {
+            apiVersion = "rbac.authorization.k8s.io/v1";
+            kind = "Role";
+            metadata = {
+              name = "kubernetes-dashboard-minimal";
+              namespace = "kube-system";
+              inherit labels;
+            };
+            rules = [
+              # Allow Dashboard to create 'kubernetes-dashboard-key-holder' secret.
+              {
+                apiGroups = [""];
+                resources = ["secrets"];
+                verbs = ["create"];
+              }
+              # Allow Dashboard to create 'kubernetes-dashboard-settings' config map.
+              {
+                apiGroups = [""];
+                resources = ["configmaps"];
+                verbs = ["create"];
+              }
+              # Allow Dashboard to get, update and delete Dashboard exclusive secrets.
+              {
+                apiGroups = [""];
+                resources = ["secrets"];
+                resourceNames = ["kubernetes-dashboard-key-holder"];
+                verbs = ["get" "update" "delete"];
+              }
+              # Allow Dashboard to get and update 'kubernetes-dashboard-settings' config map.
+              {
+                apiGroups = [""];
+                resources = ["configmaps"];
+                resourceNames = ["kubernetes-dashboard-settings"];
+                verbs = ["get" "update"];
+              }
+              # Allow Dashboard to get metrics from heapster.
+              {
+                apiGroups = [""];
+                resources = ["services"];
+                resourceNames = ["heapster"];
+                verbs = ["proxy"];
+              }
+              {
+                apiGroups = [""];
+                resources = ["services/proxy"];
+                resourceNames = ["heapster" "http:heapster:" "https:heapster:"];
+                verbs = ["get"];
+              }
+            ];
+          };
+
+          kubernetes-dashboard-rb = {
+            apiVersion = "rbac.authorization.k8s.io/v1";
+            kind = "RoleBinding";
+            metadata = {
+              name = "kubernetes-dashboard-minimal";
+              namespace = "kube-system";
+              inherit labels;
+            };
+            roleRef = {
+              apiGroup = "rbac.authorization.k8s.io";
+              kind = "Role";
+              name = "kubernetes-dashboard-minimal";
+            };
+            inherit subjects;
+          };
+        })
+    ));
   };
 }
diff --git a/nixos/modules/services/cluster/kubernetes/default.nix b/nixos/modules/services/cluster/kubernetes/default.nix
index aeb0a0d2432d..f56a529afdf6 100644
--- a/nixos/modules/services/cluster/kubernetes/default.nix
+++ b/nixos/modules/services/cluster/kubernetes/default.nix
@@ -5,8 +5,36 @@ with lib;
 let
   cfg = config.services.kubernetes;
 
-  skipAttrs = attrs: map (filterAttrs (k: v: k != "enable"))
-    (filter (v: !(hasAttr "enable" v) || v.enable) attrs);
+  # YAML config; see:
+  #   https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/
+  #   https://github.com/kubernetes/kubernetes/blob/release-1.10/pkg/kubelet/apis/kubeletconfig/v1beta1/types.go
+  #
+  # TODO: migrate the following flags to this config file
+  #
+  #   --pod-manifest-path
+  #   --address
+  #   --port
+  #   --tls-cert-file
+  #   --tls-private-key-file
+  #   --client-ca-file
+  #   --authentication-token-webhook
+  #   --authentication-token-webhook-cache-ttl
+  #   --authorization-mode
+  #   --healthz-bind-address
+  #   --healthz-port
+  #   --allow-privileged
+  #   --cluster-dns
+  #   --cluster-domain
+  #   --hairpin-mode
+  #   --feature-gates
+  kubeletConfig = pkgs.runCommand "kubelet-config.yaml" { } ''
+    echo > $out ${pkgs.lib.escapeShellArg (builtins.toJSON {
+      kind = "KubeletConfiguration";
+      apiVersion = "kubelet.config.k8s.io/v1beta1";
+      ${if cfg.kubelet.applyManifests then "staticPodPath" else null} =
+        manifests;
+    })}
+  '';
 
   infraContainer = pkgs.dockerTools.buildImage {
     name = "pause";
@@ -42,12 +70,14 @@ let
   mkKubeConfigOptions = prefix: {
     server = mkOption {
       description = "${prefix} kube-apiserver server address.";
-      default = "http://${cfg.apiserver.address}:${toString cfg.apiserver.port}";
+      default = "http://${if cfg.apiserver.advertiseAddress != null
+                          then cfg.apiserver.advertiseAddress
+                          else "127.0.0.1"}:${toString cfg.apiserver.port}";
       type = types.str;
     };
 
     caFile = mkOption {
-      description = "${prefix} certificate authrority file used to connect to kube-apiserver.";
+      description = "${prefix} certificate authority file used to connect to kube-apiserver.";
       type = types.nullOr types.path;
       default = cfg.caFile;
     };
@@ -72,12 +102,18 @@ let
     keyFile = mkDefault cfg.kubeconfig.keyFile;
   };
 
-  cniConfig = pkgs.buildEnv {
-    name = "kubernetes-cni-config";
-    paths = imap (i: entry:
-      pkgs.writeTextDir "${toString (10+i)}-${entry.type}.conf" (builtins.toJSON entry)
-    ) cfg.kubelet.cni.config;
-  };
+  cniConfig =
+    if cfg.kubelet.cni.config != [] && !(isNull cfg.kubelet.cni.configDir) then
+      throw "Verbatim CNI-config and CNI configDir cannot both be set."
+    else if !(isNull cfg.kubelet.cni.configDir) then
+      cfg.kubelet.cni.configDir
+    else
+      (pkgs.buildEnv {
+        name = "kubernetes-cni-config";
+        paths = imap (i: entry:
+          pkgs.writeTextDir "${toString (10+i)}-${entry.type}.conf" (builtins.toJSON entry)
+        ) cfg.kubelet.cni.config;
+      });
 
   manifests = pkgs.buildEnv {
     name = "kubernetes-manifests";
@@ -213,18 +249,13 @@ in {
         type = types.listOf types.str;
       };
 
-      address = mkOption {
-        description = "Kubernetes apiserver listening address.";
-        default = "127.0.0.1";
-        type = types.str;
-      };
-
-      publicAddress = mkOption {
+      bindAddress = mkOption {
         description = ''
-          Kubernetes apiserver public listening address used for read only and
-          secure port.
+          The IP address on which to listen for the --secure-port port.
+          The associated interface(s) must be reachable by the rest
+          of the cluster, and by CLI/web clients.
         '';
-        default = cfg.apiserver.address;
+        default = "0.0.0.0";
         type = types.str;
       };
 
@@ -279,7 +310,7 @@ in {
       tokenAuthFile = mkOption {
         description = ''
           Kubernetes apiserver token authentication file. See
-          <link xlink:href="https://kubernetes.io/docs/admin/authentication.html"/>
+          <link xlink:href="https://kubernetes.io/docs/reference/access-authn-authz/authentication"/>
         '';
         default = null;
         type = types.nullOr types.path;
@@ -288,7 +319,7 @@ in {
       basicAuthFile = mkOption {
         description = ''
           Kubernetes apiserver basic authentication file. See
-          <link xlink:href="https://kubernetes.io/docs/admin/authentication.html"/>
+          <link xlink:href="https://kubernetes.io/docs/reference/access-authn-authz/authentication"/>
         '';
         default = pkgs.writeText "users" ''
           kubernetes,admin,0
@@ -298,22 +329,31 @@ in {
 
       authorizationMode = mkOption {
         description = ''
-          Kubernetes apiserver authorization mode (AlwaysAllow/AlwaysDeny/ABAC/RBAC). See
-          <link xlink:href="https://kubernetes.io/docs/admin/authorization.html"/>
+          Kubernetes apiserver authorization mode (AlwaysAllow/AlwaysDeny/ABAC/Webhook/RBAC/Node). See
+          <link xlink:href="https://kubernetes.io/docs/reference/access-authn-authz/authorization/"/>
         '';
         default = ["RBAC" "Node"];
-        type = types.listOf (types.enum ["AlwaysAllow" "AlwaysDeny" "ABAC" "RBAC" "Node"]);
+        type = types.listOf (types.enum ["AlwaysAllow" "AlwaysDeny" "ABAC" "Webhook" "RBAC" "Node"]);
       };
 
       authorizationPolicy = mkOption {
         description = ''
           Kubernetes apiserver authorization policy file. See
-          <link xlink:href="https://kubernetes.io/docs/admin/authorization.html"/>
+          <link xlink:href="https://kubernetes.io/docs/reference/access-authn-authz/authorization/"/>
         '';
         default = [];
         type = types.listOf types.attrs;
       };
 
+      webhookConfig = mkOption {
+        description = ''
+          Kubernetes apiserver Webhook config file. It uses the kubeconfig file format.
+          See <link xlink:href="https://kubernetes.io/docs/reference/access-authn-authz/webhook/"/>
+        '';
+        default = null;
+        type = types.nullOr types.path;
+      };
+
       allowPrivileged = mkOption {
         description = "Whether to allow privileged containers on Kubernetes.";
         default = true;
@@ -332,16 +372,16 @@ in {
       runtimeConfig = mkOption {
         description = ''
           Api runtime configuration. See
-          <link xlink:href="https://kubernetes.io/docs/admin/cluster-management.html"/>
+          <link xlink:href="https://kubernetes.io/docs/tasks/administer-cluster/cluster-management/"/>
         '';
         default = "authentication.k8s.io/v1beta1=true";
         example = "api/all=false,api/v1=true";
         type = types.str;
       };
 
-      admissionControl = mkOption {
+      enableAdmissionPlugins = mkOption {
         description = ''
-          Kubernetes admission control plugins to use. See
+          Kubernetes admission control plugins to enable. See
           <link xlink:href="https://kubernetes.io/docs/admin/admission-controllers/"/>
         '';
         default = ["NamespaceLifecycle" "LimitRanger" "ServiceAccount" "ResourceQuota" "DefaultStorageClass" "DefaultTolerationSeconds" "NodeRestriction"];
@@ -353,6 +393,15 @@ in {
         type = types.listOf types.str;
       };
 
+      disableAdmissionPlugins = mkOption {
+        description = ''
+          Kubernetes admission control plugins to disable. See
+          <link xlink:href="https://kubernetes.io/docs/admin/admission-controllers/"/>
+        '';
+        default = [];
+        type = types.listOf types.str;
+      };
+
       serviceAccountKeyFile = mkOption {
         description = ''
           Kubernetes apiserver PEM-encoded x509 RSA private or public key file,
@@ -573,6 +622,7 @@ in {
         type = types.bool;
       };
 
+      # TODO: remove this deprecated flag
       cadvisorPort = mkOption {
         description = "Kubernetes kubelet local cadvisor port.";
         default = 4194;
@@ -629,6 +679,12 @@ in {
             }]
           '';
         };
+
+        configDir = mkOption {
+          description = "Path to Kubernetes CNI configuration directory.";
+          type = types.nullOr types.path;
+          default = null;
+        };
       };
 
       manifests = mkOption {
@@ -783,12 +839,10 @@ in {
         serviceConfig = {
           Slice = "kubernetes.slice";
           ExecStart = ''${cfg.package}/bin/kubelet \
-            ${optionalString cfg.kubelet.applyManifests
-              "--pod-manifest-path=${manifests}"} \
             ${optionalString (taints != "")
               "--register-with-taints=${taints}"} \
             --kubeconfig=${mkKubeConfig "kubelet" cfg.kubelet.kubeconfig} \
-            --require-kubeconfig \
+            --config=${kubeletConfig} \
             --address=${cfg.kubelet.address} \
             --port=${toString cfg.kubelet.port} \
             --register-node=${boolToString cfg.kubelet.registerNode} \
@@ -853,7 +907,7 @@ in {
 
     (mkIf cfg.apiserver.enable {
       systemd.services.kube-apiserver = {
-        description = "Kubernetes Kubelet Service";
+        description = "Kubernetes APIServer Service";
         wantedBy = [ "kubernetes.target" ];
         after = [ "network.target" "docker.service" ];
         serviceConfig = {
@@ -867,7 +921,7 @@ in {
             ${optionalString (cfg.etcd.keyFile != null)
               "--etcd-keyfile=${cfg.etcd.keyFile}"} \
             --insecure-port=${toString cfg.apiserver.port} \
-            --bind-address=0.0.0.0 \
+            --bind-address=${cfg.apiserver.bindAddress} \
             ${optionalString (cfg.apiserver.advertiseAddress != null)
               "--advertise-address=${cfg.apiserver.advertiseAddress}"} \
             --allow-privileged=${boolToString cfg.apiserver.allowPrivileged}\
@@ -895,11 +949,15 @@ in {
                 (concatMapStringsSep "\n" (l: builtins.toJSON l) cfg.apiserver.authorizationPolicy)
               }"
             } \
+            ${optionalString (elem "Webhook" cfg.apiserver.authorizationMode)
+              "--authorization-webhook-config-file=${cfg.apiserver.webhookConfig}"
+            } \
             --secure-port=${toString cfg.apiserver.securePort} \
             --service-cluster-ip-range=${cfg.apiserver.serviceClusterIpRange} \
             ${optionalString (cfg.apiserver.runtimeConfig != "")
               "--runtime-config=${cfg.apiserver.runtimeConfig}"} \
-            --admission_control=${concatStringsSep "," cfg.apiserver.admissionControl} \
+            --enable-admission-plugins=${concatStringsSep "," cfg.apiserver.enableAdmissionPlugins} \
+            --disable-admission-plugins=${concatStringsSep "," cfg.apiserver.disableAdmissionPlugins} \
             ${optionalString (cfg.apiserver.serviceAccountKeyFile!=null)
               "--service-account-key-file=${cfg.apiserver.serviceAccountKeyFile}"} \
             ${optionalString cfg.verbose "--v=6"} \
@@ -1055,6 +1113,7 @@ in {
         wantedBy = [ "kubernetes.target" ];
         after = [ "kube-apiserver.service" ];
         environment.ADDON_PATH = "/etc/kubernetes/addons/";
+        path = [ pkgs.gawk ];
         serviceConfig = {
           Slice = "kubernetes.slice";
           ExecStart = "${cfg.package}/bin/kube-addons";
@@ -1084,7 +1143,7 @@ in {
       ];
 
       environment.systemPackages = [ cfg.package ];
-      users.extraUsers = singleton {
+      users.users = singleton {
         name = "kubernetes";
         uid = config.ids.uids.kubernetes;
         description = "Kubernetes user";
@@ -1093,7 +1152,7 @@ in {
         home = cfg.dataDir;
         createHome = true;
       };
-      users.extraGroups.kubernetes.gid = config.ids.gids.kubernetes;
+      users.groups.kubernetes.gid = config.ids.gids.kubernetes;
 
 			# dns addon is enabled by default
       services.kubernetes.addons.dns.enable = mkDefault true;
diff --git a/nixos/modules/services/cluster/kubernetes/dns.nix b/nixos/modules/services/cluster/kubernetes/dns.nix
index 226fdadffd1a..43bbb50a48d4 100644
--- a/nixos/modules/services/cluster/kubernetes/dns.nix
+++ b/nixos/modules/services/cluster/kubernetes/dns.nix
@@ -3,26 +3,7 @@
 with lib;
 
 let
-  version = "1.14.4";
-
-  k8s-dns-kube-dns = pkgs.dockerTools.pullImage {
-    imageName = "gcr.io/google_containers/k8s-dns-kube-dns-amd64";
-    imageTag = version;
-    sha256 = "0q97xfqrigrfjl2a9cxl5in619py0zv44gch09jm8gqjkxl80imp";
-  };
-
-  k8s-dns-dnsmasq-nanny = pkgs.dockerTools.pullImage {
-    imageName = "gcr.io/google_containers/k8s-dns-dnsmasq-nanny-amd64";
-    imageTag = version;
-    sha256 = "051w5ca4qb88mwva4hbnh9xzlsvv7k1mbk3wz50lmig2mqrqqx6c";
-  };
-
-  k8s-dns-sidecar = pkgs.dockerTools.pullImage {
-    imageName = "gcr.io/google_containers/k8s-dns-sidecar-amd64";
-    imageTag = version;
-    sha256 = "1z0d129bcm8i2cqq36x5jhnrv9hirj8c6kjrmdav8vgf7py78vsm";
-  };
-
+  version = "1.14.10";
   cfg = config.services.kubernetes.addons.dns;
 in {
   options.services.kubernetes.addons.dns = {
@@ -45,18 +26,51 @@ in {
       default = "cluster.local";
       type = types.str;
     };
+
+    kube-dns = mkOption {
+      description = "Docker image to seed for the kube-dns main container.";
+      type = types.attrs;
+      default = {
+        imageName = "k8s.gcr.io/k8s-dns-kube-dns-amd64";
+        imageDigest = "sha256:b99fc3eee2a9f052f7eb4cc00f15eb12fc405fa41019baa2d6b79847ae7284a8";
+        finalImageTag = version;
+        sha256 = "0x583znk9smqn0fix7ld8sm5jgaxhqhx3fq97b1wkqm7iwhvl3pj";
+      };
+    };
+
+    dnsmasq-nanny = mkOption {
+      description = "Docker image to seed for the kube-dns dnsmasq container.";
+      type = types.attrs;
+      default = {
+        imageName = "k8s.gcr.io/k8s-dns-dnsmasq-nanny-amd64";
+        imageDigest = "sha256:bbb2a290a568125b3b996028958eb773f33b5b87a6b37bf38a28f8b62dddb3c8";
+        finalImageTag = version;
+        sha256 = "1fihml7s2mfwgac51cbqpylkwbivc8nyhgi4vb820s83zvl8a6y1";
+      };
+    };
+
+    sidecar = mkOption {
+      description = "Docker image to seed for the kube-dns sidecar container.";
+      type = types.attrs;
+      default = {
+        imageName = "k8s.gcr.io/k8s-dns-sidecar-amd64";
+        imageDigest = "sha256:4f1ab957f87b94a5ec1edc26fae50da2175461f00afecf68940c4aa079bd08a4";
+        finalImageTag = version;
+        sha256 = "08l1bv5jgrhvjzpqpbinrkgvv52snc4fzyd8ya9v18ns2klyz7m0";
+      };
+    };
   };
 
   config = mkIf cfg.enable {
-    services.kubernetes.kubelet.seedDockerImages = [
-      k8s-dns-kube-dns
-      k8s-dns-dnsmasq-nanny
-      k8s-dns-sidecar
+    services.kubernetes.kubelet.seedDockerImages = with pkgs.dockerTools; [
+      (pullImage cfg.kube-dns)
+      (pullImage cfg.dnsmasq-nanny)
+      (pullImage cfg.sidecar)
     ];
 
     services.kubernetes.addonManager.addons = {
       kubedns-deployment = {
-        apiVersion = "apps/v1beta1";
+        apiVersion = "extensions/v1beta1";
         kind = "Deployment";
         metadata = {
           labels = {
@@ -81,9 +95,38 @@ in {
               labels.k8s-app = "kube-dns";
             };
             spec = {
+              priorityClassName = "system-cluster-critical";
               containers = [
                 {
                   name = "kubedns";
+                  image = with cfg.kube-dns; "${imageName}:${finalImageTag}";
+                  resources = {
+                    limits.memory = "170Mi";
+                    requests = {
+                      cpu = "100m";
+                      memory = "70Mi";
+                    };
+                  };
+                  livenessProbe = {
+                    failureThreshold = 5;
+                    httpGet = {
+                      path = "/healthcheck/kubedns";
+                      port = 10054;
+                      scheme = "HTTP";
+                    };
+                    initialDelaySeconds = 60;
+                    successThreshold = 1;
+                    timeoutSeconds = 5;
+                  };
+                  readinessProbe = {
+                    httpGet = {
+                      path = "/readiness";
+                      port = 8081;
+                      scheme = "HTTP";
+                    };
+                    initialDelaySeconds = 3;
+                    timeoutSeconds = 5;
+                  };
                   args = [
                     "--domain=${cfg.clusterDomain}"
                     "--dns-port=10053"
@@ -96,18 +139,6 @@ in {
                       value = "10055";
                     }
                   ];
-                  image = "gcr.io/google_containers/k8s-dns-kube-dns-amd64:${version}";
-                  livenessProbe = {
-                    failureThreshold = 5;
-                    httpGet = {
-                      path = "/healthcheck/kubedns";
-                      port = 10054;
-                      scheme = "HTTP";
-                    };
-                    initialDelaySeconds = 60;
-                    successThreshold = 1;
-                    timeoutSeconds = 5;
-                  };
                   ports = [
                     {
                       containerPort = 10053;
@@ -125,22 +156,6 @@ in {
                       protocol = "TCP";
                     }
                   ];
-                  readinessProbe = {
-                    httpGet = {
-                      path = "/readiness";
-                      port = 8081;
-                      scheme = "HTTP";
-                    };
-                    initialDelaySeconds = 3;
-                    timeoutSeconds = 5;
-                  };
-                  resources = {
-                    limits.memory = "170Mi";
-                    requests = {
-                      cpu = "100m";
-                      memory = "70Mi";
-                    };
-                  };
                   volumeMounts = [
                     {
                       mountPath = "/kube-dns-config";
@@ -149,6 +164,19 @@ in {
                   ];
                 }
                 {
+                  name = "dnsmasq";
+                  image = with cfg.dnsmasq-nanny; "${imageName}:${finalImageTag}";
+                  livenessProbe = {
+                    httpGet = {
+                      path = "/healthcheck/dnsmasq";
+                      port = 10054;
+                      scheme = "HTTP";
+                    };
+                    initialDelaySeconds = 60;
+                    timeoutSeconds = 5;
+                    successThreshold = 1;
+                    failureThreshold = 5;
+                  };
                   args = [
                     "-v=2"
                     "-logtostderr"
@@ -162,19 +190,6 @@ in {
                     "--server=/in-addr.arpa/127.0.0.1#10053"
                     "--server=/ip6.arpa/127.0.0.1#10053"
                   ];
-                  image = "gcr.io/google_containers/k8s-dns-dnsmasq-nanny-amd64:${version}";
-                  livenessProbe = {
-                    failureThreshold = 5;
-                    httpGet = {
-                      path = "/healthcheck/dnsmasq";
-                      port = 10054;
-                      scheme = "HTTP";
-                    };
-                    initialDelaySeconds = 60;
-                    successThreshold = 1;
-                    timeoutSeconds = 5;
-                  };
-                  name = "dnsmasq";
                   ports = [
                     {
                       containerPort = 53;
@@ -202,24 +217,24 @@ in {
                 }
                 {
                   name = "sidecar";
-                  image = "gcr.io/google_containers/k8s-dns-sidecar-amd64:${version}";
-                  args = [
-                    "--v=2"
-                    "--logtostderr"
-                    "--probe=kubedns,127.0.0.1:10053,kubernetes.default.svc.${cfg.clusterDomain},5,A"
-                    "--probe=dnsmasq,127.0.0.1:53,kubernetes.default.svc.${cfg.clusterDomain},5,A"
-                  ];
+                  image = with cfg.sidecar; "${imageName}:${finalImageTag}";
                   livenessProbe = {
-                    failureThreshold = 5;
                     httpGet = {
                       path = "/metrics";
                       port = 10054;
                       scheme = "HTTP";
                     };
                     initialDelaySeconds = 60;
-                    successThreshold = 1;
                     timeoutSeconds = 5;
+                    successThreshold = 1;
+                    failureThreshold = 5;
                   };
+                  args = [
+                    "--v=2"
+                    "--logtostderr"
+                    "--probe=kubedns,127.0.0.1:10053,kubernetes.default.svc.${cfg.clusterDomain},5,A"
+                    "--probe=dnsmasq,127.0.0.1:53,kubernetes.default.svc.${cfg.clusterDomain},5,A"
+                  ];
                   ports = [
                     {
                       containerPort = 10054;
diff --git a/nixos/modules/services/computing/slurm/slurm.nix b/nixos/modules/services/computing/slurm/slurm.nix
index 45d34f5b76f5..1e1c5bc9f035 100644
--- a/nixos/modules/services/computing/slurm/slurm.nix
+++ b/nixos/modules/services/computing/slurm/slurm.nix
@@ -6,20 +6,36 @@ let
 
   cfg = config.services.slurm;
   # configuration file can be generated by http://slurm.schedmd.com/configurator.html
-  configFile = pkgs.writeText "slurm.conf"
+  configFile = pkgs.writeTextDir "slurm.conf"
     ''
       ${optionalString (cfg.controlMachine != null) ''controlMachine=${cfg.controlMachine}''}
       ${optionalString (cfg.controlAddr != null) ''controlAddr=${cfg.controlAddr}''}
       ${optionalString (cfg.nodeName != null) ''nodeName=${cfg.nodeName}''}
       ${optionalString (cfg.partitionName != null) ''partitionName=${cfg.partitionName}''}
       PlugStackConfig=${plugStackConfig}
+      ProctrackType=${cfg.procTrackType}
       ${cfg.extraConfig}
     '';
 
-  plugStackConfig = pkgs.writeText "plugstack.conf"
+  plugStackConfig = pkgs.writeTextDir "plugstack.conf"
     ''
       ${optionalString cfg.enableSrunX11 ''optional ${pkgs.slurm-spank-x11}/lib/x11.so''}
+      ${cfg.extraPlugstackConfig}
     '';
+
+
+  cgroupConfig = pkgs.writeTextDir "cgroup.conf"
+   ''
+     ${cfg.extraCgroupConfig}
+   '';
+
+  # slurm expects some additional config files to be
+  # in the same directory as slurm.conf
+  etcSlurm = pkgs.symlinkJoin {
+    name = "etc-slurm";
+    paths = [ configFile cgroupConfig plugStackConfig ];
+  };
+
 in
 
 {
@@ -31,13 +47,31 @@ in
     services.slurm = {
 
       server = {
-        enable = mkEnableOption "slurm control daemon";
-
+        enable = mkOption {
+          type = types.bool;
+          default = false;
+          description = ''
+            Wether to enable the slurm control daemon.
+            Note that the standard authentication method is "munge".
+            The "munge" service needs to be provided with a password file in order for
+            slurm to work properly (see <literal>services.munge.password</literal>).
+          '';
+        };
       };
 
       client = {
-        enable = mkEnableOption "slurm rlient daemon";
+        enable = mkEnableOption "slurm client daemon";
+      };
 
+      enableStools = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Wether to provide a slurm.conf file.
+          Enable this option if you do not run a slurm daemon on this host
+          (i.e. <literal>server.enable</literal> and <literal>client.enable</literal> are <literal>false</literal>)
+          but you still want to run slurm commands from this host.
+        '';
       };
 
       package = mkOption {
@@ -88,7 +122,7 @@ in
         example = "debug Nodes=linux[1-32] Default=YES MaxTime=INFINITE State=UP";
         description = ''
           Name by which the partition may be referenced. Note that now you have
-          to write patrition's parameters after the name.
+          to write the partition's parameters after the name.
         '';
       };
 
@@ -98,8 +132,20 @@ in
         description = ''
           If enabled srun will accept the option "--x11" to allow for X11 forwarding
           from within an interactive session or a batch job. This activates the
-          slurm-spank-x11 module. Note that this requires 'services.openssh.forwardX11'
-          to be enabled on the compute nodes.
+          slurm-spank-x11 module. Note that this option also enables
+          'services.openssh.forwardX11' on the client.
+
+          This option requires slurm to be compiled without native X11 support.
+        '';
+      };
+
+      procTrackType = mkOption {
+        type = types.string;
+        default = "proctrack/linuxproc";
+        description = ''
+          Plugin to be used for process tracking on a job step basis.
+          The slurmd daemon uses this mechanism to identify all processes
+          which are children of processes it spawns for a user job step.
         '';
       };
 
@@ -111,6 +157,23 @@ in
           the end of the slurm configuration file.
         '';
       };
+
+      extraPlugstackConfig = mkOption {
+        default = "";
+        type = types.lines;
+        description = ''
+          Extra configuration that will be added to the end of <literal>plugstack.conf</literal>.
+        '';
+      };
+
+      extraCgroupConfig = mkOption {
+        default = "";
+        type = types.lines;
+        description = ''
+          Extra configuration for <literal>cgroup.conf</literal>. This file is
+          used when <literal>procTrackType=proctrack/cgroup</literal>.
+        '';
+      };
     };
 
   };
@@ -123,8 +186,6 @@ in
       wrappedSlurm = pkgs.stdenv.mkDerivation {
         name = "wrappedSlurm";
 
-        propagatedBuildInputs = [ cfg.package configFile ];
-
         builder = pkgs.writeText "builder.sh" ''
           source $stdenv/setup
           mkdir -p $out/bin
@@ -136,20 +197,25 @@ in
           #!/bin/sh
           if [ -z "$SLURM_CONF" ]
           then
-            SLURM_CONF="${configFile}" "$EXE" "\$@"
+            SLURM_CONF="${etcSlurm}/slurm.conf" "$EXE" "\$@"
           else
             "$EXE" "\$0"
           fi
           EOT
             chmod +x "$wrappername"
           done
+
+          mkdir -p $out/share
+          ln -s ${getBin cfg.package}/share/man $out/share/man
         '';
       };
 
-  in mkIf (cfg.client.enable || cfg.server.enable) {
+  in mkIf (cfg.enableStools || cfg.client.enable || cfg.server.enable) {
 
     environment.systemPackages = [ wrappedSlurm ];
 
+    services.munge.enable = mkDefault true;
+
     systemd.services.slurmd = mkIf (cfg.client.enable) {
       path = with pkgs; [ wrappedSlurm coreutils ]
         ++ lib.optional cfg.enableSrunX11 slurm-spank-x11;
@@ -169,6 +235,8 @@ in
       '';
     };
 
+    services.openssh.forwardX11 = mkIf cfg.client.enable (mkDefault true);
+
     systemd.services.slurmctld = mkIf (cfg.server.enable) {
       path = with pkgs; [ wrappedSlurm munge coreutils ]
         ++ lib.optional cfg.enableSrunX11 slurm-spank-x11;
diff --git a/nixos/modules/services/continuous-integration/buildbot/master.nix b/nixos/modules/services/continuous-integration/buildbot/master.nix
index 846efc8b5b9a..8d767de37f00 100644
--- a/nixos/modules/services/continuous-integration/buildbot/master.nix
+++ b/nixos/modules/services/continuous-integration/buildbot/master.nix
@@ -191,11 +191,11 @@ in {
   };
 
   config = mkIf cfg.enable {
-    users.extraGroups = optional (cfg.group == "buildbot") {
+    users.groups = optional (cfg.group == "buildbot") {
       name = "buildbot";
     };
 
-    users.extraUsers = optional (cfg.user == "buildbot") {
+    users.users = optional (cfg.user == "buildbot") {
       name = "buildbot";
       description = "Buildbot User.";
       isNormalUser = true;
diff --git a/nixos/modules/services/continuous-integration/buildbot/worker.nix b/nixos/modules/services/continuous-integration/buildbot/worker.nix
index a97f571e89df..67c541570b97 100644
--- a/nixos/modules/services/continuous-integration/buildbot/worker.nix
+++ b/nixos/modules/services/continuous-integration/buildbot/worker.nix
@@ -84,11 +84,11 @@ in {
   };
 
   config = mkIf cfg.enable {
-    users.extraGroups = optional (cfg.group == "bbworker") {
+    users.groups = optional (cfg.group == "bbworker") {
       name = "bbworker";
     };
 
-    users.extraUsers = optional (cfg.user == "bbworker") {
+    users.users = optional (cfg.user == "bbworker") {
       name = "bbworker";
       description = "Buildbot Worker User.";
       isNormalUser = true;
diff --git a/nixos/modules/services/continuous-integration/buildkite-agent.nix b/nixos/modules/services/continuous-integration/buildkite-agent.nix
index d647b7b9fa49..9daf391c73c4 100644
--- a/nixos/modules/services/continuous-integration/buildkite-agent.nix
+++ b/nixos/modules/services/continuous-integration/buildkite-agent.nix
@@ -185,7 +185,7 @@ in
   };
 
   config = mkIf config.services.buildkite-agent.enable {
-    users.extraUsers.buildkite-agent =
+    users.users.buildkite-agent =
       { name = "buildkite-agent";
         home = cfg.dataDir;
         createHome = true;
diff --git a/nixos/modules/services/continuous-integration/gitlab-runner.nix b/nixos/modules/services/continuous-integration/gitlab-runner.nix
index 6d5cea4f77a5..a0aff1b8b5b9 100644
--- a/nixos/modules/services/continuous-integration/gitlab-runner.nix
+++ b/nixos/modules/services/continuous-integration/gitlab-runner.nix
@@ -134,7 +134,7 @@ in
     # Make the gitlab-runner command availabe so users can query the runner
     environment.systemPackages = [ cfg.package ];
 
-    users.extraUsers.gitlab-runner = {
+    users.users.gitlab-runner = {
       group = "gitlab-runner";
       extraGroups = optional hasDocker "docker";
       uid = config.ids.uids.gitlab-runner;
@@ -142,6 +142,6 @@ in
       createHome = true;
     };
 
-    users.extraGroups.gitlab-runner.gid = config.ids.gids.gitlab-runner;
+    users.groups.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 05adb18fbe91..8126f27c2b0c 100644
--- a/nixos/modules/services/continuous-integration/gocd-agent/default.nix
+++ b/nixos/modules/services/continuous-integration/gocd-agent/default.nix
@@ -135,12 +135,12 @@ in {
   };
 
   config = mkIf cfg.enable {
-    users.extraGroups = optional (cfg.group == "gocd-agent") {
+    users.groups = optional (cfg.group == "gocd-agent") {
       name = "gocd-agent";
       gid = config.ids.gids.gocd-agent;
     };
 
-    users.extraUsers = optional (cfg.user == "gocd-agent") {
+    users.users = optional (cfg.user == "gocd-agent") {
       name = "gocd-agent";
       description = "gocd-agent user";
       createHome = true;
diff --git a/nixos/modules/services/continuous-integration/gocd-server/default.nix b/nixos/modules/services/continuous-integration/gocd-server/default.nix
index 07e00f17f1e8..8f177da129e5 100644
--- a/nixos/modules/services/continuous-integration/gocd-server/default.nix
+++ b/nixos/modules/services/continuous-integration/gocd-server/default.nix
@@ -113,8 +113,8 @@ in {
 
       extraOptions = mkOption {
         default = [ ];
-        example = [ 
-          "-X debug" 
+        example = [
+          "-X debug"
           "-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005"
           "-verbose:gc"
           "-Xloggc:go-server-gc.log"
@@ -143,12 +143,12 @@ in {
   };
 
   config = mkIf cfg.enable {
-    users.extraGroups = optional (cfg.group == "gocd-server") {
+    users.groups = optional (cfg.group == "gocd-server") {
       name = "gocd-server";
       gid = config.ids.gids.gocd-server;
     };
 
-    users.extraUsers = optional (cfg.user == "gocd-server") {
+    users.users = optional (cfg.user == "gocd-server") {
       name = "gocd-server";
       description = "gocd-server user";
       createHome = true;
diff --git a/nixos/modules/services/continuous-integration/hydra/default.nix b/nixos/modules/services/continuous-integration/hydra/default.nix
index 2fa7c59a965d..c7fe4eeeab99 100644
--- a/nixos/modules/services/continuous-integration/hydra/default.nix
+++ b/nixos/modules/services/continuous-integration/hydra/default.nix
@@ -194,11 +194,11 @@ in
 
   config = mkIf cfg.enable {
 
-    users.extraGroups.hydra = {
+    users.groups.hydra = {
       gid = config.ids.gids.hydra;
     };
 
-    users.extraUsers.hydra =
+    users.users.hydra =
       { description = "Hydra";
         group = "hydra";
         createHome = true;
@@ -207,7 +207,7 @@ in
         uid = config.ids.uids.hydra;
       };
 
-    users.extraUsers.hydra-queue-runner =
+    users.users.hydra-queue-runner =
       { description = "Hydra queue runner";
         group = "hydra";
         useDefaultShell = true;
@@ -215,7 +215,7 @@ in
         uid = config.ids.uids.hydra-queue-runner;
       };
 
-    users.extraUsers.hydra-www =
+    users.users.hydra-www =
       { description = "Hydra web server";
         group = "hydra";
         useDefaultShell = true;
diff --git a/nixos/modules/services/continuous-integration/jenkins/default.nix b/nixos/modules/services/continuous-integration/jenkins/default.nix
index c2f4e9c0c5a7..1eca45fbd570 100644
--- a/nixos/modules/services/continuous-integration/jenkins/default.nix
+++ b/nixos/modules/services/continuous-integration/jenkins/default.nix
@@ -150,12 +150,12 @@ in {
       pkgs.dejavu_fonts
     ];
 
-    users.extraGroups = optional (cfg.group == "jenkins") {
+    users.groups = optional (cfg.group == "jenkins") {
       name = "jenkins";
       gid = config.ids.gids.jenkins;
     };
 
-    users.extraUsers = optional (cfg.user == "jenkins") {
+    users.users = optional (cfg.user == "jenkins") {
       name = "jenkins";
       description = "jenkins user";
       createHome = true;
diff --git a/nixos/modules/services/continuous-integration/jenkins/slave.nix b/nixos/modules/services/continuous-integration/jenkins/slave.nix
index a0216caf2b5c..d8f55fb826f2 100644
--- a/nixos/modules/services/continuous-integration/jenkins/slave.nix
+++ b/nixos/modules/services/continuous-integration/jenkins/slave.nix
@@ -50,12 +50,12 @@ in {
   };
 
   config = mkIf (cfg.enable && !masterCfg.enable) {
-    users.extraGroups = optional (cfg.group == "jenkins") {
+    users.groups = optional (cfg.group == "jenkins") {
       name = "jenkins";
       gid = config.ids.gids.jenkins;
     };
 
-    users.extraUsers = optional (cfg.user == "jenkins") {
+    users.users = optional (cfg.user == "jenkins") {
       name = "jenkins";
       description = "jenkins user";
       createHome = true;
diff --git a/nixos/modules/services/databases/4store-endpoint.nix b/nixos/modules/services/databases/4store-endpoint.nix
index d528355671f6..59ed0e5f0afd 100644
--- a/nixos/modules/services/databases/4store-endpoint.nix
+++ b/nixos/modules/services/databases/4store-endpoint.nix
@@ -52,7 +52,7 @@ with lib;
         message = "Must specify 4Store database name";
       };
 
-    users.extraUsers = singleton
+    users.users = singleton
       { name = endpointUser;
         uid = config.ids.uids.fourstorehttp;
         description = "4Store SPARQL endpoint user";
diff --git a/nixos/modules/services/databases/4store.nix b/nixos/modules/services/databases/4store.nix
index abb62e1f2637..be4351c1c38f 100644
--- a/nixos/modules/services/databases/4store.nix
+++ b/nixos/modules/services/databases/4store.nix
@@ -43,7 +43,7 @@ with lib;
         message = "Must specify 4Store database name.";
       };
 
-    users.extraUsers = singleton
+    users.users = singleton
       { name = fourStoreUser;
         uid = config.ids.uids.fourstore;
         description = "4Store database user";
diff --git a/nixos/modules/services/databases/aerospike.nix b/nixos/modules/services/databases/aerospike.nix
new file mode 100644
index 000000000000..5f33164998be
--- /dev/null
+++ b/nixos/modules/services/databases/aerospike.nix
@@ -0,0 +1,155 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.aerospike;
+
+  aerospikeConf = pkgs.writeText "aerospike.conf" ''
+    # This stanza must come first.
+    service {
+      user aerospike
+      group aerospike
+      paxos-single-replica-limit 1 # Number of nodes where the replica count is automatically reduced to 1.
+      proto-fd-max 15000
+      work-directory ${cfg.workDir}
+    }
+    logging {
+      console {
+        context any info
+      }
+    }
+    mod-lua {
+      system-path ${cfg.package}/share/udf/lua
+      user-path ${cfg.workDir}/udf/lua
+    }
+    network {
+      ${cfg.networkConfig}
+    }
+    ${cfg.extraConfig}
+  '';
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.aerospike = {
+      enable = mkEnableOption "Aerospike server";
+
+      package = mkOption {
+        default = pkgs.aerospike;
+        type = types.package;
+        description = "Which Aerospike derivation to use";
+      };
+
+      workDir = mkOption {
+        type = types.str;
+        default = "/var/lib/aerospike";
+        description = "Location where Aerospike stores its files";
+      };
+
+      networkConfig = mkOption {
+        type = types.lines;
+        default = ''
+          service {
+            address any
+            port 3000
+          }
+
+          heartbeat {
+            address any
+            mode mesh
+            port 3002
+            interval 150
+            timeout 10
+          }
+
+          fabric {
+            address any
+            port 3001
+          }
+
+          info {
+            address any
+            port 3003
+          }
+        '';
+        description = "network section of configuration file";
+      };
+
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        example = ''
+          namespace test {
+            replication-factor 2
+            memory-size 4G
+            default-ttl 30d
+            storage-engine memory
+          }
+        '';
+        description = "Extra configuration";
+      };
+    };
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf config.services.aerospike.enable {
+
+    users.users.aerospike = {
+      name = "aerospike";
+      group = "aerospike";
+      uid = config.ids.uids.aerospike;
+      description = "Aerospike server user";
+    };
+    users.groups.aerospike.gid = config.ids.gids.aerospike;
+
+    systemd.services.aerospike = rec {
+      description = "Aerospike server";
+
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+
+      serviceConfig = {
+        ExecStart = "${cfg.package}/bin/asd --fgdaemon --config-file ${aerospikeConf}";
+        User = "aerospike";
+        Group = "aerospike";
+        LimitNOFILE = 100000;
+        PermissionsStartOnly = true;
+      };
+
+      preStart = ''
+        if [ $(echo "$(${pkgs.procps}/bin/sysctl -n kernel.shmall) < 4294967296" | ${pkgs.bc}/bin/bc) == "1"  ]; then
+          echo "kernel.shmall too low, setting to 4G pages"
+          ${pkgs.procps}/bin/sysctl -w kernel.shmall=4294967296
+        fi
+        if [ $(echo "$(${pkgs.procps}/bin/sysctl -n kernel.shmmax) < 1073741824" | ${pkgs.bc}/bin/bc) == "1"  ]; then
+          echo "kernel.shmmax too low, setting to 1GB"
+          ${pkgs.procps}/bin/sysctl -w kernel.shmmax=1073741824
+        fi
+        if [ $(echo "$(cat /proc/sys/net/core/rmem_max) < 15728640" | ${pkgs.bc}/bin/bc) == "1" ]; then
+          echo "increasing socket buffer limit (/proc/sys/net/core/rmem_max): $(cat /proc/sys/net/core/rmem_max) -> 15728640"
+          echo 15728640 > /proc/sys/net/core/rmem_max
+        fi
+        if [ $(echo "$(cat /proc/sys/net/core/wmem_max) <  5242880" | ${pkgs.bc}/bin/bc) == "1"  ]; then
+          echo "increasing socket buffer limit (/proc/sys/net/core/wmem_max): $(cat /proc/sys/net/core/wmem_max) -> 5242880"
+          echo  5242880 > /proc/sys/net/core/wmem_max
+        fi
+        install -d -m0700 -o ${serviceConfig.User} -g ${serviceConfig.Group} "${cfg.workDir}"
+        install -d -m0700 -o ${serviceConfig.User} -g ${serviceConfig.Group} "${cfg.workDir}/smd"
+        install -d -m0700 -o ${serviceConfig.User} -g ${serviceConfig.Group} "${cfg.workDir}/udf"
+        install -d -m0700 -o ${serviceConfig.User} -g ${serviceConfig.Group} "${cfg.workDir}/udf/lua"
+      '';
+    };
+
+  };
+
+}
diff --git a/nixos/modules/services/databases/cassandra.nix b/nixos/modules/services/databases/cassandra.nix
index 1e5cd8f54130..09b3fbd8a62a 100644
--- a/nixos/modules/services/databases/cassandra.nix
+++ b/nixos/modules/services/databases/cassandra.nix
@@ -420,7 +420,7 @@ in {
       9160
     ];
 
-    users.extraUsers.cassandra =
+    users.users.cassandra =
       if config.ids.uids ? "cassandra"
       then { uid = config.ids.uids.cassandra; } // cassandraUser
       else cassandraUser ;
diff --git a/nixos/modules/services/databases/clickhouse.nix b/nixos/modules/services/databases/clickhouse.nix
index 631d7f8cba79..1b8771cec391 100644
--- a/nixos/modules/services/databases/clickhouse.nix
+++ b/nixos/modules/services/databases/clickhouse.nix
@@ -27,14 +27,14 @@ with lib;
 
   config = mkIf cfg.enable {
 
-    users.extraUsers.clickhouse = {
+    users.users.clickhouse = {
       name = "clickhouse";
       uid = config.ids.uids.clickhouse;
       group = "clickhouse";
       description = "ClickHouse server user";
     };
 
-    users.extraGroups.clickhouse.gid = config.ids.gids.clickhouse;
+    users.groups.clickhouse.gid = config.ids.gids.clickhouse;
 
     systemd.services.clickhouse = {
       description = "ClickHouse server";
diff --git a/nixos/modules/services/databases/couchdb.nix b/nixos/modules/services/databases/couchdb.nix
index 52247bfb983e..ca89b1198205 100644
--- a/nixos/modules/services/databases/couchdb.nix
+++ b/nixos/modules/services/databases/couchdb.nix
@@ -198,13 +198,13 @@ in {
       };
     };
 
-    users.extraUsers.couchdb = {
+    users.users.couchdb = {
       description = "CouchDB Server user";
       group = "couchdb";
       uid = config.ids.uids.couchdb;
     };
 
-    users.extraGroups.couchdb.gid = config.ids.gids.couchdb;
+    users.groups.couchdb.gid = config.ids.gids.couchdb;
 
   };
 }
diff --git a/nixos/modules/services/databases/firebird.nix b/nixos/modules/services/databases/firebird.nix
index b9f66612d4eb..cc81b440450b 100644
--- a/nixos/modules/services/databases/firebird.nix
+++ b/nixos/modules/services/databases/firebird.nix
@@ -154,13 +154,13 @@ in
       # there are some additional settings which should be reviewed
     '';
 
-    users.extraUsers.firebird = {
+    users.users.firebird = {
       description = "Firebird server user";
       group = "firebird";
       uid = config.ids.uids.firebird;
     };
 
-    users.extraGroups.firebird.gid = config.ids.gids.firebird;
+    users.groups.firebird.gid = config.ids.gids.firebird;
 
   };
 }
diff --git a/nixos/modules/services/databases/foundationdb.nix b/nixos/modules/services/databases/foundationdb.nix
index 693d2fde9916..91337cf791dc 100644
--- a/nixos/modules/services/databases/foundationdb.nix
+++ b/nixos/modules/services/databases/foundationdb.nix
@@ -325,14 +325,14 @@ in
 
     environment.systemPackages = [ pkg ];
 
-    users.extraUsers = optionalAttrs (cfg.user == "foundationdb") (singleton
+    users.users = optionalAttrs (cfg.user == "foundationdb") (singleton
       { name        = "foundationdb";
         description = "FoundationDB User";
         uid         = config.ids.uids.foundationdb;
         group       = cfg.group;
       });
 
-    users.extraGroups = optionalAttrs (cfg.group == "foundationdb") (singleton
+    users.groups = optionalAttrs (cfg.group == "foundationdb") (singleton
       { name = "foundationdb";
         gid  = config.ids.gids.foundationdb;
       });
diff --git a/nixos/modules/services/databases/hbase.nix b/nixos/modules/services/databases/hbase.nix
index 629d02209a9c..4772e897efe2 100644
--- a/nixos/modules/services/databases/hbase.nix
+++ b/nixos/modules/services/databases/hbase.nix
@@ -122,13 +122,13 @@ in {
       };
     };
 
-    users.extraUsers.hbase = {
+    users.users.hbase = {
       description = "HBase Server user";
       group = "hbase";
       uid = config.ids.uids.hbase;
     };
 
-    users.extraGroups.hbase.gid = config.ids.gids.hbase;
+    users.groups.hbase.gid = config.ids.gids.hbase;
 
   };
 }
diff --git a/nixos/modules/services/databases/influxdb.nix b/nixos/modules/services/databases/influxdb.nix
index 15b711f57b13..d7a028b25d8d 100644
--- a/nixos/modules/services/databases/influxdb.nix
+++ b/nixos/modules/services/databases/influxdb.nix
@@ -182,13 +182,13 @@ in
         '';
     };
 
-    users.extraUsers = optional (cfg.user == "influxdb") {
+    users.users = optional (cfg.user == "influxdb") {
       name = "influxdb";
       uid = config.ids.uids.influxdb;
       description = "Influxdb daemon user";
     };
 
-    users.extraGroups = optional (cfg.group == "influxdb") {
+    users.groups = optional (cfg.group == "influxdb") {
       name = "influxdb";
       gid = config.ids.gids.influxdb;
     };
diff --git a/nixos/modules/services/databases/memcached.nix b/nixos/modules/services/databases/memcached.nix
index 46bc6fc5c132..7af452e4dced 100644
--- a/nixos/modules/services/databases/memcached.nix
+++ b/nixos/modules/services/databases/memcached.nix
@@ -64,7 +64,7 @@ in
 
   config = mkIf config.services.memcached.enable {
 
-    users.extraUsers = optional (cfg.user == "memcached") {
+    users.users = optional (cfg.user == "memcached") {
       name = "memcached";
       description = "Memcached server user";
     };
diff --git a/nixos/modules/services/databases/mongodb.nix b/nixos/modules/services/databases/mongodb.nix
index 78dbf0d784cf..4c46d9228e5f 100644
--- a/nixos/modules/services/databases/mongodb.nix
+++ b/nixos/modules/services/databases/mongodb.nix
@@ -93,7 +93,7 @@ in
 
   config = mkIf config.services.mongodb.enable {
 
-    users.extraUsers.mongodb = mkIf (cfg.user == "mongodb")
+    users.users.mongodb = mkIf (cfg.user == "mongodb")
       { name = "mongodb";
         uid = config.ids.uids.mongodb;
         description = "MongoDB server user";
diff --git a/nixos/modules/services/databases/mysql.nix b/nixos/modules/services/databases/mysql.nix
index 66c9330c3550..3eb7879e2d9f 100644
--- a/nixos/modules/services/databases/mysql.nix
+++ b/nixos/modules/services/databases/mysql.nix
@@ -221,18 +221,20 @@ in
       mkDefault (if versionAtLeast config.system.nixos.stateVersion "17.09" then "/var/lib/mysql"
                  else "/var/mysql");
 
-    users.extraUsers.mysql = {
+    users.users.mysql = {
       description = "MySQL server user";
       group = "mysql";
       uid = config.ids.uids.mysql;
     };
 
-    users.extraGroups.mysql.gid = config.ids.gids.mysql;
+    users.groups.mysql.gid = config.ids.gids.mysql;
 
     environment.systemPackages = [mysql];
 
-    systemd.services.mysql =
-      { description = "MySQL Server";
+    systemd.services.mysql = let
+      hasNotify = (cfg.package == pkgs.mariadb);
+    in {
+        description = "MySQL Server";
 
         after = [ "network.target" ];
         wantedBy = [ "multi-user.target" ];
@@ -256,17 +258,16 @@ in
 
             mkdir -m 0755 -p ${cfg.pidDir}
             chown -R ${cfg.user} ${cfg.pidDir}
-
-            # Make the socket directory
-            mkdir -p /run/mysqld
-            chmod 0755 /run/mysqld
-            chown -R ${cfg.user} /run/mysqld
           '';
 
-        serviceConfig.ExecStart = "${mysql}/bin/mysqld --defaults-extra-file=${myCnf} ${mysqldOptions}";
+        serviceConfig = {
+          Type = if hasNotify then "notify" else "simple";
+          RuntimeDirectory = "mysqld";
+          ExecStart = "${mysql}/bin/mysqld --defaults-extra-file=${myCnf} ${mysqldOptions}";
+        };
 
-        postStart =
-          ''
+        postStart = ''
+          ${lib.optionalString (!hasNotify) ''
             # Wait until the MySQL server is available for use
             count=0
             while [ ! -e /run/mysqld/mysqld.sock ]
@@ -281,6 +282,7 @@ in
                 count=$((count++))
                 sleep 1
             done
+          ''}
 
             if [ -f /tmp/mysql_init ]
             then
diff --git a/nixos/modules/services/databases/neo4j.nix b/nixos/modules/services/databases/neo4j.nix
index 424e08a6ee34..5533182c3116 100644
--- a/nixos/modules/services/databases/neo4j.nix
+++ b/nixos/modules/services/databases/neo4j.nix
@@ -1,32 +1,87 @@
-{ config, lib, pkgs, ... }:
+{ config, options, lib, pkgs, ... }:
 
 with lib;
 
 let
   cfg = config.services.neo4j;
+  certDirOpt = options.services.neo4j.directories.certificates;
+  isDefaultPathOption = opt: isOption opt && opt.type == types.path && opt.highestPrio >= 1500;
+
+  sslPolicies = mapAttrsToList (
+    name: conf: ''
+      dbms.ssl.policy.${name}.allow_key_generation=${boolToString conf.allowKeyGeneration}
+      dbms.ssl.policy.${name}.base_directory=${conf.baseDirectory}
+      ${optionalString (conf.ciphers != null) ''
+        dbms.ssl.policy.${name}.ciphers=${concatStringsSep "," conf.ciphers}
+      ''}
+      dbms.ssl.policy.${name}.client_auth=${conf.clientAuth}
+      ${if length (splitString "/" conf.privateKey) > 1 then
+        ''dbms.ssl.policy.${name}.private_key=${conf.privateKey}''
+      else
+        ''dbms.ssl.policy.${name}.private_key=${conf.baseDirectory}/${conf.privateKey}''
+      }
+      ${if length (splitString "/" conf.privateKey) > 1 then
+        ''dbms.ssl.policy.${name}.public_certificate=${conf.publicCertificate}''
+      else
+        ''dbms.ssl.policy.${name}.public_certificate=${conf.baseDirectory}/${conf.publicCertificate}''
+      }
+      dbms.ssl.policy.${name}.revoked_dir=${conf.revokedDir}
+      dbms.ssl.policy.${name}.tls_versions=${concatStringsSep "," conf.tlsVersions}
+      dbms.ssl.policy.${name}.trust_all=${boolToString conf.trustAll}
+      dbms.ssl.policy.${name}.trusted_dir=${conf.trustedDir}
+    ''
+  ) cfg.ssl.policies;
 
   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}
+    # General
+    dbms.allow_upgrade=${boolToString cfg.allowUpgrade}
+    dbms.connectors.default_listen_address=${cfg.defaultListenAddress}
+    dbms.read_only=${boolToString cfg.readOnly}
+    ${optionalString (cfg.workerCount > 0) ''
+      dbms.threads.worker_count=${toString cfg.workerCount}
     ''}
-    ${optionalString cfg.enableHttps ''
-      dbms.connector.https.type=HTTP
-      dbms.connector.https.enabled=true
-      dbms.connector.https.encryption=TLS
-      dbms.connector.https.address=${cfg.listenAddress}:${toString cfg.httpsPort}
+
+    # Directories
+    dbms.directories.certificates=${cfg.directories.certificates}
+    dbms.directories.data=${cfg.directories.data}
+    dbms.directories.logs=${cfg.directories.home}/logs
+    dbms.directories.plugins=${cfg.directories.plugins}
+    ${optionalString (cfg.constrainLoadCsv) ''
+      dbms.directories.import=${cfg.directories.imports}
     ''}
-    dbms.shell.enabled=true
-    ${cfg.extraServerConfig}
+
+    # HTTP Connector
+    ${optionalString (cfg.http.enable) ''
+      dbms.connector.http.enabled=${boolToString cfg.http.enable}
+      dbms.connector.http.listen_address=${cfg.http.listenAddress}
+    ''}
+    ${optionalString (!cfg.http.enable) ''
+      # It is not possible to disable the HTTP connector. To fully prevent
+      # clients from connecting to HTTP, block the HTTP port (7474 by default)
+      # via firewall. listen_address is set to the loopback interface to
+      # prevent remote clients from connecting.
+      dbms.connector.http.listen_address=127.0.0.1
+    ''}
+
+    # HTTPS Connector
+    dbms.connector.https.enabled=${boolToString cfg.https.enable}
+    dbms.connector.https.listen_address=${cfg.https.listenAddress}
+    https.ssl_policy=${cfg.https.sslPolicy}
+
+    # BOLT Connector
+    dbms.connector.bolt.enabled=${boolToString cfg.bolt.enable}
+    dbms.connector.bolt.listen_address=${cfg.bolt.listenAddress}
+    bolt.ssl_policy=${cfg.bolt.sslPolicy}
+    dbms.connector.bolt.tls_level=${cfg.bolt.tlsLevel}
+
+    # neo4j-shell
+    dbms.shell.enabled=${boolToString cfg.shell.enable}
+
+    # SSL Policies
+    ${concatStringsSep "\n" sslPolicies}
+
+    # Default retention policy from neo4j.conf
+    dbms.tx_log.rotation.retention_policy=1 days
 
     # Default JVM parameters from neo4j.conf
     dbms.jvm.additional=-XX:+UseG1GC
@@ -36,8 +91,14 @@ let
     dbms.jvm.additional=-XX:+TrustFinalNonStaticFields
     dbms.jvm.additional=-XX:+DisableExplicitGC
     dbms.jvm.additional=-Djdk.tls.ephemeralDHKeySize=2048
-
+    dbms.jvm.additional=-Djdk.tls.rejectClientInitiatedRenegotiation=true
     dbms.jvm.additional=-Dunsupported.dbms.udc.source=tarball
+
+    # Usage Data Collector
+    dbms.udc.enabled=${boolToString cfg.udc.enable}
+
+    # Extra Configuration
+    ${cfg.extraServerConfig}
   '';
 
 in {
@@ -45,105 +106,547 @@ in {
   ###### interface
 
   options.services.neo4j = {
+
     enable = mkOption {
-      description = "Whether to enable neo4j.";
+      type = types.bool;
       default = false;
+      description = ''
+        Whether to enable Neo4j Community Edition.
+      '';
+    };
+
+    allowUpgrade = mkOption {
       type = types.bool;
+      default = false;
+      description = ''
+        Allow upgrade of Neo4j database files from an older version.
+      '';
+    };
+
+    constrainLoadCsv = mkOption {
+      type = types.bool;
+      default = true;
+      description = ''
+        Sets the root directory for file URLs used with the Cypher
+        <literal>LOAD CSV</literal> clause to be that defined by
+        <option>directories.imports</option>. It restricts
+        access to only those files within that directory and its
+        subdirectories.
+        </para>
+        <para>
+        Setting this option to <literal>false</literal> introduces
+        possible security problems.
+      '';
+    };
+
+    defaultListenAddress = mkOption {
+      type = types.str;
+      default = "127.0.0.1";
+      description = ''
+        Default network interface to listen for incoming connections. To
+        listen for connections on all interfaces, use "0.0.0.0".
+        </para>
+        <para>
+        Specifies the default IP address and address part of connector
+        specific <option>listenAddress</option> options. To bind specific
+        connectors to a specific network interfaces, specify the entire
+        <option>listenAddress</option> option for that connector.
+      '';
+    };
+
+    extraServerConfig = mkOption {
+      type = types.lines;
+      default = "";
+      description = ''
+        Extra configuration for Neo4j Community server. Refer to the
+        <link xlink:href="https://neo4j.com/docs/operations-manual/current/reference/configuration-settings/">complete reference</link>
+        of Neo4j configuration settings.
+      '';
     };
 
     package = mkOption {
-      description = "Neo4j package to use.";
+      type = types.package;
       default = pkgs.neo4j;
       defaultText = "pkgs.neo4j";
-      type = types.package;
+      description = ''
+        Neo4j package to use.
+      '';
     };
 
-    listenAddress = mkOption {
-      description = "Neo4j listen address.";
-      default = "127.0.0.1";
-      type = types.str;
+    readOnly = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Only allow read operations from this Neo4j instance.
+      '';
     };
 
-    port = mkOption {
-      description = "Neo4j port to listen for HTTP traffic.";
-      default = 7474;
-      type = types.int;
+    workerCount = mkOption {
+      type = types.ints.between 0 44738;
+      default = 0;
+      description = ''
+        Number of Neo4j worker threads, where the default of
+        <literal>0</literal> indicates a worker count equal to the number of
+        available processors.
+      '';
     };
 
-    enableBolt = mkOption {
-      description = "Enable bolt for Neo4j.";
-      default = true;
-      type = types.bool;
+    bolt = {
+      enable = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Enable the BOLT connector for Neo4j. Setting this option to
+          <literal>false</literal> will stop Neo4j from listening for incoming
+          connections on the BOLT port (7687 by default).
+        '';
+      };
+
+      listenAddress = mkOption {
+        type = types.str;
+        default = ":7687";
+        description = ''
+          Neo4j listen address for BOLT traffic. The listen address is
+          expressed in the format <literal>&lt;ip-address&gt;:&lt;port-number&gt;</literal>.
+        '';
+      };
+
+      sslPolicy = mkOption {
+        type = types.str;
+        default = "legacy";
+        description = ''
+          Neo4j SSL policy for BOLT traffic.
+          </para>
+          <para>
+          The legacy policy is a special policy which is not defined in
+          the policy configuration section, but rather derives from
+          <option>directories.certificates</option> and
+          associated files (by default: <filename>neo4j.key</filename> and
+          <filename>neo4j.cert</filename>). Its use will be deprecated.
+          </para>
+          <para>
+          Note: This connector must be configured to support/require
+          SSL/TLS for the legacy policy to actually be utilized. See
+          <option>bolt.tlsLevel</option>.
+        '';
+      };
+
+      tlsLevel = mkOption {
+        type = types.enum [ "REQUIRED" "OPTIONAL" "DISABLED" ];
+        default = "OPTIONAL";
+        description = ''
+          SSL/TSL requirement level for BOLT traffic.
+        '';
+      };
     };
 
-    boltPort = mkOption {
-      description = "Neo4j port to listen for BOLT traffic.";
-      default = 7687;
-      type = types.int;
+    directories = {
+      certificates = mkOption {
+        type = types.path;
+        default = "${cfg.directories.home}/certificates";
+        description = ''
+          Directory for storing certificates to be used by Neo4j for
+          TLS connections.
+          </para>
+          <para>
+          When setting this directory to something other than its default,
+          ensure the directory's existence, and that read/write permissions are
+          given to the Neo4j daemon user <literal>neo4j</literal>.
+          </para>
+          <para>
+          Note that changing this directory from its default will prevent
+          the directory structure required for each SSL policy from being
+          automatically generated. A policy's directory structure as defined by
+          its <option>baseDirectory</option>,<option>revokedDir</option> and
+          <option>trustedDir</option> must then be setup manually. The
+          existence of these directories is mandatory, as well as the presence
+          of the certificate file and the private key. Ensure the correct
+          permissions are set on these directories and files.
+        '';
+      };
+
+      data = mkOption {
+        type = types.path;
+        default = "${cfg.directories.home}/data";
+        description = ''
+          Path of the data directory. You must not configure more than one
+          Neo4j installation to use the same data directory.
+          </para>
+          <para>
+          When setting this directory to something other than its default,
+          ensure the directory's existence, and that read/write permissions are
+          given to the Neo4j daemon user <literal>neo4j</literal>.
+        '';
+      };
+
+      home = mkOption {
+        type = types.path;
+        default = "/var/lib/neo4j";
+        description = ''
+          Path of the Neo4j home directory. Other default directories are
+          subdirectories of this path. This directory will be created if
+          non-existent, and its ownership will be <command>chown</command> to
+          the Neo4j daemon user <literal>neo4j</literal>.
+        '';
+      };
+
+      imports = mkOption {
+        type = types.path;
+        default = "${cfg.directories.home}/import";
+        description = ''
+          The root directory for file URLs used with the Cypher
+          <literal>LOAD CSV</literal> clause. Only meaningful when
+          <option>constrainLoadCvs</option> is set to
+          <literal>true</literal>.
+          </para>
+          <para>
+          When setting this directory to something other than its default,
+          ensure the directory's existence, and that read permission is
+          given to the Neo4j daemon user <literal>neo4j</literal>.
+        '';
+      };
+
+      plugins = mkOption {
+        type = types.path;
+        default = "${cfg.directories.home}/plugins";
+        description = ''
+          Path of the database plugin directory. Compiled Java JAR files that
+          contain database procedures will be loaded if they are placed in
+          this directory.
+          </para>
+          <para>
+          When setting this directory to something other than its default,
+          ensure the directory's existence, and that read permission is
+          given to the Neo4j daemon user <literal>neo4j</literal>.
+        '';
+      };
     };
 
-    enableHttps = mkOption {
-      description = "Enable https for Neo4j.";
-      default = false;
-      type = types.bool;
+    http = {
+      enable = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          The HTTP connector is required for Neo4j, and cannot be disabled.
+          Setting this option to <literal>false</literal> will force the HTTP
+          connector's <option>listenAddress</option> to the loopback
+          interface to prevent connection of remote clients. To prevent all
+          clients from connecting, block the HTTP port (7474 by default) by
+          firewall.
+        '';
+      };
+
+      listenAddress = mkOption {
+        type = types.str;
+        default = ":7474";
+        description = ''
+          Neo4j listen address for HTTP traffic. The listen address is
+          expressed in the format <literal>&lt;ip-address&gt;:&lt;port-number&gt;</literal>.
+        '';
+      };
     };
 
-    httpsPort = mkOption {
-      description = "Neo4j port to listen for HTTPS traffic.";
-      default = 7473;
-      type = types.int;
+    https = {
+      enable = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Enable the HTTPS connector for Neo4j. Setting this option to
+          <literal>false</literal> will stop Neo4j from listening for incoming
+          connections on the HTTPS port (7473 by default).
+        '';
+      };
+
+      listenAddress = mkOption {
+        type = types.str;
+        default = ":7473";
+        description = ''
+          Neo4j listen address for HTTPS traffic. The listen address is
+          expressed in the format <literal>&lt;ip-address&gt;:&lt;port-number&gt;</literal>.
+        '';
+      };
+
+      sslPolicy = mkOption {
+        type = types.str;
+        default = "legacy";
+        description = ''
+          Neo4j SSL policy for HTTPS traffic.
+          </para>
+          <para>
+          The legacy policy is a special policy which is not defined in the
+          policy configuration section, but rather derives from
+          <option>directories.certificates</option> and
+          associated files (by default: <filename>neo4j.key</filename> and
+          <filename>neo4j.cert</filename>). Its use will be deprecated.
+        '';
+      };
     };
 
-    certDir = mkOption {
-      description = "Neo4j TLS certificates directory.";
-      default = "${cfg.dataDir}/certificates";
-      type = types.path;
+    shell = {
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Enable a remote shell server which Neo4j Shell clients can log in to.
+          Only applicable to <command>neo4j-shell</command>.
+        '';
+      };
     };
 
-    dataDir = mkOption {
-      description = "Neo4j data directory.";
-      default = "/var/lib/neo4j";
-      type = types.path;
+    ssl.policies = mkOption {
+      type = with types; attrsOf (submodule ({ name, config, options, ... }: {
+        options = {
+
+          allowKeyGeneration = mkOption {
+            type = types.bool;
+            default = false;
+            description = ''
+              Allows the generation of a private key and associated self-signed
+              certificate. Only performed when both objects cannot be found for
+              this policy. It is recommended to turn this off again after keys
+              have been generated.
+              </para>
+              <para>
+              The public certificate is required to be duplicated to the
+              directory holding trusted certificates as defined by the
+              <option>trustedDir</option> option.
+              </para>
+              <para>
+              Keys should in general be generated and distributed offline by a
+              trusted certificate authority and not by utilizing this mode.
+            '';
+          };
+
+          baseDirectory = mkOption {
+            type = types.path;
+            default = "${cfg.directories.certificates}/${name}";
+            description = ''
+              The mandatory base directory for cryptographic objects of this
+              policy. This path is only automatically generated when this
+              option as well as <option>directories.certificates</option> are
+              left at their default. Ensure read/write permissions are given
+              to the Neo4j daemon user <literal>neo4j</literal>.
+              </para>
+              <para>
+              It is also possible to override each individual
+              configuration with absolute paths. See the
+              <option>privateKey</option> and <option>publicCertificate</option>
+              policy options.
+            '';
+          };
+
+          ciphers = mkOption {
+            type = types.nullOr (types.listOf types.str);
+            default = null;
+            description = ''
+              Restrict the allowed ciphers of this policy to those defined
+              here. The default ciphers are those of the JVM platform.
+            '';
+          };
+
+          clientAuth = mkOption {
+            type = types.enum [ "NONE" "OPTIONAL" "REQUIRE" ];
+            default = "REQUIRE";
+            description = ''
+              The client authentication stance for this policy.
+            '';
+          };
+
+          privateKey = mkOption {
+            type = types.str;
+            default = "private.key";
+            description = ''
+              The name of private PKCS #8 key file for this policy to be found
+              in the <option>baseDirectory</option>, or the absolute path to
+              the key file. It is mandatory that a key can be found or generated.
+            '';
+          };
+
+          publicCertificate = mkOption {
+            type = types.str;
+            default = "public.crt";
+            description = ''
+              The name of public X.509 certificate (chain) file in PEM format
+              for this policy to be found in the <option>baseDirectory</option>,
+              or the absolute path to the certificate file. It is mandatory
+              that a certificate can be found or generated.
+              </para>
+              <para>
+              The public certificate is required to be duplicated to the
+              directory holding trusted certificates as defined by the
+              <option>trustedDir</option> option.
+            '';
+          };
+
+          revokedDir = mkOption {
+            type = types.path;
+            default = "${config.baseDirectory}/revoked";
+            description = ''
+              Path to directory of CRLs (Certificate Revocation Lists) in
+              PEM format. Must be an absolute path. The existence of this
+              directory is mandatory and will need to be created manually when:
+              setting this option to something other than its default; setting
+              either this policy's <option>baseDirectory</option> or
+              <option>directories.certificates</option> to something other than
+              their default. Ensure read/write permissions are given to the
+              Neo4j daemon user <literal>neo4j</literal>.
+            '';
+          };
+
+          tlsVersions = mkOption {
+            type = types.listOf types.str;
+            default = [ "TLSv1.2" ];
+            description = ''
+              Restrict the TLS protocol versions of this policy to those
+              defined here.
+            '';
+          };
+
+          trustAll = mkOption {
+            type = types.bool;
+            default = false;
+            description = ''
+              Makes this policy trust all remote parties. Enabling this is not
+              recommended and the policy's trusted directory will be ignored.
+              Use of this mode is discouraged. It would offer encryption but
+              no security.
+            '';
+          };
+
+          trustedDir = mkOption {
+            type = types.path;
+            default = "${config.baseDirectory}/trusted";
+            description = ''
+              Path to directory of X.509 certificates in PEM format for
+              trusted parties. Must be an absolute path. The existence of this
+              directory is mandatory and will need to be created manually when:
+              setting this option to something other than its default; setting
+              either this policy's <option>baseDirectory</option> or
+              <option>directories.certificates</option> to something other than
+              their default. Ensure read/write permissions are given to the
+              Neo4j daemon user <literal>neo4j</literal>.
+              </para>
+              <para>
+              The public certificate as defined by
+              <option>publicCertificate</option> is required to be duplicated
+              to this directory.
+            '';
+          };
+
+          directoriesToCreate = mkOption {
+            type = types.listOf types.path;
+            internal = true;
+            readOnly = true;
+            description = ''
+              Directories of this policy that will be created automatically
+              when the certificates directory is left at its default value.
+              This includes all options of type path that are left at their
+              default value.
+            '';
+          };
+
+        };
+
+        config.directoriesToCreate = optionals
+          (certDirOpt.highestPrio >= 1500 && options.baseDirectory.highestPrio >= 1500)
+          (map (opt: opt.value) (filter isDefaultPathOption (attrValues options)));
+
+      }));
+      default = {};
+      description = ''
+        Defines the SSL policies for use with Neo4j connectors. Each attribute
+        of this set defines a policy, with the attribute name defining the name
+        of the policy and its namespace. Refer to the operations manual section
+        on Neo4j's
+        <link xlink:href="https://neo4j.com/docs/operations-manual/current/security/ssl-framework/">SSL Framework</link>
+        for further details.
+      '';
     };
 
-    extraServerConfig = mkOption {
-      description = "Extra configuration for neo4j server.";
-      default = "";
-      type = types.lines;
+    udc = {
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Enable the Usage Data Collector which Neo4j uses to collect usage
+          data. Refer to the operations manual section on the
+          <link xlink:href="https://neo4j.com/docs/operations-manual/current/configuration/usage-data-collector/">Usage Data Collector</link>
+          for more information.
+        '';
+      };
     };
+
   };
 
   ###### implementation
 
-  config = mkIf cfg.enable {
-    systemd.services.neo4j = {
-      description = "Neo4j Daemon";
-      wantedBy = [ "multi-user.target" ];
-      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;
-        LimitNOFILE = 40000;
-      };
-      preStart = ''
-        mkdir -m 0700 -p ${cfg.dataDir}/{data/graph.db,conf,logs}
-        ln -fs ${serverConfig} ${cfg.dataDir}/conf/neo4j.conf
-        if [ "$(id -u)" = 0 ]; then chown -R neo4j ${cfg.dataDir}; fi
-      '';
-    };
+  config =
+    let
+      # Assertion helpers
+      policyNameList = attrNames cfg.ssl.policies;
+      validPolicyNameList = [ "legacy" ] ++ policyNameList;
+      validPolicyNameString = concatStringsSep ", " validPolicyNameList;
+
+      # Capture various directories left at their default so they can be created.
+      defaultDirectoriesToCreate = map (opt: opt.value) (filter isDefaultPathOption (attrValues options.services.neo4j.directories));
+      policyDirectoriesToCreate = concatMap (pol: pol.directoriesToCreate) (attrValues cfg.ssl.policies);
+    in
+
+    mkIf cfg.enable {
+      assertions = [
+        { assertion = !elem "legacy" policyNameList;
+          message = "The policy 'legacy' is special to Neo4j, and its name is reserved."; }
+        { assertion = elem cfg.bolt.sslPolicy validPolicyNameList;
+          message = "Invalid policy assigned: `services.neo4j.bolt.sslPolicy = \"${cfg.bolt.sslPolicy}\"`, defined policies are: ${validPolicyNameString}"; }
+        { assertion = elem cfg.https.sslPolicy validPolicyNameList;
+          message = "Invalid policy assigned: `services.neo4j.https.sslPolicy = \"${cfg.https.sslPolicy}\"`, defined policies are: ${validPolicyNameString}"; }
+      ];
+
+      systemd.services.neo4j = {
+        description = "Neo4j Daemon";
+        wantedBy = [ "multi-user.target" ];
+        after = [ "network.target" ];
+        environment = {
+          NEO4J_HOME = "${cfg.package}/share/neo4j";
+          NEO4J_CONF = "${cfg.directories.home}/conf";
+        };
+        serviceConfig = {
+          ExecStart = "${cfg.package}/bin/neo4j console";
+          User = "neo4j";
+          PermissionsStartOnly = true;
+          LimitNOFILE = 40000;
+        };
+
+        preStart = ''
+          # Directories Setup
+          #   Always ensure home exists with nested conf, logs directories.
+          mkdir -m 0700 -p ${cfg.directories.home}/{conf,logs}
 
-    environment.systemPackages = [ cfg.package ];
+          #   Create other sub-directories and policy directories that have been left at their default.
+          ${concatMapStringsSep "\n" (
+            dir: ''
+              mkdir -m 0700 -p ${dir}
+          '') (defaultDirectoriesToCreate ++ policyDirectoriesToCreate)}
 
-    users.extraUsers = singleton {
-      name = "neo4j";
-      uid = config.ids.uids.neo4j;
-      description = "Neo4j daemon user";
-      home = cfg.dataDir;
+          # Place the configuration where Neo4j can find it.
+          ln -fs ${serverConfig} ${cfg.directories.home}/conf/neo4j.conf
+
+          # Ensure neo4j user ownership
+          chown -R neo4j ${cfg.directories.home}
+        '';
+      };
+
+      environment.systemPackages = [ cfg.package ];
+
+      users.users = singleton {
+        name = "neo4j";
+        uid = config.ids.uids.neo4j;
+        description = "Neo4j daemon user";
+        home = cfg.directories.home;
+      };
     };
+
+  meta = {
+    maintainers = with lib.maintainers; [ patternspandemic ];
   };
 }
diff --git a/nixos/modules/services/databases/openldap.nix b/nixos/modules/services/databases/openldap.nix
index a67c61eb9949..9f2bf5ef8a9c 100644
--- a/nixos/modules/services/databases/openldap.nix
+++ b/nixos/modules/services/databases/openldap.nix
@@ -145,13 +145,13 @@ in
           "${configOpts}";
     };
 
-    users.extraUsers.openldap =
+    users.users.openldap =
       { name = cfg.user;
         group = cfg.group;
         uid = config.ids.uids.openldap;
       };
 
-    users.extraGroups.openldap =
+    users.groups.openldap =
       { name = cfg.group;
         gid = config.ids.gids.openldap;
       };
diff --git a/nixos/modules/services/databases/opentsdb.nix b/nixos/modules/services/databases/opentsdb.nix
index 489cdcffe658..b26fa9093ef4 100644
--- a/nixos/modules/services/databases/opentsdb.nix
+++ b/nixos/modules/services/databases/opentsdb.nix
@@ -97,13 +97,13 @@ in {
       };
     };
 
-    users.extraUsers.opentsdb = {
+    users.users.opentsdb = {
       description = "OpenTSDB Server user";
       group = "opentsdb";
       uid = config.ids.uids.opentsdb;
     };
 
-    users.extraGroups.opentsdb.gid = config.ids.gids.opentsdb;
+    users.groups.opentsdb.gid = config.ids.gids.opentsdb;
 
   };
 }
diff --git a/nixos/modules/services/databases/pgmanage.nix b/nixos/modules/services/databases/pgmanage.nix
index d1b48c06440e..1a34c7f5ecee 100644
--- a/nixos/modules/services/databases/pgmanage.nix
+++ b/nixos/modules/services/databases/pgmanage.nix
@@ -41,7 +41,9 @@ let
 
   pgmanage = "pgmanage";
 
-  pgmanageOptions = {
+in {
+
+  options.services.pgmanage = {
     enable = mkEnableOption "PostgreSQL Administration for the web";
 
     package = mkOption {
@@ -176,47 +178,29 @@ let
     };
   };
 
-
-in {
-
-  options.services.pgmanage = pgmanageOptions;
-
-  # This is deprecated and should be removed for NixOS-18.03.
-  options.services.postage = pgmanageOptions;
-
-  config = mkMerge [
-    { assertions = [
-        { assertion = !config.services.postage.enable;
-          message =
-            "services.postage is deprecated in favour of pgmanage. " +
-            "They have the same options so just substitute postage for pgmanage." ;
-        }
-      ];
-    }
-    (mkIf cfg.enable {
-      systemd.services.pgmanage = {
-        description = "pgmanage - PostgreSQL Administration for the web";
-        wants    = [ "postgresql.service" ];
-        after    = [ "postgresql.service" ];
-        wantedBy = [ "multi-user.target" ];
-        serviceConfig = {
-          User         = pgmanage;
-          Group        = pgmanage;
-          ExecStart    = "${pkgs.pgmanage}/sbin/pgmanage -c ${confFile}" +
-                         optionalString cfg.localOnly " --local-only=true";
-        };
+  config = mkIf cfg.enable {
+    systemd.services.pgmanage = {
+      description = "pgmanage - PostgreSQL Administration for the web";
+      wants    = [ "postgresql.service" ];
+      after    = [ "postgresql.service" ];
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        User         = pgmanage;
+        Group        = pgmanage;
+        ExecStart    = "${pkgs.pgmanage}/sbin/pgmanage -c ${confFile}" +
+                       optionalString cfg.localOnly " --local-only=true";
       };
-      users = {
-        users."${pgmanage}" = {
-          name  = pgmanage;
-          group = pgmanage;
-          home  = cfg.sqlRoot;
-          createHome = true;
-        };
-        groups."${pgmanage}" = {
-          name = pgmanage;
-        };
+    };
+    users = {
+      users."${pgmanage}" = {
+        name  = pgmanage;
+        group = pgmanage;
+        home  = cfg.sqlRoot;
+        createHome = true;
       };
-    })
-  ];
+      groups."${pgmanage}" = {
+        name = pgmanage;
+      };
+    };
+  };
 }
diff --git a/nixos/modules/services/databases/postgresql.nix b/nixos/modules/services/databases/postgresql.nix
index 4ad4728ccda6..e33bee9db6e9 100644
--- a/nixos/modules/services/databases/postgresql.nix
+++ b/nixos/modules/services/databases/postgresql.nix
@@ -24,14 +24,13 @@ let
 
   postgresql = postgresqlAndPlugins cfg.package;
 
-  flags = optional cfg.enableTCPIP "-i";
-
   # The main PostgreSQL configuration file.
   configFile = pkgs.writeText "postgresql.conf"
     ''
       hba_file = '${pkgs.writeText "pg_hba.conf" cfg.authentication}'
       ident_file = '${pkgs.writeText "pg_ident.conf" cfg.identMap}'
       log_destination = 'stderr'
+      listen_addresses = '${if cfg.enableTCPIP then "*" else "localhost"}'
       port = ${toString cfg.port}
       ${cfg.extraConfig}
     '';
@@ -184,14 +183,14 @@ in
         host  all all ::1/128      md5
       '';
 
-    users.extraUsers.postgres =
+    users.users.postgres =
       { name = "postgres";
         uid = config.ids.uids.postgres;
         group = "postgres";
         description = "PostgreSQL server user";
       };
 
-    users.extraGroups.postgres.gid = config.ids.gids.postgres;
+    users.groups.postgres.gid = config.ids.gids.postgres;
 
     environment.systemPackages = [ postgresql ];
 
@@ -229,7 +228,7 @@ in
                 "${cfg.dataDir}/recovery.conf"
             ''}
 
-             exec postgres ${toString flags}
+             exec postgres
           '';
 
         serviceConfig =
diff --git a/nixos/modules/services/databases/redis.nix b/nixos/modules/services/databases/redis.nix
index e4e38a4364a0..cc7b51982d1d 100644
--- a/nixos/modules/services/databases/redis.nix
+++ b/nixos/modules/services/databases/redis.nix
@@ -217,7 +217,7 @@ in
       allowedTCPPorts = [ cfg.port ];
     };
 
-    users.extraUsers.redis =
+    users.users.redis =
       { name = cfg.user;
         description = "Redis database user";
       };
diff --git a/nixos/modules/services/databases/rethinkdb.nix b/nixos/modules/services/databases/rethinkdb.nix
index cd8c386b08db..789d9c851d64 100644
--- a/nixos/modules/services/databases/rethinkdb.nix
+++ b/nixos/modules/services/databases/rethinkdb.nix
@@ -96,12 +96,12 @@ in
       '';
     };
 
-    users.extraUsers.rethinkdb = mkIf (cfg.user == "rethinkdb")
+    users.users.rethinkdb = mkIf (cfg.user == "rethinkdb")
       { name = "rethinkdb";
         description = "RethinkDB server user";
       };
 
-    users.extraGroups = optionalAttrs (cfg.group == "rethinkdb") (singleton
+    users.groups = optionalAttrs (cfg.group == "rethinkdb") (singleton
       { name = "rethinkdb";
       });
 
diff --git a/nixos/modules/services/databases/riak-cs.nix b/nixos/modules/services/databases/riak-cs.nix
index 198efc29222a..2cb204f729a7 100644
--- a/nixos/modules/services/databases/riak-cs.nix
+++ b/nixos/modules/services/databases/riak-cs.nix
@@ -145,7 +145,7 @@ in
       ${cfg.extraAdvancedConfig}
     '';
 
-    users.extraUsers.riak-cs = {
+    users.users.riak-cs = {
       name = "riak-cs";
       uid = config.ids.uids.riak-cs;
       group = "riak";
diff --git a/nixos/modules/services/databases/riak.nix b/nixos/modules/services/databases/riak.nix
index e0ebf164aef0..ac086cf55996 100644
--- a/nixos/modules/services/databases/riak.nix
+++ b/nixos/modules/services/databases/riak.nix
@@ -102,14 +102,14 @@ in
       ${cfg.extraAdvancedConfig}
     '';
 
-    users.extraUsers.riak = {
+    users.users.riak = {
       name = "riak";
       uid = config.ids.uids.riak;
       group = "riak";
       description = "Riak server user";
     };
 
-    users.extraGroups.riak.gid = config.ids.gids.riak;
+    users.groups.riak.gid = config.ids.gids.riak;
 
     systemd.services.riak = {
       description = "Riak Server";
diff --git a/nixos/modules/services/databases/stanchion.nix b/nixos/modules/services/databases/stanchion.nix
index a4597cac3cd6..9fe49f51edd2 100644
--- a/nixos/modules/services/databases/stanchion.nix
+++ b/nixos/modules/services/databases/stanchion.nix
@@ -143,14 +143,14 @@ in
       ${cfg.extraConfig}
     '';
 
-    users.extraUsers.stanchion = {
+    users.users.stanchion = {
       name = "stanchion";
       uid = config.ids.uids.stanchion;
       group = "stanchion";
       description = "Stanchion server user";
     };
 
-    users.extraGroups.stanchion.gid = config.ids.gids.stanchion;
+    users.groups.stanchion.gid = config.ids.gids.stanchion;
 
     systemd.services.stanchion = {
       description = "Stanchion Server";
diff --git a/nixos/modules/services/databases/virtuoso.nix b/nixos/modules/services/databases/virtuoso.nix
index 3231fede08fa..6ffc44a5274e 100644
--- a/nixos/modules/services/databases/virtuoso.nix
+++ b/nixos/modules/services/databases/virtuoso.nix
@@ -54,7 +54,7 @@ with lib;
 
   config = mkIf cfg.enable {
 
-    users.extraUsers = singleton
+    users.users = singleton
       { name = virtuosoUser;
         uid = config.ids.uids.virtuoso;
         description = "virtuoso user";
diff --git a/nixos/modules/services/desktops/bamf.nix b/nixos/modules/services/desktops/bamf.nix
new file mode 100644
index 000000000000..0928ee81a648
--- /dev/null
+++ b/nixos/modules/services/desktops/bamf.nix
@@ -0,0 +1,23 @@
+# Bamf
+
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+  ###### interface
+
+  options = {
+    services.bamf = {
+      enable = mkEnableOption "bamf";
+    };
+  };
+
+  ###### implementation
+
+  config = mkIf config.services.bamf.enable {
+    services.dbus.packages = [ pkgs.bamf ];
+
+    systemd.packages = [ pkgs.bamf ];
+  };
+}
diff --git a/nixos/modules/services/desktops/flatpak.nix b/nixos/modules/services/desktops/flatpak.nix
index 024dc65629a8..cfca1893bd82 100644
--- a/nixos/modules/services/desktops/flatpak.nix
+++ b/nixos/modules/services/desktops/flatpak.nix
@@ -40,12 +40,12 @@ in {
 
     systemd.packages = [ pkgs.flatpak pkgs.xdg-desktop-portal ] ++ cfg.extraPortals;
 
-    environment.variables = {
-      PATH = [
-        "$HOME/.local/share/flatpak/exports/bin"
-        "/var/lib/flatpak/exports/bin"
-      ];
+    environment.profiles = [
+      "$HOME/.local/share/flatpak/exports"
+      "/var/lib/flatpak/exports"
+    ];
 
+    environment.variables = {
       XDG_DESKTOP_PORTAL_PATH = map (p: "${p}/share/xdg-desktop-portal/portals") cfg.extraPortals;
     };
   };
diff --git a/nixos/modules/services/desktops/pipewire.nix b/nixos/modules/services/desktops/pipewire.nix
index 263a06156f84..13f3d61e84ca 100644
--- a/nixos/modules/services/desktops/pipewire.nix
+++ b/nixos/modules/services/desktops/pipewire.nix
@@ -3,20 +3,34 @@
 
 with lib;
 
-{
+let
+  cfg = config.services.pipewire;
+  packages = with pkgs; [ pipewire ];
+
+in {
   ###### interface
   options = {
     services.pipewire = {
       enable = mkEnableOption "pipewire service";
+
+      socketActivation = mkOption {
+        default = true;
+        type = types.bool;
+        description = ''
+          Automatically run pipewire when connections are made to the pipewire socket.
+        '';
+      };
     };
   };
 
 
   ###### implementation
-  config = mkIf config.services.pipewire.enable {
-    environment.systemPackages = [ pkgs.pipewire ];
+  config = mkIf cfg.enable {
+    environment.systemPackages = packages;
+
+    systemd.packages = packages;
 
-    systemd.packages = [ pkgs.pipewire ];
+    systemd.user.sockets.pipewire.wantedBy = lib.mkIf cfg.socketActivation [ "sockets.target" ];
   };
 
   meta.maintainers = with lib.maintainers; [ jtojnar ];
diff --git a/nixos/modules/services/development/bloop.nix b/nixos/modules/services/development/bloop.nix
new file mode 100644
index 000000000000..56904b7c40e6
--- /dev/null
+++ b/nixos/modules/services/development/bloop.nix
@@ -0,0 +1,37 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.bloop;
+
+in {
+
+  options.services.bloop = {
+    install = mkOption {
+      type = types.bool;
+      default = false;
+      description = ''
+        Whether to install a user service for the Bloop server.
+
+        The service must be manually started for each user with
+        "systemctl --user start bloop".
+      '';
+    };
+  };
+
+  config = mkIf (cfg.install) {
+    systemd.user.services.bloop = {
+      description = "Bloop Scala build server";
+
+      serviceConfig = {
+        Type      = "simple";
+        ExecStart = ''${pkgs.bloop}/bin/blp-server'';
+        Restart   = "always";
+      };
+    };
+
+    environment.systemPackages = [ pkgs.bloop ];
+  };
+}
diff --git a/nixos/modules/services/editors/infinoted.nix b/nixos/modules/services/editors/infinoted.nix
index 9074a4345eae..bba21caca85d 100644
--- a/nixos/modules/services/editors/infinoted.nix
+++ b/nixos/modules/services/editors/infinoted.nix
@@ -111,12 +111,12 @@ in {
   };
 
   config = mkIf (cfg.enable) {
-    users.extraUsers = optional (cfg.user == "infinoted")
+    users.users = optional (cfg.user == "infinoted")
       { name = "infinoted";
         description = "Infinoted user";
         group = cfg.group;
       };
-    users.extraGroups = optional (cfg.group == "infinoted")
+    users.groups = optional (cfg.group == "infinoted")
       { name = "infinoted";
       };
   
diff --git a/nixos/modules/services/games/minecraft-server.nix b/nixos/modules/services/games/minecraft-server.nix
index d2c8af6de0c5..f50d2897843a 100644
--- a/nixos/modules/services/games/minecraft-server.nix
+++ b/nixos/modules/services/games/minecraft-server.nix
@@ -45,7 +45,7 @@ in
   };
 
   config = mkIf cfg.enable {
-    users.extraUsers.minecraft = {
+    users.users.minecraft = {
       description     = "Minecraft Server Service user";
       home            = cfg.dataDir;
       createHome      = true;
diff --git a/nixos/modules/services/games/minetest-server.nix b/nixos/modules/services/games/minetest-server.nix
index 58b73ac4f6bf..2de42f20f6cc 100644
--- a/nixos/modules/services/games/minetest-server.nix
+++ b/nixos/modules/services/games/minetest-server.nix
@@ -79,7 +79,7 @@ in
   };
 
   config = mkIf cfg.enable {
-    users.extraUsers.minetest = {
+    users.users.minetest = {
       description     = "Minetest Server Service user";
       home            = "/var/lib/minetest";
       createHome      = true;
diff --git a/nixos/modules/services/games/terraria.nix b/nixos/modules/services/games/terraria.nix
index 21aff780b672..ddf17599296a 100644
--- a/nixos/modules/services/games/terraria.nix
+++ b/nixos/modules/services/games/terraria.nix
@@ -105,14 +105,14 @@ in
   };
 
   config = mkIf cfg.enable {
-    users.extraUsers.terraria = {
+    users.users.terraria = {
       description = "Terraria server service user";
       home        = "/var/lib/terraria";
       createHome  = true;
       uid         = config.ids.uids.terraria;
     };
 
-    users.extraGroups.terraria = {
+    users.groups.terraria = {
       gid = config.ids.gids.terraria;
       members = [ "terraria" ];
     };
diff --git a/nixos/modules/services/hardware/fwupd.nix b/nixos/modules/services/hardware/fwupd.nix
index d8abde2a600a..d97d690920a6 100644
--- a/nixos/modules/services/hardware/fwupd.nix
+++ b/nixos/modules/services/hardware/fwupd.nix
@@ -85,6 +85,6 @@ in {
   };
 
   meta = {
-    maintainers = pkgs.fwupd.maintainers;
+    maintainers = pkgs.fwupd.meta.maintainers;
   };
 }
diff --git a/nixos/modules/services/hardware/pcscd.nix b/nixos/modules/services/hardware/pcscd.nix
index fa97e8bf746b..f3fc4c3cc79e 100644
--- a/nixos/modules/services/hardware/pcscd.nix
+++ b/nixos/modules/services/hardware/pcscd.nix
@@ -61,8 +61,8 @@ in {
       description = "PCSC-Lite daemon";
       environment.PCSCLITE_HP_DROPDIR = pluginEnv;
       serviceConfig = {
-        ExecStart = "${pkgs.pcsclite}/sbin/pcscd -f -x -c ${cfgFile}";
-        ExecReload = "${pkgs.pcsclite}/sbin/pcscd -H";
+        ExecStart = "${getBin pkgs.pcsclite}/sbin/pcscd -f -x -c ${cfgFile}";
+        ExecReload = "${getBin pkgs.pcsclite}/sbin/pcscd -H";
       };
     };
   };
diff --git a/nixos/modules/services/hardware/sane.nix b/nixos/modules/services/hardware/sane.nix
index d651ccaa5776..fe05c5a5c06f 100644
--- a/nixos/modules/services/hardware/sane.nix
+++ b/nixos/modules/services/hardware/sane.nix
@@ -124,7 +124,7 @@ in
       environment.sessionVariables = env;
       services.udev.packages = backends;
 
-      users.extraGroups."scanner".gid = config.ids.gids.scanner;
+      users.groups."scanner".gid = config.ids.gids.scanner;
     })
 
     (mkIf config.services.saned.enable {
@@ -152,7 +152,7 @@ in
         };
       };
 
-      users.extraUsers."scanner" = {
+      users.users."scanner" = {
         uid = config.ids.uids.scanner;
         group = "scanner";
       };
diff --git a/nixos/modules/services/hardware/tcsd.nix b/nixos/modules/services/hardware/tcsd.nix
index d957b5063d38..d4b0a9495d75 100644
--- a/nixos/modules/services/hardware/tcsd.nix
+++ b/nixos/modules/services/hardware/tcsd.nix
@@ -137,13 +137,13 @@ in
       serviceConfig.ExecStart = "${pkgs.trousers}/sbin/tcsd -f -c ${tcsdConf}";
     };
 
-    users.extraUsers = optionalAttrs (cfg.user == "tss") (singleton
+    users.users = optionalAttrs (cfg.user == "tss") (singleton
       { name = "tss";
         group = "tss";
         uid = config.ids.uids.tss;
       });
 
-    users.extraGroups = optionalAttrs (cfg.group == "tss") (singleton
+    users.groups = optionalAttrs (cfg.group == "tss") (singleton
       { name = "tss";
         gid = config.ids.gids.tss;
       });
diff --git a/nixos/modules/services/hardware/thinkfan.nix b/nixos/modules/services/hardware/thinkfan.nix
index 5a898631e090..d17121ca1c5b 100644
--- a/nixos/modules/services/hardware/thinkfan.nix
+++ b/nixos/modules/services/hardware/thinkfan.nix
@@ -28,11 +28,14 @@ let
     # temperatures are read from the file.
     #
     # For example:
-    # sensor /proc/acpi/ibm/thermal (0, 0, 10)
+    # tp_thermal /proc/acpi/ibm/thermal (0, 0, 10)
     # will add a fixed value of 10 °C the 3rd value read from that file. Check out
     # http://www.thinkwiki.org/wiki/Thermal_Sensors to find out how much you may
     # want to add to certain temperatures.
-    
+
+    ${cfg.fan}
+    ${cfg.sensors}
+
     #  Syntax:
     #  (LEVEL, LOW, HIGH)
     #  LEVEL is the fan level to use (0-7 with thinkpad_acpi)
@@ -41,8 +44,6 @@ let
     #  All numbers are integers.
     #
 
-    sensor ${cfg.sensor} (0, 10, 15, 2, 10, 5, 0, 3, 0, 3)
-    
     ${cfg.levels}
   '';
 
@@ -53,20 +54,52 @@ in {
     services.thinkfan = {
 
       enable = mkOption {
+        type = types.bool;
         default = false;
         description = ''
           Whether to enable thinkfan, fan controller for IBM/Lenovo ThinkPads.
         '';
       };
 
-      sensor = mkOption {
-        default = "/proc/acpi/ibm/thermal";
+      sensors = mkOption {
+        type = types.lines;
+        default = ''
+          tp_thermal /proc/acpi/ibm/thermal (0,0,10)
+        '';
+        description =''
+          thinkfan can read temperatures from three possible sources:
+
+            /proc/acpi/ibm/thermal
+              Which is provided by the thinkpad_acpi kernel
+              module (keyword tp_thermal)
+
+            /sys/class/hwmon/*/temp*_input
+              Which may be provided by any hwmon drivers (keyword
+              hwmon)
+
+            S.M.A.R.T. (since 0.9 and requires the USE_ATASMART compilation flag)
+              Which reads the temperature directly from the hard
+              disk using libatasmart (keyword atasmart)
+
+          Multiple sensors may be added, in which case they will be
+          numbered in their order of appearance.
+        '';
+      };
+
+      fan = mkOption {
+        type = types.str;
+        default = "tp_fan /proc/acpi/ibm/fan";
         description =''
-          Sensor used by thinkfan
+          Specifies the fan we want to use.
+          On anything other than a Thinkpad you'll probably
+          use some PWM control file in /sys/class/hwmon.
+          A sysfs fan would be specified like this:
+            pwm_fan /sys/class/hwmon/hwmon2/device/pwm1
         '';
       };
 
       levels = mkOption {
+        type = types.lines;
         default = ''
           (0,     0,      55)
           (1,     48,     60)
@@ -76,8 +109,12 @@ in {
           (7,     60,     85)
           (127,   80,     32767)
         '';
-        description =''
-          Sensor used by thinkfan
+        description = ''
+          (LEVEL, LOW, HIGH)
+          LEVEL is the fan level to use (0-7 with thinkpad_acpi).
+          LOW is the temperature at which to step down to the previous level.
+          HIGH is the temperature at which to step up to the next level.
+          All numbers are integers.
         '';
       };
 
diff --git a/nixos/modules/services/hardware/udev.nix b/nixos/modules/services/hardware/udev.nix
index 7bfc3bb64872..0266286aaacf 100644
--- a/nixos/modules/services/hardware/udev.nix
+++ b/nixos/modules/services/hardware/udev.nix
@@ -4,8 +4,6 @@ with lib;
 
 let
 
-  inherit (pkgs) stdenv writeText procps;
-
   udev = config.systemd.package;
 
   cfg = config.services.udev;
diff --git a/nixos/modules/services/hardware/udisks2.nix b/nixos/modules/services/hardware/udisks2.nix
index ad5dc8e8a49b..ed8703be921c 100644
--- a/nixos/modules/services/hardware/udisks2.nix
+++ b/nixos/modules/services/hardware/udisks2.nix
@@ -40,15 +40,8 @@ with lib;
       '';
 
     services.udev.packages = [ pkgs.udisks2 ];
-    
-    systemd.services.udisks2 = {
-      description = "Udisks2 service";
-      serviceConfig = {
-        Type = "dbus";
-        BusName = "org.freedesktop.UDisks2";
-        ExecStart = "${pkgs.udisks2}/libexec/udisks2/udisksd --no-debug";
-      };
-    };
+
+    systemd.packages = [ pkgs.udisks2 ];
   };
 
 }
diff --git a/nixos/modules/services/hardware/usbmuxd.nix b/nixos/modules/services/hardware/usbmuxd.nix
index 7ebd49fa01c2..93ced0b9f04d 100644
--- a/nixos/modules/services/hardware/usbmuxd.nix
+++ b/nixos/modules/services/hardware/usbmuxd.nix
@@ -43,13 +43,13 @@ in
 
   config = mkIf cfg.enable {
 
-    users.extraUsers = optional (cfg.user == defaultUserGroup) {
+    users.users = optional (cfg.user == defaultUserGroup) {
       name = cfg.user;
       description = "usbmuxd user";
       group = cfg.group;
     };
 
-    users.extraGroups = optional (cfg.group == defaultUserGroup) {
+    users.groups = optional (cfg.group == defaultUserGroup) {
       name = cfg.group;
     };
 
@@ -65,7 +65,7 @@ in
       serviceConfig = {
         # Trigger the udev rule manually. This doesn't require replugging the
         # device when first enabling the option to get it to work
-        ExecStartPre = "${pkgs.libudev}/bin/udevadm trigger -s usb -a idVendor=${apple}";
+        ExecStartPre = "${pkgs.udev}/bin/udevadm trigger -s usb -a idVendor=${apple}";
         ExecStart = "${pkgs.usbmuxd}/bin/usbmuxd -U ${cfg.user} -f";
       };
     };
diff --git a/nixos/modules/services/logging/graylog.nix b/nixos/modules/services/logging/graylog.nix
index 95f31829882f..74a7b3c9b470 100644
--- a/nixos/modules/services/logging/graylog.nix
+++ b/nixos/modules/services/logging/graylog.nix
@@ -127,7 +127,7 @@ in
 
   config = mkIf cfg.enable {
 
-    users.extraUsers = mkIf (cfg.user == "graylog") {
+    users.users = mkIf (cfg.user == "graylog") {
       graylog = {
         uid = config.ids.uids.graylog;
         description = "Graylog server daemon user";
diff --git a/nixos/modules/services/logging/journaldriver.nix b/nixos/modules/services/logging/journaldriver.nix
new file mode 100644
index 000000000000..74ac3d4c2365
--- /dev/null
+++ b/nixos/modules/services/logging/journaldriver.nix
@@ -0,0 +1,112 @@
+# This module implements a systemd service for running journaldriver,
+# a log forwarding agent that sends logs from journald to Stackdriver
+# Logging.
+#
+# It can be enabled without extra configuration when running on GCP.
+# On machines hosted elsewhere, the other configuration options need
+# to be set.
+#
+# For further information please consult the documentation in the
+# upstream repository at: https://github.com/aprilabank/journaldriver/
+
+{ config, lib, pkgs, ...}:
+
+with lib; let cfg = config.services.journaldriver;
+in {
+  options.services.journaldriver = {
+    enable = mkOption {
+      type        = types.bool;
+      default     = false;
+      description = ''
+        Whether to enable journaldriver to forward journald logs to
+        Stackdriver Logging.
+      '';
+    };
+
+    logLevel = mkOption {
+      type        = types.str;
+      default     = "info";
+      description = ''
+        Log level at which journaldriver logs its own output.
+      '';
+    };
+
+    logName = mkOption {
+      type        = with types; nullOr str;
+      default     = null;
+      description = ''
+        Configures the name of the target log in Stackdriver Logging.
+        This option can be set to, for example, the hostname of a
+        machine to improve the user experience in the logging
+        overview.
+      '';
+    };
+
+    googleCloudProject = mkOption {
+      type        = with types; nullOr str;
+      default     = null;
+      description = ''
+        Configures the name of the Google Cloud project to which to
+        forward journald logs.
+
+        This option is required on non-GCP machines, but should not be
+        set on GCP instances.
+      '';
+    };
+
+    logStream = mkOption {
+      type        = with types; nullOr str;
+      default     = null;
+      description = ''
+        Configures the name of the Stackdriver Logging log stream into
+        which to write journald entries.
+
+        This option is required on non-GCP machines, but should not be
+        set on GCP instances.
+      '';
+    };
+
+    applicationCredentials = mkOption {
+      type        = with types; nullOr path;
+      default     = null;
+      description = ''
+        Path to the service account private key (in JSON-format) used
+        to forward log entries to Stackdriver Logging on non-GCP
+        instances.
+
+        This option is required on non-GCP machines, but should not be
+        set on GCP instances.
+      '';
+    };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.services.journaldriver = {
+      description = "Stackdriver Logging journal forwarder";
+      script      = "${pkgs.journaldriver}/bin/journaldriver";
+      after       = [ "network-online.target" ];
+      wantedBy    = [ "multi-user.target" ];
+
+      serviceConfig = {
+        Restart        = "always";
+        DynamicUser    = true;
+
+        # This directive lets systemd automatically configure
+        # permissions on /var/lib/journaldriver, the directory in
+        # which journaldriver persists its cursor state.
+        StateDirectory = "journaldriver";
+
+        # This group is required for accessing journald.
+        SupplementaryGroups = "systemd-journal";
+      };
+
+      environment = {
+        RUST_LOG                       = cfg.logLevel;
+        LOG_NAME                       = cfg.logName;
+        LOG_STREAM                     = cfg.logStream;
+        GOOGLE_CLOUD_PROJECT           = cfg.googleCloudProject;
+        GOOGLE_APPLICATION_CREDENTIALS = cfg.applicationCredentials;
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/logging/journalwatch.nix b/nixos/modules/services/logging/journalwatch.nix
index d49795fe2b77..2c9bc18c8c3c 100644
--- a/nixos/modules/services/logging/journalwatch.nix
+++ b/nixos/modules/services/logging/journalwatch.nix
@@ -197,7 +197,7 @@ in {
 
   config = mkIf cfg.enable {
 
-    users.extraUsers.${user} = {
+    users.users.${user} = {
       isSystemUser = true;
       createHome = true;
       home = dataDir;
@@ -241,6 +241,6 @@ in {
   };
 
   meta = {
-    maintainers = with stdenv.lib.maintainers; [ florianjacob ];
+    maintainers = with lib.maintainers; [ florianjacob ];
   };
 }
diff --git a/nixos/modules/services/logging/logcheck.nix b/nixos/modules/services/logging/logcheck.nix
index a4cab0c94cdc..1477d273d5ee 100644
--- a/nixos/modules/services/logging/logcheck.nix
+++ b/nixos/modules/services/logging/logcheck.nix
@@ -213,7 +213,7 @@ in
         mapAttrsToList writeIgnoreRule cfg.ignore
         ++ mapAttrsToList writeIgnoreCronRule cfg.ignoreCron;
 
-    users.extraUsers = optionalAttrs (cfg.user == "logcheck") (singleton
+    users.users = optionalAttrs (cfg.user == "logcheck") (singleton
       { name = "logcheck";
         uid = config.ids.uids.logcheck;
         shell = "/bin/sh";
diff --git a/nixos/modules/services/mail/dovecot.nix b/nixos/modules/services/mail/dovecot.nix
index 50477fdd25ba..04df97fdbbec 100644
--- a/nixos/modules/services/mail/dovecot.nix
+++ b/nixos/modules/services/mail/dovecot.nix
@@ -9,8 +9,6 @@ let
   baseDir = "/run/dovecot2";
   stateDir = "/var/lib/dovecot";
 
-  canCreateMailUserGroup = cfg.mailUser != null && cfg.mailGroup != null;
-
   dovecotConf = concatStrings [
     ''
       base_dir = ${baseDir}
@@ -309,7 +307,7 @@ in
      ++ optional cfg.enablePop3 "pop3"
      ++ optional cfg.enableLmtp "lmtp";
 
-    users.extraUsers = [
+    users.users = [
       { name = "dovenull";
         uid = config.ids.uids.dovenull2;
         description = "Dovecot user for untrusted logins";
@@ -328,7 +326,7 @@ in
            group = cfg.mailGroup;
          });
 
-    users.extraGroups = optional (cfg.group == "dovecot2")
+    users.groups = optional (cfg.group == "dovecot2")
       { name = "dovecot2";
         gid = config.ids.gids.dovecot2;
       }
diff --git a/nixos/modules/services/mail/dspam.nix b/nixos/modules/services/mail/dspam.nix
index 89076ff05462..167b5aeccc84 100644
--- a/nixos/modules/services/mail/dspam.nix
+++ b/nixos/modules/services/mail/dspam.nix
@@ -86,13 +86,13 @@ in {
 
   config = mkIf cfg.enable (mkMerge [
     {
-      users.extraUsers = optionalAttrs (cfg.user == "dspam") (singleton
+      users.users = optionalAttrs (cfg.user == "dspam") (singleton
         { name = "dspam";
           group = cfg.group;
           uid = config.ids.uids.dspam;
         });
 
-      users.extraGroups = optionalAttrs (cfg.group == "dspam") (singleton
+      users.groups = optionalAttrs (cfg.group == "dspam") (singleton
         { name = "dspam";
           gid = config.ids.gids.dspam;
         });
diff --git a/nixos/modules/services/mail/exim.nix b/nixos/modules/services/mail/exim.nix
index 440eae281f40..06c4b2811b3f 100644
--- a/nixos/modules/services/mail/exim.nix
+++ b/nixos/modules/services/mail/exim.nix
@@ -77,14 +77,14 @@ in
       systemPackages = [ exim ];
     };
 
-    users.extraUsers = singleton {
+    users.users = singleton {
       name = cfg.user;
       description = "Exim mail transfer agent user";
       uid = config.ids.uids.exim;
       group = cfg.group;
     };
 
-    users.extraGroups = singleton {
+    users.groups = singleton {
       name = cfg.group;
       gid = config.ids.gids.exim;
     };
@@ -94,6 +94,7 @@ in
     systemd.services.exim = {
       description = "Exim Mail Daemon";
       wantedBy = [ "multi-user.target" ];
+      restartTriggers = [ config.environment.etc."exim.conf".source ];
       serviceConfig = {
         ExecStart   = "${exim}/bin/exim -bdf -q30m";
         ExecReload  = "${coreutils}/bin/kill -HUP $MAINPID";
diff --git a/nixos/modules/services/mail/mailhog.nix b/nixos/modules/services/mail/mailhog.nix
index 206fb50d31a2..b78f4c8e0e66 100644
--- a/nixos/modules/services/mail/mailhog.nix
+++ b/nixos/modules/services/mail/mailhog.nix
@@ -24,7 +24,7 @@ in {
 
   config = mkIf cfg.enable {
 
-    users.extraUsers.mailhog = {
+    users.users.mailhog = {
       name = cfg.user;
       description = "MailHog service user";
     };
diff --git a/nixos/modules/services/mail/mlmmj.nix b/nixos/modules/services/mail/mlmmj.nix
index b6439b44fb5f..11565bc02f89 100644
--- a/nixos/modules/services/mail/mlmmj.nix
+++ b/nixos/modules/services/mail/mlmmj.nix
@@ -94,7 +94,7 @@ in
 
   config = mkIf cfg.enable {
 
-    users.extraUsers = singleton {
+    users.users = singleton {
       name = cfg.user;
       description = "mlmmj user";
       home = stateDir;
@@ -104,7 +104,7 @@ in
       useDefaultShell = true;
     };
 
-    users.extraGroups = singleton {
+    users.groups = singleton {
       name = cfg.group;
       gid = config.ids.gids.mlmmj;
     };
diff --git a/nixos/modules/services/mail/nullmailer.nix b/nixos/modules/services/mail/nullmailer.nix
index 59cb512c115b..418c02af4b7f 100644
--- a/nixos/modules/services/mail/nullmailer.nix
+++ b/nixos/modules/services/mail/nullmailer.nix
@@ -201,13 +201,13 @@ with lib;
     };
 
     users = {
-      extraUsers = singleton {
+      users = singleton {
         name = cfg.user;
         description = "Nullmailer relay-only mta user";
         group = cfg.group;
       };
 
-      extraGroups = singleton {
+      groups = singleton {
         name = cfg.group;
       };
     };
diff --git a/nixos/modules/services/mail/opendkim.nix b/nixos/modules/services/mail/opendkim.nix
index 59a8373843a1..7855efb46c73 100644
--- a/nixos/modules/services/mail/opendkim.nix
+++ b/nixos/modules/services/mail/opendkim.nix
@@ -88,13 +88,13 @@ in {
 
   config = mkIf cfg.enable {
 
-    users.extraUsers = optionalAttrs (cfg.user == "opendkim") (singleton
+    users.users = optionalAttrs (cfg.user == "opendkim") (singleton
       { name = "opendkim";
         group = cfg.group;
         uid = config.ids.uids.opendkim;
       });
 
-    users.extraGroups = optionalAttrs (cfg.group == "opendkim") (singleton
+    users.groups = optionalAttrs (cfg.group == "opendkim") (singleton
       { name = "opendkim";
         gid = config.ids.gids.opendkim;
       });
diff --git a/nixos/modules/services/mail/opensmtpd.nix b/nixos/modules/services/mail/opensmtpd.nix
index 53acdba42457..4276552d4f03 100644
--- a/nixos/modules/services/mail/opensmtpd.nix
+++ b/nixos/modules/services/mail/opensmtpd.nix
@@ -10,7 +10,7 @@ let
 
   sendmail = pkgs.runCommand "opensmtpd-sendmail" {} ''
     mkdir -p $out/bin
-    ln -s ${pkgs.opensmtpd}/sbin/smtpctl $out/bin/sendmail
+    ln -s ${cfg.package}/sbin/smtpctl $out/bin/sendmail
   '';
 
 in {
@@ -27,6 +27,13 @@ in {
         description = "Whether to enable the OpenSMTPD server.";
       };
 
+      package = mkOption {
+        type = types.package;
+        default = pkgs.opensmtpd;
+        defaultText = "pkgs.opensmtpd";
+        description = "The OpenSMTPD package to use.";
+      };
+
       addSendmailToSystemPath = mkOption {
         type = types.bool;
         default = true;
@@ -76,12 +83,12 @@ in {
   ###### implementation
 
   config = mkIf cfg.enable {
-    users.extraGroups = {
+    users.groups = {
       smtpd.gid = config.ids.gids.smtpd;
       smtpq.gid = config.ids.gids.smtpq;
     };
 
-    users.extraUsers = {
+    users.users = {
       smtpd = {
         description = "OpenSMTPD process user";
         uid = config.ids.uids.smtpd;
@@ -97,7 +104,7 @@ in {
     systemd.services.opensmtpd = let
       procEnv = pkgs.buildEnv {
         name = "opensmtpd-procs";
-        paths = [ pkgs.opensmtpd ] ++ cfg.procPackages;
+        paths = [ cfg.package ] ++ cfg.procPackages;
         pathsToLink = [ "/libexec/opensmtpd" ];
       };
     in {
@@ -115,7 +122,7 @@ in {
         chown smtpq.root /var/spool/smtpd/purge
         chmod 700 /var/spool/smtpd/purge
       '';
-      serviceConfig.ExecStart = "${pkgs.opensmtpd}/sbin/smtpd -d -f ${conf} ${args}";
+      serviceConfig.ExecStart = "${cfg.package}/sbin/smtpd -d -f ${conf} ${args}";
       environment.OPENSMTPD_PROC_PATH = "${procEnv}/libexec/opensmtpd";
     };
 
diff --git a/nixos/modules/services/mail/postfix.nix b/nixos/modules/services/mail/postfix.nix
index 5ab331ac067f..33249aa3e554 100644
--- a/nixos/modules/services/mail/postfix.nix
+++ b/nixos/modules/services/mail/postfix.nix
@@ -616,14 +616,14 @@ in
         setgid = true;
       };
 
-      users.extraUsers = optional (user == "postfix")
+      users.users = optional (user == "postfix")
         { name = "postfix";
           description = "Postfix mail server user";
           uid = config.ids.uids.postfix;
           group = group;
         };
 
-      users.extraGroups =
+      users.groups =
         optional (group == "postfix")
         { name = group;
           gid = config.ids.gids.postfix;
diff --git a/nixos/modules/services/mail/postgrey.nix b/nixos/modules/services/mail/postgrey.nix
index d4ae25c066ac..241f75eae279 100644
--- a/nixos/modules/services/mail/postgrey.nix
+++ b/nixos/modules/services/mail/postgrey.nix
@@ -136,14 +136,14 @@ in {
     environment.systemPackages = [ pkgs.postgrey ];
 
     users = {
-      extraUsers = {
+      users = {
         postgrey = {
           description = "Postgrey Daemon";
           uid = config.ids.uids.postgrey;
           group = "postgrey";
         };
       };
-      extraGroups = {
+      groups = {
         postgrey = {
           gid = config.ids.gids.postgrey;
         };
diff --git a/nixos/modules/services/mail/postsrsd.nix b/nixos/modules/services/mail/postsrsd.nix
index a1af16ec9ac1..8f12a16906c5 100644
--- a/nixos/modules/services/mail/postsrsd.nix
+++ b/nixos/modules/services/mail/postsrsd.nix
@@ -90,13 +90,13 @@ in {
 
     services.postsrsd.domain = mkDefault config.networking.hostName;
 
-    users.extraUsers = optionalAttrs (cfg.user == "postsrsd") (singleton
+    users.users = optionalAttrs (cfg.user == "postsrsd") (singleton
       { name = "postsrsd";
         group = cfg.group;
         uid = config.ids.uids.postsrsd;
       });
 
-    users.extraGroups = optionalAttrs (cfg.group == "postsrsd") (singleton
+    users.groups = optionalAttrs (cfg.group == "postsrsd") (singleton
       { name = "postsrsd";
         gid = config.ids.gids.postsrsd;
       });
diff --git a/nixos/modules/services/mail/rmilter.nix b/nixos/modules/services/mail/rmilter.nix
index e17b7516bfff..7f38d7570132 100644
--- a/nixos/modules/services/mail/rmilter.nix
+++ b/nixos/modules/services/mail/rmilter.nix
@@ -194,14 +194,14 @@ in
 
     (mkIf cfg.enable {
 
-      users.extraUsers = singleton {
+      users.users = singleton {
         name = cfg.user;
         description = "rmilter daemon";
         uid = config.ids.uids.rmilter;
         group = cfg.group;
       };
 
-      users.extraGroups = singleton {
+      users.groups = singleton {
         name = cfg.group;
         gid = config.ids.gids.rmilter;
       };
@@ -238,12 +238,12 @@ in
     })
 
     (mkIf (cfg.enable && cfg.rspamd.enable && rspamdCfg.enable) {
-      users.extraUsers.${cfg.user}.extraGroups = [ rspamdCfg.group ];
+      users.users.${cfg.user}.extraGroups = [ rspamdCfg.group ];
     })
 
     (mkIf (cfg.enable && cfg.postfix.enable) {
       services.postfix.extraConfig = cfg.postfix.configFragment;
-      users.extraUsers.${postfixCfg.user}.extraGroups = [ cfg.group ];
+      users.users.${postfixCfg.user}.extraGroups = [ cfg.group ];
     })
   ];
 }
diff --git a/nixos/modules/services/mail/rspamd.nix b/nixos/modules/services/mail/rspamd.nix
index 09fb587e74b5..b3dae60c2c7e 100644
--- a/nixos/modules/services/mail/rspamd.nix
+++ b/nixos/modules/services/mail/rspamd.nix
@@ -282,14 +282,14 @@ in
     # Allow users to run 'rspamc' and 'rspamadm'.
     environment.systemPackages = [ pkgs.rspamd ];
 
-    users.extraUsers = singleton {
+    users.users = singleton {
       name = cfg.user;
       description = "rspamd daemon";
       uid = config.ids.uids.rspamd;
       group = cfg.group;
     };
 
-    users.extraGroups = singleton {
+    users.groups = singleton {
       name = cfg.group;
       gid = config.ids.gids.rspamd;
     };
diff --git a/nixos/modules/services/mail/spamassassin.nix b/nixos/modules/services/mail/spamassassin.nix
index d483a8c3d67d..0c11ea431368 100644
--- a/nixos/modules/services/mail/spamassassin.nix
+++ b/nixos/modules/services/mail/spamassassin.nix
@@ -128,14 +128,14 @@ in
       systemPackages = [ pkgs.spamassassin ];
     };
 
-    users.extraUsers = singleton {
+    users.users = singleton {
       name = "spamd";
       description = "Spam Assassin Daemon";
       uid = config.ids.uids.spamd;
       group = "spamd";
     };
 
-    users.extraGroups = singleton {
+    users.groups = singleton {
       name = "spamd";
       gid = config.ids.gids.spamd;
     };
diff --git a/nixos/modules/services/misc/airsonic.nix b/nixos/modules/services/misc/airsonic.nix
index b92104787a56..083587b8ebb1 100644
--- a/nixos/modules/services/misc/airsonic.nix
+++ b/nixos/modules/services/misc/airsonic.nix
@@ -107,7 +107,7 @@ in {
       };
     };
 
-    users.extraUsers.airsonic = {
+    users.users.airsonic = {
       description = "Airsonic service user";
       name = cfg.user;
       home = cfg.home;
diff --git a/nixos/modules/services/misc/apache-kafka.nix b/nixos/modules/services/misc/apache-kafka.nix
index 82fa1cc2e7e5..363ac4411e11 100644
--- a/nixos/modules/services/misc/apache-kafka.nix
+++ b/nixos/modules/services/misc/apache-kafka.nix
@@ -124,7 +124,7 @@ in {
 
     environment.systemPackages = [cfg.package];
 
-    users.extraUsers = singleton {
+    users.users = singleton {
       name = "apache-kafka";
       uid = config.ids.uids.apache-kafka;
       description = "Apache Kafka daemon user";
diff --git a/nixos/modules/services/misc/autorandr.nix b/nixos/modules/services/misc/autorandr.nix
index 3020130ad1f6..4708e16e2a6c 100644
--- a/nixos/modules/services/misc/autorandr.nix
+++ b/nixos/modules/services/misc/autorandr.nix
@@ -12,6 +12,16 @@ in {
 
     services.autorandr = {
       enable = mkEnableOption "handling of hotplug and sleep events by autorandr";
+
+      defaultTarget = mkOption {
+        default = "default";
+        type = types.str;
+        description = ''
+          Fallback if no monitor layout can be detected. See the docs
+          (https://github.com/phillipberndt/autorandr/blob/v1.0/README.md#how-to-use)
+          for further reference.
+        '';
+      };
     };
 
   };
@@ -22,13 +32,21 @@ in {
 
     environment.systemPackages = [ pkgs.autorandr ];
 
-    systemd.packages = [ pkgs.autorandr ];
-
     systemd.services.autorandr = {
       wantedBy = [ "sleep.target" ];
+      description = "Autorandr execution hook";
+      after = [ "sleep.target" ];
+
+      serviceConfig = {
+        StartLimitInterval = 5;
+        StartLimitBurst = 1;
+        ExecStart = "${pkgs.autorandr}/bin/autorandr --batch --change --default ${cfg.defaultTarget}";
+        Type = "oneshot";
+        RemainAfterExit = false;
+      };
     };
 
   };
 
-  meta.maintainers = with maintainers; [ gnidorah ];
+  meta.maintainers = with maintainers; [ gnidorah ma27 ];
 }
diff --git a/nixos/modules/services/misc/bepasty.nix b/nixos/modules/services/misc/bepasty.nix
index c499e428af35..62835c194e42 100644
--- a/nixos/modules/services/misc/bepasty.nix
+++ b/nixos/modules/services/misc/bepasty.nix
@@ -168,14 +168,14 @@ in
         })
     ) cfg.servers;
 
-    users.extraUsers = [{
+    users.users = [{
       uid = config.ids.uids.bepasty;
       name = user;
       group = group;
       home = default_home;
     }];
 
-    users.extraGroups = [{
+    users.groups = [{
       name = group;
       gid = config.ids.gids.bepasty;
     }];
diff --git a/nixos/modules/services/misc/calibre-server.nix b/nixos/modules/services/misc/calibre-server.nix
index 6b19f780ec0c..84c04f403d3a 100644
--- a/nixos/modules/services/misc/calibre-server.nix
+++ b/nixos/modules/services/misc/calibre-server.nix
@@ -49,12 +49,12 @@ in
 
     environment.systemPackages = [ pkgs.calibre ];
 
-    users.extraUsers.calibre-server = {
+    users.users.calibre-server = {
         uid = config.ids.uids.calibre-server;
         group = "calibre-server";
       };
 
-    users.extraGroups.calibre-server = {
+    users.groups.calibre-server = {
         gid = config.ids.gids.calibre-server;
       };
 
diff --git a/nixos/modules/services/misc/cfdyndns.nix b/nixos/modules/services/misc/cfdyndns.nix
index 69a33d0b8c1b..dcf416022734 100644
--- a/nixos/modules/services/misc/cfdyndns.nix
+++ b/nixos/modules/services/misc/cfdyndns.nix
@@ -54,14 +54,14 @@ in
       };
     };
 
-    users.extraUsers = {
+    users.users = {
       cfdyndns = {
         group = "cfdyndns";
         uid = config.ids.uids.cfdyndns;
       };
     };
 
-    users.extraGroups = {
+    users.groups = {
       cfdyndns = {
         gid = config.ids.gids.cfdyndns;
       };
diff --git a/nixos/modules/services/misc/cgminer.nix b/nixos/modules/services/misc/cgminer.nix
index d5071d8ff767..b1cf5a7d1104 100644
--- a/nixos/modules/services/misc/cgminer.nix
+++ b/nixos/modules/services/misc/cgminer.nix
@@ -110,7 +110,7 @@ in
 
   config = mkIf config.services.cgminer.enable {
 
-    users.extraUsers = optionalAttrs (cfg.user == "cgminer") (singleton
+    users.users = optionalAttrs (cfg.user == "cgminer") (singleton
       { name = "cgminer";
         uid = config.ids.uids.cgminer;
         description = "Cgminer user";
diff --git a/nixos/modules/services/misc/clipmenu.nix b/nixos/modules/services/misc/clipmenu.nix
new file mode 100644
index 000000000000..3ba050044cac
--- /dev/null
+++ b/nixos/modules/services/misc/clipmenu.nix
@@ -0,0 +1,31 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.clipmenu;
+in {
+
+  options.services.clipmenu = {
+    enable = mkEnableOption "clipmenu, the clipboard management daemon";
+
+    package = mkOption {
+      type = types.package;
+      default = pkgs.clipmenu;
+      defaultText = "pkgs.clipmenu";
+      description = "clipmenu derivation to use.";
+    };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.user.services.clipmenu = {
+      enable      = true;
+      description = "Clipboard management daemon";
+      wantedBy = [ "graphical-session.target" ];
+      after    = [ "graphical-session.target" ];
+      serviceConfig.ExecStart = "${cfg.package}/bin/clipmenud";
+    };
+
+    environment.systemPackages = [ cfg.package ];
+  };
+}
diff --git a/nixos/modules/services/misc/couchpotato.nix b/nixos/modules/services/misc/couchpotato.nix
index 496487622351..70aa895f76d8 100644
--- a/nixos/modules/services/misc/couchpotato.nix
+++ b/nixos/modules/services/misc/couchpotato.nix
@@ -34,7 +34,7 @@ in
       };
     };
 
-    users.extraUsers = singleton
+    users.users = singleton
       { name = "couchpotato";
         group = "couchpotato";
         home = "/var/lib/couchpotato/";
@@ -42,7 +42,7 @@ in
         uid = config.ids.uids.couchpotato;
       };
 
-    users.extraGroups = singleton
+    users.groups = singleton
       { name = "couchpotato";
         gid = config.ids.gids.couchpotato;
       };
diff --git a/nixos/modules/services/misc/dictd.nix b/nixos/modules/services/misc/dictd.nix
index 7e3b6431a133..8d3e294622d1 100644
--- a/nixos/modules/services/misc/dictd.nix
+++ b/nixos/modules/services/misc/dictd.nix
@@ -45,7 +45,7 @@ in
     # get the command line client on system path to make some use of the service
     environment.systemPackages = [ pkgs.dict ];
 
-    users.extraUsers = singleton
+    users.users = singleton
       { name = "dictd";
         group = "dictd";
         description = "DICT.org dictd server";
@@ -53,7 +53,7 @@ in
         uid = config.ids.uids.dictd;
       };
 
-    users.extraGroups = singleton
+    users.groups = singleton
       { name = "dictd";
         gid = config.ids.gids.dictd;
       };
diff --git a/nixos/modules/services/misc/disnix.nix b/nixos/modules/services/misc/disnix.nix
index e4517c636e88..bb3ac1ecf075 100644
--- a/nixos/modules/services/misc/disnix.nix
+++ b/nixos/modules/services/misc/disnix.nix
@@ -7,16 +7,6 @@ let
 
   cfg = config.services.disnix;
 
-  dysnomia = pkgs.dysnomia.override (origArgs: {
-    enableApacheWebApplication = config.services.httpd.enable;
-    enableAxis2WebService = config.services.tomcat.axis2.enable;
-    enableEjabberdDump = config.services.ejabberd.enable;
-    enableMySQLDatabase = config.services.mysql.enable;
-    enablePostgreSQLDatabase = config.services.postgresql.enable;
-    enableSubversionRepository = config.services.svnserve.enable;
-    enableTomcatWebApplication = config.services.tomcat.enable;
-    enableMongoDatabase = config.services.mongodb.enable;
-  });
 in
 
 {
@@ -71,7 +61,7 @@ in
       ++ optional cfg.useWebServiceInterface "${pkgs.dbus_java}/share/java/dbus.jar";
     services.tomcat.webapps = optional cfg.useWebServiceInterface pkgs.DisnixWebService;
 
-    users.extraGroups = singleton
+    users.groups = singleton
       { name = "disnix";
         gid = config.ids.gids.disnix;
       };
diff --git a/nixos/modules/services/misc/docker-registry.nix b/nixos/modules/services/misc/docker-registry.nix
index 45931cb42b54..08031d33c131 100644
--- a/nixos/modules/services/misc/docker-registry.nix
+++ b/nixos/modules/services/misc/docker-registry.nix
@@ -5,44 +5,7 @@ with lib;
 let
   cfg = config.services.dockerRegistry;
 
-  blobCache = if cfg.enableRedisCache
-    then "redis"
-    else "inmemory";
-
-  registryConfig = {
-    version =  "0.1";
-    log.fields.service = "registry";
-    storage = {
-      cache.blobdescriptor = blobCache;
-      filesystem.rootdirectory = cfg.storagePath;
-      delete.enabled = cfg.enableDelete;
-    };
-    http = {
-      addr = ":${builtins.toString cfg.port}";
-      headers.X-Content-Type-Options = ["nosniff"];
-    };
-    health.storagedriver = {
-      enabled = true;
-      interval = "10s";
-      threshold = 3;
-    };
-  };
-
-  registryConfig.redis = mkIf cfg.enableRedisCache {
-    addr = "${cfg.redisUrl}";
-    password = "${cfg.redisPassword}";
-    db = 0;
-    dialtimeout = "10ms";
-    readtimeout = "10ms";
-    writetimeout = "10ms";
-    pool = {
-      maxidle = 16;
-      maxactive = 64;
-      idletimeout = "300s";
-    };
-  };
-
-  configFile = pkgs.writeText "docker-registry-config.yml" (builtins.toJSON (registryConfig // cfg.extraConfig));
+  configFile = pkgs.writeText "docker-registry-config.yml" (builtins.toJSON (recursiveUpdate registryConfig cfg.extraConfig));
 
 in {
   options.services.dockerRegistry = {
@@ -91,7 +54,7 @@ in {
         Docker extra registry configuration via environment variables.
       '';
       default = {};
-      type = types.attrsOf types.str;
+      type = types.attrs;
     };
 
     enableGarbageCollect = mkEnableOption "garbage collect";
@@ -120,6 +83,7 @@ in {
       serviceConfig = {
         User = "docker-registry";
         WorkingDirectory = cfg.storagePath;
+        AmbientCapabilities = mkIf (cfg.port < 1024) "cap_net_bind_service";
       };
     };
 
@@ -139,7 +103,7 @@ in {
       startAt = optional cfg.enableGarbageCollect cfg.garbageCollectDates;
     };
 
-    users.extraUsers.docker-registry = {
+    users.users.docker-registry = {
       createHome = true;
       home = cfg.storagePath;
     };
diff --git a/nixos/modules/services/misc/dysnomia.nix b/nixos/modules/services/misc/dysnomia.nix
index 9e66e0811ab7..ba74b18b6970 100644
--- a/nixos/modules/services/misc/dysnomia.nix
+++ b/nixos/modules/services/misc/dysnomia.nix
@@ -62,9 +62,6 @@ let
       cd $out
 
       ${concatMapStrings (containerName:
-        let
-          components = cfg.components."${containerName}";
-        in
         linkMutableComponents { inherit containerName; }
       ) (builtins.attrNames cfg.components)}
     '';
diff --git a/nixos/modules/services/misc/emby.nix b/nixos/modules/services/misc/emby.nix
index e295f0f930e1..92a68b602510 100644
--- a/nixos/modules/services/misc/emby.nix
+++ b/nixos/modules/services/misc/emby.nix
@@ -4,7 +4,6 @@ with lib;
 
 let
   cfg = config.services.emby;
-  emby = pkgs.emby;
 in
 {
   options = {
@@ -54,14 +53,14 @@ in
       };
     };
 
-    users.extraUsers = mkIf (cfg.user == "emby") {
+    users.users = mkIf (cfg.user == "emby") {
       emby = {
         group = cfg.group;
         uid = config.ids.uids.emby;
       };
     };
 
-    users.extraGroups = mkIf (cfg.group == "emby") {
+    users.groups = mkIf (cfg.group == "emby") {
       emby = {
         gid = config.ids.gids.emby;
       };
diff --git a/nixos/modules/services/misc/errbot.nix b/nixos/modules/services/misc/errbot.nix
index cb2fa6776240..ac6ba2181de2 100644
--- a/nixos/modules/services/misc/errbot.nix
+++ b/nixos/modules/services/misc/errbot.nix
@@ -76,8 +76,8 @@ in {
   };
 
   config = mkIf (cfg.instances != {}) {
-    users.extraUsers.errbot.group = "errbot";
-    users.extraGroups.errbot = {};
+    users.users.errbot.group = "errbot";
+    users.groups.errbot = {};
 
     systemd.services = mapAttrs' (name: instanceCfg: nameValuePair "errbot-${name}" (
     let
diff --git a/nixos/modules/services/misc/etcd.nix b/nixos/modules/services/misc/etcd.nix
index 7c91462883f1..2d1893dae64b 100644
--- a/nixos/modules/services/misc/etcd.nix
+++ b/nixos/modules/services/misc/etcd.nix
@@ -188,7 +188,7 @@ in {
 
     environment.systemPackages = [ pkgs.etcdctl ];
 
-    users.extraUsers = singleton {
+    users.users = singleton {
       name = "etcd";
       uid = config.ids.uids.etcd;
       description = "Etcd daemon user";
diff --git a/nixos/modules/services/misc/exhibitor.nix b/nixos/modules/services/misc/exhibitor.nix
index 600bd780e7b0..a90c7f402e7f 100644
--- a/nixos/modules/services/misc/exhibitor.nix
+++ b/nixos/modules/services/misc/exhibitor.nix
@@ -4,7 +4,6 @@ with lib;
 
 let
   cfg = config.services.exhibitor;
-  exhibitor = cfg.package;
   exhibitorConfig = ''
     zookeeper-install-directory=${cfg.baseDir}/zookeeper
     zookeeper-data-directory=${cfg.zkDataDir}
@@ -408,7 +407,7 @@ in
         chmod -R u+w ${cfg.baseDir}/zookeeper/conf
       '';
     };
-    users.extraUsers = singleton {
+    users.users = singleton {
       name = "zookeeper";
       uid = config.ids.uids.zookeeper;
       description = "Zookeeper daemon user";
diff --git a/nixos/modules/services/misc/felix.nix b/nixos/modules/services/misc/felix.nix
index d6ad9dcaebc2..1c5ece868258 100644
--- a/nixos/modules/services/misc/felix.nix
+++ b/nixos/modules/services/misc/felix.nix
@@ -47,12 +47,12 @@ in
   ###### implementation
 
   config = mkIf cfg.enable {
-    users.extraGroups = singleton
+    users.groups = singleton
       { name = "osgi";
         gid = config.ids.gids.osgi;
       };
 
-    users.extraUsers = singleton
+    users.users = singleton
       { name = "osgi";
         uid = config.ids.uids.osgi;
         description = "OSGi user";
diff --git a/nixos/modules/services/misc/folding-at-home.nix b/nixos/modules/services/misc/folding-at-home.nix
index 164221cbab7f..122c89ce0680 100644
--- a/nixos/modules/services/misc/folding-at-home.nix
+++ b/nixos/modules/services/misc/folding-at-home.nix
@@ -42,7 +42,7 @@ in {
 
   config = mkIf cfg.enable {
 
-    users.extraUsers = singleton
+    users.users = singleton
       { name = fahUser;
         uid = config.ids.uids.foldingathome;
         description = "Folding@Home user";
diff --git a/nixos/modules/services/misc/gammu-smsd.nix b/nixos/modules/services/misc/gammu-smsd.nix
index 2d406b634437..3057d7fd1a09 100644
--- a/nixos/modules/services/misc/gammu-smsd.nix
+++ b/nixos/modules/services/misc/gammu-smsd.nix
@@ -200,7 +200,7 @@ in {
   };
 
   config = mkIf cfg.enable {
-    users.extraUsers.${cfg.user} = {
+    users.users.${cfg.user} = {
       description = "gammu-smsd user";
       uid = config.ids.uids.gammu-smsd;
       extraGroups = [ "${cfg.device.group}" ];
diff --git a/nixos/modules/services/misc/geoip-updater.nix b/nixos/modules/services/misc/geoip-updater.nix
index e0b9df96f8e8..baf0a8d73d19 100644
--- a/nixos/modules/services/misc/geoip-updater.nix
+++ b/nixos/modules/services/misc/geoip-updater.nix
@@ -251,7 +251,7 @@ in
       }
     ];
 
-    users.extraUsers.geoip = {
+    users.users.geoip = {
       group = "root";
       description = "GeoIP database updater";
       uid = config.ids.uids.geoip;
diff --git a/nixos/modules/services/misc/gitea.nix b/nixos/modules/services/misc/gitea.nix
index 63e976ae566c..5d664728e0b5 100644
--- a/nixos/modules/services/misc/gitea.nix
+++ b/nixos/modules/services/misc/gitea.nix
@@ -4,6 +4,7 @@ with lib;
 
 let
   cfg = config.services.gitea;
+  gitea = cfg.package;
   pg = config.services.postgresql;
   usePostgresql = cfg.database.type == "postgres";
   configFile = pkgs.writeText "app.ini" ''
@@ -57,6 +58,13 @@ in
         description = "Enable Gitea Service.";
       };
 
+      package = mkOption {
+        default = pkgs.gitea;
+        type = types.package;
+        defaultText = "pkgs.gitea";
+        description = "gitea derivation to use";
+      };
+
       useWizard = mkOption {
         default = false;
         type = types.bool;
@@ -156,6 +164,30 @@ in
         };
       };
 
+      dump = {
+        enable = mkOption {
+          type = types.bool;
+          default = false;
+          description = ''
+            Enable a timer that runs gitea dump to generate backup-files of the
+            current gitea database and repositories.
+          '';
+        };
+
+        interval = mkOption {
+          type = types.str;
+          default = "04:31";
+          example = "hourly";
+          description = ''
+            Run a gitea dump at this interval. Runs by default at 04:31 every day.
+
+            The format is described in
+            <citerefentry><refentrytitle>systemd.time</refentrytitle>
+            <manvolnum>7</manvolnum></citerefentry>.
+          '';
+        };
+      };
+
       appName = mkOption {
         type = types.str;
         default = "gitea: Gitea Service";
@@ -203,7 +235,7 @@ in
 
       staticRootPath = mkOption {
         type = types.str;
-        default = "${pkgs.gitea.data}";
+        default = "${gitea.data}";
         example = "/var/lib/gitea/data";
         description = "Upper level of template and static files path.";
       };
@@ -223,7 +255,7 @@ in
       description = "gitea";
       after = [ "network.target" "postgresql.service" ];
       wantedBy = [ "multi-user.target" ];
-      path = [ pkgs.gitea.bin ];
+      path = [ gitea.bin ];
 
       preStart = let
         runConfig = "${cfg.stateDir}/custom/conf/app.ini";
@@ -250,10 +282,10 @@ in
 
         mkdir -p ${cfg.repositoryRoot}
         # update all hooks' binary paths
-        HOOKS=$(find ${cfg.repositoryRoot} -mindepth 4 -maxdepth 4 -type f -wholename "*git/hooks/*")
+        HOOKS=$(find ${cfg.repositoryRoot} -mindepth 4 -maxdepth 5 -type f -wholename "*git/hooks/*")
         if [ "$HOOKS" ]
         then
-          sed -ri 's,/nix/store/[a-z0-9.-]+/bin/gitea,${pkgs.gitea.bin}/bin/gitea,g' $HOOKS
+          sed -ri 's,/nix/store/[a-z0-9.-]+/bin/gitea,${gitea.bin}/bin/gitea,g' $HOOKS
           sed -ri 's,/nix/store/[a-z0-9.-]+/bin/env,${pkgs.coreutils}/bin/env,g' $HOOKS
           sed -ri 's,/nix/store/[a-z0-9.-]+/bin/bash,${pkgs.bash}/bin/bash,g' $HOOKS
           sed -ri 's,/nix/store/[a-z0-9.-]+/bin/perl,${pkgs.perl}/bin/perl,g' $HOOKS
@@ -261,7 +293,12 @@ in
         if [ ! -d ${cfg.stateDir}/conf/locale ]
         then
           mkdir -p ${cfg.stateDir}/conf
-          cp -r ${pkgs.gitea.out}/locale ${cfg.stateDir}/conf/locale
+          cp -r ${gitea.out}/locale ${cfg.stateDir}/conf/locale
+        fi
+        # update command option in authorized_keys
+        if [ -r ${cfg.stateDir}/.ssh/authorized_keys ]
+        then
+          sed -ri 's,/nix/store/[a-z0-9.-]+/bin/gitea,${gitea.bin}/bin/gitea,g' ${cfg.stateDir}/.ssh/authorized_keys
         fi
       '' + optionalString (usePostgresql && cfg.database.createDatabase) ''
         if ! test -e "${cfg.stateDir}/db-created"; then
@@ -288,7 +325,7 @@ in
         User = cfg.user;
         WorkingDirectory = cfg.stateDir;
         PermissionsStartOnly = true;
-        ExecStart = "${pkgs.gitea.bin}/bin/gitea web";
+        ExecStart = "${gitea.bin}/bin/gitea web";
         Restart = "always";
       };
 
@@ -300,7 +337,7 @@ in
     };
 
     users = mkIf (cfg.user == "gitea") {
-      extraUsers.gitea = {
+      users.gitea = {
         description = "Gitea Service";
         home = cfg.stateDir;
         createHome = true;
@@ -318,5 +355,32 @@ in
         name = "gitea-database-password";
         text = cfg.database.password;
       })));
+
+    systemd.services.gitea-dump = mkIf cfg.dump.enable {
+       description = "gitea dump";
+       after = [ "gitea.service" ];
+       wantedBy = [ "default.target" ];
+       path = [ gitea.bin ];
+
+       environment = {
+         USER = cfg.user;
+         HOME = cfg.stateDir;
+         GITEA_WORK_DIR = cfg.stateDir;
+       };
+
+       serviceConfig = {
+         Type = "oneshot";
+         User = cfg.user;
+         ExecStart = "${gitea.bin}/bin/gitea dump";
+         WorkingDirectory = cfg.stateDir;
+       };
+    };
+
+    systemd.timers.gitea-dump = mkIf cfg.dump.enable {
+      description = "Update timer for gitea-dump";
+      partOf = [ "gitea-dump.service" ];
+      wantedBy = [ "timers.target" ];
+      timerConfig.OnCalendar = cfg.dump.interval;
+    };
   };
 }
diff --git a/nixos/modules/services/misc/gitit.nix b/nixos/modules/services/misc/gitit.nix
index 94a98e0335df..0025d96bd37b 100644
--- a/nixos/modules/services/misc/gitit.nix
+++ b/nixos/modules/services/misc/gitit.nix
@@ -645,15 +645,15 @@ in
 
   config = mkIf cfg.enable {
 
-    users.extraUsers.gitit = {
-      group = config.users.extraGroups.gitit.name;
+    users.users.gitit = {
+      group = config.users.groups.gitit.name;
       description = "Gitit user";
       home = homeDir;
       createHome = true;
       uid = config.ids.uids.gitit;
     };
 
-    users.extraGroups.gitit.gid = config.ids.gids.gitit;
+    users.groups.gitit.gid = config.ids.gids.gitit;
 
     systemd.services.gitit = let
       uid = toString config.ids.uids.gitit;
@@ -715,8 +715,8 @@ NAMED
       '';
 
       serviceConfig = {
-        User = config.users.extraUsers.gitit.name;
-        Group = config.users.extraGroups.gitit.name;
+        User = config.users.users.gitit.name;
+        Group = config.users.groups.gitit.name;
         ExecStart = with cfg; gititSh haskellPackages extraPackages;
       };
     };
diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix
index be13fed860bd..b09f0408e102 100644
--- a/nixos/modules/services/misc/gitlab.nix
+++ b/nixos/modules/services/misc/gitlab.nix
@@ -129,6 +129,7 @@ let
         };
       };
       extra = {};
+      uploads.storage_path = cfg.statePath;
     };
   };
 
@@ -443,7 +444,7 @@ in {
     # Use postfix to send out mails.
     services.postfix.enable = mkDefault true;
 
-    users.extraUsers = [
+    users.users = [
       { name = cfg.user;
         group = cfg.group;
         home = "${cfg.statePath}/home";
@@ -452,7 +453,7 @@ in {
       }
     ];
 
-    users.extraGroups = [
+    users.groups = [
       { name = cfg.group;
         gid = config.ids.gids.gitlab;
       }
@@ -565,13 +566,9 @@ in {
 
         ${pkgs.openssl}/bin/openssl rand -hex 32 > ${cfg.statePath}/config/gitlab_shell_secret
 
-        # The uploads directory is hardcoded somewhere deep in rails. It is
-        # symlinked in the gitlab package to /run/gitlab/uploads to make it
-        # configurable
         mkdir -p /run/gitlab
-        mkdir -p ${cfg.statePath}/{log,uploads}
+        mkdir -p ${cfg.statePath}/log
         ln -sf ${cfg.statePath}/log /run/gitlab/log
-        ln -sf ${cfg.statePath}/uploads /run/gitlab/uploads
         ln -sf ${cfg.statePath}/tmp /run/gitlab/tmp
         ln -sf $GITLAB_SHELL_CONFIG_PATH /run/gitlab/shell-config.yml
         chown -R ${cfg.user}:${cfg.group} /run/gitlab
@@ -587,6 +584,8 @@ in {
           ln -sf ${smtpSettings} ${cfg.statePath}/config/initializers/smtp_settings.rb
         ''}
         ln -sf ${cfg.statePath}/config /run/gitlab/config
+        rm ${cfg.statePath}/lib
+        ln -sf ${pkgs.gitlab}/share/gitlab/lib ${cfg.statePath}/lib
         cp ${cfg.packages.gitlab}/share/gitlab/VERSION ${cfg.statePath}/VERSION
 
         # JSON is a subset of YAML
@@ -638,10 +637,6 @@ in {
         chmod -R ug+rwX,o-rwx ${cfg.statePath}/repositories
         chmod -R ug-s ${cfg.statePath}/repositories
         find ${cfg.statePath}/repositories -type d -print0 | xargs -0 chmod g+s
-        chmod 770 ${cfg.statePath}/uploads
-        chown -R ${cfg.user} ${cfg.statePath}/uploads
-        find ${cfg.statePath}/uploads -type f -exec chmod 0644 {} \;
-        find ${cfg.statePath}/uploads -type d -not -path ${cfg.statePath}/uploads -exec chmod 0770 {} \;
       '';
 
       serviceConfig = {
diff --git a/nixos/modules/services/misc/gitolite.nix b/nixos/modules/services/misc/gitolite.nix
index 6e60316d000c..b9c2a966e6f5 100644
--- a/nixos/modules/services/misc/gitolite.nix
+++ b/nixos/modules/services/misc/gitolite.nix
@@ -140,7 +140,7 @@ in
       push( @{$RC{ENABLE}}, 'git-annex-shell ua');
     '';
 
-    users.extraUsers.${cfg.user} = {
+    users.users.${cfg.user} = {
       description     = "Gitolite user";
       home            = cfg.dataDir;
       createHome      = true;
@@ -148,7 +148,7 @@ in
       group           = cfg.group;
       useDefaultShell = true;
     };
-    users.extraGroups."${cfg.group}".gid = config.ids.gids.gitolite;
+    users.groups."${cfg.group}".gid = config.ids.gids.gitolite;
 
     systemd.services."gitolite-init" = {
       description = "Gitolite initialization";
diff --git a/nixos/modules/services/misc/gogs.nix b/nixos/modules/services/misc/gogs.nix
index ba744d37e71c..ee99967c261b 100644
--- a/nixos/modules/services/misc/gogs.nix
+++ b/nixos/modules/services/misc/gogs.nix
@@ -254,7 +254,7 @@ in
     };
 
     users = mkIf (cfg.user == "gogs") {
-      extraUsers.gogs = {
+      users.gogs = {
         description = "Go Git Service";
         uid = config.ids.uids.gogs;
         group = "gogs";
@@ -262,7 +262,7 @@ in
         createHome = true;
         shell = pkgs.bash;
       };
-      extraGroups.gogs.gid = config.ids.gids.gogs;
+      groups.gogs.gid = config.ids.gids.gogs;
     };
 
     warnings = optional (cfg.database.password != "")
diff --git a/nixos/modules/services/misc/gollum.nix b/nixos/modules/services/misc/gollum.nix
index 0888221ab62f..d1823bc6d4df 100644
--- a/nixos/modules/services/misc/gollum.nix
+++ b/nixos/modules/services/misc/gollum.nix
@@ -93,8 +93,8 @@ in
       '';
 
       serviceConfig = {
-        User = config.users.extraUsers.gollum.name;
-        Group = config.users.extraGroups.gollum.name;
+        User = config.users.users.gollum.name;
+        Group = config.users.groups.gollum.name;
         PermissionsStartOnly = true;
         ExecStart = ''
           ${pkgs.gollum}/bin/gollum \
diff --git a/nixos/modules/services/misc/gpsd.nix b/nixos/modules/services/misc/gpsd.nix
index a4a4c7b5d937..3bfcb636a3c6 100644
--- a/nixos/modules/services/misc/gpsd.nix
+++ b/nixos/modules/services/misc/gpsd.nix
@@ -53,6 +53,14 @@ in
         '';
       };
 
+      nowait = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          don't wait for client connects to poll GPS
+        '';
+      };
+
       port = mkOption {
         type = types.int;
         default = 2947;
@@ -78,14 +86,14 @@ in
 
   config = mkIf cfg.enable {
 
-    users.extraUsers = singleton
+    users.users = singleton
       { name = "gpsd";
         inherit uid;
         description = "gpsd daemon user";
         home = "/var/empty";
       };
 
-    users.extraGroups = singleton
+    users.groups = singleton
       { name = "gpsd";
         inherit gid;
       };
@@ -99,7 +107,8 @@ in
         ExecStart = ''
           ${pkgs.gpsd}/sbin/gpsd -D "${toString cfg.debugLevel}"  \
             -S "${toString cfg.port}"                             \
-            ${if cfg.readonly then "-b" else ""}                  \
+            ${optionalString cfg.readonly "-b"}                   \
+            ${optionalString cfg.nowait "-n"}                     \
             "${cfg.device}"
         '';
       };
diff --git a/nixos/modules/services/misc/home-assistant.nix b/nixos/modules/services/misc/home-assistant.nix
index 1dc7b44ee37b..0756e81612ac 100644
--- a/nixos/modules/services/misc/home-assistant.nix
+++ b/nixos/modules/services/misc/home-assistant.nix
@@ -37,7 +37,7 @@ let
   # List of components used in config
   extraComponents = filter useComponent availableComponents;
 
-  package = if cfg.autoExtraComponents
+  package = if (cfg.autoExtraComponents && cfg.config != null)
     then (cfg.package.override { inherit extraComponents; })
     else cfg.package;
 
@@ -110,7 +110,9 @@ in {
       '';
       description = ''
         Home Assistant package to use.
-        Override <literal>extraPackages</literal> in order to add additional dependencies.
+        Override <literal>extraPackages</literal> or <literal>extraComponents</literal> in order to add additional dependencies.
+        If you specify <option>config</option> and do not set <option>autoExtraComponents</option>
+        to <literal>false</literal>, overriding <literal>extraComponents</literal> will have no effect.
       '';
     };
 
@@ -128,9 +130,17 @@ in {
         you might need to specify it in <literal>extraPackages</literal>.
       '';
     };
+
+    openFirewall = mkOption {
+      default = false;
+      type = types.bool;
+      description = "Whether to open the firewall for the specified port.";
+    };
   };
 
   config = mkIf cfg.enable {
+    networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ];
+
     systemd.services.home-assistant = {
       description = "Home Assistant";
       after = [ "network.target" ];
@@ -162,13 +172,13 @@ in {
       after = wants;
     };
 
-    users.extraUsers.hass = {
+    users.users.hass = {
       home = cfg.configDir;
       createHome = true;
       group = "hass";
       uid = config.ids.uids.hass;
     };
 
-    users.extraGroups.hass.gid = config.ids.gids.hass;
+    users.groups.hass.gid = config.ids.gids.hass;
   };
 }
diff --git a/nixos/modules/services/misc/ihaskell.nix b/nixos/modules/services/misc/ihaskell.nix
index 6da9cc8c47e6..11597706d0d1 100644
--- a/nixos/modules/services/misc/ihaskell.nix
+++ b/nixos/modules/services/misc/ihaskell.nix
@@ -38,23 +38,23 @@ in
 
   config = mkIf cfg.enable {
 
-    users.extraUsers.ihaskell = {
-      group = config.users.extraGroups.ihaskell.name;
+    users.users.ihaskell = {
+      group = config.users.groups.ihaskell.name;
       description = "IHaskell user";
       home = "/var/lib/ihaskell";
       createHome = true;
       uid = config.ids.uids.ihaskell;
     };
 
-    users.extraGroups.ihaskell.gid = config.ids.gids.ihaskell;
+    users.groups.ihaskell.gid = config.ids.gids.ihaskell;
 
     systemd.services.ihaskell = {
       description = "IHaskell notebook instance";
       wantedBy = [ "multi-user.target" ];
       after = [ "network.target" ];
       serviceConfig = {
-        User = config.users.extraUsers.ihaskell.name;
-        Group = config.users.extraGroups.ihaskell.name;
+        User = config.users.users.ihaskell.name;
+        Group = config.users.groups.ihaskell.name;
         ExecStart = "${pkgs.runtimeShell} -c \"cd $HOME;${ihaskell}/bin/ihaskell-notebook\"";
       };
     };
diff --git a/nixos/modules/services/misc/jackett.nix b/nixos/modules/services/misc/jackett.nix
index 87a41ee70b54..db72d36f2ac7 100644
--- a/nixos/modules/services/misc/jackett.nix
+++ b/nixos/modules/services/misc/jackett.nix
@@ -36,12 +36,12 @@ in
       };
     };
 
-    users.extraUsers.jackett = {
+    users.users.jackett = {
       uid = config.ids.uids.jackett;
       home = "/var/lib/jackett";
       group = "jackett";
     };
-    users.extraGroups.jackett.gid = config.ids.gids.jackett;
+    users.groups.jackett.gid = config.ids.gids.jackett;
 
   };
 }
diff --git a/nixos/modules/services/misc/leaps.nix b/nixos/modules/services/misc/leaps.nix
index b92cf27f58dc..d4e88ecbebdb 100644
--- a/nixos/modules/services/misc/leaps.nix
+++ b/nixos/modules/services/misc/leaps.nix
@@ -1,4 +1,4 @@
-{ config, pkgs, lib, ... } @ args:
+{ config, pkgs, lib, ... }:
 
 with lib;
 
diff --git a/nixos/modules/services/misc/mathics.nix b/nixos/modules/services/misc/mathics.nix
index 50715858881a..c588a30d76cd 100644
--- a/nixos/modules/services/misc/mathics.nix
+++ b/nixos/modules/services/misc/mathics.nix
@@ -26,23 +26,23 @@ in {
 
   config = mkIf cfg.enable {
 
-    users.extraUsers.mathics = {
-      group = config.users.extraGroups.mathics.name;
+    users.users.mathics = {
+      group = config.users.groups.mathics.name;
       description = "Mathics user";
       home = "/var/lib/mathics";
       createHome = true;
       uid = config.ids.uids.mathics;
     };
 
-    users.extraGroups.mathics.gid = config.ids.gids.mathics;
+    users.groups.mathics.gid = config.ids.gids.mathics;
 
     systemd.services.mathics = {
       description = "Mathics notebook server";
       wantedBy = [ "multi-user.target" ];
       after = [ "network.target" ];
       serviceConfig = {
-        User = config.users.extraUsers.mathics.name;
-        Group = config.users.extraGroups.mathics.name;
+        User = config.users.users.mathics.name;
+        Group = config.users.groups.mathics.name;
         ExecStart = concatStringsSep " " [
           "${pkgs.mathics}/bin/mathicsserver"
           "--port" (toString cfg.port)
diff --git a/nixos/modules/services/misc/matrix-synapse.nix b/nixos/modules/services/misc/matrix-synapse.nix
index f7441988b272..3e3de9114708 100644
--- a/nixos/modules/services/misc/matrix-synapse.nix
+++ b/nixos/modules/services/misc/matrix-synapse.nix
@@ -635,7 +635,7 @@ in {
   };
 
   config = mkIf cfg.enable {
-    users.extraUsers = [
+    users.users = [
       { name = "matrix-synapse";
         group = "matrix-synapse";
         home = cfg.dataDir;
@@ -644,7 +644,7 @@ in {
         uid = config.ids.uids.matrix-synapse;
       } ];
 
-    users.extraGroups = [
+    users.groups = [
       { name = "matrix-synapse";
         gid = config.ids.gids.matrix-synapse;
       } ];
diff --git a/nixos/modules/services/misc/mediatomb.nix b/nixos/modules/services/misc/mediatomb.nix
index 40ec2831ff09..e8e9c0946d7f 100644
--- a/nixos/modules/services/misc/mediatomb.nix
+++ b/nixos/modules/services/misc/mediatomb.nix
@@ -4,7 +4,6 @@ with lib;
 
 let
 
-  uid = config.ids.uids.mediatomb;
   gid = config.ids.gids.mediatomb;
   cfg = config.services.mediatomb;
 
@@ -267,12 +266,12 @@ in {
       serviceConfig.User = "${cfg.user}";
     };
 
-    users.extraGroups = optionalAttrs (cfg.group == "mediatomb") (singleton {
+    users.groups = optionalAttrs (cfg.group == "mediatomb") (singleton {
       name = "mediatomb";
       gid = gid;
     });
 
-    users.extraUsers = optionalAttrs (cfg.user == "mediatomb") (singleton {
+    users.users = optionalAttrs (cfg.user == "mediatomb") (singleton {
       name = "mediatomb";
       isSystemUser = true;
       group = cfg.group;
diff --git a/nixos/modules/services/misc/nix-daemon.nix b/nixos/modules/services/misc/nix-daemon.nix
index 277ae9e292ce..e64df8dc7d2d 100644
--- a/nixos/modules/services/misc/nix-daemon.nix
+++ b/nixos/modules/services/misc/nix-daemon.nix
@@ -33,7 +33,7 @@ let
       sh = pkgs.runtimeShell;
       binshDeps = pkgs.writeReferencesToFile sh;
     in
-      pkgs.runCommand "nix.conf" { extraOptions = cfg.extraOptions; } ''
+      pkgs.runCommand "nix.conf" { extraOptions = cfg.extraOptions; } (''
         ${optionalString (!isNix20) ''
           extraPaths=$(for i in $(cat ${binshDeps}); do if test -d $i; then echo $i; fi; done)
         ''}
@@ -62,7 +62,11 @@ let
         ''}
         $extraOptions
         END
-      '';
+      '' + optionalString cfg.checkConfig ''
+        echo "Checking that Nix can read nix.conf..."
+        ln -s $out ./nix.conf
+        NIX_CONF_DIR=$PWD ${cfg.package}/bin/nix show-config >/dev/null
+      '');
 
 in
 
@@ -126,11 +130,13 @@ in
         default = false;
         description = "
           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. 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.
+          will set up automatically for each build. This prevents impurities
+          in builds by disallowing access to dependencies outside of the Nix
+          store by using network and mount namespaces in a chroot environment.
+          This isn't enabled by default for possible performance impacts due to
+          the initial setup time of a sandbox for each build. It doesn't affect
+          derivation hashes, so changing this option will not trigger a rebuild
+          of packages.
         ";
       };
 
@@ -340,7 +346,7 @@ in
         default =
           [
             "$HOME/.nix-defexpr/channels"
-            "nixpkgs=/nix/var/nix/profiles/per-user/root/channels/nixos/nixpkgs"
+            "nixpkgs=/nix/var/nix/profiles/per-user/root/channels/nixos"
             "nixos-config=/etc/nixos/configuration.nix"
             "/nix/var/nix/profiles/per-user/root/channels"
           ];
@@ -351,6 +357,13 @@ in
         '';
       };
 
+      checkConfig = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          If enabled (the default), checks that Nix can parse the generated nix.conf.
+        '';
+      };
     };
 
   };
@@ -437,7 +450,7 @@ in
 
     nix.nrBuildUsers = mkDefault (lib.max 32 cfg.maxJobs);
 
-    users.extraUsers = nixbldUsers;
+    users.users = nixbldUsers;
 
     services.xserver.displayManager.hiddenUsers = map ({ name, ... }: name) nixbldUsers;
 
diff --git a/nixos/modules/services/misc/nix-ssh-serve.nix b/nixos/modules/services/misc/nix-ssh-serve.nix
index 5bd9cf9086f1..87ed7f0a61b9 100644
--- a/nixos/modules/services/misc/nix-ssh-serve.nix
+++ b/nixos/modules/services/misc/nix-ssh-serve.nix
@@ -36,7 +36,7 @@ in {
 
   config = mkIf cfg.enable {
 
-    users.extraUsers.nix-ssh = {
+    users.users.nix-ssh = {
       description = "Nix SSH store user";
       uid = config.ids.uids.nix-ssh;
       useDefaultShell = true;
@@ -55,7 +55,7 @@ in {
       Match All
     '';
 
-    users.extraUsers.nix-ssh.openssh.authorizedKeys.keys = cfg.keys;
+    users.users.nix-ssh.openssh.authorizedKeys.keys = cfg.keys;
 
   };
 }
diff --git a/nixos/modules/services/misc/nixos-manual.nix b/nixos/modules/services/misc/nixos-manual.nix
index 4bd1c20edf71..3916c3052e8b 100644
--- a/nixos/modules/services/misc/nixos-manual.nix
+++ b/nixos/modules/services/misc/nixos-manual.nix
@@ -99,7 +99,7 @@ in
 
     services.nixosManual.browser = mkOption {
       type = types.path;
-      default = "${pkgs.w3m-nox}/bin/w3m";
+      default = "${pkgs.w3m-nographics}/bin/w3m";
       description = ''
         Browser used to show the manual.
       '';
diff --git a/nixos/modules/services/misc/nzbget.nix b/nixos/modules/services/misc/nzbget.nix
index a186d57ceba2..a472b6c7157c 100644
--- a/nixos/modules/services/misc/nzbget.nix
+++ b/nixos/modules/services/misc/nzbget.nix
@@ -4,7 +4,7 @@ with lib;
 
 let
   cfg = config.services.nzbget;
-  nzbget = pkgs.nzbget; in {
+in {
   options = {
     services.nzbget = {
       enable = mkEnableOption "NZBGet";
@@ -86,14 +86,14 @@ let
       };
     };
 
-    users.extraUsers = mkIf (cfg.user == "nzbget") {
+    users.users = mkIf (cfg.user == "nzbget") {
       nzbget = {
         group = cfg.group;
         uid = config.ids.uids.nzbget;
       };
     };
 
-    users.extraGroups = mkIf (cfg.group == "nzbget") {
+    users.groups = mkIf (cfg.group == "nzbget") {
       nzbget = {
         gid = config.ids.gids.nzbget;
       };
diff --git a/nixos/modules/services/misc/octoprint.nix b/nixos/modules/services/misc/octoprint.nix
index 6883993a893b..baa7c3ade52e 100644
--- a/nixos/modules/services/misc/octoprint.nix
+++ b/nixos/modules/services/misc/octoprint.nix
@@ -86,13 +86,13 @@ in
 
   config = mkIf cfg.enable {
 
-    users.extraUsers = optionalAttrs (cfg.user == "octoprint") (singleton
+    users.users = optionalAttrs (cfg.user == "octoprint") (singleton
       { name = "octoprint";
         group = cfg.group;
         uid = config.ids.uids.octoprint;
       });
 
-    users.extraGroups = optionalAttrs (cfg.group == "octoprint") (singleton
+    users.groups = optionalAttrs (cfg.group == "octoprint") (singleton
       { name = "octoprint";
         gid = config.ids.gids.octoprint;
       });
diff --git a/nixos/modules/services/misc/osrm.nix b/nixos/modules/services/misc/osrm.nix
index 7ec8b15906fc..f89f37ccd9df 100644
--- a/nixos/modules/services/misc/osrm.nix
+++ b/nixos/modules/services/misc/osrm.nix
@@ -69,7 +69,7 @@ in
       wantedBy = [ "multi-user.target" ];
 
       serviceConfig = {
-        User = config.users.extraUsers.osrm.name;
+        User = config.users.users.osrm.name;
         ExecStart = ''
           ${pkgs.osrm-backend}/bin/osrm-routed \
             --ip ${cfg.address} \
diff --git a/nixos/modules/services/misc/plex.nix b/nixos/modules/services/misc/plex.nix
index 46221ace3084..8fe5879c2764 100644
--- a/nixos/modules/services/misc/plex.nix
+++ b/nixos/modules/services/misc/plex.nix
@@ -4,7 +4,6 @@ with lib;
 
 let
   cfg = config.services.plex;
-  plex = pkgs.plex;
 in
 {
   options = {
@@ -157,14 +156,14 @@ in
       allowedUDPPorts = [ 1900 5353 32410 32412 32413 32414 ];
     };
 
-    users.extraUsers = mkIf (cfg.user == "plex") {
+    users.users = mkIf (cfg.user == "plex") {
       plex = {
         group = cfg.group;
         uid = config.ids.uids.plex;
       };
     };
 
-    users.extraGroups = mkIf (cfg.group == "plex") {
+    users.groups = mkIf (cfg.group == "plex") {
       plex = {
         gid = config.ids.gids.plex;
       };
diff --git a/nixos/modules/services/misc/plexpy.nix b/nixos/modules/services/misc/plexpy.nix
index df9f12581247..2a589fdfb27f 100644
--- a/nixos/modules/services/misc/plexpy.nix
+++ b/nixos/modules/services/misc/plexpy.nix
@@ -74,7 +74,7 @@ in
       };
     };
 
-    users.extraUsers = mkIf (cfg.user == "plexpy") {
+    users.users = mkIf (cfg.user == "plexpy") {
       plexpy = { group = cfg.group; uid = config.ids.uids.plexpy; };
     };
   };
diff --git a/nixos/modules/services/misc/pykms.nix b/nixos/modules/services/misc/pykms.nix
index 897e856e2a2d..a11296e1bd02 100644
--- a/nixos/modules/services/misc/pykms.nix
+++ b/nixos/modules/services/misc/pykms.nix
@@ -73,7 +73,7 @@ in {
     };
 
     users = {
-      extraUsers.pykms = {
+      users.pykms = {
         name = "pykms";
         group = "pykms";
         home  = home;
@@ -82,7 +82,7 @@ in {
         description = "PyKMS daemon user";
       };
 
-      extraGroups.pykms = {
+      groups.pykms = {
         gid = config.ids.gids.pykms;
       };
     };
diff --git a/nixos/modules/services/misc/radarr.nix b/nixos/modules/services/misc/radarr.nix
index 245ad9f9a6df..7738eacc6ae9 100644
--- a/nixos/modules/services/misc/radarr.nix
+++ b/nixos/modules/services/misc/radarr.nix
@@ -36,12 +36,12 @@ in
       };
     };
 
-    users.extraUsers.radarr = {
+    users.users.radarr = {
       uid = config.ids.uids.radarr;
       home = "/var/lib/radarr";
       group = "radarr";
     };
-    users.extraGroups.radarr.gid = config.ids.gids.radarr;
+    users.groups.radarr.gid = config.ids.gids.radarr;
 
   };
 }
diff --git a/nixos/modules/services/misc/redmine.nix b/nixos/modules/services/misc/redmine.nix
index 3997b3f0dca0..9a9424449f80 100644
--- a/nixos/modules/services/misc/redmine.nix
+++ b/nixos/modules/services/misc/redmine.nix
@@ -128,13 +128,13 @@ in {
       }
     ];
 
-    users.extraUsers = [
+    users.users = [
       { name = "redmine";
         group = "redmine";
         uid = config.ids.uids.redmine;
       } ];
 
-    users.extraGroups = [
+    users.groups = [
       { name = "redmine";
         gid = config.ids.gids.redmine;
       } ];
diff --git a/nixos/modules/services/misc/ripple-data-api.nix b/nixos/modules/services/misc/ripple-data-api.nix
index dbca56b13335..042b496d35ee 100644
--- a/nixos/modules/services/misc/ripple-data-api.nix
+++ b/nixos/modules/services/misc/ripple-data-api.nix
@@ -185,7 +185,7 @@ in {
       ];
     };
 
-    users.extraUsers = singleton
+    users.users = singleton
       { name = "ripple-data-api";
         description = "Ripple data api user";
         uid = config.ids.uids.ripple-data-api;
diff --git a/nixos/modules/services/misc/rippled.nix b/nixos/modules/services/misc/rippled.nix
index 8bcf35a8ad38..9d9a0ba44da5 100644
--- a/nixos/modules/services/misc/rippled.nix
+++ b/nixos/modules/services/misc/rippled.nix
@@ -406,7 +406,7 @@ in
 
   config = mkIf cfg.enable {
 
-    users.extraUsers = singleton
+    users.users = singleton
       { name = "rippled";
         description = "Ripple server user";
         uid = config.ids.uids.rippled;
diff --git a/nixos/modules/services/misc/serviio.nix b/nixos/modules/services/misc/serviio.nix
index a6612e9c6adb..8808f2d21931 100644
--- a/nixos/modules/services/misc/serviio.nix
+++ b/nixos/modules/services/misc/serviio.nix
@@ -63,7 +63,7 @@ in {
       };
     };
 
-    users.extraUsers = [
+    users.users = [
       { 
         name = "serviio";
         group = "serviio";
@@ -74,7 +74,7 @@ in {
       }
     ];
 
-    users.extraGroups = [
+    users.groups = [
       { name = "serviio";} 
     ];
 
diff --git a/nixos/modules/services/misc/siproxd.nix b/nixos/modules/services/misc/siproxd.nix
index 9e8fb6c228f2..dcaf73aca448 100644
--- a/nixos/modules/services/misc/siproxd.nix
+++ b/nixos/modules/services/misc/siproxd.nix
@@ -161,7 +161,7 @@ in
 
   config = mkIf cfg.enable {
 
-    users.extraUsers = singleton {
+    users.users = singleton {
       name = "siproxyd";
       uid = config.ids.uids.siproxd;
     };
diff --git a/nixos/modules/services/misc/sonarr.nix b/nixos/modules/services/misc/sonarr.nix
index ecde2c33bfa9..edba4e6c23eb 100644
--- a/nixos/modules/services/misc/sonarr.nix
+++ b/nixos/modules/services/misc/sonarr.nix
@@ -36,12 +36,12 @@ in
       };
     };
 
-    users.extraUsers.sonarr = {
+    users.users.sonarr = {
       uid = config.ids.uids.sonarr;
       home = "/var/lib/sonarr";
       group = "sonarr";
     };
-    users.extraGroups.sonarr.gid = config.ids.gids.sonarr;
+    users.groups.sonarr.gid = config.ids.gids.sonarr;
 
   };
 }
diff --git a/nixos/modules/services/misc/subsonic.nix b/nixos/modules/services/misc/subsonic.nix
index c2efd53d413a..1612b197f35f 100644
--- a/nixos/modules/services/misc/subsonic.nix
+++ b/nixos/modules/services/misc/subsonic.nix
@@ -130,7 +130,7 @@ let cfg = config.services.subsonic; in {
                 ! [ -e "${cfg.home}" ] &&
                 [ -d "$oldHome" ] &&
                 [ $(${pkgs.coreutils}/bin/stat -c %u "$oldHome") -eq \
-                    ${toString config.users.extraUsers.subsonic.uid} ]; then
+                    ${toString config.users.users.subsonic.uid} ]; then
             logger Moving "$oldHome" to "${cfg.home}"
             ${pkgs.coreutils}/bin/mv -T "$oldHome" "${cfg.home}"
         fi
@@ -152,7 +152,7 @@ let cfg = config.services.subsonic; in {
       };
     };
 
-    users.extraUsers.subsonic = {
+    users.users.subsonic = {
       description = "Subsonic daemon user";
       home = cfg.home;
       createHome = true;
@@ -160,6 +160,6 @@ let cfg = config.services.subsonic; in {
       uid = config.ids.uids.subsonic;
     };
 
-    users.extraGroups.subsonic.gid = config.ids.gids.subsonic;
+    users.groups.subsonic.gid = config.ids.gids.subsonic;
   };
 }
diff --git a/nixos/modules/services/misc/taskserver/default.nix b/nixos/modules/services/misc/taskserver/default.nix
index ba9f52f1904b..7daf12f91714 100644
--- a/nixos/modules/services/misc/taskserver/default.nix
+++ b/nixos/modules/services/misc/taskserver/default.nix
@@ -7,16 +7,6 @@ let
 
   taskd = "${pkgs.taskserver}/bin/taskd";
 
-  mkVal = val:
-    if val == true then "true"
-    else if val == false then "false"
-    else if isList val then concatStringsSep ", " val
-    else toString val;
-
-  mkConfLine = key: val: let
-    result = "${key} = ${mkVal val}";
-  in optionalString (val != null && val != []) result;
-
   mkManualPkiOption = desc: mkOption {
     type = types.nullOr types.path;
     default = null;
diff --git a/nixos/modules/services/misc/uhub.nix b/nixos/modules/services/misc/uhub.nix
index 15071202b9c2..005951b9231e 100644
--- a/nixos/modules/services/misc/uhub.nix
+++ b/nixos/modules/services/misc/uhub.nix
@@ -161,11 +161,11 @@ in
   config = mkIf cfg.enable {
 
     users = {
-      extraUsers = singleton {
+      users = singleton {
         name = "uhub";
         uid = config.ids.uids.uhub;
       };
-      extraGroups = singleton {
+      groups = singleton {
         name = "uhub";
         gid = config.ids.gids.uhub;
       };
diff --git a/nixos/modules/services/misc/xmr-stak.nix b/nixos/modules/services/misc/xmr-stak.nix
index 57f439365471..a87878c31e0d 100644
--- a/nixos/modules/services/misc/xmr-stak.nix
+++ b/nixos/modules/services/misc/xmr-stak.nix
@@ -10,9 +10,6 @@ let
     inherit (cfg) openclSupport cudaSupport;
   };
 
-  xmrConfArg = optionalString (cfg.configText != "") ("-c " +
-    pkgs.writeText "xmr-stak-config.txt" cfg.configText);
-
 in
 
 {
@@ -29,22 +26,34 @@ in
         description = "List of parameters to pass to xmr-stak.";
       };
 
-      configText = mkOption {
-        type = types.lines;
-        default = "";
-        example = ''
-          "currency" : "monero",
-          "pool_list" :
-            [ { "pool_address" : "pool.supportxmr.com:5555",
-                "wallet_address" : "<long-hash>",
-                "pool_password" : "minername",
-                "pool_weight" : 1,
-              },
-            ],
+      configFiles = mkOption {
+        type = types.attrsOf types.str;
+        default = {};
+        example = literalExample ''
+          {
+            "config.txt" = '''
+              "verbose_level" : 4,
+              "h_print_time" : 60,
+              "tls_secure_algo" : true,
+            ''';
+            "pools.txt" = '''
+              "currency" : "monero7",
+              "pool_list" :
+              [ { "pool_address" : "pool.supportxmr.com:443",
+                  "wallet_address" : "my-wallet-address",
+                  "rig_id" : "",
+                  "pool_password" : "nixos",
+                  "use_nicehash" : false,
+                  "use_tls" : true,
+                  "tls_fingerprint" : "",
+                  "pool_weight" : 23
+                },
+              ],
+            ''';
+          }
         '';
         description = ''
-          Verbatim xmr-stak config.txt. If empty, the <literal>-c</literal>
-          parameter will not be added to the xmr-stak command.
+          Content of config files like config.txt, pools.txt or cpu.txt.
         '';
       };
     };
@@ -58,10 +67,13 @@ in
       environment = mkIf cfg.cudaSupport {
         LD_LIBRARY_PATH = "${pkgs.linuxPackages_latest.nvidia_x11}/lib";
       };
-      script = ''
-        exec ${pkg}/bin/xmr-stak ${xmrConfArg} ${concatStringsSep " " cfg.extraArgs}
-      '';
+
+      preStart = concatStrings (flip mapAttrsToList cfg.configFiles (fn: content: ''
+        ln -sf '${pkgs.writeText "xmr-stak-${fn}" content}' '${fn}'
+      ''));
+
       serviceConfig = let rootRequired = cfg.openclSupport || cfg.cudaSupport; in {
+        ExecStart = "${pkg}/bin/xmr-stak ${concatStringsSep " " cfg.extraArgs}";
         # xmr-stak generates cpu and/or gpu configuration files
         WorkingDirectory = "/tmp";
         PrivateTmp = true;
@@ -70,4 +82,12 @@ in
       };
     };
   };
+
+  imports = [
+    (mkRemovedOptionModule ["services" "xmr-stak" "configText"] ''
+      This option was removed in favour of `services.xmr-stak.configFiles`
+      because the new config file `pools.txt` was introduced. You are
+      now able to define all other config files like cpu.txt or amd.txt.
+    '')
+  ];
 }
diff --git a/nixos/modules/services/misc/zookeeper.nix b/nixos/modules/services/misc/zookeeper.nix
index 91539592511c..cb7cc97d5a5c 100644
--- a/nixos/modules/services/misc/zookeeper.nix
+++ b/nixos/modules/services/misc/zookeeper.nix
@@ -144,7 +144,7 @@ in {
       '';
     };
 
-    users.extraUsers = singleton {
+    users.users = singleton {
       name = "zookeeper";
       uid = config.ids.uids.zookeeper;
       description = "Zookeeper daemon user";
diff --git a/nixos/modules/services/monitoring/bosun.nix b/nixos/modules/services/monitoring/bosun.nix
index 496838a131ba..8bf741adb6e3 100644
--- a/nixos/modules/services/monitoring/bosun.nix
+++ b/nixos/modules/services/monitoring/bosun.nix
@@ -153,13 +153,13 @@ in {
       };
     };
 
-    users.extraUsers.bosun = {
+    users.users.bosun = {
       description = "bosun user";
       group = "bosun";
       uid = config.ids.uids.bosun;
     };
 
-    users.extraGroups.bosun.gid = config.ids.gids.bosun;
+    users.groups.bosun.gid = config.ids.gids.bosun;
 
   };
 
diff --git a/nixos/modules/services/monitoring/collectd.nix b/nixos/modules/services/monitoring/collectd.nix
index dfbac3446e03..6606980cdad8 100644
--- a/nixos/modules/services/monitoring/collectd.nix
+++ b/nixos/modules/services/monitoring/collectd.nix
@@ -97,7 +97,7 @@ in {
       '';
     };
 
-    users.extraUsers = optional (cfg.user == "collectd") {
+    users.users = optional (cfg.user == "collectd") {
       name = "collectd";
     };
   };
diff --git a/nixos/modules/services/monitoring/dd-agent/dd-agent.nix b/nixos/modules/services/monitoring/dd-agent/dd-agent.nix
index beaa2c01b298..cf65b6c28cf2 100644
--- a/nixos/modules/services/monitoring/dd-agent/dd-agent.nix
+++ b/nixos/modules/services/monitoring/dd-agent/dd-agent.nix
@@ -57,7 +57,7 @@ let
     instances:
       - use_mount: no
   '';
-  
+
   networkConfig = pkgs.writeText "network.yaml" ''
     init_config:
 
@@ -68,13 +68,13 @@ let
           - lo
           - lo0
   '';
-  
+
   postgresqlConfig = pkgs.writeText "postgres.yaml" cfg.postgresqlConfig;
   nginxConfig = pkgs.writeText "nginx.yaml" cfg.nginxConfig;
   mongoConfig = pkgs.writeText "mongo.yaml" cfg.mongoConfig;
   jmxConfig = pkgs.writeText "jmx.yaml" cfg.jmxConfig;
   processConfig = pkgs.writeText "process.yaml" cfg.processConfig;
-  
+
   etcfiles =
     let
       defaultConfd = import ./dd-agent-defaults.nix;
@@ -150,7 +150,7 @@ in {
       default = null;
       type = types.uniq (types.nullOr types.string);
     };
-    
+
     mongoConfig = mkOption {
       description = "MongoDB integration configuration";
       default = null;
@@ -166,7 +166,7 @@ in {
     processConfig = mkOption {
       description = ''
         Process integration configuration
- 
+
         See http://docs.datadoghq.com/integrations/process/
       '';
       default = null;
@@ -178,7 +178,7 @@ in {
   config = mkIf cfg.enable {
     environment.systemPackages = [ pkgs."dd-agent" pkgs.sysstat pkgs.procps ];
 
-    users.extraUsers.datadog = {
+    users.users.datadog = {
       description = "Datadog Agent User";
       uid = config.ids.uids.datadog;
       group = "datadog";
@@ -186,11 +186,11 @@ in {
       createHome = true;
     };
 
-    users.extraGroups.datadog.gid = config.ids.gids.datadog;
+    users.groups.datadog.gid = config.ids.gids.datadog;
 
     systemd.services.dd-agent = {
       description = "Datadog agent monitor";
-      path = [ pkgs."dd-agent" pkgs.python pkgs.sysstat pkgs.procps ];
+      path = [ pkgs."dd-agent" pkgs.python pkgs.sysstat pkgs.procps pkgs.gohai ];
       wantedBy = [ "multi-user.target" ];
       serviceConfig = {
         ExecStart = "${pkgs.dd-agent}/bin/dd-agent foreground";
diff --git a/nixos/modules/services/monitoring/fusion-inventory.nix b/nixos/modules/services/monitoring/fusion-inventory.nix
index c3b869e00880..9c976c65ea49 100644
--- a/nixos/modules/services/monitoring/fusion-inventory.nix
+++ b/nixos/modules/services/monitoring/fusion-inventory.nix
@@ -46,7 +46,7 @@ in {
 
   config = mkIf cfg.enable {
 
-    users.extraUsers = singleton {
+    users.users = singleton {
       name = "fusion-inventory";
       description = "FusionInventory user";
     };
diff --git a/nixos/modules/services/monitoring/grafana.nix b/nixos/modules/services/monitoring/grafana.nix
index eceb91525db4..3e801f9b838d 100644
--- a/nixos/modules/services/monitoring/grafana.nix
+++ b/nixos/modules/services/monitoring/grafana.nix
@@ -265,7 +265,7 @@ in {
       '';
     };
 
-    users.extraUsers.grafana = {
+    users.users.grafana = {
       uid = config.ids.uids.grafana;
       description = "Grafana user";
       home = cfg.dataDir;
diff --git a/nixos/modules/services/monitoring/graphite.nix b/nixos/modules/services/monitoring/graphite.nix
index 4b1ad34b3a4e..7ad26c137e51 100644
--- a/nixos/modules/services/monitoring/graphite.nix
+++ b/nixos/modules/services/monitoring/graphite.nix
@@ -638,13 +638,13 @@ in {
       cfg.web.enable || cfg.api.enable ||
       cfg.seyren.enable || cfg.pager.enable || cfg.beacon.enable
      ) {
-      users.extraUsers = singleton {
+      users.users = singleton {
         name = "graphite";
         uid = config.ids.uids.graphite;
         description = "Graphite daemon user";
         home = dataDir;
       };
-      users.extraGroups.graphite.gid = config.ids.gids.graphite;
+      users.groups.graphite.gid = config.ids.gids.graphite;
     })
   ];
 }
diff --git a/nixos/modules/services/monitoring/heapster.nix b/nixos/modules/services/monitoring/heapster.nix
index deee64aa41ea..fbdff2eb5dbe 100644
--- a/nixos/modules/services/monitoring/heapster.nix
+++ b/nixos/modules/services/monitoring/heapster.nix
@@ -49,7 +49,7 @@ in {
       };
     };
 
-    users.extraUsers = singleton {
+    users.users = singleton {
       name = "heapster";
       uid = config.ids.uids.heapster;
       description = "Heapster user";
diff --git a/nixos/modules/services/monitoring/munin.nix b/nixos/modules/services/monitoring/munin.nix
index 358ffd431dd4..ff9604c7dbcd 100644
--- a/nixos/modules/services/monitoring/munin.nix
+++ b/nixos/modules/services/monitoring/munin.nix
@@ -150,14 +150,14 @@ in
 
     environment.systemPackages = [ pkgs.munin ];
 
-    users.extraUsers = [{
+    users.users = [{
       name = "munin";
       description = "Munin monitoring user";
       group = "munin";
       uid = config.ids.uids.munin;
     }];
 
-    users.extraGroups = [{
+    users.groups = [{
       name = "munin";
       gid = config.ids.gids.munin;
     }];
diff --git a/nixos/modules/services/monitoring/nagios.nix b/nixos/modules/services/monitoring/nagios.nix
index 4914c5db97d2..3e1d727b416e 100644
--- a/nixos/modules/services/monitoring/nagios.nix
+++ b/nixos/modules/services/monitoring/nagios.nix
@@ -143,7 +143,7 @@ in
 
 
   config = mkIf cfg.enable {
-    users.extraUsers.nagios = {
+    users.users.nagios = {
       description = "Nagios user ";
       uid         = config.ids.uids.nagios;
       home        = nagiosState;
diff --git a/nixos/modules/services/monitoring/netdata.nix b/nixos/modules/services/monitoring/netdata.nix
index d23b329eeb25..eefddf5a206b 100644
--- a/nixos/modules/services/monitoring/netdata.nix
+++ b/nixos/modules/services/monitoring/netdata.nix
@@ -100,11 +100,11 @@ in {
     };
 
 
-    users.extraUsers = optional (cfg.user == defaultUser) {
+    users.users = optional (cfg.user == defaultUser) {
       name = defaultUser;
     };
 
-    users.extraGroups = optional (cfg.group == defaultUser) {
+    users.groups = optional (cfg.group == defaultUser) {
       name = defaultUser;
     };
 
diff --git a/nixos/modules/services/monitoring/prometheus/default.nix b/nixos/modules/services/monitoring/prometheus/default.nix
index 80122e69d167..5dda763bd56b 100644
--- a/nixos/modules/services/monitoring/prometheus/default.nix
+++ b/nixos/modules/services/monitoring/prometheus/default.nix
@@ -471,8 +471,8 @@ in {
   };
 
   config = mkIf cfg.enable {
-    users.extraGroups.${promGroup}.gid = config.ids.gids.prometheus;
-    users.extraUsers.${promUser} = {
+    users.groups.${promGroup}.gid = config.ids.gids.prometheus;
+    users.users.${promUser} = {
       description = "Prometheus daemon user";
       uid = config.ids.uids.prometheus;
       group = promGroup;
diff --git a/nixos/modules/services/monitoring/prometheus/exporters.nix b/nixos/modules/services/monitoring/prometheus/exporters.nix
index 780448d8bad8..8d2c303a69e8 100644
--- a/nixos/modules/services/monitoring/prometheus/exporters.nix
+++ b/nixos/modules/services/monitoring/prometheus/exporters.nix
@@ -20,6 +20,7 @@ let
   exporterOpts = {
     blackbox  = import ./exporters/blackbox.nix  { inherit config lib pkgs; };
     collectd  = import ./exporters/collectd.nix  { inherit config lib pkgs; };
+    dnsmasq   = import ./exporters/dnsmasq.nix   { inherit config lib pkgs; };
     dovecot   = import ./exporters/dovecot.nix   { inherit config lib pkgs; };
     fritzbox  = import ./exporters/fritzbox.nix  { inherit config lib pkgs; };
     json      = import ./exporters/json.nix      { inherit config lib pkgs; };
diff --git a/nixos/modules/services/monitoring/prometheus/exporters/dnsmasq.nix b/nixos/modules/services/monitoring/prometheus/exporters/dnsmasq.nix
new file mode 100644
index 000000000000..b1fab85109af
--- /dev/null
+++ b/nixos/modules/services/monitoring/prometheus/exporters/dnsmasq.nix
@@ -0,0 +1,39 @@
+{ config, lib, pkgs }:
+
+with lib;
+
+let
+  cfg = config.services.prometheus.exporters.dnsmasq;
+in
+{
+  port = 9153;
+  extraOpts = {
+    dnsmasqListenAddress = mkOption {
+      type = types.str;
+      default = "localhost:53";
+      description = ''
+        Address on which dnsmasq listens.
+      '';
+    };
+    leasesPath = mkOption {
+      type = types.path;
+      default = "/var/lib/misc/dnsmasq.leases";
+      example = "/var/lib/dnsmasq/dnsmasq.leases";
+      description = ''
+        Path to the <literal>dnsmasq.leases</literal> file.
+      '';
+    };
+  };
+  serviceOpts = {
+    serviceConfig = {
+      DynamicUser = true;
+      ExecStart = ''
+        ${pkgs.prometheus-dnsmasq-exporter}/bin/dnsmasq_exporter \
+          --listen ${cfg.listenAddress}:${toString cfg.port} \
+          --dnsmasq ${cfg.dnsmasqListenAddress} \
+          --leases_path ${cfg.leasesPath} \
+          ${concatStringsSep " \\\n  " cfg.extraFlags}
+      '';
+    };
+  };
+}
diff --git a/nixos/modules/services/monitoring/prometheus/exporters/node.nix b/nixos/modules/services/monitoring/prometheus/exporters/node.nix
index c85f5f9cfb2d..ee7bf39f199a 100644
--- a/nixos/modules/services/monitoring/prometheus/exporters/node.nix
+++ b/nixos/modules/services/monitoring/prometheus/exporters/node.nix
@@ -27,6 +27,7 @@ in
   };
   serviceOpts = {
     serviceConfig = {
+      RuntimeDirectory = "prometheus-node-exporter";
       ExecStart = ''
         ${pkgs.prometheus-node-exporter}/bin/node_exporter \
           ${concatMapStringsSep " " (x: "--collector." + x) cfg.enabledCollectors} \
diff --git a/nixos/modules/services/monitoring/riemann-dash.nix b/nixos/modules/services/monitoring/riemann-dash.nix
index 523f74cb72b9..7eb4d888b0cc 100644
--- a/nixos/modules/services/monitoring/riemann-dash.nix
+++ b/nixos/modules/services/monitoring/riemann-dash.nix
@@ -51,9 +51,9 @@ in {
 
   config = mkIf cfg.enable {
 
-    users.extraGroups.riemanndash.gid = config.ids.gids.riemanndash;
+    users.groups.riemanndash.gid = config.ids.gids.riemanndash;
 
-    users.extraUsers.riemanndash = {
+    users.users.riemanndash = {
       description = "riemann-dash daemon user";
       uid = config.ids.uids.riemanndash;
       group = "riemanndash";
diff --git a/nixos/modules/services/monitoring/riemann-tools.nix b/nixos/modules/services/monitoring/riemann-tools.nix
index de858813a762..4e8832dadc5e 100644
--- a/nixos/modules/services/monitoring/riemann-tools.nix
+++ b/nixos/modules/services/monitoring/riemann-tools.nix
@@ -40,9 +40,9 @@ in {
 
   config = mkIf cfg.enableHealth {
 
-    users.extraGroups.riemanntools.gid = config.ids.gids.riemanntools;
+    users.groups.riemanntools.gid = config.ids.gids.riemanntools;
 
-    users.extraUsers.riemanntools = {
+    users.users.riemanntools = {
       description = "riemann-tools daemon user";
       uid = config.ids.uids.riemanntools;
       group = "riemanntools";
diff --git a/nixos/modules/services/monitoring/riemann.nix b/nixos/modules/services/monitoring/riemann.nix
index ac5d0134a80d..237de53456f9 100644
--- a/nixos/modules/services/monitoring/riemann.nix
+++ b/nixos/modules/services/monitoring/riemann.nix
@@ -69,9 +69,9 @@ in {
 
   config = mkIf cfg.enable {
 
-    users.extraGroups.riemann.gid = config.ids.gids.riemann;
+    users.groups.riemann.gid = config.ids.gids.riemann;
 
-    users.extraUsers.riemann = {
+    users.users.riemann = {
       description = "riemann daemon user";
       uid = config.ids.uids.riemann;
       group = "riemann";
diff --git a/nixos/modules/services/monitoring/scollector.nix b/nixos/modules/services/monitoring/scollector.nix
index 2684482c6184..6ecb21d628de 100644
--- a/nixos/modules/services/monitoring/scollector.nix
+++ b/nixos/modules/services/monitoring/scollector.nix
@@ -123,13 +123,13 @@ in {
       };
     };
 
-    users.extraUsers.scollector = {
+    users.users.scollector = {
       description = "scollector user";
       group = "scollector";
       uid = config.ids.uids.scollector;
     };
 
-    users.extraGroups.scollector.gid = config.ids.gids.scollector;
+    users.groups.scollector.gid = config.ids.gids.scollector;
 
   };
 
diff --git a/nixos/modules/services/monitoring/statsd.nix b/nixos/modules/services/monitoring/statsd.nix
index 7b0e9981cbb1..ea155821ecc9 100644
--- a/nixos/modules/services/monitoring/statsd.nix
+++ b/nixos/modules/services/monitoring/statsd.nix
@@ -125,7 +125,7 @@ in
       message = "Only builtin backends (graphite, console, repeater) or backends enumerated in `pkgs.nodePackages` are allowed!";
     }) cfg.backends;
 
-    users.extraUsers = singleton {
+    users.users = singleton {
       name = "statsd";
       uid = config.ids.uids.statsd;
       description = "Statsd daemon user";
diff --git a/nixos/modules/services/monitoring/telegraf.nix b/nixos/modules/services/monitoring/telegraf.nix
index 49dc9d8143e6..6bfcd7143e1c 100644
--- a/nixos/modules/services/monitoring/telegraf.nix
+++ b/nixos/modules/services/monitoring/telegraf.nix
@@ -62,7 +62,7 @@ in {
       };
     };
 
-    users.extraUsers = [{
+    users.users = [{
       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 29dc68f90cc9..bc755612fd9b 100644
--- a/nixos/modules/services/monitoring/ups.nix
+++ b/nixos/modules/services/monitoring/ups.nix
@@ -259,7 +259,7 @@ in
 
 
 /*
-    users.extraUsers = [
+    users.users = [
       { name = "nut";
         uid = 84;
         home = "/var/lib/nut";
@@ -269,7 +269,7 @@ in
       }
     ];
 
-    users.extraGroups = [
+    users.groups = [
       { name = "nut";
         gid = 84;
       }
diff --git a/nixos/modules/services/monitoring/uptime.nix b/nixos/modules/services/monitoring/uptime.nix
index 29616a085c8f..b4d3a2640109 100644
--- a/nixos/modules/services/monitoring/uptime.nix
+++ b/nixos/modules/services/monitoring/uptime.nix
@@ -1,6 +1,6 @@
 { config, pkgs, lib, ... }:
 let
-  inherit (lib) mkOption mkEnableOption mkIf mkMerge types optionalAttrs optional;
+  inherit (lib) mkOption mkEnableOption mkIf mkMerge types optional;
 
   cfg = config.services.uptime;
 
diff --git a/nixos/modules/services/monitoring/vnstat.nix b/nixos/modules/services/monitoring/vnstat.nix
index ca56e4a7b958..cb2f8c07edb9 100644
--- a/nixos/modules/services/monitoring/vnstat.nix
+++ b/nixos/modules/services/monitoring/vnstat.nix
@@ -16,7 +16,7 @@ in {
   };
 
   config = mkIf cfg.enable {
-    users.extraUsers.vnstatd = {
+    users.users.vnstatd = {
       isSystemUser = true;
       description = "vnstat daemon user";
       home = "/var/lib/vnstat";
diff --git a/nixos/modules/services/monitoring/zabbix-agent.nix b/nixos/modules/services/monitoring/zabbix-agent.nix
index 88a63b4bf161..87857225e7d7 100644
--- a/nixos/modules/services/monitoring/zabbix-agent.nix
+++ b/nixos/modules/services/monitoring/zabbix-agent.nix
@@ -68,7 +68,7 @@ in
 
   config = mkIf cfg.enable {
 
-    users.extraUsers = mkIf (!config.services.zabbixServer.enable) (singleton
+    users.users = mkIf (!config.services.zabbixServer.enable) (singleton
       { name = "zabbix";
         uid = config.ids.uids.zabbix;
         description = "Zabbix daemon user";
diff --git a/nixos/modules/services/monitoring/zabbix-server.nix b/nixos/modules/services/monitoring/zabbix-server.nix
index acd1279ddf47..f62d55457ed4 100644
--- a/nixos/modules/services/monitoring/zabbix-server.nix
+++ b/nixos/modules/services/monitoring/zabbix-server.nix
@@ -85,7 +85,7 @@ in
 
     services.postgresql.enable = useLocalPostgres;
 
-    users.extraUsers = singleton
+    users.users = singleton
       { name = "zabbix";
         uid = config.ids.uids.zabbix;
         description = "Zabbix daemon user";
diff --git a/nixos/modules/services/network-filesystems/beegfs.nix b/nixos/modules/services/network-filesystems/beegfs.nix
index a6a2ec6cbc36..182fabf6405f 100644
--- a/nixos/modules/services/network-filesystems/beegfs.nix
+++ b/nixos/modules/services/network-filesystems/beegfs.nix
@@ -31,7 +31,7 @@ let
     connPortShift = ${toString cfg.connPortShift}
     storeAllowFirstRunInit = false
 
-    ${cfg.mgmtd.extraConfig}
+    ${cfg.meta.extraConfig}
   '';
 
   configStorage = name: cfg: pkgs.writeText "storage-${name}.conf" ''
diff --git a/nixos/modules/services/network-filesystems/ceph.nix b/nixos/modules/services/network-filesystems/ceph.nix
index 5de8ae79a246..4e3bc839d400 100644
--- a/nixos/modules/services/network-filesystems/ceph.nix
+++ b/nixos/modules/services/network-filesystems/ceph.nix
@@ -332,13 +332,13 @@ in
       in
         generators.toINI {} totalConfig;
 
-    users.extraUsers = singleton {
+    users.users = singleton {
       name = "ceph";
       uid = config.ids.uids.ceph;
       description = "Ceph daemon user";
     };
 
-    users.extraGroups = singleton {
+    users.groups = singleton {
       name = "ceph";
       gid = config.ids.gids.ceph;
     };
diff --git a/nixos/modules/services/network-filesystems/davfs2.nix b/nixos/modules/services/network-filesystems/davfs2.nix
index 6b2a770100c5..c16e12378d75 100644
--- a/nixos/modules/services/network-filesystems/davfs2.nix
+++ b/nixos/modules/services/network-filesystems/davfs2.nix
@@ -57,12 +57,12 @@ in
     environment.systemPackages = [ pkgs.davfs2 ];
     environment.etc."davfs2/davfs2.conf".source = cfgFile;
 
-    users.extraGroups = optionalAttrs (cfg.davGroup == "davfs2") (singleton {
+    users.groups = optionalAttrs (cfg.davGroup == "davfs2") (singleton {
       name = "davfs2";
       gid = config.ids.gids.davfs2;
     });
 
-    users.extraUsers = optionalAttrs (cfg.davUser == "davfs2") (singleton {
+    users.users = optionalAttrs (cfg.davUser == "davfs2") (singleton {
       name = "davfs2";
       createHome = false;
       group = cfg.davGroup;
diff --git a/nixos/modules/services/network-filesystems/ipfs.nix b/nixos/modules/services/network-filesystems/ipfs.nix
index e2122ddb8ede..21b664e5b2f9 100644
--- a/nixos/modules/services/network-filesystems/ipfs.nix
+++ b/nixos/modules/services/network-filesystems/ipfs.nix
@@ -186,6 +186,14 @@ in {
         default = [];
       };
 
+      localDiscovery = mkOption {
+        type = types.bool;
+        description = ''Whether to enable local discovery for the ipfs daemon.
+          This will allow ipfs to scan ports on your local network. Some hosting services will ban you if you do this.
+        '';
+        default = true;
+      };
+
       serviceFdlimit = mkOption {
         type = types.nullOr types.int;
         default = null;
@@ -204,7 +212,7 @@ in {
       user_allow_other
     ''; };
 
-    users.extraUsers = mkIf (cfg.user == "ipfs") {
+    users.users = mkIf (cfg.user == "ipfs") {
       ipfs = {
         group = cfg.group;
         home = cfg.dataDir;
@@ -214,7 +222,7 @@ in {
       };
     };
 
-    users.extraGroups = mkIf (cfg.group == "ipfs") {
+    users.groups = mkIf (cfg.group == "ipfs") {
       ipfs.gid = config.ids.gids.ipfs;
     };
 
@@ -232,7 +240,13 @@ in {
       '';
       script = ''
         if [[ ! -f ${cfg.dataDir}/config ]]; then
-          ipfs init ${optionalString cfg.emptyRepo "-e"}
+          ipfs init ${optionalString cfg.emptyRepo "-e"} \
+            ${optionalString (! cfg.localDiscovery) "--profile=server"}
+        else
+          ${if cfg.localDiscovery
+            then "ipfs config profile apply local-discovery"
+            else "ipfs config profile apply server"
+          }
         fi
       '';
 
diff --git a/nixos/modules/services/network-filesystems/openafs/client.nix b/nixos/modules/services/network-filesystems/openafs/client.nix
index 3826fe3edfd0..52c0966e05bc 100644
--- a/nixos/modules/services/network-filesystems/openafs/client.nix
+++ b/nixos/modules/services/network-filesystems/openafs/client.nix
@@ -1,6 +1,7 @@
-{ config, pkgs, lib, ... }:
+{ config, lib, pkgs, ... }:
 
-with import ./lib.nix { inherit lib; };
+# openafsMod, openafsBin, mkCellServDB
+with import ./lib.nix { inherit config lib pkgs; };
 
 let
   inherit (lib) getBin mkOption mkIf optionalString singleton types;
@@ -8,8 +9,8 @@ let
   cfg = config.services.openafsClient;
 
   cellServDB = pkgs.fetchurl {
-    url = http://dl.central.org/dl/cellservdb/CellServDB.2017-03-14;
-    sha256 = "1197z6c5xrijgf66rhaymnm5cvyg2yiy1i20y4ah4mrzmjx0m7sc";
+    url = http://dl.central.org/dl/cellservdb/CellServDB.2018-05-14;
+    sha256 = "1wmjn6mmyy2r8p10nlbdzs4nrqxy8a9pjyrdciy5nmppg4053rk2";
   };
 
   clientServDB = pkgs.writeText "client-cellServDB-${cfg.cellName}" (mkCellServDB cfg.cellName cfg.cellServDB);
@@ -21,8 +22,6 @@ let
     echo "${cfg.mountPoint}:${cfg.cache.directory}:${toString cfg.cache.blocks}" > $out/cacheinfo
   '';
 
-  openafsMod = config.boot.kernelPackages.openafs;
-  openafsBin = lib.getBin pkgs.openafs;
 in
 {
   ###### interface
@@ -147,6 +146,19 @@ in
         '';
       };
 
+      packages = {
+        module = mkOption {
+          default = config.boot.kernelPackages.openafs;
+          type = types.package;
+          description = "OpenAFS kernel module package. MUST match the userland package!";
+        };
+        programs = mkOption {
+          default = getBin pkgs.openafs;
+          type = types.package;
+          description = "OpenAFS programs package. MUST match the kernel module package!";
+        };
+      };
+
       sparse = mkOption {
         default = true;
         type = types.bool;
@@ -180,7 +192,7 @@ in
       }
     ];
 
-    environment.systemPackages = [ pkgs.openafs ];
+    environment.systemPackages = [ openafsBin ];
 
     environment.etc = {
       clientCellServDB = {
diff --git a/nixos/modules/services/network-filesystems/openafs/lib.nix b/nixos/modules/services/network-filesystems/openafs/lib.nix
index ecfc72d2eaf9..cc68eea91f2d 100644
--- a/nixos/modules/services/network-filesystems/openafs/lib.nix
+++ b/nixos/modules/services/network-filesystems/openafs/lib.nix
@@ -1,4 +1,4 @@
-{ lib, ...}:
+{ config, lib, pkgs, ...}:
 
 let
   inherit (lib) concatStringsSep mkOption types;
@@ -8,7 +8,8 @@ in rec {
   mkCellServDB = cellName: db: ''
     >${cellName}
   '' + (concatStringsSep "\n" (map (dbm: if (dbm.ip != "" && dbm.dnsname != "") then dbm.ip + " #" + dbm.dnsname else "")
-                                   db));
+                                   db))
+     + "\n";
 
   # CellServDB configuration type
   cellServDBConfig = {
@@ -25,4 +26,8 @@ in rec {
       description = "DNS full-qualified domain name of a database server";
     };
   };
+
+  openafsMod = config.services.openafsClient.packages.module;
+  openafsBin = config.services.openafsClient.packages.programs;
+  openafsSrv = config.services.openafsServer.package;
 }
diff --git a/nixos/modules/services/network-filesystems/openafs/server.nix b/nixos/modules/services/network-filesystems/openafs/server.nix
index 429eb945ac9e..4c80ed0839f7 100644
--- a/nixos/modules/services/network-filesystems/openafs/server.nix
+++ b/nixos/modules/services/network-filesystems/openafs/server.nix
@@ -1,9 +1,10 @@
-{ config, pkgs, lib, ... }:
+{ config, lib, pkgs, ... }:
 
-with import ./lib.nix { inherit lib; };
+# openafsBin, openafsSrv, mkCellServDB
+with import ./lib.nix { inherit config lib pkgs; };
 
 let
-  inherit (lib) concatStringsSep intersperse mapAttrsToList mkForce mkIf mkMerge mkOption optionalString types;
+  inherit (lib) concatStringsSep mkIf mkOption optionalString types;
 
   bosConfig = pkgs.writeText "BosConfig" (''
     restrictmode 1
@@ -11,21 +12,21 @@ let
     checkbintime 3 0 5 0 0
   '' + (optionalString cfg.roles.database.enable ''
     bnode simple vlserver 1
-    parm ${openafsBin}/libexec/openafs/vlserver ${optionalString cfg.dottedPrincipals "-allow-dotted-principals"} ${cfg.roles.database.vlserverArgs}
+    parm ${openafsSrv}/libexec/openafs/vlserver ${optionalString cfg.dottedPrincipals "-allow-dotted-principals"} ${cfg.roles.database.vlserverArgs}
     end
     bnode simple ptserver 1
-    parm ${openafsBin}/libexec/openafs/ptserver ${optionalString cfg.dottedPrincipals "-allow-dotted-principals"} ${cfg.roles.database.ptserverArgs}
+    parm ${openafsSrv}/libexec/openafs/ptserver ${optionalString cfg.dottedPrincipals "-allow-dotted-principals"} ${cfg.roles.database.ptserverArgs}
     end
   '') + (optionalString cfg.roles.fileserver.enable ''
     bnode dafs dafs 1
-    parm ${openafsBin}/libexec/openafs/dafileserver ${optionalString cfg.dottedPrincipals "-allow-dotted-principals"} -udpsize ${udpSizeStr} ${cfg.roles.fileserver.fileserverArgs}
-    parm ${openafsBin}/libexec/openafs/davolserver ${optionalString cfg.dottedPrincipals "-allow-dotted-principals"} -udpsize ${udpSizeStr} ${cfg.roles.fileserver.volserverArgs}
-    parm ${openafsBin}/libexec/openafs/salvageserver ${cfg.roles.fileserver.salvageserverArgs}
-    parm ${openafsBin}/libexec/openafs/dasalvager ${cfg.roles.fileserver.salvagerArgs}
+    parm ${openafsSrv}/libexec/openafs/dafileserver ${optionalString cfg.dottedPrincipals "-allow-dotted-principals"} -udpsize ${udpSizeStr} ${cfg.roles.fileserver.fileserverArgs}
+    parm ${openafsSrv}/libexec/openafs/davolserver ${optionalString cfg.dottedPrincipals "-allow-dotted-principals"} -udpsize ${udpSizeStr} ${cfg.roles.fileserver.volserverArgs}
+    parm ${openafsSrv}/libexec/openafs/salvageserver ${cfg.roles.fileserver.salvageserverArgs}
+    parm ${openafsSrv}/libexec/openafs/dasalvager ${cfg.roles.fileserver.salvagerArgs}
     end
   '') + (optionalString (cfg.roles.database.enable && cfg.roles.backup.enable) ''
     bnode simple buserver 1
-    parm ${openafsBin}/libexec/openafs/buserver ${cfg.roles.backup.buserverArgs} ${optionalString (cfg.roles.backup.cellServDB != []) "-cellservdb /etc/openafs/backup/"}
+    parm ${openafsSrv}/libexec/openafs/buserver ${cfg.roles.backup.buserverArgs} ${optionalString (cfg.roles.backup.cellServDB != []) "-cellservdb /etc/openafs/backup/"}
     end
   ''));
 
@@ -39,8 +40,6 @@ let
 
   udpSizeStr = toString cfg.udpPacketSize;
 
-  openafsBin = lib.getBin pkgs.openafs;
-
 in {
 
   options = {
@@ -79,6 +78,12 @@ in {
         description = "Definition of all cell-local database server machines.";
       };
 
+      package = mkOption {
+        default = pkgs.openafs.server or pkgs.openafs;
+        type = types.package;
+        description = "OpenAFS package for the server binaries";
+      };
+
       roles = {
         fileserver = {
           enable = mkOption {
@@ -213,7 +218,7 @@ in {
       }
     ];
 
-    environment.systemPackages = [ pkgs.openafs ];
+    environment.systemPackages = [ openafsBin ];
 
     environment.etc = {
       bosConfig = {
@@ -244,7 +249,10 @@ in {
         after = [ "syslog.target" "network.target" ];
         wantedBy = [ "multi-user.target" ];
         restartIfChanged = false;
-        unitConfig.ConditionPathExists = [ "/etc/openafs/server/rxkad.keytab" ];
+        unitConfig.ConditionPathExists = [
+          "|/etc/openafs/server/rxkad.keytab"
+          "|/etc/openafs/server/KeyFileExt"
+        ];
         preStart = ''
           mkdir -m 0755 -p /var/openafs
           ${optionalString (netInfo != null) "cp ${netInfo} /var/openafs/netInfo"}
diff --git a/nixos/modules/services/network-filesystems/tahoe.nix b/nixos/modules/services/network-filesystems/tahoe.nix
index 80b34c48f1d2..534862a3c9e4 100644
--- a/nixos/modules/services/network-filesystems/tahoe.nix
+++ b/nixos/modules/services/network-filesystems/tahoe.nix
@@ -255,7 +255,7 @@ in
               cp /etc/tahoe-lafs/introducer-"${node}".cfg ${lib.escapeShellArg nodedir}/tahoe.cfg
             '';
           });
-        users.extraUsers = flip mapAttrs' cfg.introducers (node: _:
+        users.users = flip mapAttrs' cfg.introducers (node: _:
           nameValuePair "tahoe.introducer-${node}" {
             description = "Tahoe node user for introducer ${node}";
             isSystemUser = true;
@@ -355,7 +355,7 @@ in
               cp /etc/tahoe-lafs/${lib.escapeShellArg node}.cfg ${lib.escapeShellArg nodedir}/tahoe.cfg
             '';
           });
-        users.extraUsers = flip mapAttrs' cfg.nodes (node: _:
+        users.users = flip mapAttrs' cfg.nodes (node: _:
           nameValuePair "tahoe.${node}" {
             description = "Tahoe node user for node ${node}";
             isSystemUser = true;
diff --git a/nixos/modules/services/network-filesystems/xtreemfs.nix b/nixos/modules/services/network-filesystems/xtreemfs.nix
index 95d7641e8b53..c93e201da56c 100644
--- a/nixos/modules/services/network-filesystems/xtreemfs.nix
+++ b/nixos/modules/services/network-filesystems/xtreemfs.nix
@@ -432,14 +432,14 @@ in
 
     environment.systemPackages = [ xtreemfs ];
 
-    users.extraUsers.xtreemfs =
+    users.users.xtreemfs =
       { uid = config.ids.uids.xtreemfs;
         description = "XtreemFS user";
         createHome = true;
         home = home;
       };
 
-    users.extraGroups.xtreemfs =
+    users.groups.xtreemfs =
       { gid = config.ids.gids.xtreemfs;
       };
 
diff --git a/nixos/modules/services/network-filesystems/yandex-disk.nix b/nixos/modules/services/network-filesystems/yandex-disk.nix
index 44b0edf62018..e93f45b49867 100644
--- a/nixos/modules/services/network-filesystems/yandex-disk.nix
+++ b/nixos/modules/services/network-filesystems/yandex-disk.nix
@@ -73,7 +73,7 @@ in
 
   config = mkIf cfg.enable {
 
-    users.extraUsers = mkIf (cfg.user == null) [ {
+    users.users = mkIf (cfg.user == null) [ {
       name = u;
       uid = config.ids.uids.yandexdisk;
       group = "nogroup";
diff --git a/nixos/modules/services/networking/amuled.nix b/nixos/modules/services/networking/amuled.nix
index 9898f164c5cf..57f02542eafd 100644
--- a/nixos/modules/services/networking/amuled.nix
+++ b/nixos/modules/services/networking/amuled.nix
@@ -45,14 +45,14 @@ in
 
   config = mkIf cfg.enable {
 
-    users.extraUsers = mkIf (cfg.user == null) [
+    users.users = mkIf (cfg.user == null) [
       { name = "amule";
         description = "AMule daemon";
         group = "amule";
         uid = config.ids.uids.amule;
       } ];
 
-    users.extraGroups = mkIf (cfg.user == null) [
+    users.groups = mkIf (cfg.user == null) [
       { name = "amule";
         gid = config.ids.gids.amule;
       } ];
diff --git a/nixos/modules/services/networking/aria2.nix b/nixos/modules/services/networking/aria2.nix
index df9c92db2e54..98eb00861016 100644
--- a/nixos/modules/services/networking/aria2.nix
+++ b/nixos/modules/services/networking/aria2.nix
@@ -92,7 +92,7 @@ in
       allowedTCPPorts = [ config.services.aria2.rpcListenPort ];
     };
 
-    users.extraUsers.aria2 = {
+    users.users.aria2 = {
       group = "aria2";
       uid = config.ids.uids.aria2;
       description = "aria2 user";
@@ -100,7 +100,7 @@ in
       createHome = false;
     };
 
-    users.extraGroups.aria2.gid = config.ids.gids.aria2;
+    users.groups.aria2.gid = config.ids.gids.aria2;
 
     systemd.services.aria2 = {
       description = "aria2 Service";
diff --git a/nixos/modules/services/networking/asterisk.nix b/nixos/modules/services/networking/asterisk.nix
index 514204db33fa..b8ec2b25a227 100644
--- a/nixos/modules/services/networking/asterisk.nix
+++ b/nixos/modules/services/networking/asterisk.nix
@@ -211,7 +211,7 @@ in
 
     environment.etc.asterisk.source = asteriskEtc;
 
-    users.extraUsers.asterisk =
+    users.users.asterisk =
       { name = asteriskUser;
         group = asteriskGroup;
         uid = config.ids.uids.asterisk;
@@ -219,7 +219,7 @@ in
         home = varlibdir;
       };
 
-    users.extraGroups.asterisk =
+    users.groups.asterisk =
       { name = asteriskGroup;
         gid = config.ids.gids.asterisk;
       };
diff --git a/nixos/modules/services/networking/avahi-daemon.nix b/nixos/modules/services/networking/avahi-daemon.nix
index 9ccdacb20e91..81e11db10409 100644
--- a/nixos/modules/services/networking/avahi-daemon.nix
+++ b/nixos/modules/services/networking/avahi-daemon.nix
@@ -187,14 +187,14 @@ in
 
     services.avahi.hostName = mkDefault config.networking.hostName;
 
-    users.extraUsers = singleton
+    users.users = singleton
       { name = "avahi";
         uid = config.ids.uids.avahi;
         description = "`avahi-daemon' privilege separation user";
         home = "/var/empty";
       };
 
-    users.extraGroups = singleton
+    users.groups = singleton
       { name = "avahi";
         gid = config.ids.gids.avahi;
       };
diff --git a/nixos/modules/services/networking/bind.nix b/nixos/modules/services/networking/bind.nix
index 763283dfe7a2..abcd1ef6ff5d 100644
--- a/nixos/modules/services/networking/bind.nix
+++ b/nixos/modules/services/networking/bind.nix
@@ -27,6 +27,7 @@ let
         forwarders { ${concatMapStrings (entry: " ${entry}; ") cfg.forwarders} };
         directory "/var/run/named";
         pid-file "/var/run/named/named.pid";
+        ${cfg.extraOptions}
       };
 
       ${cfg.extraConfig}
@@ -141,6 +142,15 @@ in
         ";
       };
 
+      extraOptions = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Extra lines to be added verbatim to the options section of the
+          generated named configuration file.
+        '';
+      };
+
       configFile = mkOption {
         type = types.path;
         default = confFile;
@@ -160,7 +170,7 @@ in
 
   config = mkIf config.services.bind.enable {
 
-    users.extraUsers = singleton
+    users.users = singleton
       { name = bindUser;
         uid = config.ids.uids.bind;
         description = "BIND daemon user";
diff --git a/nixos/modules/services/networking/bird.nix b/nixos/modules/services/networking/bird.nix
index c25bd0fdc541..9f08cc0a79ed 100644
--- a/nixos/modules/services/networking/bird.nix
+++ b/nixos/modules/services/networking/bird.nix
@@ -60,11 +60,11 @@ let
           };
         };
         users = {
-          extraUsers.${variant} = {
+          users.${variant} = {
             description = "BIRD Internet Routing Daemon user";
             group = variant;
           };
-          extraGroups.${variant} = {};
+          groups.${variant} = {};
         };
       };
     };
diff --git a/nixos/modules/services/networking/bitlbee.nix b/nixos/modules/services/networking/bitlbee.nix
index bd26804788f3..392a8d5c2e7c 100644
--- a/nixos/modules/services/networking/bitlbee.nix
+++ b/nixos/modules/services/networking/bitlbee.nix
@@ -149,7 +149,7 @@ in
 
   config = mkIf config.services.bitlbee.enable {
 
-    users.extraUsers = singleton
+    users.users = singleton
       { name = "bitlbee";
         uid = bitlbeeUid;
         description = "BitlBee user";
@@ -157,7 +157,7 @@ in
         createHome = true;
       };
 
-    users.extraGroups = singleton
+    users.groups = singleton
       { name = "bitlbee";
         gid = config.ids.gids.bitlbee;
       };
diff --git a/nixos/modules/services/networking/btsync.nix b/nixos/modules/services/networking/btsync.nix
index 6e479a5860ac..33e85ef58e6e 100644
--- a/nixos/modules/services/networking/btsync.nix
+++ b/nixos/modules/services/networking/btsync.nix
@@ -284,7 +284,7 @@ in
 
     services.btsync.package = mkOptionDefault pkgs.bittorrentSync14;
 
-    users.extraUsers.btsync = {
+    users.users.btsync = {
       description     = "Bittorrent Sync Service user";
       home            = cfg.storagePath;
       createHome      = true;
@@ -292,7 +292,7 @@ in
       group           = "btsync";
     };
 
-    users.extraGroups = [
+    users.groups = [
       { name = "btsync";
       }];
 
diff --git a/nixos/modules/services/networking/charybdis.nix b/nixos/modules/services/networking/charybdis.nix
index c354ec61fe23..6d57faa9ac2b 100644
--- a/nixos/modules/services/networking/charybdis.nix
+++ b/nixos/modules/services/networking/charybdis.nix
@@ -71,14 +71,14 @@ in
 
   config = mkIf cfg.enable (lib.mkMerge [
     {
-      users.extraUsers = singleton {
+      users.users = singleton {
         name = cfg.user;
         description = "Charybdis IRC daemon user";
         uid = config.ids.uids.ircd;
         group = cfg.group;
       };
 
-      users.extraGroups = singleton {
+      users.groups = singleton {
         name = cfg.group;
         gid = config.ids.gids.ircd;
       };
diff --git a/nixos/modules/services/networking/chrony.nix b/nixos/modules/services/networking/chrony.nix
index 9bf266b38054..cef30661cc33 100644
--- a/nixos/modules/services/networking/chrony.nix
+++ b/nixos/modules/services/networking/chrony.nix
@@ -4,8 +4,6 @@ with lib;
 
 let
 
-  inherit (pkgs) chrony;
-
   stateDir = "/var/lib/chrony";
 
   keyFile = "/etc/chrony.keys";
@@ -96,12 +94,12 @@ in
     # Make chronyc available in the system path
     environment.systemPackages = [ pkgs.chrony ];
 
-    users.extraGroups = singleton
+    users.groups = singleton
       { name = "chrony";
         gid = config.ids.gids.chrony;
       };
 
-    users.extraUsers = singleton
+    users.users = singleton
       { name = "chrony";
         uid = config.ids.uids.chrony;
         group = "chrony";
@@ -109,7 +107,7 @@ in
         home = stateDir;
       };
 
-    systemd.services.timesyncd.enable = mkForce false;
+    services.timesyncd.enable = mkForce false;
 
     systemd.services.chronyd =
       { description = "chrony NTP daemon";
diff --git a/nixos/modules/services/networking/cjdns.nix b/nixos/modules/services/networking/cjdns.nix
index 12c2677c3368..39b62bdc7094 100644
--- a/nixos/modules/services/networking/cjdns.nix
+++ b/nixos/modules/services/networking/cjdns.nix
@@ -260,7 +260,8 @@ in
         RestartSec = 1;
         CapabilityBoundingSet = "CAP_NET_ADMIN CAP_NET_RAW CAP_SETUID";
         ProtectSystem = true;
-        MemoryDenyWriteExecute = true;
+        # Doesn't work on i686, causing service to fail
+        MemoryDenyWriteExecute = !pkgs.stdenv.isi686;
         ProtectHome = true;
         PrivateTmp = true;
       };
diff --git a/nixos/modules/services/networking/cntlm.nix b/nixos/modules/services/networking/cntlm.nix
index 3978a1969ce9..4e4e3104c3a8 100644
--- a/nixos/modules/services/networking/cntlm.nix
+++ b/nixos/modules/services/networking/cntlm.nix
@@ -117,7 +117,7 @@ in
       };
     };
 
-    users.extraUsers.cntlm = {
+    users.users.cntlm = {
       name = "cntlm";
       description = "cntlm system-wide daemon";
       isSystemUser = true;
diff --git a/nixos/modules/services/networking/consul.nix b/nixos/modules/services/networking/consul.nix
index 6333970cb338..ab3f81037681 100644
--- a/nixos/modules/services/networking/consul.nix
+++ b/nixos/modules/services/networking/consul.nix
@@ -155,7 +155,7 @@ in
   config = mkIf cfg.enable (
     mkMerge [{
 
-      users.extraUsers."consul" = {
+      users.users."consul" = {
         description = "Consul agent daemon user";
         uid = config.ids.uids.consul;
         # The shell is needed for health checks
diff --git a/nixos/modules/services/networking/coturn.nix b/nixos/modules/services/networking/coturn.nix
index b3c64490d97e..c430ce5af92a 100644
--- a/nixos/modules/services/networking/coturn.nix
+++ b/nixos/modules/services/networking/coturn.nix
@@ -294,12 +294,12 @@ in {
   };
 
   config = mkIf cfg.enable {
-    users.extraUsers = [
+    users.users = [
       { name = "turnserver";
         uid = config.ids.uids.turnserver;
         description = "coturn TURN server user";
       } ];
-    users.extraGroups = [
+    users.groups = [
       { name = "turnserver";
         gid = config.ids.gids.turnserver;
         members = [ "turnserver" ];
diff --git a/nixos/modules/services/networking/dhcpd.nix b/nixos/modules/services/networking/dhcpd.nix
index fd7e317eee95..0b2063bc4246 100644
--- a/nixos/modules/services/networking/dhcpd.nix
+++ b/nixos/modules/services/networking/dhcpd.nix
@@ -197,7 +197,7 @@ in
   config = mkIf (cfg4.enable || cfg6.enable) {
 
     users = {
-      extraUsers.dhcpd = {
+      users.dhcpd = {
         uid = config.ids.uids.dhcpd;
         description = "DHCP daemon user";
       };
diff --git a/nixos/modules/services/networking/dnscache.nix b/nixos/modules/services/networking/dnscache.nix
index ba5c8e2d5e53..fc30f50317fe 100644
--- a/nixos/modules/services/networking/dnscache.nix
+++ b/nixos/modules/services/networking/dnscache.nix
@@ -84,7 +84,7 @@ in {
 
   config = mkIf config.services.dnscache.enable {
     environment.systemPackages = [ pkgs.djbdns ];
-    users.extraUsers.dnscache = {};
+    users.users.dnscache = {};
 
     systemd.services.dnscache = {
       description = "djbdns dnscache server";
diff --git a/nixos/modules/services/networking/dnschain.nix b/nixos/modules/services/networking/dnschain.nix
index ee1cd3600039..0c2add424bac 100644
--- a/nixos/modules/services/networking/dnschain.nix
+++ b/nixos/modules/services/networking/dnschain.nix
@@ -141,7 +141,7 @@ in
         dns = "127.0.0.1:${toString cfg.dns.port}";
       };
 
-    users.extraUsers = singleton {
+    users.users = singleton {
       name = username;
       description = "DNSChain daemon user";
       home = dataDir;
diff --git a/nixos/modules/services/networking/dnscrypt-proxy.nix b/nixos/modules/services/networking/dnscrypt-proxy.nix
index 857657eea4db..8edcf925dbfa 100644
--- a/nixos/modules/services/networking/dnscrypt-proxy.nix
+++ b/nixos/modules/services/networking/dnscrypt-proxy.nix
@@ -145,6 +145,9 @@ in
       }
     ];
 
+    # make man 8 dnscrypt-proxy work
+    environment.systemPackages = [ pkgs.dnscrypt-proxy ];
+
     users.users.dnscrypt-proxy = {
       description = "dnscrypt-proxy daemon user";
       isSystemUser = true;
@@ -192,6 +195,7 @@ in
     security.apparmor.profiles = singleton (pkgs.writeText "apparmor-dnscrypt-proxy" ''
       ${pkgs.dnscrypt-proxy}/bin/dnscrypt-proxy {
         /dev/null rw,
+        /dev/random r,
         /dev/urandom r,
 
         /etc/passwd r,
@@ -211,6 +215,9 @@ in
         ${getLib pkgs.gcc.cc}/lib/libssp.so.* mr,
         ${getLib pkgs.libsodium}/lib/libsodium.so.* mr,
         ${getLib pkgs.systemd}/lib/libsystemd.so.* mr,
+        ${getLib pkgs.utillinuxMinimal.out}/lib/libmount.so.* mr,
+        ${getLib pkgs.utillinuxMinimal.out}/lib/libblkid.so.* mr,
+        ${getLib pkgs.utillinuxMinimal.out}/lib/libuuid.so.* mr,
         ${getLib pkgs.xz}/lib/liblzma.so.* mr,
         ${getLib pkgs.libgcrypt}/lib/libgcrypt.so.* mr,
         ${getLib pkgs.libgpgerror}/lib/libgpg-error.so.* mr,
diff --git a/nixos/modules/services/networking/dnsdist.nix b/nixos/modules/services/networking/dnsdist.nix
new file mode 100644
index 000000000000..12eee136e639
--- /dev/null
+++ b/nixos/modules/services/networking/dnsdist.nix
@@ -0,0 +1,61 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.dnsdist;
+  configFile = pkgs.writeText "dndist.conf" ''
+    setLocal('${cfg.listenAddress}:${toString cfg.listenPort}')
+    ${cfg.extraConfig}
+    '';
+in {
+  options = {
+    services.dnsdist = {
+      enable = mkEnableOption "dnsdist domain name server";
+
+      listenAddress = mkOption {
+        type = types.str;
+        description = "Listen IP Address";
+        default = "0.0.0.0";
+      };
+      listenPort = mkOption {
+        type = types.int;
+        description = "Listen port";
+        default = 53;
+      };
+
+      extraConfig = mkOption {
+        type = types.lines;
+        default = ''
+        '';
+        description = ''
+          Extra lines to be added verbatim to dnsdist.conf.
+        '';
+      };
+    };
+  };
+
+  config = mkIf config.services.dnsdist.enable {
+    systemd.services.dnsdist = {
+      description = "dnsdist load balancer";
+      wantedBy = [ "multi-user.target" ];
+      after = ["network.target"];
+
+      serviceConfig = {
+        Restart="on-failure";
+        RestartSec="1";
+        DynamicUser = true;
+        StartLimitInterval="0";
+        PrivateTmp=true;
+        PrivateDevices=true;
+        CapabilityBoundingSet="CAP_NET_BIND_SERVICE CAP_SETGID CAP_SETUID";
+        ExecStart = "${pkgs.dnsdist}/bin/dnsdist --supervised --disable-syslog --config ${configFile}";
+        ProtectSystem="full";
+        ProtectHome=true;
+        RestrictAddressFamilies="AF_UNIX AF_INET AF_INET6";
+        LimitNOFILE="16384";
+        TasksMax="8192";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/networking/dnsmasq.nix b/nixos/modules/services/networking/dnsmasq.nix
index 91a3e54474ac..24d16046c63e 100644
--- a/nixos/modules/services/networking/dnsmasq.nix
+++ b/nixos/modules/services/networking/dnsmasq.nix
@@ -86,7 +86,7 @@ in
 
     services.dbus.packages = [ dnsmasq ];
 
-    users.extraUsers = singleton {
+    users.users = singleton {
       name = "dnsmasq";
       uid = config.ids.uids.dnsmasq;
       description = "Dnsmasq daemon user";
diff --git a/nixos/modules/services/networking/ejabberd.nix b/nixos/modules/services/networking/ejabberd.nix
index 82ed7fc4a837..ef5e2cee6f20 100644
--- a/nixos/modules/services/networking/ejabberd.nix
+++ b/nixos/modules/services/networking/ejabberd.nix
@@ -94,7 +94,7 @@ in {
   config = mkIf cfg.enable {
     environment.systemPackages = [ cfg.package ];
 
-    users.extraUsers = optionalAttrs (cfg.user == "ejabberd") (singleton
+    users.users = optionalAttrs (cfg.user == "ejabberd") (singleton
       { name = "ejabberd";
         group = cfg.group;
         home = cfg.spoolDir;
@@ -102,7 +102,7 @@ in {
         uid = config.ids.uids.ejabberd;
       });
 
-    users.extraGroups = optionalAttrs (cfg.group == "ejabberd") (singleton
+    users.groups = optionalAttrs (cfg.group == "ejabberd") (singleton
       { name = "ejabberd";
         gid = config.ids.gids.ejabberd;
       });
diff --git a/nixos/modules/services/networking/firewall.nix b/nixos/modules/services/networking/firewall.nix
index c4bd0e7f9eef..36f1dd8d2479 100644
--- a/nixos/modules/services/networking/firewall.nix
+++ b/nixos/modules/services/networking/firewall.nix
@@ -148,38 +148,42 @@ let
     ip46tables -A nixos-fw -m conntrack --ctstate ESTABLISHED,RELATED -j nixos-fw-accept
 
     # Accept connections to the allowed TCP ports.
-    ${concatMapStrings (port:
+    ${concatStrings (mapAttrsToList (iface: cfg:
+      concatMapStrings (port:
         ''
-          ip46tables -A nixos-fw -p tcp --dport ${toString port} -j nixos-fw-accept
+          ip46tables -A nixos-fw -p tcp --dport ${toString port} -j nixos-fw-accept ${optionalString (iface != "default") "-i ${iface}"}
         ''
       ) cfg.allowedTCPPorts
-    }
+    ) cfg.interfaces)}
 
     # Accept connections to the allowed TCP port ranges.
-    ${concatMapStrings (rangeAttr:
+    ${concatStrings (mapAttrsToList (iface: cfg:
+      concatMapStrings (rangeAttr:
         let range = toString rangeAttr.from + ":" + toString rangeAttr.to; in
         ''
-          ip46tables -A nixos-fw -p tcp --dport ${range} -j nixos-fw-accept
+          ip46tables -A nixos-fw -p tcp --dport ${range} -j nixos-fw-accept ${optionalString (iface != "default") "-i ${iface}"}
         ''
       ) cfg.allowedTCPPortRanges
-    }
+    ) cfg.interfaces)}
 
     # Accept packets on the allowed UDP ports.
-    ${concatMapStrings (port:
+    ${concatStrings (mapAttrsToList (iface: cfg:
+      concatMapStrings (port:
         ''
-          ip46tables -A nixos-fw -p udp --dport ${toString port} -j nixos-fw-accept
+          ip46tables -A nixos-fw -p udp --dport ${toString port} -j nixos-fw-accept ${optionalString (iface != "default") "-i ${iface}"}
         ''
       ) cfg.allowedUDPPorts
-    }
+    ) cfg.interfaces)}
 
     # Accept packets on the allowed UDP port ranges.
-    ${concatMapStrings (rangeAttr:
+    ${concatStrings (mapAttrsToList (iface: cfg:
+      concatMapStrings (rangeAttr:
         let range = toString rangeAttr.from + ":" + toString rangeAttr.to; in
         ''
-          ip46tables -A nixos-fw -p udp --dport ${range} -j nixos-fw-accept
+          ip46tables -A nixos-fw -p udp --dport ${range} -j nixos-fw-accept ${optionalString (iface != "default") "-i ${iface}"}
         ''
       ) cfg.allowedUDPPortRanges
-    }
+    ) cfg.interfaces)}
 
     # Accept IPv4 multicast.  Not a big security risk since
     # probably nobody is listening anyway.
@@ -254,106 +258,30 @@ let
     fi
   '';
 
-in
-
-{
-
-  ###### interface
-
-  options = {
-
-    networking.firewall.enable = mkOption {
-      type = types.bool;
-      default = true;
-      description =
-        ''
-          Whether to enable the firewall.  This is a simple stateful
-          firewall that blocks connection attempts to unauthorised TCP
-          or UDP ports on this machine.  It does not affect packet
-          forwarding.
-        '';
-    };
-
-    networking.firewall.logRefusedConnections = mkOption {
-      type = types.bool;
-      default = true;
-      description =
-        ''
-          Whether to log rejected or dropped incoming connections.
-        '';
-    };
-
-    networking.firewall.logRefusedPackets = mkOption {
-      type = types.bool;
-      default = false;
-      description =
-        ''
-          Whether to log all rejected or dropped incoming packets.
-          This tends to give a lot of log messages, so it's mostly
-          useful for debugging.
-        '';
-    };
-
-    networking.firewall.logRefusedUnicastsOnly = mkOption {
-      type = types.bool;
-      default = true;
-      description =
-        ''
-          If <option>networking.firewall.logRefusedPackets</option>
-          and this option are enabled, then only log packets
-          specifically directed at this machine, i.e., not broadcasts
-          or multicasts.
-        '';
-    };
-
-    networking.firewall.rejectPackets = mkOption {
-      type = types.bool;
-      default = false;
-      description =
-        ''
-          If set, refused packets are rejected rather than dropped
-          (ignored).  This means that an ICMP "port unreachable" error
-          message is sent back to the client (or a TCP RST packet in
-          case of an existing connection).  Rejecting packets makes
-          port scanning somewhat easier.
-        '';
-    };
-
-    networking.firewall.trustedInterfaces = mkOption {
-      type = types.listOf types.str;
-      default = [ ];
-      example = [ "enp0s2" ];
-      description =
-        ''
-          Traffic coming in from these interfaces will be accepted
-          unconditionally.  Traffic from the loopback (lo) interface
-          will always be accepted.
-        '';
-    };
-
-    networking.firewall.allowedTCPPorts = mkOption {
+  commonOptions = {
+    allowedTCPPorts = mkOption {
       type = types.listOf types.int;
       default = [ ];
       example = [ 22 80 ];
       description =
-        ''
+        '' 
           List of TCP ports on which incoming connections are
           accepted.
         '';
     };
 
-    networking.firewall.allowedTCPPortRanges = mkOption {
+    allowedTCPPortRanges = mkOption {
       type = types.listOf (types.attrsOf types.int);
       default = [ ];
       example = [ { from = 8999; to = 9003; } ];
       description =
-        ''
+        '' 
           A range of TCP ports on which incoming connections are
           accepted.
         '';
     };
 
-    networking.firewall.allowedUDPPorts = mkOption {
+    allowedUDPPorts = mkOption {
       type = types.listOf types.int;
       default = [ ];
       example = [ 53 ];
@@ -363,7 +291,7 @@ in
         '';
     };
 
-    networking.firewall.allowedUDPPortRanges = mkOption {
+    allowedUDPPortRanges = mkOption {
       type = types.listOf (types.attrsOf types.int);
       default = [ ];
       example = [ { from = 60000; to = 61000; } ];
@@ -372,133 +300,226 @@ in
           Range of open UDP ports.
         '';
     };
+  };
 
-    networking.firewall.allowPing = mkOption {
-      type = types.bool;
-      default = true;
-      description =
-        ''
-          Whether to respond to incoming ICMPv4 echo requests
-          ("pings").  ICMPv6 pings are always allowed because the
-          larger address space of IPv6 makes network scanning much
-          less effective.
-        '';
-    };
+in
 
-    networking.firewall.pingLimit = mkOption {
-      type = types.nullOr (types.separatedString " ");
-      default = null;
-      example = "--limit 1/minute --limit-burst 5";
-      description =
-        ''
-          If pings are allowed, this allows setting rate limits
-          on them.  If non-null, this option should be in the form of
-          flags like "--limit 1/minute --limit-burst 5"
-        '';
-    };
+{
 
-    networking.firewall.checkReversePath = mkOption {
-      type = types.either types.bool (types.enum ["strict" "loose"]);
-      default = kernelHasRPFilter;
-      example = "loose";
-      description =
-        ''
-          Performs a reverse path filter test on a packet.  If a reply
-          to the packet would not be sent via the same interface that
-          the packet arrived on, it is refused.
+  ###### interface
 
-          If using asymmetric routing or other complicated routing, set
-          this option to loose mode or disable it and setup your own
-          counter-measures.
+  options = {
 
-          This option can be either true (or "strict"), "loose" (only
-          drop the packet if the source address is not reachable via any
-          interface) or false.  Defaults to the value of
-          kernelHasRPFilter.
+    networking.firewall = {
+      enable = mkOption {
+        type = types.bool;
+        default = true;
+        description =
+          ''
+            Whether to enable the firewall.  This is a simple stateful
+            firewall that blocks connection attempts to unauthorised TCP
+            or UDP ports on this machine.  It does not affect packet
+            forwarding.
+          '';
+      };
 
-          (needs kernel 3.3+)
-        '';
-    };
+      logRefusedConnections = mkOption {
+        type = types.bool;
+        default = true;
+        description =
+          ''
+            Whether to log rejected or dropped incoming connections.
+          '';
+      };
 
-    networking.firewall.logReversePathDrops = mkOption {
-      type = types.bool;
-      default = false;
-      description =
-        ''
-          Logs dropped packets failing the reverse path filter test if
-          the option networking.firewall.checkReversePath is enabled.
-        '';
-    };
+      logRefusedPackets = mkOption {
+        type = types.bool;
+        default = false;
+        description =
+          ''
+            Whether to log all rejected or dropped incoming packets.
+            This tends to give a lot of log messages, so it's mostly
+            useful for debugging.
+          '';
+      };
 
-    networking.firewall.connectionTrackingModules = mkOption {
-      type = types.listOf types.str;
-      default = [ ];
-      example = [ "ftp" "irc" "sane" "sip" "tftp" "amanda" "h323" "netbios_sn" "pptp" "snmp" ];
-      description =
-        ''
-          List of connection-tracking helpers that are auto-loaded.
-          The complete list of possible values is given in the example.
-
-          As helpers can pose as a security risk, it is advised to
-          set this to an empty list and disable the setting
-          networking.firewall.autoLoadConntrackHelpers unless you
-          know what you are doing. Connection tracking is disabled
-          by default.
-
-          Loading of helpers is recommended to be done through the
-          CT target.  More info:
-          https://home.regit.org/netfilter-en/secure-use-of-helpers/
-        '';
-    };
+      logRefusedUnicastsOnly = mkOption {
+        type = types.bool;
+        default = true;
+        description =
+          ''
+            If <option>networking.firewall.logRefusedPackets</option>
+            and this option are enabled, then only log packets
+            specifically directed at this machine, i.e., not broadcasts
+            or multicasts.
+          '';
+      };
 
-    networking.firewall.autoLoadConntrackHelpers = mkOption {
-      type = types.bool;
-      default = false;
-      description =
-        ''
-          Whether to auto-load connection-tracking helpers.
-          See the description at networking.firewall.connectionTrackingModules
+      rejectPackets = mkOption {
+        type = types.bool;
+        default = false;
+        description =
+          ''
+            If set, refused packets are rejected rather than dropped
+            (ignored).  This means that an ICMP "port unreachable" error
+            message is sent back to the client (or a TCP RST packet in
+            case of an existing connection).  Rejecting packets makes
+            port scanning somewhat easier.
+          '';
+      };
 
-          (needs kernel 3.5+)
-        '';
-    };
+      trustedInterfaces = mkOption {
+        type = types.listOf types.str;
+        default = [ ];
+        example = [ "enp0s2" ];
+        description =
+          ''
+            Traffic coming in from these interfaces will be accepted
+            unconditionally.  Traffic from the loopback (lo) interface
+            will always be accepted.
+          '';
+      };
 
-    networking.firewall.extraCommands = mkOption {
-      type = types.lines;
-      default = "";
-      example = "iptables -A INPUT -p icmp -j ACCEPT";
-      description =
-        ''
-          Additional shell commands executed as part of the firewall
-          initialisation script.  These are executed just before the
-          final "reject" firewall rule is added, so they can be used
-          to allow packets that would otherwise be refused.
-        '';
-    };
+      allowPing = mkOption {
+        type = types.bool;
+        default = true;
+        description =
+          ''
+            Whether to respond to incoming ICMPv4 echo requests
+            ("pings").  ICMPv6 pings are always allowed because the
+            larger address space of IPv6 makes network scanning much
+            less effective.
+          '';
+      };
 
-    networking.firewall.extraPackages = mkOption {
-      type = types.listOf types.package;
-      default = [ ];
-      example = literalExample "[ pkgs.ipset ]";
-      description =
-        ''
-          Additional packages to be included in the environment of the system
-          as well as the path of networking.firewall.extraCommands.
-        '';
-    };
+      pingLimit = mkOption {
+        type = types.nullOr (types.separatedString " ");
+        default = null;
+        example = "--limit 1/minute --limit-burst 5";
+        description =
+          ''
+            If pings are allowed, this allows setting rate limits
+            on them.  If non-null, this option should be in the form of
+            flags like "--limit 1/minute --limit-burst 5"
+          '';
+      };
 
-    networking.firewall.extraStopCommands = mkOption {
-      type = types.lines;
-      default = "";
-      example = "iptables -P INPUT ACCEPT";
-      description =
-        ''
-          Additional shell commands executed as part of the firewall
-          shutdown script.  These are executed just after the removal
-          of the NixOS input rule, or if the service enters a failed
-          state.
-        '';
-    };
+      checkReversePath = mkOption {
+        type = types.either types.bool (types.enum ["strict" "loose"]);
+        default = kernelHasRPFilter;
+        example = "loose";
+        description =
+          ''
+            Performs a reverse path filter test on a packet.  If a reply
+            to the packet would not be sent via the same interface that
+            the packet arrived on, it is refused.
+
+            If using asymmetric routing or other complicated routing, set
+            this option to loose mode or disable it and setup your own
+            counter-measures.
+
+            This option can be either true (or "strict"), "loose" (only
+            drop the packet if the source address is not reachable via any
+            interface) or false.  Defaults to the value of
+            kernelHasRPFilter.
+
+            (needs kernel 3.3+)
+          '';
+      };
+
+      logReversePathDrops = mkOption {
+        type = types.bool;
+        default = false;
+        description =
+          ''
+            Logs dropped packets failing the reverse path filter test if
+            the option networking.firewall.checkReversePath is enabled.
+          '';
+      };
+
+      connectionTrackingModules = mkOption {
+        type = types.listOf types.str;
+        default = [ ];
+        example = [ "ftp" "irc" "sane" "sip" "tftp" "amanda" "h323" "netbios_sn" "pptp" "snmp" ];
+        description =
+          ''
+            List of connection-tracking helpers that are auto-loaded.
+            The complete list of possible values is given in the example.
+
+            As helpers can pose as a security risk, it is advised to
+            set this to an empty list and disable the setting
+            networking.firewall.autoLoadConntrackHelpers unless you
+            know what you are doing. Connection tracking is disabled
+            by default.
+
+            Loading of helpers is recommended to be done through the
+            CT target.  More info:
+            https://home.regit.org/netfilter-en/secure-use-of-helpers/
+          '';
+      };
+
+      autoLoadConntrackHelpers = mkOption {
+        type = types.bool;
+        default = false;
+        description =
+          ''
+            Whether to auto-load connection-tracking helpers.
+            See the description at networking.firewall.connectionTrackingModules
+
+            (needs kernel 3.5+)
+          '';
+      };
+
+      extraCommands = mkOption {
+        type = types.lines;
+        default = "";
+        example = "iptables -A INPUT -p icmp -j ACCEPT";
+        description =
+          ''
+            Additional shell commands executed as part of the firewall
+            initialisation script.  These are executed just before the
+            final "reject" firewall rule is added, so they can be used
+            to allow packets that would otherwise be refused.
+          '';
+      };
+
+      extraPackages = mkOption {
+        type = types.listOf types.package;
+        default = [ ];
+        example = literalExample "[ pkgs.ipset ]";
+        description =
+          ''
+            Additional packages to be included in the environment of the system
+            as well as the path of networking.firewall.extraCommands.
+          '';
+      };
+
+      extraStopCommands = mkOption {
+        type = types.lines;
+        default = "";
+        example = "iptables -P INPUT ACCEPT";
+        description =
+          ''
+            Additional shell commands executed as part of the firewall
+            shutdown script.  These are executed just after the removal
+            of the NixOS input rule, or if the service enters a failed
+            state.
+          '';
+      };
+
+      interfaces = mkOption {
+        default = {
+          default = mapAttrs (name: value: cfg."${name}") commonOptions;
+        };
+        type = with types; attrsOf (submodule [ { options = commonOptions; } ]);
+        description =
+          ''
+            Interface-specific open ports. Setting this value will override
+            all values of the <literal>networking.firewall.allowed*</literal>
+            options.
+          '';
+      };
+    } // commonOptions;
 
   };
 
diff --git a/nixos/modules/services/networking/freenet.nix b/nixos/modules/services/networking/freenet.nix
index 3903a2c708cb..3da3ab0c7df4 100644
--- a/nixos/modules/services/networking/freenet.nix
+++ b/nixos/modules/services/networking/freenet.nix
@@ -50,7 +50,7 @@ in
       serviceConfig.Nice = cfg.nice;
     };
 
-    users.extraUsers.freenet = {
+    users.users.freenet = {
       group = "freenet";
       description = "Freenet daemon user";
       home = varDir;
@@ -58,7 +58,7 @@ in
       uid = config.ids.uids.freenet;
     };
 
-    users.extraGroups.freenet.gid = config.ids.gids.freenet;
+    users.groups.freenet.gid = config.ids.gids.freenet;
   };
 
 }
diff --git a/nixos/modules/services/networking/freeradius.nix b/nixos/modules/services/networking/freeradius.nix
index 45cba1ce2770..e192b70c129c 100644
--- a/nixos/modules/services/networking/freeradius.nix
+++ b/nixos/modules/services/networking/freeradius.nix
@@ -59,7 +59,7 @@ in
   config = mkIf (cfg.enable) {
 
     users = {
-      extraUsers.radius = {
+      users.radius = {
         /*uid = config.ids.uids.radius;*/
         description = "Radius daemon user";
       };
diff --git a/nixos/modules/services/networking/gale.nix b/nixos/modules/services/networking/gale.nix
index fd83f9e3c1b7..7083d87c4073 100644
--- a/nixos/modules/services/networking/gale.nix
+++ b/nixos/modules/services/networking/gale.nix
@@ -104,7 +104,7 @@ in
          systemPackages = [ pkgs.gale ];
        };
 
-       users.extraUsers = [{
+       users.users = [{
          name = cfg.user;
          description = "Gale daemon";
          uid = config.ids.uids.gale;
@@ -113,7 +113,7 @@ in
          createHome = true;
        }];
 
-       users.extraGroups = [{
+       users.groups = [{
          name = cfg.group;
          gid = config.ids.gids.gale;
        }];
diff --git a/nixos/modules/services/networking/gateone.nix b/nixos/modules/services/networking/gateone.nix
index 78ff0b76198c..4456a95402ed 100644
--- a/nixos/modules/services/networking/gateone.nix
+++ b/nixos/modules/services/networking/gateone.nix
@@ -23,12 +23,12 @@ config = mkIf cfg.enable {
   environment.systemPackages = with pkgs.pythonPackages; [
     gateone pkgs.openssh pkgs.procps pkgs.coreutils pkgs.cacert];
 
-  users.extraUsers.gateone = {
+  users.users.gateone = {
     description = "GateOne privilege separation user";
     uid = config.ids.uids.gateone;
     home = cfg.settingsDir;
   };
-  users.extraGroups.gateone.gid = config.ids.gids.gateone;
+  users.groups.gateone.gid = config.ids.gids.gateone;
 
   systemd.services.gateone = with pkgs; {
     description = "GateOne web-based terminal";
diff --git a/nixos/modules/services/networking/gdomap.nix b/nixos/modules/services/networking/gdomap.nix
index b3fd91d037fa..3d829cb69135 100644
--- a/nixos/modules/services/networking/gdomap.nix
+++ b/nixos/modules/services/networking/gdomap.nix
@@ -2,9 +2,6 @@
 
 with lib;
 
-let
-  cfg = config.services.gdomap;
-in
 {
   #
   # interface
diff --git a/nixos/modules/services/networking/git-daemon.nix b/nixos/modules/services/networking/git-daemon.nix
index cd3fcd0f8f66..c0020349ec74 100644
--- a/nixos/modules/services/networking/git-daemon.nix
+++ b/nixos/modules/services/networking/git-daemon.nix
@@ -104,13 +104,13 @@ in
 
   config = mkIf cfg.enable {
 
-    users.extraUsers = if cfg.user != "git" then {} else singleton
+    users.users = if cfg.user != "git" then {} else singleton
       { name = "git";
         uid = config.ids.uids.git;
         description = "Git daemon user";
       };
 
-    users.extraGroups = if cfg.group != "git" then {} else singleton
+    users.groups = if cfg.group != "git" then {} else singleton
       { name = "git";
         gid = config.ids.gids.git;
       };
diff --git a/nixos/modules/services/networking/gnunet.nix b/nixos/modules/services/networking/gnunet.nix
index 008b09e81a57..6a1db81413c5 100644
--- a/nixos/modules/services/networking/gnunet.nix
+++ b/nixos/modules/services/networking/gnunet.nix
@@ -126,7 +126,7 @@ in
 
   config = mkIf config.services.gnunet.enable {
 
-    users.extraUsers.gnunet = {
+    users.users.gnunet = {
       group = "gnunet";
       description = "GNUnet User";
       home = homeDir;
@@ -134,7 +134,7 @@ in
       uid = config.ids.uids.gnunet;
     };
 
-    users.extraGroups.gnunet.gid = config.ids.gids.gnunet;
+    users.groups.gnunet.gid = config.ids.gids.gnunet;
 
     # The user tools that talk to `gnunetd' should come from the same source,
     # so install them globally.
diff --git a/nixos/modules/services/networking/hans.nix b/nixos/modules/services/networking/hans.nix
index dd34ef8d4ca1..20e57e4626ef 100644
--- a/nixos/modules/services/networking/hans.nix
+++ b/nixos/modules/services/networking/hans.nix
@@ -135,7 +135,7 @@ in
       };
     };
 
-    users.extraUsers = singleton {
+    users.users = singleton {
       name = hansUser;
       description = "Hans daemon user";
     };
diff --git a/nixos/modules/services/networking/haproxy.nix b/nixos/modules/services/networking/haproxy.nix
index 09e48ec4bff0..0438d0bf8d86 100644
--- a/nixos/modules/services/networking/haproxy.nix
+++ b/nixos/modules/services/networking/haproxy.nix
@@ -52,11 +52,11 @@ with lib;
 
     environment.systemPackages = [ pkgs.haproxy ];
 
-    users.extraUsers.haproxy = {
+    users.users.haproxy = {
       group = "haproxy";
       uid = config.ids.uids.haproxy;
     };
 
-    users.extraGroups.haproxy.gid = config.ids.uids.haproxy;
+    users.groups.haproxy.gid = config.ids.uids.haproxy;
   };
 }
diff --git a/nixos/modules/services/networking/hostapd.nix b/nixos/modules/services/networking/hostapd.nix
index 63f56437d1c8..3af0441a89d8 100644
--- a/nixos/modules/services/networking/hostapd.nix
+++ b/nixos/modules/services/networking/hostapd.nix
@@ -29,7 +29,7 @@ let
     ctrl_interface_group=${cfg.group}
 
     ${if cfg.wpa then ''
-      wpa=1
+      wpa=2
       wpa_passphrase=${cfg.wpaPassphrase}
       '' else ""}
 
diff --git a/nixos/modules/services/networking/i2p.nix b/nixos/modules/services/networking/i2p.nix
index e6ee5fd1f957..3b6010531f13 100644
--- a/nixos/modules/services/networking/i2p.nix
+++ b/nixos/modules/services/networking/i2p.nix
@@ -11,14 +11,14 @@ in {
 
   ###### implementation
   config = mkIf cfg.enable {
-    users.extraUsers.i2p = {
+    users.users.i2p = {
       group = "i2p";
       description = "i2p User";
       home = homeDir;
       createHome = true;
       uid = config.ids.uids.i2p;
     };
-    users.extraGroups.i2p.gid = config.ids.gids.i2p;
+    users.groups.i2p.gid = config.ids.gids.i2p;
     systemd.services.i2p = {
       description = "I2P router with administration interface for hidden services";
       after = [ "network.target" ];
diff --git a/nixos/modules/services/networking/i2pd.nix b/nixos/modules/services/networking/i2pd.nix
index 8f5aeee4a16b..4f219fe56b4c 100644
--- a/nixos/modules/services/networking/i2pd.nix
+++ b/nixos/modules/services/networking/i2pd.nix
@@ -103,7 +103,7 @@ let
 
     ${flip concatMapStrings
       (collect (proto: proto ? port && proto ? address && proto ? name) cfg.proto)
-      (proto: let portStr = toString proto.port; in ''
+      (proto: ''
         [${proto.name}]
         enabled = ${boolToString proto.enable}
         address = ${proto.address}
@@ -122,7 +122,7 @@ let
     # DO NOT EDIT -- this file has been generated automatically.
     ${flip concatMapStrings
       (collect (tun: tun ? port && tun ? destination) cfg.outTunnels)
-      (tun: let portStr = toString tun.port; in ''
+      (tun: ''
         [${tun.name}]
         type = client
         destination = ${tun.destination}
@@ -456,7 +456,7 @@ in
 
   config = mkIf cfg.enable {
 
-    users.extraUsers.i2pd = {
+    users.users.i2pd = {
       group = "i2pd";
       description = "I2Pd User";
       home = homeDir;
@@ -464,7 +464,7 @@ in
       uid = config.ids.uids.i2pd;
     };
 
-    users.extraGroups.i2pd.gid = config.ids.gids.i2pd;
+    users.groups.i2pd.gid = config.ids.gids.i2pd;
 
     systemd.services.i2pd = {
       description = "Minimal I2P router";
diff --git a/nixos/modules/services/networking/iodine.nix b/nixos/modules/services/networking/iodine.nix
index 3f41421d27f7..58ad0df4ff20 100644
--- a/nixos/modules/services/networking/iodine.nix
+++ b/nixos/modules/services/networking/iodine.nix
@@ -140,11 +140,11 @@ in
       };
     };
 
-    users.extraUsers = singleton {
+    users.users = singleton {
       name = iodinedUser;
       uid = config.ids.uids.iodined;
       description = "Iodine daemon user";
     };
-    users.extraGroups.iodined.gid = config.ids.gids.iodined;
+    users.groups.iodined.gid = config.ids.gids.iodined;
   };
 }
diff --git a/nixos/modules/services/networking/ircd-hybrid/default.nix b/nixos/modules/services/networking/ircd-hybrid/default.nix
index bd583fb020ec..2bd898edf897 100644
--- a/nixos/modules/services/networking/ircd-hybrid/default.nix
+++ b/nixos/modules/services/networking/ircd-hybrid/default.nix
@@ -112,14 +112,14 @@ in
 
   config = mkIf config.services.ircdHybrid.enable {
 
-    users.extraUsers = singleton
+    users.users = singleton
       { name = "ircd";
         description = "IRCD owner";
         group = "ircd";
         uid = config.ids.uids.ircd;
       };
 
-    users.extraGroups.ircd.gid = config.ids.gids.ircd;
+    users.groups.ircd.gid = config.ids.gids.ircd;
 
     systemd.services."ircd-hybrid" = {
       description = "IRCD Hybrid server";
diff --git a/nixos/modules/services/networking/iwd.nix b/nixos/modules/services/networking/iwd.nix
index 344212ad8329..cfc536fc5b5f 100644
--- a/nixos/modules/services/networking/iwd.nix
+++ b/nixos/modules/services/networking/iwd.nix
@@ -28,6 +28,10 @@ in {
 
       serviceConfig.ExecStart = "${pkgs.iwd}/libexec/iwd";
     };
+
+    systemd.tmpfiles.rules = [
+      "d /var/lib/iwd 0700 root root -"
+    ];
   };
 
   meta.maintainers = with lib.maintainers; [ mic92 ];
diff --git a/nixos/modules/services/networking/kippo.nix b/nixos/modules/services/networking/kippo.nix
index 834de4fdc09f..40c38254a57c 100644
--- a/nixos/modules/services/networking/kippo.nix
+++ b/nixos/modules/services/networking/kippo.nix
@@ -73,12 +73,12 @@ rec {
         ${cfg.extraConfig}
     '';
 
-    users.extraUsers = singleton {
+    users.users = singleton {
       name = "kippo";
       description = "kippo web server privilege separation user";
       uid = 108; # why does config.ids.uids.kippo give an error?
     };
-    users.extraGroups = singleton { name = "kippo";gid=108; };
+    users.groups = singleton { name = "kippo";gid=108; };
 
     systemd.services.kippo = with pkgs; {
       description = "Kippo Web Server";
diff --git a/nixos/modules/services/networking/kresd.nix b/nixos/modules/services/networking/kresd.nix
index aac02b811d71..ca34ff9df4ef 100644
--- a/nixos/modules/services/networking/kresd.nix
+++ b/nixos/modules/services/networking/kresd.nix
@@ -62,13 +62,13 @@ in
   config = mkIf cfg.enable {
     environment.etc."kresd.conf".source = configFile; # not required
 
-    users.extraUsers = singleton
+    users.users = singleton
       { name = "kresd";
         uid = config.ids.uids.kresd;
         group = "kresd";
         description = "Knot-resolver daemon user";
       };
-    users.extraGroups = singleton
+    users.groups = singleton
       { name = "kresd";
         gid = config.ids.gids.kresd;
       };
diff --git a/nixos/modules/services/networking/lambdabot.nix b/nixos/modules/services/networking/lambdabot.nix
index 5a61a9f96782..b7c8bd008fe1 100644
--- a/nixos/modules/services/networking/lambdabot.nix
+++ b/nixos/modules/services/networking/lambdabot.nix
@@ -67,7 +67,7 @@ in
       };
     };
 
-    users.extraUsers.lambdabot = {
+    users.users.lambdabot = {
       group = "lambdabot";
       description = "Lambdabot daemon user";
       home = "/var/lib/lambdabot";
@@ -75,7 +75,7 @@ in
       uid = config.ids.uids.lambdabot;
     };
 
-    users.extraGroups.lambdabot.gid = config.ids.gids.lambdabot;
+    users.groups.lambdabot.gid = config.ids.gids.lambdabot;
 
   };
 
diff --git a/nixos/modules/services/networking/lldpd.nix b/nixos/modules/services/networking/lldpd.nix
index db1534edfd7c..dec30cc92f6a 100644
--- a/nixos/modules/services/networking/lldpd.nix
+++ b/nixos/modules/services/networking/lldpd.nix
@@ -20,13 +20,13 @@ in
   };
 
   config = mkIf cfg.enable {
-    users.extraUsers._lldpd = {
+    users.users._lldpd = {
       description = "lldpd user";
       group = "_lldpd";
       home = "/var/run/lldpd";
       isSystemUser = true;
     };
-    users.extraGroups._lldpd = {};
+    users.groups._lldpd = {};
 
     environment.systemPackages = [ pkgs.lldpd ];
     systemd.packages = [ pkgs.lldpd ];
diff --git a/nixos/modules/services/networking/mailpile.nix b/nixos/modules/services/networking/mailpile.nix
index e164d41483c7..c42d3d5a44cb 100644
--- a/nixos/modules/services/networking/mailpile.nix
+++ b/nixos/modules/services/networking/mailpile.nix
@@ -41,14 +41,14 @@ in
 
   config = mkIf config.services.mailpile.enable {
 
-    users.extraUsers.mailpile =
+    users.users.mailpile =
       { uid = config.ids.uids.mailpile;
         description = "Mailpile user";
         createHome = true;
         home = "/var/lib/mailpile";
       };
 
-    users.extraGroups.mailpile =
+    users.groups.mailpile =
       { gid = config.ids.gids.mailpile;
       };
 
diff --git a/nixos/modules/services/networking/matterbridge.nix b/nixos/modules/services/networking/matterbridge.nix
index e2f478405953..1fd63348c16c 100644
--- a/nixos/modules/services/networking/matterbridge.nix
+++ b/nixos/modules/services/networking/matterbridge.nix
@@ -92,12 +92,12 @@ in
     warnings = optional options.services.matterbridge.configFile.isDefined
       "The option services.matterbridge.configFile is insecure and should be replaced with services.matterbridge.configPath";
 
-    users.extraUsers = optional (cfg.user == "matterbridge")
+    users.users = optional (cfg.user == "matterbridge")
       { name = "matterbridge";
         group = "matterbridge";
       };
 
-    users.extraGroups = optional (cfg.group == "matterbridge")
+    users.groups = optional (cfg.group == "matterbridge")
       { name = "matterbridge";
       };
 
diff --git a/nixos/modules/services/networking/minidlna.nix b/nixos/modules/services/networking/minidlna.nix
index 6401631bf620..1858f03cac1f 100644
--- a/nixos/modules/services/networking/minidlna.nix
+++ b/nixos/modules/services/networking/minidlna.nix
@@ -84,13 +84,13 @@ in
         '') cfg.mediaDirs}
       '';
 
-    users.extraUsers.minidlna = {
+    users.users.minidlna = {
       description = "MiniDLNA daemon user";
       group = "minidlna";
       uid = config.ids.uids.minidlna;
     };
 
-    users.extraGroups.minidlna.gid = config.ids.gids.minidlna;
+    users.groups.minidlna.gid = config.ids.gids.minidlna;
 
     systemd.services.minidlna =
       { description = "MiniDLNA Server";
diff --git a/nixos/modules/services/networking/mjpg-streamer.nix b/nixos/modules/services/networking/mjpg-streamer.nix
index 1286b0c7ef6c..e0a6c112e3cb 100644
--- a/nixos/modules/services/networking/mjpg-streamer.nix
+++ b/nixos/modules/services/networking/mjpg-streamer.nix
@@ -49,7 +49,7 @@ in {
 
   config = mkIf cfg.enable {
 
-    users.extraUsers = optional (cfg.user == "mjpg-streamer") {
+    users.users = optional (cfg.user == "mjpg-streamer") {
       name = "mjpg-streamer";
       uid = config.ids.uids.mjpg-streamer;
       group = cfg.group;
diff --git a/nixos/modules/services/networking/monero.nix b/nixos/modules/services/networking/monero.nix
index 31379189f5de..8241c32bad07 100644
--- a/nixos/modules/services/networking/monero.nix
+++ b/nixos/modules/services/networking/monero.nix
@@ -197,7 +197,7 @@ in
 
   config = mkIf cfg.enable {
 
-    users.extraUsers = singleton {
+    users.users = singleton {
       name = "monero";
       uid  = config.ids.uids.monero;
       description = "Monero daemon user";
@@ -205,7 +205,7 @@ in
       createHome = true;
     };
 
-    users.extraGroups = singleton {
+    users.groups = singleton {
       name = "monero";
       gid  = config.ids.gids.monero;
     };
diff --git a/nixos/modules/services/networking/morty.nix b/nixos/modules/services/networking/morty.nix
new file mode 100644
index 000000000000..cc81e27e9399
--- /dev/null
+++ b/nixos/modules/services/networking/morty.nix
@@ -0,0 +1,96 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.morty;
+
+in
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.morty = {
+
+      enable = mkEnableOption
+        "Morty proxy server. See https://github.com/asciimoo/morty";
+
+      ipv6 = mkOption {
+        type = types.bool;
+        default = true;
+        description = "Allow IPv6 HTTP requests?";
+        defaultText = "Allow IPv6 HTTP requests.";
+      };
+
+      key = mkOption {
+        type = types.string;
+        default = "";
+        description = "HMAC url validation key (hexadecimal encoded).
+	Leave blank to disable. Without validation key, anyone can
+	submit proxy requests. Leave blank to disable.";
+        defaultText = "No HMAC url validation. Generate with echo -n somevalue | openssl dgst -sha1 -hmac somekey";
+      };
+
+      timeout = mkOption {
+        type = types.int;
+        default = 2;
+        description = "Request timeout in seconds.";
+        defaultText = "A resource now gets 2 seconds to respond.";
+      };
+
+      package = mkOption {
+        type = types.package;
+        default = pkgs.morty;
+        defaultText = "pkgs.morty";
+        description = "morty package to use.";
+      };
+
+      port = mkOption {
+        type = types.int;
+        default = 3000;
+        description = "Listing port";
+      };
+
+      listenAddress = mkOption {
+        type = types.string;
+        default = "127.0.0.1";
+        description = "The address on which the service listens";
+        defaultText = "127.0.0.1 (localhost)";
+      };
+
+    };
+
+  };
+
+  ###### Service definition
+
+  config = mkIf config.services.morty.enable {
+
+    users.users.morty =
+      { description = "Morty user";
+        createHome = true;
+        home = "/var/lib/morty";
+      };
+
+    systemd.services.morty =
+      {
+        description = "Morty sanitizing proxy server.";
+        after = [ "network.target" ];
+        wantedBy = [ "multi-user.target" ];
+        serviceConfig = {
+          User = "morty";
+          ExecStart = ''${cfg.package}/bin/morty              \
+	    -listen ${cfg.listenAddress}:${toString cfg.port} \
+	    ${optionalString cfg.ipv6 "-ipv6"}                \
+	    ${optionalString (cfg.key != "") "-key " + cfg.key} \
+	  '';
+        };
+      };
+    environment.systemPackages = [ cfg.package ];
+
+  };
+}
diff --git a/nixos/modules/services/networking/mosquitto.nix b/nixos/modules/services/networking/mosquitto.nix
index d8135f4d0ffa..332dc541345e 100644
--- a/nixos/modules/services/networking/mosquitto.nix
+++ b/nixos/modules/services/networking/mosquitto.nix
@@ -218,7 +218,7 @@ in
         ) cfg.users);
     };
 
-    users.extraUsers.mosquitto = {
+    users.users.mosquitto = {
       description = "Mosquitto MQTT Broker Daemon owner";
       group = "mosquitto";
       uid = config.ids.uids.mosquitto;
@@ -226,7 +226,7 @@ in
       createHome = true;
     };
 
-    users.extraGroups.mosquitto.gid = config.ids.gids.mosquitto;
+    users.groups.mosquitto.gid = config.ids.gids.mosquitto;
 
   };
 }
diff --git a/nixos/modules/services/networking/murmur.nix b/nixos/modules/services/networking/murmur.nix
index 873d62dbf341..fcc813e6898f 100644
--- a/nixos/modules/services/networking/murmur.nix
+++ b/nixos/modules/services/networking/murmur.nix
@@ -238,7 +238,7 @@ in
   };
 
   config = mkIf cfg.enable {
-    users.extraUsers.murmur = {
+    users.users.murmur = {
       description     = "Murmur Service user";
       home            = "/var/lib/murmur";
       createHome      = true;
@@ -248,7 +248,7 @@ in
     systemd.services.murmur = {
       description = "Murmur Chat Service";
       wantedBy    = [ "multi-user.target" ];
-      after       = [ "network.target "];
+      after       = [ "network-online.target "];
 
       serviceConfig = {
         Type      = "forking";
diff --git a/nixos/modules/services/networking/namecoind.nix b/nixos/modules/services/networking/namecoind.nix
index 11f7d7e5caef..8de23b442f93 100644
--- a/nixos/modules/services/networking/namecoind.nix
+++ b/nixos/modules/services/networking/namecoind.nix
@@ -153,7 +153,7 @@ in
       config = ${configFile}
     '';
 
-    users.extraUsers = singleton {
+    users.users = singleton {
       name = "namecoin";
       uid  = config.ids.uids.namecoin;
       description = "Namecoin daemon user";
@@ -161,7 +161,7 @@ in
       createHome = true;
     };
 
-    users.extraGroups = singleton {
+    users.groups = singleton {
       name = "namecoin";
       gid  = config.ids.gids.namecoin;
     };
diff --git a/nixos/modules/services/networking/nat.nix b/nixos/modules/services/networking/nat.nix
index da3827c35e63..89d8590093dd 100644
--- a/nixos/modules/services/networking/nat.nix
+++ b/nixos/modules/services/networking/nat.nix
@@ -38,19 +38,19 @@ let
     # NAT the marked packets.
     ${optionalString (cfg.internalInterfaces != []) ''
       iptables -w -t nat -A nixos-nat-post -m mark --mark 1 \
-        -o ${cfg.externalInterface} ${dest}
+        ${optionalString (cfg.externalInterface != null) "-o ${cfg.externalInterface}"} ${dest}
     ''}
 
     # NAT packets coming from the internal IPs.
     ${concatMapStrings (range: ''
       iptables -w -t nat -A nixos-nat-post \
-        -s '${range}' -o ${cfg.externalInterface} ${dest}
+        -s '${range}' ${optionalString (cfg.externalInterface != null) "-o ${cfg.externalInterface}"} ${dest}
     '') cfg.internalIPs}
 
     # NAT from external ports to internal ports.
     ${concatMapStrings (fwd: ''
       iptables -w -t nat -A nixos-nat-pre \
-        -i ${cfg.externalInterface} -p ${fwd.proto} \
+        -i ${toString cfg.externalInterface} -p ${fwd.proto} \
         --dport ${builtins.toString fwd.sourcePort} \
         -j DNAT --to-destination ${fwd.destination}
 
@@ -81,7 +81,7 @@ let
 
     ${optionalString (cfg.dmzHost != null) ''
       iptables -w -t nat -A nixos-nat-pre \
-        -i ${cfg.externalInterface} -j DNAT \
+        -i ${toString cfg.externalInterface} -j DNAT \
         --to-destination ${cfg.dmzHost}
     ''}
 
@@ -134,7 +134,8 @@ in
     };
 
     networking.nat.externalInterface = mkOption {
-      type = types.str;
+      type = types.nullOr types.str;
+      default = null;
       example = "eth1";
       description =
         ''
@@ -236,6 +237,15 @@ in
     { networking.firewall.extraCommands = mkBefore flushNat; }
     (mkIf config.networking.nat.enable {
 
+      assertions = [
+        { assertion = (cfg.dmzHost != null)    -> (cfg.externalInterface != null);
+          message = "networking.nat.dmzHost requires networking.nat.externalInterface";
+        }
+        { assertion = (cfg.forwardPorts != []) -> (cfg.externalInterface != null);
+          message = "networking.nat.forwardPorts requires networking.nat.externalInterface";
+        }
+      ];
+
       environment.systemPackages = [ pkgs.iptables ];
 
       boot = {
diff --git a/nixos/modules/services/networking/networkmanager.nix b/nixos/modules/services/networking/networkmanager.nix
index f4c4adcaaeb8..b0bc1c83d6b7 100644
--- a/nixos/modules/services/networking/networkmanager.nix
+++ b/nixos/modules/services/networking/networkmanager.nix
@@ -6,21 +6,17 @@ with lib;
 let
   cfg = config.networking.networkmanager;
 
+  dynamicHostsEnabled =
+    cfg.dynamicHosts.enable && cfg.dynamicHosts.hostsDirs != {};
+
   # /var/lib/misc is for dnsmasq.leases.
   stateDirs = "/var/lib/NetworkManager /var/lib/dhclient /var/lib/misc";
 
-  dns =
-    if cfg.dns == "none" then "none"
-    else if cfg.dns == "dnsmasq" then "dnsmasq"
-    else if config.services.resolved.enable then "systemd-resolved"
-    else if config.services.unbound.enable then "unbound"
-    else "default";
-
   configFile = writeText "NetworkManager.conf" ''
     [main]
     plugins=keyfile
     dhcp=${cfg.dhcp}
-    dns=${dns}
+    dns=${cfg.dns}
 
     [keyfile]
     ${optionalString (cfg.unmanaged != [])
@@ -38,6 +34,8 @@ let
 
     [device]
     wifi.scan-rand-mac-address=${if cfg.wifi.scanRandMacAddress then "yes" else "no"}
+
+    ${cfg.extraConfig}
   '';
 
   /*
@@ -120,6 +118,14 @@ in {
         '';
       };
 
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Configuration appended to the generated NetworkManager.conf.
+        '';
+      };
+
       unmanaged = mkOption {
         type = types.listOf types.string;
         default = [];
@@ -207,19 +213,73 @@ in {
       };
 
       dns = mkOption {
-        type = types.enum [ "auto" "dnsmasq" "none" ];
-        default = "auto";
+        type = types.enum [ "default" "dnsmasq" "unbound" "systemd-resolved" "none" ];
+        default = "default";
         description = ''
+          Set the DNS (<literal>resolv.conf</literal>) processing mode.
+          </para>
+          <para>
           Options:
-            - auto: Check for systemd-resolved, unbound, or use default.
-            - dnsmasq:
-              Enable NetworkManager's dnsmasq integration. NetworkManager will run
-              dnsmasq as a local caching nameserver, using a "split DNS"
-              configuration if you are connected to a VPN, and then update
-              resolv.conf to point to the local nameserver.
-            - none:
-              Disable NetworkManager's DNS integration completely.
-              It will not touch your /etc/resolv.conf.
+          <variablelist>
+          <varlistentry>
+            <term><literal>"default"</literal></term>
+            <listitem><para>
+              NetworkManager will update <literal>/etc/resolv.conf</literal> to
+              reflect the nameservers provided by currently active connections.
+            </para></listitem>
+          </varlistentry>
+          <varlistentry>
+            <term><literal>"dnsmasq"</literal></term>
+            <listitem>
+              <para>
+                Enable NetworkManager's dnsmasq integration. NetworkManager will
+                run dnsmasq as a local caching nameserver, using a "split DNS"
+                configuration if you are connected to a VPN, and then update
+                <literal>resolv.conf</literal> to point to the local nameserver.
+              </para>
+              <para>
+                It is possible to pass custom options to the dnsmasq instance by
+                adding them to files in the
+                <literal>/etc/NetworkManager/dnsmasq.d/</literal> directory.
+              </para>
+              <para>
+                When multiple upstream servers are available, dnsmasq will
+                initially contact them in parallel and then use the fastest to
+                respond, probing again other servers after some time.  This
+                behavior can be modified passing the
+                <literal>all-servers</literal> or <literal>strict-order</literal>
+                options to dnsmasq (see the manual page for more details).
+              </para>
+              <para>
+                Note that this option causes NetworkManager to launch and manage
+                its own instance of the dnsmasq daemon, which is
+                <emphasis>not</emphasis> the same as setting
+                <literal>services.dnsmasq.enable = true;</literal>.
+              </para>
+            </listitem>
+          </varlistentry>
+          <varlistentry>
+            <term><literal>"unbound"</literal></term>
+            <listitem><para>
+              NetworkManager will talk to unbound and dnssec-triggerd,
+              providing a "split DNS" configuration with DNSSEC support.
+              <literal>/etc/resolv.conf</literal> will be managed by
+              dnssec-trigger daemon.
+            </para></listitem>
+          </varlistentry>
+          <varlistentry>
+            <term><literal>"systemd-resolved"</literal></term>
+            <listitem><para>
+              NetworkManager will push the DNS configuration to systemd-resolved.
+            </para></listitem>
+          </varlistentry>
+          <varlistentry>
+            <term><literal>"none"</literal></term>
+            <listitem><para>
+              NetworkManager will not modify resolv.conf.
+            </para></listitem>
+          </varlistentry>
+          </variablelist>
         '';
       };
 
@@ -260,6 +320,52 @@ in {
           so you don't need to to that yourself.
         '';
       };
+
+      dynamicHosts = {
+        enable = mkOption {
+          type = types.bool;
+          default = false;
+          description = ''
+            Enabling this option requires the
+            <option>networking.networkmanager.dns</option> option to be
+            set to <literal>dnsmasq</literal>. If enabled, the directories
+            defined by the
+            <option>networking.networkmanager.dynamicHosts.hostsDirs</option>
+            option will be set up when the service starts. The dnsmasq instance
+            managed by NetworkManager will then watch those directories for
+            hosts files (see the <literal>--hostsdir</literal> option of
+            dnsmasq). This way a non-privileged user can add or override DNS
+            entries on the local system (depending on what hosts directories
+            that are configured)..
+          '';
+        };
+        hostsDirs = mkOption {
+          type = with types; attrsOf (submodule {
+            options = {
+              user = mkOption {
+                type = types.str;
+                default = "root";
+                description = ''
+                  The user that will own the hosts directory.
+                '';
+              };
+              group = mkOption {
+                type = types.str;
+                default = "root";
+                description = ''
+                  The group that will own the hosts directory.
+                '';
+              };
+            };
+          });
+          default = {};
+          description = ''
+            Defines a set of directories (relative to
+            <literal>/run/NetworkManager/hostdirs</literal>) that dnsmasq will
+            watch for hosts files.
+          '';
+        };
+      };
     };
   };
 
@@ -268,10 +374,17 @@ in {
 
   config = mkIf cfg.enable {
 
-    assertions = [{
-      assertion = config.networking.wireless.enable == false;
-      message = "You can not use networking.networkmanager with networking.wireless";
-    }];
+    assertions = [
+      { assertion = config.networking.wireless.enable == false;
+        message = "You can not use networking.networkmanager with networking.wireless";
+      }
+      { assertion = !dynamicHostsEnabled || (dynamicHostsEnabled && cfg.dns == "dnsmasq");
+        message = ''
+          To use networking.networkmanager.dynamicHosts you also need to set
+          networking.networkmanager.dns = "dnsmasq"
+        '';
+      }
+    ];
 
     environment.etc = with cfg.basePackages; [
       { source = configFile;
@@ -305,11 +418,17 @@ in {
       ++ lib.imap1 (i: s: {
         inherit (s) source;
         target = "NetworkManager/dispatcher.d/${dispatcherTypesSubdirMap.${s.type}}03userscript${lib.fixedWidthNumber 4 i}";
-      }) cfg.dispatcherScripts;
+      }) cfg.dispatcherScripts
+      ++ optional (dynamicHostsEnabled)
+           { target = "NetworkManager/dnsmasq.d/dyndns.conf";
+             text = concatMapStrings (n: ''
+               hostsdir=/run/NetworkManager/hostsdirs/${n}
+             '') (attrNames cfg.dynamicHosts.hostsDirs);
+           };
 
     environment.systemPackages = cfg.packages;
 
-    users.extraGroups = [{
+    users.groups = [{
       name = "networkmanager";
       gid = config.ids.gids.networkmanager;
     }
@@ -317,7 +436,7 @@ in {
       name = "nm-openvpn";
       gid = config.ids.gids.nm-openvpn;
     }];
-    users.extraUsers = [{
+    users.users = [{
       name = "nm-openvpn";
       uid = config.ids.uids.nm-openvpn;
       extraGroups = [ "networkmanager" ];
@@ -341,6 +460,21 @@ in {
       '';
     };
 
+    systemd.services.nm-setup-hostsdirs = mkIf dynamicHostsEnabled {
+      wantedBy = [ "network-manager.service" ];
+      before = [ "network-manager.service" ];
+      partOf = [ "network-manager.service" ];
+      script = concatStrings (mapAttrsToList (n: d: ''
+        mkdir -p "/run/NetworkManager/hostsdirs/${n}"
+        chown "${d.user}:${d.group}" "/run/NetworkManager/hostsdirs/${n}"
+        chmod 0775 "/run/NetworkManager/hostsdirs/${n}"
+      '') cfg.dynamicHosts.hostsDirs);
+      serviceConfig = {
+        Type = "oneshot";
+        RemainAfterExist = true;
+      };
+    };
+
     # Turn off NixOS' network management
     networking = {
       useDHCP = false;
diff --git a/nixos/modules/services/networking/ngircd.nix b/nixos/modules/services/networking/ngircd.nix
index 6a5290ffdee2..4b2fa7795922 100644
--- a/nixos/modules/services/networking/ngircd.nix
+++ b/nixos/modules/services/networking/ngircd.nix
@@ -51,7 +51,7 @@ in {
       serviceConfig.User = "ngircd";
     };
 
-    users.extraUsers.ngircd = {
+    users.users.ngircd = {
       uid = config.ids.uids.ngircd;
       description = "ngircd user.";
     };
diff --git a/nixos/modules/services/networking/nix-serve.nix b/nixos/modules/services/networking/nix-serve.nix
index 8499e7c0f7c4..e83cad949ae8 100644
--- a/nixos/modules/services/networking/nix-serve.nix
+++ b/nixos/modules/services/networking/nix-serve.nix
@@ -64,7 +64,7 @@ in
       };
     };
 
-    users.extraUsers.nix-serve = {
+    users.users.nix-serve = {
       description = "Nix-serve user";
       uid = config.ids.uids.nix-serve;
     };
diff --git a/nixos/modules/services/networking/nntp-proxy.nix b/nixos/modules/services/networking/nntp-proxy.nix
index 7eebecb23b00..d24d6f77a491 100644
--- a/nixos/modules/services/networking/nntp-proxy.nix
+++ b/nixos/modules/services/networking/nntp-proxy.nix
@@ -210,7 +210,7 @@ in
 
   config = mkIf cfg.enable {
 
-    users.extraUsers = singleton
+    users.users = singleton
       { name = proxyUser;
         uid = config.ids.uids.nntp-proxy;
         description = "NNTP-Proxy daemon user";
diff --git a/nixos/modules/services/networking/nsd.nix b/nixos/modules/services/networking/nsd.nix
index fc910e59c323..cde47bf23eae 100644
--- a/nixos/modules/services/networking/nsd.nix
+++ b/nixos/modules/services/networking/nsd.nix
@@ -897,12 +897,12 @@ in
 
     environment.systemPackages = [ nsdPkg ];
 
-    users.extraGroups = singleton {
+    users.groups = singleton {
       name = username;
       gid = config.ids.gids.nsd;
     };
 
-    users.extraUsers = singleton {
+    users.users = singleton {
       name = username;
       description = "NSD service user";
       home = stateDir;
diff --git a/nixos/modules/services/networking/ntpd.nix b/nixos/modules/services/networking/ntpd.nix
index 88e6dbf22b9e..342350d49ab3 100644
--- a/nixos/modules/services/networking/ntpd.nix
+++ b/nixos/modules/services/networking/ntpd.nix
@@ -67,7 +67,7 @@ in
     environment.systemPackages = [ pkgs.ntp ];
     services.timesyncd.enable = mkForce false;
 
-    users.extraUsers = singleton
+    users.users = singleton
       { name = ntpUser;
         uid = config.ids.uids.ntp;
         description = "NTP daemon user";
diff --git a/nixos/modules/services/networking/nylon.nix b/nixos/modules/services/networking/nylon.nix
index 4864ecf3f92f..b7b59d95bf02 100644
--- a/nixos/modules/services/networking/nylon.nix
+++ b/nixos/modules/services/networking/nylon.nix
@@ -151,7 +151,7 @@ in
 
   config = mkIf (length(enabledNylons) > 0) {
 
-    users.extraUsers.nylon = {
+    users.users.nylon = {
       group = "nylon";
       description = "Nylon SOCKS Proxy";
       home = homeDir;
@@ -159,7 +159,7 @@ in
       uid = config.ids.uids.nylon;
     };
 
-    users.extraGroups.nylon.gid = config.ids.gids.nylon;
+    users.groups.nylon.gid = config.ids.gids.nylon;
 
     systemd.services = fold (a: b: a // b) {} nylonUnits;
 
diff --git a/nixos/modules/services/networking/oidentd.nix b/nixos/modules/services/networking/oidentd.nix
index ba7acd879546..8cf34623ab5e 100644
--- a/nixos/modules/services/networking/oidentd.nix
+++ b/nixos/modules/services/networking/oidentd.nix
@@ -32,13 +32,13 @@ with lib;
           optionalString config.networking.enableIPv6 " -a ::";
     };
 
-    users.extraUsers.oidentd = {
+    users.users.oidentd = {
       description = "Ident Protocol daemon user";
       group = "oidentd";
       uid = config.ids.uids.oidentd;
     };
 
-    users.extraGroups.oidentd.gid = config.ids.gids.oidentd;
+    users.groups.oidentd.gid = config.ids.gids.oidentd;
 
   };
 
diff --git a/nixos/modules/services/networking/openntpd.nix b/nixos/modules/services/networking/openntpd.nix
index 4bb9da54fe09..57638ebc9c01 100644
--- a/nixos/modules/services/networking/openntpd.nix
+++ b/nixos/modules/services/networking/openntpd.nix
@@ -7,7 +7,7 @@ let
 
   package = pkgs.openntpd_nixos;
 
-  cfgFile = pkgs.writeText "openntpd.conf" ''
+  configFile = ''
     ${concatStringsSep "\n" (map (s: "server ${s}") cfg.servers)}
     ${cfg.extraConfig}
   '';
@@ -31,8 +31,8 @@ in
       type = with types; lines;
       default = "";
       example = ''
-        listen on 127.0.0.1 
-        listen on ::1 
+        listen on 127.0.0.1
+        listen on ::1
       '';
       description = ''
         Additional text appended to <filename>openntpd.conf</filename>.
@@ -57,7 +57,9 @@ in
     # Add ntpctl to the environment for status checking
     environment.systemPackages = [ package ];
 
-    users.extraUsers = singleton {
+    environment.etc."ntpd.conf".text = configFile;
+
+    users.users = singleton {
       name = "ntp";
       uid = config.ids.uids.ntp;
       description = "OpenNTP daemon user";
@@ -71,7 +73,7 @@ in
       before = [ "time-sync.target" ];
       after = [ "dnsmasq.service" "bind.service" "network-online.target" ];
       serviceConfig = {
-        ExecStart = "${package}/sbin/ntpd -f ${cfgFile} -p ${pidFile} ${cfg.extraOptions}";
+        ExecStart = "${package}/sbin/ntpd -p ${pidFile} ${cfg.extraOptions}";
         Type = "forking";
         PIDFile = pidFile;
       };
diff --git a/nixos/modules/services/networking/openvpn.nix b/nixos/modules/services/networking/openvpn.nix
index a418839d22b8..b94b4026fd91 100644
--- a/nixos/modules/services/networking/openvpn.nix
+++ b/nixos/modules/services/networking/openvpn.nix
@@ -131,6 +131,9 @@ in
               Configuration of this OpenVPN instance.  See
               <citerefentry><refentrytitle>openvpn</refentrytitle><manvolnum>8</manvolnum></citerefentry>
               for details.
+
+              To import an external config file, use the following definition:
+              <literal>config = "config /path/to/config.ovpn"</literal>
             '';
           };
 
diff --git a/nixos/modules/services/networking/owamp.nix b/nixos/modules/services/networking/owamp.nix
new file mode 100644
index 000000000000..821a0258f4be
--- /dev/null
+++ b/nixos/modules/services/networking/owamp.nix
@@ -0,0 +1,47 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.owamp;
+in
+{
+
+  ###### interface
+
+  options = {
+    services.owamp.enable = mkEnableOption ''Enable OWAMP server'';
+  };
+
+
+  ###### implementation
+
+  config = mkIf cfg.enable {
+    users.users = singleton {
+      name = "owamp";
+      group = "owamp";
+      description = "Owamp daemon";
+    };
+
+    users.groups = singleton {
+      name = "owamp";
+    };
+
+    systemd.services.owamp = {
+      description = "Owamp server";
+      wantedBy = [ "multi-user.target" ];
+
+      serviceConfig = {
+        ExecStart="${pkgs.owamp}/bin/owampd -R /run/owamp -d /run/owamp -v -Z ";
+        PrivateTmp = true;
+        Restart = "always";
+        Type="simple";
+        User = "owamp";
+        Group = "owamp";
+        RuntimeDirectory = "owamp";
+        StateDirectory = "owamp";
+        AmbientCapabilities = "cap_net_bind_service";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/networking/pdns-recursor.nix b/nixos/modules/services/networking/pdns-recursor.nix
index 26be72d2a61e..d07deb9dcc67 100644
--- a/nixos/modules/services/networking/pdns-recursor.nix
+++ b/nixos/modules/services/networking/pdns-recursor.nix
@@ -128,7 +128,7 @@ in {
 
   config = mkIf cfg.enable {
 
-    users.extraUsers."${username}" = {
+    users.users."${username}" = {
       home = dataDir;
       createHome = true;
       uid = config.ids.uids.pdns-recursor;
diff --git a/nixos/modules/services/networking/pdnsd.nix b/nixos/modules/services/networking/pdnsd.nix
index f4467b818958..f5b174dd7b7b 100644
--- a/nixos/modules/services/networking/pdnsd.nix
+++ b/nixos/modules/services/networking/pdnsd.nix
@@ -62,14 +62,14 @@ in
     };
 
   config = mkIf cfg.enable {
-    users.extraUsers = singleton {
+    users.users = singleton {
       name = pdnsdUser;
       uid = config.ids.uids.pdnsd;
       group = pdnsdGroup;
       description = "pdnsd user";
     };
 
-    users.extraGroups = singleton {
+    users.groups = singleton {
       name = pdnsdGroup;
       gid = config.ids.gids.pdnsd;
     };
diff --git a/nixos/modules/services/networking/polipo.nix b/nixos/modules/services/networking/polipo.nix
index 847fc88ead4c..529115a1c6e1 100644
--- a/nixos/modules/services/networking/polipo.nix
+++ b/nixos/modules/services/networking/polipo.nix
@@ -85,7 +85,7 @@ in
 
   config = mkIf cfg.enable {
 
-    users.extraUsers = singleton
+    users.users = singleton
       { name = "polipo";
         uid = config.ids.uids.polipo;
         description = "Polipo caching proxy user";
@@ -93,7 +93,7 @@ in
         createHome = true;
       };
 
-    users.extraGroups = singleton
+    users.groups = singleton
       { name = "polipo";
         gid = config.ids.gids.polipo;
         members = [ "polipo" ];
diff --git a/nixos/modules/services/networking/prayer.nix b/nixos/modules/services/networking/prayer.nix
index 8cd4a0823534..f63f86496bee 100644
--- a/nixos/modules/services/networking/prayer.nix
+++ b/nixos/modules/services/networking/prayer.nix
@@ -72,14 +72,14 @@ in
   config = mkIf config.services.prayer.enable {
     environment.systemPackages = [ prayer ];
 
-    users.extraUsers = singleton
+    users.users = singleton
       { name = prayerUser;
         uid = config.ids.uids.prayer;
         description = "Prayer daemon user";
         home = stateDir;
       };
 
-    users.extraGroups = singleton
+    users.groups = singleton
       { name = prayerGroup;
         gid = config.ids.gids.prayer;
       };
diff --git a/nixos/modules/services/networking/prosody.nix b/nixos/modules/services/networking/prosody.nix
index 1b4f81f6b56e..a37ef98caec6 100644
--- a/nixos/modules/services/networking/prosody.nix
+++ b/nixos/modules/services/networking/prosody.nix
@@ -487,7 +487,7 @@ in
         '') cfg.virtualHosts) }
     '';
 
-    users.extraUsers.prosody = mkIf (cfg.user == "prosody") {
+    users.users.prosody = mkIf (cfg.user == "prosody") {
       uid = config.ids.uids.prosody;
       description = "Prosody user";
       createHome = true;
@@ -495,7 +495,7 @@ in
       home = "${cfg.dataDir}";
     };
 
-    users.extraGroups.prosody = mkIf (cfg.group == "prosody") {
+    users.groups.prosody = mkIf (cfg.group == "prosody") {
       gid = config.ids.gids.prosody;
     };
 
diff --git a/nixos/modules/services/networking/quagga.nix b/nixos/modules/services/networking/quagga.nix
index 22204e53203c..5acdd5af8f8f 100644
--- a/nixos/modules/services/networking/quagga.nix
+++ b/nixos/modules/services/networking/quagga.nix
@@ -95,26 +95,25 @@ in
 {
 
   ###### interface
-
-  options.services.quagga =
+  imports = [
     {
-
-      zebra = (serviceOptions "zebra") // {
-
-        enable = mkOption {
-          type = types.bool;
-          default = any isEnabled services;
-          description = ''
-            Whether to enable the Zebra routing manager.
-
-            The Zebra routing manager is automatically enabled
-            if any routing protocols are configured.
-          '';
+      options.services.quagga = {
+        zebra = (serviceOptions "zebra") // {
+          enable = mkOption {
+            type = types.bool;
+            default = any isEnabled services;
+            description = ''
+              Whether to enable the Zebra routing manager.
+
+              The Zebra routing manager is automatically enabled
+              if any routing protocols are configured.
+            '';
+          };
         };
-
       };
-
-    } // (genAttrs services serviceOptions);
+    }
+    { options.services.quagga = (genAttrs services serviceOptions); }
+  ];
 
   ###### implementation
 
diff --git a/nixos/modules/services/networking/quassel.nix b/nixos/modules/services/networking/quassel.nix
index bc7d6912b5ce..d850bb8b1305 100644
--- a/nixos/modules/services/networking/quassel.nix
+++ b/nixos/modules/services/networking/quassel.nix
@@ -72,14 +72,14 @@ in
 
   config = mkIf cfg.enable {
 
-    users.extraUsers = mkIf (cfg.user == null) [
+    users.users = mkIf (cfg.user == null) [
       { name = "quassel";
         description = "Quassel IRC client daemon";
         group = "quassel";
         uid = config.ids.uids.quassel;
       }];
 
-    users.extraGroups = mkIf (cfg.user == null) [
+    users.groups = mkIf (cfg.user == null) [
       { name = "quassel";
         gid = config.ids.gids.quassel;
       }];
diff --git a/nixos/modules/services/networking/radicale.nix b/nixos/modules/services/networking/radicale.nix
index 97ee05046ff0..2afab5ee3b3e 100644
--- a/nixos/modules/services/networking/radicale.nix
+++ b/nixos/modules/services/networking/radicale.nix
@@ -59,7 +59,7 @@ in
   config = mkIf cfg.enable {
     environment.systemPackages = [ cfg.package ];
 
-    users.extraUsers = singleton
+    users.users = singleton
       { name = "radicale";
         uid = config.ids.uids.radicale;
         description = "radicale user";
@@ -67,7 +67,7 @@ in
         createHome = true;
       };
 
-    users.extraGroups = singleton
+    users.groups = singleton
       { name = "radicale";
         gid = config.ids.gids.radicale;
       };
diff --git a/nixos/modules/services/networking/radvd.nix b/nixos/modules/services/networking/radvd.nix
index 85d7f9e4a41b..020faa34922a 100644
--- a/nixos/modules/services/networking/radvd.nix
+++ b/nixos/modules/services/networking/radvd.nix
@@ -52,7 +52,7 @@ in
 
   config = mkIf cfg.enable {
 
-    users.extraUsers.radvd =
+    users.users.radvd =
       { uid = config.ids.uids.radvd;
         description = "Router Advertisement Daemon User";
       };
diff --git a/nixos/modules/services/networking/rdnssd.nix b/nixos/modules/services/networking/rdnssd.nix
index a102242eae71..887772f6e5f0 100644
--- a/nixos/modules/services/networking/rdnssd.nix
+++ b/nixos/modules/services/networking/rdnssd.nix
@@ -64,7 +64,7 @@ in
       };
     };
 
-    users.extraUsers.rdnssd = {
+    users.users.rdnssd = {
       description = "RDNSSD Daemon User";
       uid = config.ids.uids.rdnssd;
     };
diff --git a/nixos/modules/services/networking/resilio.nix b/nixos/modules/services/networking/resilio.nix
index 2956a5ecbc04..ee7f82ac7bee 100644
--- a/nixos/modules/services/networking/resilio.nix
+++ b/nixos/modules/services/networking/resilio.nix
@@ -236,7 +236,7 @@ in
         }
       ];
 
-    users.extraUsers.rslsync = {
+    users.users.rslsync = {
       description     = "Resilio Sync Service user";
       home            = cfg.storagePath;
       createHome      = true;
@@ -244,7 +244,7 @@ in
       group           = "rslsync";
     };
 
-    users.extraGroups = [ { name = "rslsync"; } ];
+    users.groups = [ { name = "rslsync"; } ];
 
     systemd.services.resilio = with pkgs; {
       description = "Resilio Sync Service";
diff --git a/nixos/modules/services/networking/rpcbind.nix b/nixos/modules/services/networking/rpcbind.nix
index cddcb09054e0..0a5df6987092 100644
--- a/nixos/modules/services/networking/rpcbind.nix
+++ b/nixos/modules/services/networking/rpcbind.nix
@@ -37,7 +37,7 @@ with lib;
       wantedBy = [ "multi-user.target" ];
     };
 
-    users.extraUsers.rpc = {
+    users.users.rpc = {
       group = "nogroup";
       uid = config.ids.uids.rpc;
     };
diff --git a/nixos/modules/services/networking/sabnzbd.nix b/nixos/modules/services/networking/sabnzbd.nix
index cacf753fdcd7..62b24d4377f8 100644
--- a/nixos/modules/services/networking/sabnzbd.nix
+++ b/nixos/modules/services/networking/sabnzbd.nix
@@ -41,7 +41,7 @@ in
 
   config = mkIf cfg.enable {
 
-    users.extraUsers.sabnzbd = {
+    users.users.sabnzbd = {
           uid = config.ids.uids.sabnzbd;
           group = "sabnzbd";
           description = "sabnzbd user";
@@ -49,7 +49,7 @@ in
           createHome = true;
     };
 
-    users.extraGroups.sabnzbd = {
+    users.groups.sabnzbd = {
       gid = config.ids.gids.sabnzbd;
     };
 
diff --git a/nixos/modules/services/networking/searx.nix b/nixos/modules/services/networking/searx.nix
index c7a128ae212d..9412d0ef8a62 100644
--- a/nixos/modules/services/networking/searx.nix
+++ b/nixos/modules/services/networking/searx.nix
@@ -47,14 +47,14 @@ in
 
   config = mkIf config.services.searx.enable {
 
-    users.extraUsers.searx =
+    users.users.searx =
       { uid = config.ids.uids.searx;
         description = "Searx user";
         createHome = true;
         home = "/var/lib/searx";
       };
 
-    users.extraGroups.searx =
+    users.groups.searx =
       { gid = config.ids.gids.searx;
       };
 
diff --git a/nixos/modules/services/networking/seeks.nix b/nixos/modules/services/networking/seeks.nix
index f5bc60be3457..40729225b6d0 100644
--- a/nixos/modules/services/networking/seeks.nix
+++ b/nixos/modules/services/networking/seeks.nix
@@ -46,14 +46,14 @@ in
 
   config = mkIf config.services.seeks.enable {
 
-    users.extraUsers.seeks =
+    users.users.seeks =
       { uid = config.ids.uids.seeks;
         description = "Seeks user";
         createHome = true;
         home = "/var/lib/seeks";
       };
 
-    users.extraGroups.seeks =
+    users.groups.seeks =
       { gid = config.ids.gids.seeks;
       };
 
diff --git a/nixos/modules/services/networking/shairport-sync.nix b/nixos/modules/services/networking/shairport-sync.nix
index 908de9efd6fb..0b87140b0d8d 100644
--- a/nixos/modules/services/networking/shairport-sync.nix
+++ b/nixos/modules/services/networking/shairport-sync.nix
@@ -55,7 +55,7 @@ in
     services.avahi.publish.enable = true;
     services.avahi.publish.userServices = true;
 
-    users.extraUsers = singleton
+    users.users = singleton
       { name = cfg.user;
         description = "Shairport user";
         isSystemUser = true;
diff --git a/nixos/modules/services/networking/shout.nix b/nixos/modules/services/networking/shout.nix
index 3664c2857739..9784f1d160f3 100644
--- a/nixos/modules/services/networking/shout.nix
+++ b/nixos/modules/services/networking/shout.nix
@@ -82,7 +82,7 @@ in {
   };
 
   config = mkIf cfg.enable {
-    users.extraUsers = singleton {
+    users.users = singleton {
       name = "shout";
       uid = config.ids.uids.shout;
       description = "Shout daemon user";
diff --git a/nixos/modules/services/networking/smokeping.nix b/nixos/modules/services/networking/smokeping.nix
index c5c131cb4c50..9ba6e48f417c 100644
--- a/nixos/modules/services/networking/smokeping.nix
+++ b/nixos/modules/services/networking/smokeping.nix
@@ -278,7 +278,7 @@ in
       "fping6".source = "${pkgs.fping}/bin/fping6";
     };
     environment.systemPackages = [ pkgs.fping ];
-    users.extraUsers = singleton {
+    users.users = singleton {
       name = cfg.user;
       isNormalUser = false;
       isSystemUser = true;
diff --git a/nixos/modules/services/networking/sniproxy.nix b/nixos/modules/services/networking/sniproxy.nix
index 4d0f36923293..0345c12d3afe 100644
--- a/nixos/modules/services/networking/sniproxy.nix
+++ b/nixos/modules/services/networking/sniproxy.nix
@@ -82,14 +82,14 @@ in
       };
     };
 
-    users.extraUsers = mkIf (cfg.user == "sniproxy") {
+    users.users = mkIf (cfg.user == "sniproxy") {
       sniproxy = {
         group = cfg.group;
         uid = config.ids.uids.sniproxy;
       };
     };
 
-    users.extraGroups = mkIf (cfg.group == "sniproxy") {
+    users.groups = mkIf (cfg.group == "sniproxy") {
       sniproxy = {
         gid = config.ids.gids.sniproxy;
       };
diff --git a/nixos/modules/services/networking/spiped.nix b/nixos/modules/services/networking/spiped.nix
index 005d7182351a..e60d9abf42a6 100644
--- a/nixos/modules/services/networking/spiped.nix
+++ b/nixos/modules/services/networking/spiped.nix
@@ -171,8 +171,8 @@ in
       message   = "A pipe must either encrypt or decrypt";
     }) cfg.config;
 
-    users.extraGroups.spiped.gid = config.ids.gids.spiped;
-    users.extraUsers.spiped = {
+    users.groups.spiped.gid = config.ids.gids.spiped;
+    users.users.spiped = {
       description = "Secure Pipe Service user";
       group       = "spiped";
       uid         = config.ids.uids.spiped;
diff --git a/nixos/modules/services/networking/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix
index aab1203086ce..7b2d1920f0f1 100644
--- a/nixos/modules/services/networking/ssh/sshd.nix
+++ b/nixos/modules/services/networking/ssh/sshd.nix
@@ -49,7 +49,7 @@ let
         ${concatMapStrings (f: readFile f + "\n") u.openssh.authorizedKeys.keyFiles}
       '';
     };
-    usersWithKeys = attrValues (flip filterAttrs config.users.extraUsers (n: u:
+    usersWithKeys = attrValues (flip filterAttrs config.users.users (n: u:
       length u.openssh.authorizedKeys.keys != 0 || length u.openssh.authorizedKeys.keyFiles != 0
     ));
   in listToAttrs (map mkAuthKeyFile usersWithKeys);
@@ -198,6 +198,10 @@ in
           [ { type = "rsa"; bits = 4096; path = "/etc/ssh/ssh_host_rsa_key"; }
             { type = "ed25519"; path = "/etc/ssh/ssh_host_ed25519_key"; }
           ];
+        example =
+          [ { type = "rsa"; bits = 4096; path = "/etc/ssh/ssh_host_rsa_key"; rounds = 100; openSSHFormat = true; }
+            { type = "ed25519"; path = "/etc/ssh/ssh_host_ed25519_key"; rounds = 100; comment = "key comment"; }
+          ];
         description = ''
           NixOS can automatically generate SSH host keys.  This option
           specifies the path, type and size of each key.  See
@@ -272,6 +276,31 @@ in
         '';
       };
 
+      logLevel = mkOption {
+        type = types.enum [ "QUIET" "FATAL" "ERROR" "INFO" "VERBOSE" "DEBUG" "DEBUG1" "DEBUG2" "DEBUG3" ];
+        default = "VERBOSE";
+        description = ''
+          Gives the verbosity level that is used when logging messages from sshd(8). The possible values are:
+          QUIET, FATAL, ERROR, INFO, VERBOSE, DEBUG, DEBUG1, DEBUG2, and DEBUG3. The default is VERBOSE. DEBUG and DEBUG1
+          are equivalent. DEBUG2 and DEBUG3 each specify higher levels of debugging output. Logging with a DEBUG level
+          violates the privacy of users and is not recommended.
+
+          LogLevel VERBOSE logs user's key fingerprint on login.
+          Needed to have a clear audit track of which key was used to log in.
+        '';
+      };
+
+      useDns = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Specifies whether sshd(8) should look up the remote host name, and to check that the resolved host name for
+          the remote IP address maps back to the very same IP address.
+          If this option is set to no (the default) then only addresses and not host names may be used in
+          ~/.ssh/authorized_keys from and sshd_config Match Host directives.
+        '';
+      };
+
       extraConfig = mkOption {
         type = types.lines;
         default = "";
@@ -301,7 +330,7 @@ in
 
   config = mkIf cfg.enable {
 
-    users.extraUsers.sshd =
+    users.users.sshd =
       { isSystemUser = true;
         description = "SSH privilege separation user";
       };
@@ -309,7 +338,9 @@ in
     services.openssh.moduliFile = mkDefault "${cfgc.package}/etc/ssh/moduli";
 
     environment.etc = authKeysFiles //
-      { "ssh/moduli".source = cfg.moduliFile; };
+      { "ssh/moduli".source = cfg.moduliFile;
+        "ssh/sshd_config".text = cfg.extraConfig;
+      };
 
     systemd =
       let
@@ -331,7 +362,14 @@ in
 
                 ${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 ""
+                      ssh-keygen \
+                        -t "${k.type}" \
+                        ${if k ? bits then "-b ${toString k.bits}" else ""} \
+                        ${if k ? rounds then "-a ${toString k.rounds}" else ""} \
+                        ${if k ? comment then "-C '${k.comment}'" else ""} \
+                        ${if k ? openSSHFormat && k.openSSHFormat then "-o" else ""} \
+                        -f "${k.path}" \
+                        -N ""
                   fi
                 '')}
               '';
@@ -340,7 +378,7 @@ in
               { ExecStart =
                   (optionalString cfg.startWhenNeeded "-") +
                   "${cfgc.package}/bin/sshd " + (optionalString cfg.startWhenNeeded "-i ") +
-                  "-f ${pkgs.writeText "sshd_config" cfg.extraConfig}";
+                  "-f /etc/ssh/sshd_config";
                 KillMode = "process";
               } // (if cfg.startWhenNeeded then {
                 StandardInput = "socket";
@@ -377,6 +415,9 @@ in
         unixAuth = cfg.passwordAuthentication;
       };
 
+    # These values are merged with the ones defined externally, see:
+    # https://github.com/NixOS/nixpkgs/pull/10155
+    # https://github.com/NixOS/nixpkgs/pull/41745
     services.openssh.authorizedKeysFiles =
       [ ".ssh/authorized_keys" ".ssh/authorized_keys2" "/etc/ssh/authorized_keys.d/%u" ];
 
@@ -426,9 +467,14 @@ in
         Ciphers ${concatStringsSep "," cfg.ciphers}
         MACs ${concatStringsSep "," cfg.macs}
 
-        # LogLevel VERBOSE logs user's key fingerprint on login.
-        # Needed to have a clear audit track of which key was used to log in.
-        LogLevel VERBOSE
+        LogLevel ${cfg.logLevel}
+
+        ${if cfg.useDns then ''
+          UseDNS yes
+        '' else ''
+          UseDNS no
+        ''}
+
       '';
 
     assertions = [{ assertion = if cfg.forwardX11 then cfgc.setXAuthLocation else true;
diff --git a/nixos/modules/services/networking/sslh.nix b/nixos/modules/services/networking/sslh.nix
index e3d65c49fbf2..0222e8ce8b58 100644
--- a/nixos/modules/services/networking/sslh.nix
+++ b/nixos/modules/services/networking/sslh.nix
@@ -4,15 +4,14 @@ with lib;
 
 let
   cfg = config.services.sslh;
+  user = "sslh";
   configFile = pkgs.writeText "sslh.conf" ''
     verbose: ${boolToString cfg.verbose};
     foreground: true;
     inetd: false;
     numeric: false;
-    transparent: false;
+    transparent: ${boolToString cfg.transparent};
     timeout: "${toString cfg.timeout}";
-    user: "nobody";
-    pidfile: "${cfg.pidfile}";
 
     listen:
     (
@@ -50,16 +49,16 @@ in
         description = "Timeout in seconds.";
       };
 
-      pidfile = mkOption {
-        type = types.path;
-        default = "/run/sslh.pid";
-        description = "PID file path for sslh daemon.";
+      transparent = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Will the services behind sslh (Apache, sshd and so on) see the external IP and ports as if the external world connected directly to them";
       };
 
       listenAddress = mkOption {
         type = types.str;
-        default = config.networking.hostName;
-        description = "Listening hostname.";
+        default = "0.0.0.0";
+        description = "Listening address or hostname.";
       };
 
       port = mkOption {
@@ -76,14 +75,91 @@ in
     };
   };
 
-  config = mkIf cfg.enable {
-    systemd.services.sslh = {
-      description = "Applicative Protocol Multiplexer (e.g. share SSH and HTTPS on the same port)";
-      after = [ "network.target" ];
-      wantedBy = [ "multi-user.target" ];
-      serviceConfig.ExecStart = "${pkgs.sslh}/bin/sslh -F${configFile}";
-      serviceConfig.KillMode = "process";
-      serviceConfig.PIDFile = "${cfg.pidfile}";
-    };
-  };
+  config = mkMerge [
+    (mkIf cfg.enable {
+      users.users.${user} = {
+        description = "sslh daemon user";
+        isSystemUser = true;
+      };
+
+      systemd.services.sslh = {
+        description = "Applicative Protocol Multiplexer (e.g. share SSH and HTTPS on the same port)";
+        after = [ "network.target" ];
+        wantedBy = [ "multi-user.target" ];
+
+        serviceConfig = {
+          User                 = user;
+          Group                = "nogroup";
+          PermissionsStartOnly = true;
+          Restart              = "always";
+          RestartSec           = "1s";
+          ExecStart            = "${pkgs.sslh}/bin/sslh -F${configFile}";
+          KillMode             = "process";
+          AmbientCapabilities  = "CAP_NET_BIND_SERVICE CAP_NET_ADMIN CAP_SETGID CAP_SETUID";
+          PrivateTmp           = true;
+          PrivateDevices       = true;
+          ProtectSystem        = "full";
+          ProtectHome          = true;
+        };
+      };
+    })
+
+    # code from https://github.com/yrutschle/sslh#transparent-proxy-support
+    # the only difference is using iptables mark 0x2 instead of 0x1 to avoid conflicts with nixos/nat module
+    (mkIf (cfg.enable && cfg.transparent) {
+      # Set route_localnet = 1 on all interfaces so that ssl can use "localhost" as destination
+      boot.kernel.sysctl."net.ipv4.conf.default.route_localnet" = 1;
+      boot.kernel.sysctl."net.ipv4.conf.all.route_localnet"     = 1;
+
+      systemd.services.sslh = let
+        iptablesCommands = [
+          # DROP martian packets as they would have been if route_localnet was zero
+          # Note: packets not leaving the server aren't affected by this, thus sslh will still work
+          { table = "raw";    command = "PREROUTING  ! -i lo -d 127.0.0.0/8 -j DROP"; }
+          { table = "mangle"; command = "POSTROUTING ! -o lo -s 127.0.0.0/8 -j DROP"; }
+          # Mark all connections made by ssl for special treatment (here sslh is run as user ${user})
+          { table = "nat";    command = "OUTPUT -m owner --uid-owner ${user} -p tcp --tcp-flags FIN,SYN,RST,ACK SYN -j CONNMARK --set-xmark 0x02/0x0f"; }
+          # Outgoing packets that should go to sslh instead have to be rerouted, so mark them accordingly (copying over the connection mark)
+          { table = "mangle"; command = "OUTPUT ! -o lo -p tcp -m connmark --mark 0x02/0x0f -j CONNMARK --restore-mark --mask 0x0f"; }
+        ];
+        ip6tablesCommands = [
+          { table = "raw";    command = "PREROUTING  ! -i lo -d ::1/128     -j DROP"; }
+          { table = "mangle"; command = "POSTROUTING ! -o lo -s ::1/128     -j DROP"; }
+          { table = "nat";    command = "OUTPUT -m owner --uid-owner ${user} -p tcp --tcp-flags FIN,SYN,RST,ACK SYN -j CONNMARK --set-xmark 0x02/0x0f"; }
+          { table = "mangle"; command = "OUTPUT ! -o lo -p tcp -m connmark --mark 0x02/0x0f -j CONNMARK --restore-mark --mask 0x0f"; }
+        ];
+      in {
+        path = [ pkgs.iptables pkgs.iproute pkgs.procps ];
+
+        preStart = ''
+          # Cleanup old iptables entries which might be still there
+          ${concatMapStringsSep "\n" ({table, command}: "while iptables -w -t ${table} -D ${command} 2>/dev/null; do echo; done") iptablesCommands}
+          ${concatMapStringsSep "\n" ({table, command}:       "iptables -w -t ${table} -A ${command}"                           ) iptablesCommands}
+
+          # Configure routing for those marked packets
+          ip rule  add fwmark 0x2 lookup 100
+          ip route add local 0.0.0.0/0 dev lo table 100
+
+        '' + optionalString config.networking.enableIPv6 ''
+          ${concatMapStringsSep "\n" ({table, command}: "while ip6tables -w -t ${table} -D ${command} 2>/dev/null; do echo; done") ip6tablesCommands}
+          ${concatMapStringsSep "\n" ({table, command}:       "ip6tables -w -t ${table} -A ${command}"                           ) ip6tablesCommands}
+
+          ip -6 rule  add fwmark 0x2 lookup 100
+          ip -6 route add local ::/0 dev lo table 100
+        '';
+
+        postStop = ''
+          ${concatMapStringsSep "\n" ({table, command}: "iptables -w -t ${table} -D ${command}") iptablesCommands}
+
+          ip rule  del fwmark 0x2 lookup 100
+          ip route del local 0.0.0.0/0 dev lo table 100
+        '' + optionalString config.networking.enableIPv6 ''
+          ${concatMapStringsSep "\n" ({table, command}: "ip6tables -w -t ${table} -D ${command}") ip6tablesCommands}
+
+          ip -6 rule  del fwmark 0x2 lookup 100
+          ip -6 route del local ::/0 dev lo table 100
+        '';
+      };
+    })
+  ];
 }
diff --git a/nixos/modules/services/networking/strongswan-swanctl/swanctl-params.nix b/nixos/modules/services/networking/strongswan-swanctl/swanctl-params.nix
index ad211f41eef0..b16d299917fe 100644
--- a/nixos/modules/services/networking/strongswan-swanctl/swanctl-params.nix
+++ b/nixos/modules/services/networking/strongswan-swanctl/swanctl-params.nix
@@ -938,9 +938,12 @@ in {
         protection.
       '';
 
-      hw_offload = mkYesNoParam no ''
+      hw_offload = mkEnumParam ["yes" "no" "auto"] "no" ''
         Enable hardware offload for this CHILD_SA, if supported by the IPsec
-        implementation.
+        implementation. The value <literal>yes</literal> enforces offloading
+        and the installation will fail if it's not supported by either kernel or
+        device. The value <literal>auto</literal> enables offloading, if it's
+        supported, but the installation does not fail otherwise.
       '';
 
       start_action = mkEnumParam ["none" "trap" "start"] "none" ''
diff --git a/nixos/modules/services/networking/supplicant.nix b/nixos/modules/services/networking/supplicant.nix
index dc90a4bcc620..3c4321ab9e9d 100644
--- a/nixos/modules/services/networking/supplicant.nix
+++ b/nixos/modules/services/networking/supplicant.nix
@@ -183,7 +183,7 @@ in
 
       example = literalExample ''
         { "wlan0 wlan1" = {
-            configFile = "/etc/wpa_supplicant";
+            configFile.path = "/etc/wpa_supplicant.conf";
             userControlled.group = "network";
             extraConf = '''
               ap_scan=1
diff --git a/nixos/modules/services/networking/supybot.nix b/nixos/modules/services/networking/supybot.nix
index 2cfb9fc9b923..64eb11068329 100644
--- a/nixos/modules/services/networking/supybot.nix
+++ b/nixos/modules/services/networking/supybot.nix
@@ -45,7 +45,7 @@ in
 
     environment.systemPackages = [ pkgs.pythonPackages.limnoria ];
 
-    users.extraUsers = singleton {
+    users.users = singleton {
       name = "supybot";
       uid = config.ids.uids.supybot;
       group = "supybot";
@@ -54,7 +54,7 @@ in
       createHome = true;
     };
 
-    users.extraGroups.supybot = {
+    users.groups.supybot = {
       name = "supybot";
       gid = config.ids.gids.supybot;
     };
diff --git a/nixos/modules/services/networking/syncthing.nix b/nixos/modules/services/networking/syncthing.nix
index e485c073cbdd..c610b3b66606 100644
--- a/nixos/modules/services/networking/syncthing.nix
+++ b/nixos/modules/services/networking/syncthing.nix
@@ -103,7 +103,7 @@ in {
     systemd.packages = [ pkgs.syncthing ];
 
     users = mkIf (cfg.user == defaultUser) {
-      extraUsers."${defaultUser}" =
+      users."${defaultUser}" =
         { group = cfg.group;
           home  = cfg.dataDir;
           createHome = true;
@@ -111,7 +111,7 @@ in {
           description = "Syncthing daemon user";
         };
 
-      extraGroups."${defaultUser}".gid =
+      groups."${defaultUser}".gid =
         config.ids.gids.syncthing;
     };
 
diff --git a/nixos/modules/services/networking/tcpcrypt.nix b/nixos/modules/services/networking/tcpcrypt.nix
index ee005e11aa32..a0ccb9950094 100644
--- a/nixos/modules/services/networking/tcpcrypt.nix
+++ b/nixos/modules/services/networking/tcpcrypt.nix
@@ -29,7 +29,7 @@ in
 
   config = mkIf cfg.enable {
 
-    users.extraUsers = singleton {
+    users.users = singleton {
       name = "tcpcryptd";
       uid = config.ids.uids.tcpcryptd;
       description = "tcpcrypt daemon user";
diff --git a/nixos/modules/services/networking/tinc.nix b/nixos/modules/services/networking/tinc.nix
index e3c9b5282b8c..35cdddc590b8 100644
--- a/nixos/modules/services/networking/tinc.nix
+++ b/nixos/modules/services/networking/tinc.nix
@@ -163,12 +163,7 @@ in
         wantedBy = [ "multi-user.target" ];
         after = [ "network.target" ];
         path = [ data.package ];
-        restartTriggers =
-          let
-            drvlist = [ config.environment.etc."tinc/${network}/tinc.conf".source ]
-                        ++ mapAttrsToList (host: _: config.environment.etc."tinc/${network}/hosts/${host}".source) data.hosts;
-          in # drvlist might be too long to be used directly
-            [ (builtins.hashString "sha256" (concatMapStrings (d: d.outPath) drvlist)) ];
+        restartTriggers = [ config.environment.etc."tinc/${network}/tinc.conf".source ];
         serviceConfig = {
           Type = "simple";
           Restart = "always";
@@ -207,13 +202,14 @@ in
           ${concatStringsSep "\n" (mapAttrsToList (network: data:
             optionalString (versionAtLeast data.package.version "1.1pre") ''
               makeWrapper ${data.package}/bin/tinc "$out/bin/tinc.${network}" \
-                --add-flags "--pidfile=/run/tinc.${network}.pid"
+                --add-flags "--pidfile=/run/tinc.${network}.pid" \
+                --add-flags "--config=/etc/tinc/${network}"
             '') cfg.networks)}
         '';
       };
     in [ cli-wrappers ];
 
-    users.extraUsers = flip mapAttrs' cfg.networks (network: _:
+    users.users = flip mapAttrs' cfg.networks (network: _:
       nameValuePair ("tinc.${network}") ({
         description = "Tinc daemon user for ${network}";
         isSystemUser = true;
diff --git a/nixos/modules/services/networking/tinydns.nix b/nixos/modules/services/networking/tinydns.nix
index 184888ef05da..7d5db71601ef 100644
--- a/nixos/modules/services/networking/tinydns.nix
+++ b/nixos/modules/services/networking/tinydns.nix
@@ -32,7 +32,7 @@ with lib;
   config = mkIf config.services.tinydns.enable {
     environment.systemPackages = [ pkgs.djbdns ];
 
-    users.extraUsers.tinydns = {};
+    users.users.tinydns = {};
 
     systemd.services.tinydns = {
       description = "djbdns tinydns server";
diff --git a/nixos/modules/services/networking/tox-bootstrapd.nix b/nixos/modules/services/networking/tox-bootstrapd.nix
index cb0e6b158651..1d3492151690 100644
--- a/nixos/modules/services/networking/tox-bootstrapd.nix
+++ b/nixos/modules/services/networking/tox-bootstrapd.nix
@@ -56,7 +56,7 @@ in
 
   config = mkIf config.services.toxBootstrapd.enable {
 
-    users.extraUsers = singleton
+    users.users = singleton
       { name = "tox-bootstrapd";
         uid = config.ids.uids.tox-bootstrapd;
         description = "Tox bootstrap daemon user";
diff --git a/nixos/modules/services/networking/toxvpn.nix b/nixos/modules/services/networking/toxvpn.nix
index 5e13402d7645..f5baea9222be 100644
--- a/nixos/modules/services/networking/toxvpn.nix
+++ b/nixos/modules/services/networking/toxvpn.nix
@@ -57,7 +57,7 @@ with lib;
 
     environment.systemPackages = [ pkgs.toxvpn ];
 
-    users.extraUsers = {
+    users.users = {
       toxvpn = {
         uid        = config.ids.uids.toxvpn;
         home       = "/var/lib/toxvpn";
diff --git a/nixos/modules/services/networking/tvheadend.nix b/nixos/modules/services/networking/tvheadend.nix
index cdd8747ba898..f495c39967e8 100644
--- a/nixos/modules/services/networking/tvheadend.nix
+++ b/nixos/modules/services/networking/tvheadend.nix
@@ -3,7 +3,7 @@
 with lib;
 
 let cfg     = config.services.tvheadend;
-    pidFile = "${config.users.extraUsers.tvheadend.home}/tvheadend.pid";
+    pidFile = "${config.users.users.tvheadend.home}/tvheadend.pid";
 in
 
 {
@@ -25,7 +25,7 @@ in
   };
 
   config = mkIf cfg.enable {
-    users.extraUsers.tvheadend = {
+    users.users.tvheadend = {
       description = "Tvheadend Service user";
       home        = "/var/lib/tvheadend";
       createHome  = true;
diff --git a/nixos/modules/services/networking/unbound.nix b/nixos/modules/services/networking/unbound.nix
index f069a9883a7f..1a35979ad44c 100644
--- a/nixos/modules/services/networking/unbound.nix
+++ b/nixos/modules/services/networking/unbound.nix
@@ -60,7 +60,7 @@ in
       };
 
       interfaces = mkOption {
-        default = [ "127.0.0.1" "::1" ];
+        default = [ "127.0.0.1" ] ++ optional config.networking.enableIPv6 "::1";
         type = types.listOf types.str;
         description = "What addresses the server should listen on.";
       };
@@ -112,8 +112,8 @@ in
         mkdir -m 0755 -p ${stateDir}/dev/
         cp ${confFile} ${stateDir}/unbound.conf
         ${optionalString cfg.enableRootTrustAnchor ''
-        ${pkgs.unbound}/bin/unbound-anchor -a ${rootTrustAnchorFile} || echo "Root anchor updated!"
-        chown unbound ${stateDir} ${rootTrustAnchorFile}
+          ${pkgs.unbound}/bin/unbound-anchor -a ${rootTrustAnchorFile} || echo "Root anchor updated!"
+          chown unbound ${stateDir} ${rootTrustAnchorFile}
         ''}
         touch ${stateDir}/dev/random
         ${pkgs.utillinux}/bin/mount --bind -n /dev/urandom ${stateDir}/dev/random
@@ -126,9 +126,14 @@ in
         ProtectSystem = true;
         ProtectHome = true;
         PrivateDevices = true;
+        Restart = "always";
+        RestartSec = "5s";
       };
     };
 
+    # If networkmanager is enabled, ask it to interface with unbound.
+    networking.networkmanager.dns = "unbound";
+
   };
 
 }
diff --git a/nixos/modules/services/networking/unifi.nix b/nixos/modules/services/networking/unifi.nix
index 94958bfdd83e..ac10e77ba306 100644
--- a/nixos/modules/services/networking/unifi.nix
+++ b/nixos/modules/services/networking/unifi.nix
@@ -114,7 +114,7 @@ in
 
   config = mkIf cfg.enable {
 
-    users.extraUsers.unifi = {
+    users.users.unifi = {
       uid = config.ids.uids.unifi;
       description = "UniFi controller daemon user";
       home = "${stateDir}";
diff --git a/nixos/modules/services/networking/vsftpd.nix b/nixos/modules/services/networking/vsftpd.nix
index 6b3d658bd852..1f9107c3ce9c 100644
--- a/nixos/modules/services/networking/vsftpd.nix
+++ b/nixos/modules/services/networking/vsftpd.nix
@@ -193,7 +193,7 @@ in
         message = "vsftpd: If forceLocalLoginsSSL or forceLocalDataSSL is true then a rsaCertFile must be provided!";
       };
 
-    users.extraUsers =
+    users.users =
       [ { name = "vsftpd";
           uid = config.ids.uids.vsftpd;
           description = "VSFTPD user";
@@ -207,7 +207,7 @@ in
           home = cfg.anonymousUserHome;
         };
 
-    users.extraGroups.ftp.gid = config.ids.gids.ftp;
+    users.groups.ftp.gid = config.ids.gids.ftp;
 
     # If you really have to access root via FTP use mkOverride or userlistDeny
     # = false and whitelist root
diff --git a/nixos/modules/services/networking/wireguard.nix b/nixos/modules/services/networking/wireguard.nix
index 0591917c7423..acb4778d8485 100644
--- a/nixos/modules/services/networking/wireguard.nix
+++ b/nixos/modules/services/networking/wireguard.nix
@@ -193,7 +193,7 @@ let
         after = [ "network.target" ];
         wantedBy = [ "multi-user.target" ];
         environment.DEVICE = name;
-        path = with pkgs; [ kmod iproute wireguard ];
+        path = with pkgs; [ kmod iproute wireguard-tools ];
 
         serviceConfig = {
           Type = "oneshot";
@@ -279,7 +279,7 @@ in
   config = mkIf (cfg.interfaces != {}) {
 
     boot.extraModulePackages = [ kernel.wireguard ];
-    environment.systemPackages = [ pkgs.wireguard ];
+    environment.systemPackages = [ pkgs.wireguard-tools ];
 
     systemd.services = mapAttrs' generateUnit cfg.interfaces;
 
diff --git a/nixos/modules/services/networking/xrdp.nix b/nixos/modules/services/networking/xrdp.nix
index bf23c6ae6192..0e882873b4ba 100644
--- a/nixos/modules/services/networking/xrdp.nix
+++ b/nixos/modules/services/networking/xrdp.nix
@@ -97,6 +97,7 @@ in
     # xrdp can run X11 program even if "services.xserver.enable = false"
     environment.pathsToLink =
       [ "/etc/xdg" "/share/xdg" "/share/applications" "/share/icons" "/share/pixmaps" ];
+    fonts.enableDefaultFonts = mkDefault true;
 
     systemd = {
       services.xrdp = {
diff --git a/nixos/modules/services/networking/zerotierone.nix b/nixos/modules/services/networking/zerotierone.nix
index cd1617b8e2ba..4c1ee75d536c 100644
--- a/nixos/modules/services/networking/zerotierone.nix
+++ b/nixos/modules/services/networking/zerotierone.nix
@@ -47,7 +47,7 @@ in
     };
 
     # ZeroTier does not issue DHCP leases, but some strangers might...
-    networking.dhcpcd.denyInterfaces = [ "zt0" ];
+    networking.dhcpcd.denyInterfaces = [ "zt*" ];
 
     # ZeroTier receives UDP transmissions on port 9993 by default
     networking.firewall.allowedUDPPorts = [ 9993 ];
diff --git a/nixos/modules/services/networking/znc.nix b/nixos/modules/services/networking/znc.nix
index 72313ab2ee14..f817db2ad000 100644
--- a/nixos/modules/services/networking/znc.nix
+++ b/nixos/modules/services/networking/znc.nix
@@ -26,7 +26,6 @@ let
   };
 
   # Keep znc.conf in nix store, then symlink or copy into `dataDir`, depending on `mutable`.
-  notNull = a: ! isNull a;
   mkZncConf = confOpts: ''
     Version = 1.6.3
     ${concatMapStrings (n: "LoadModule = ${n}\n") confOpts.modules}
@@ -36,6 +35,7 @@ let
             IPv4 = true
             IPv6 = true
             SSL = ${boolToString confOpts.useSSL}
+            ${lib.optionalString (confOpts.uriPrefix != null) "URIPrefix = ${confOpts.uriPrefix}"}
     </Listener>
 
     <User ${confOpts.userName}>
@@ -310,6 +310,16 @@ in
           '';
         };
 
+        uriPrefix = mkOption {
+          type = types.nullOr types.str;
+          default = null;
+          example = "/znc/";
+          description = ''
+            An optional URI prefix for the ZNC web interface. Can be
+            used to make ZNC available behind a reverse proxy.
+          '';
+        };
+
         extraZncConf = mkOption {
           default = "";
           type = types.lines;
@@ -402,7 +412,7 @@ in
       script = "${pkgs.znc}/bin/znc --foreground --datadir ${cfg.dataDir} ${toString cfg.extraFlags}";
     };
 
-    users.extraUsers = optional (cfg.user == defaultUser)
+    users.users = optional (cfg.user == defaultUser)
       { name = defaultUser;
         description = "ZNC server daemon owner";
         group = defaultUser;
@@ -411,7 +421,7 @@ in
         createHome = true;
       };
 
-    users.extraGroups = optional (cfg.user == defaultUser)
+    users.groups = optional (cfg.user == defaultUser)
       { name = defaultUser;
         gid = config.ids.gids.znc;
         members = [ defaultUser ];
diff --git a/nixos/modules/services/printing/cupsd.nix b/nixos/modules/services/printing/cupsd.nix
index c4147986439c..dbf18ec1d114 100644
--- a/nixos/modules/services/printing/cupsd.nix
+++ b/nixos/modules/services/printing/cupsd.nix
@@ -124,6 +124,16 @@ in
         '';
       };
 
+      startWhenNeeded = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          If set, CUPS is socket-activated; that is,
+          instead of having it permanently running as a daemon,
+          systemd will start it on the first incoming connection.
+        '';
+      };
+
       listenAddresses = mkOption {
         type = types.listOf types.str;
         default = [ "localhost:631" ];
@@ -268,7 +278,7 @@ in
 
   config = mkIf config.services.printing.enable {
 
-    users.extraUsers = singleton
+    users.users = singleton
       { name = "cups";
         uid = config.ids.uids.cups;
         group = "lp";
@@ -287,8 +297,13 @@ in
 
     systemd.packages = [ cups.out ];
 
+    systemd.sockets.cups = mkIf cfg.startWhenNeeded {
+      wantedBy = [ "sockets.target" ];
+      listenStreams = map (x: replaceStrings ["localhost"] ["127.0.0.1"] (removePrefix "*:" x)) cfg.listenAddresses;
+    };
+
     systemd.services.cups =
-      { wantedBy = [ "multi-user.target" ];
+      { wantedBy = optionals (!cfg.startWhenNeeded) [ "multi-user.target" ];
         wants = [ "network.target" ];
         after = [ "network.target" ];
 
diff --git a/nixos/modules/services/scheduling/atd.nix b/nixos/modules/services/scheduling/atd.nix
index 77a3f6b51e80..a32907647a0d 100644
--- a/nixos/modules/services/scheduling/atd.nix
+++ b/nixos/modules/services/scheduling/atd.nix
@@ -57,14 +57,14 @@ in
 
     security.pam.services.atd = {};
 
-    users.extraUsers = singleton
+    users.users = singleton
       { name = "atd";
         uid = config.ids.uids.atd;
         description = "atd user";
         home = "/var/empty";
       };
 
-    users.extraGroups = singleton
+    users.groups = singleton
       { name = "atd";
         gid = config.ids.gids.atd;
       };
diff --git a/nixos/modules/services/scheduling/chronos.nix b/nixos/modules/services/scheduling/chronos.nix
index 6c39997fec88..9a8ed4c09ac1 100644
--- a/nixos/modules/services/scheduling/chronos.nix
+++ b/nixos/modules/services/scheduling/chronos.nix
@@ -49,6 +49,6 @@ in {
       };
     };
 
-    users.extraUsers.chronos.uid = config.ids.uids.chronos;
+    users.users.chronos.uid = config.ids.uids.chronos;
   };
 }
diff --git a/nixos/modules/services/scheduling/fcron.nix b/nixos/modules/services/scheduling/fcron.nix
index e3b6b638f5a7..ae3828977753 100644
--- a/nixos/modules/services/scheduling/fcron.nix
+++ b/nixos/modules/services/scheduling/fcron.nix
@@ -115,7 +115,7 @@ in
       ];
 
     environment.systemPackages = [ pkgs.fcron ];
-    users.extraUsers.fcron = {
+    users.users.fcron = {
       uid = config.ids.uids.fcron;
       home = "/var/spool/fcron";
       group = "fcron";
@@ -128,6 +128,7 @@ in
         owner = "fcron";
         group = "fcron";
         setgid = true;
+        setuid = true;
       };
       fcrondyn = {
         source = "${pkgs.fcron}/bin/fcrondyn";
diff --git a/nixos/modules/services/scheduling/marathon.nix b/nixos/modules/services/scheduling/marathon.nix
index 19c9a708f21f..0961a67770e1 100644
--- a/nixos/modules/services/scheduling/marathon.nix
+++ b/nixos/modules/services/scheduling/marathon.nix
@@ -93,6 +93,6 @@ in {
       };
     };
 
-    users.extraUsers.${cfg.user} = { };
+    users.users.${cfg.user} = { };
   };
 }
diff --git a/nixos/modules/services/search/hound.nix b/nixos/modules/services/search/hound.nix
index a94a851e80ec..6740928db9a7 100644
--- a/nixos/modules/services/search/hound.nix
+++ b/nixos/modules/services/search/hound.nix
@@ -88,12 +88,12 @@ in {
   };
 
   config = mkIf cfg.enable {
-    users.extraGroups = optional (cfg.group == "hound") {
+    users.groups = optional (cfg.group == "hound") {
       name = "hound";
       gid = config.ids.gids.hound;
     };
 
-    users.extraUsers = optional (cfg.user == "hound") {
+    users.users = optional (cfg.user == "hound") {
       name = "hound";
       description = "hound code search";
       createHome = true;
diff --git a/nixos/modules/services/search/kibana.nix b/nixos/modules/services/search/kibana.nix
index 9d7d2d799189..5885a72c6628 100644
--- a/nixos/modules/services/search/kibana.nix
+++ b/nixos/modules/services/search/kibana.nix
@@ -193,7 +193,7 @@ in {
 
     environment.systemPackages = [ cfg.package ];
 
-    users.extraUsers = singleton {
+    users.users = singleton {
       name = "kibana";
       uid = config.ids.uids.kibana;
       description = "Kibana service user";
diff --git a/nixos/modules/services/security/clamav.nix b/nixos/modules/services/security/clamav.nix
index 4161c61ed375..9ad0095252de 100644
--- a/nixos/modules/services/security/clamav.nix
+++ b/nixos/modules/services/security/clamav.nix
@@ -79,7 +79,7 @@ in
   config = mkIf (cfg.updater.enable || cfg.daemon.enable) {
     environment.systemPackages = [ pkg ];
 
-    users.extraUsers = singleton {
+    users.users = singleton {
       name = clamavUser;
       uid = config.ids.uids.clamav;
       group = clamavGroup;
@@ -87,7 +87,7 @@ in
       home = stateDir;
     };
 
-    users.extraGroups = singleton {
+    users.groups = singleton {
       name = clamavGroup;
       gid = config.ids.gids.clamav;
     };
diff --git a/nixos/modules/services/security/fprot.nix b/nixos/modules/services/security/fprot.nix
index a12aa01503e3..b1ca4ab23452 100644
--- a/nixos/modules/services/security/fprot.nix
+++ b/nixos/modules/services/security/fprot.nix
@@ -53,14 +53,14 @@ in {
       target = "f-prot.conf";
     };
 
-    users.extraUsers = singleton
+    users.users = singleton
       { name = fprotUser;
         uid = config.ids.uids.fprot;
         description = "F-Prot daemon user";
         home = stateDir;
       };
 
-    users.extraGroups = singleton
+    users.groups = singleton
       { name = fprotGroup;
         gid = config.ids.gids.fprot;
       };
diff --git a/nixos/modules/services/security/munge.nix b/nixos/modules/services/security/munge.nix
index 919c2c2b0e15..5bca15833544 100644
--- a/nixos/modules/services/security/munge.nix
+++ b/nixos/modules/services/security/munge.nix
@@ -35,7 +35,15 @@ in
 
     environment.systemPackages = [ pkgs.munge ];
 
-    systemd.services.munged = { 
+    users.users.munge = {
+      description   = "Munge daemon user";
+      isSystemUser  = true;
+      group         = "munge";
+    };
+
+    users.groups.munge = {};
+
+    systemd.services.munged = {
       wantedBy = [ "multi-user.target" ];
       after = [ "network.target" ];
 
@@ -44,14 +52,20 @@ in
       preStart = ''
         chmod 0700 ${cfg.password}
         mkdir -p /var/lib/munge -m 0711
+        chown -R munge:munge /var/lib/munge
         mkdir -p /var/log/munge -m 0700
+        chown -R munge:munge /var/log/munge
         mkdir -p /run/munge -m 0755
+        chown -R munge:munge /run/munge
       '';
 
       serviceConfig = {
         ExecStart = "${pkgs.munge}/bin/munged --syslog --key-file ${cfg.password}";
         PIDFile = "/run/munge/munged.pid";
         ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
+        PermissionsStartOnly = "true";
+        User = "munge";
+        Group = "munge";
       };
 
     };
diff --git a/nixos/modules/services/security/oauth2_proxy.nix b/nixos/modules/services/security/oauth2_proxy.nix
index 433d97c2a7d7..0c5fe8c0ef5f 100644
--- a/nixos/modules/services/security/oauth2_proxy.nix
+++ b/nixos/modules/services/security/oauth2_proxy.nix
@@ -72,6 +72,7 @@ let
 
   mapConfig = key: attr:
   if (!isNull attr && attr != []) then (
+    if isDerivation attr then mapConfig key (toString attr) else
     if (builtins.typeOf attr) == "set" then concatStringsSep " "
       (mapAttrsToList (name: value: mapConfig (key + "-" + name) value) attr) else
     if (builtins.typeOf attr) == "list" then concatMapStringsSep " " (mapConfig key) attr else
@@ -543,7 +544,7 @@ in
       cookie.secret = mkDefault null;
     };
 
-    users.extraUsers.oauth2_proxy = {
+    users.users.oauth2_proxy = {
       description = "OAuth2 Proxy";
     };
 
diff --git a/nixos/modules/services/security/oauth2_proxy_nginx.nix b/nixos/modules/services/security/oauth2_proxy_nginx.nix
new file mode 100644
index 000000000000..2aa2c57fd22c
--- /dev/null
+++ b/nixos/modules/services/security/oauth2_proxy_nginx.nix
@@ -0,0 +1,64 @@
+{ pkgs, config, lib, ... }:
+with lib;
+let
+  cfg = config.services.oauth2_proxy.nginx;
+in
+{
+  options.services.oauth2_proxy.nginx = {
+    proxy = mkOption {
+      type = types.string;
+      default = config.services.oauth2_proxy.httpAddress;
+      description = ''
+        The address of the reverse proxy endpoint for oauth2_proxy
+      '';
+    };
+    virtualHosts = mkOption {
+      type = types.listOf types.string;
+      default = [];
+      description = ''
+        A list of nginx virtual hosts to put behind the oauth2 proxy
+      '';
+    };
+  };
+  config.services.oauth2_proxy = mkIf (cfg.virtualHosts != [] && (hasPrefix "127.0.0.1:" cfg.proxy)) {
+    enable = true;
+  };
+  config.services.nginx = mkMerge ((optional (cfg.virtualHosts != []) {
+    recommendedProxySettings = true; # needed because duplicate headers
+  }) ++ (map (vhost: {
+    virtualHosts.${vhost} = {
+      locations."/oauth2/" = {
+        proxyPass = cfg.proxy;
+        extraConfig = ''
+          proxy_set_header X-Scheme                $scheme;
+          proxy_set_header X-Auth-Request-Redirect $request_uri;
+        '';
+      };
+      locations."/oauth2/auth" = {
+        proxyPass = cfg.proxy;
+        extraConfig = ''
+          proxy_set_header X-Scheme         $scheme;
+          # nginx auth_request includes headers but not body
+          proxy_set_header Content-Length   "";
+          proxy_pass_request_body           off;
+        '';
+      };
+      locations."/".extraConfig = ''
+        auth_request /oauth2/auth;
+        error_page 401 = /oauth2/sign_in;
+
+        # pass information via X-User and X-Email headers to backend,
+        # requires running with --set-xauthrequest flag
+        auth_request_set $user   $upstream_http_x_auth_request_user;
+        auth_request_set $email  $upstream_http_x_auth_request_email;
+        proxy_set_header X-User  $user;
+        proxy_set_header X-Email $email;
+
+        # if you enabled --cookie-refresh, this is needed for it to work with auth_request
+        auth_request_set $auth_cookie $upstream_http_set_cookie;
+        add_header Set-Cookie $auth_cookie;
+      '';
+
+    };
+  }) cfg.virtualHosts));
+}
diff --git a/nixos/modules/services/security/tor.nix b/nixos/modules/services/security/tor.nix
index 806252f49b8d..dcb41d187c2b 100644
--- a/nixos/modules/services/security/tor.nix
+++ b/nixos/modules/services/security/tor.nix
@@ -39,7 +39,7 @@ let
     ''}
 
     ${optint "ControlPort" cfg.controlPort}
-    ${optionalString cfg.controlSocket.enable "ControlSocket ${torRunDirectory}/control GroupWritable RelaxDirModeCheck"}
+    ${optionalString cfg.controlSocket.enable "ControlPort unix:${torRunDirectory}/control GroupWritable RelaxDirModeCheck"}
   ''
   # Client connection config
   + optionalString cfg.client.enable ''
@@ -360,7 +360,7 @@ in
 
                 <important>
                   <para>
-                    WARNING: THE FOLLOWING PARAGRAPH IS NOT LEGAL ADVISE.
+                    WARNING: THE FOLLOWING PARAGRAPH IS NOT LEGAL ADVICE.
                     Consult with your lawer when in doubt.
                   </para>
 
@@ -686,8 +686,8 @@ in
         always create a container/VM with a separate Tor daemon instance.
       '';
 
-    users.extraGroups.tor.gid = config.ids.gids.tor;
-    users.extraUsers.tor =
+    users.groups.tor.gid = config.ids.gids.tor;
+    users.users.tor =
       { description = "Tor Daemon User";
         createHome  = true;
         home        = torDirectory;
@@ -695,19 +695,38 @@ in
         uid         = config.ids.uids.tor;
       };
 
+    # We have to do this instead of using RuntimeDirectory option in
+    # the service below because systemd has no way to set owners of
+    # RuntimeDirectory and putting this into the service below
+    # requires that service to relax it's sandbox since this needs
+    # writable /run
+    systemd.services.tor-init =
+      { description = "Tor Daemon Init";
+        wantedBy = [ "tor.service" ];
+        after = [ "local-fs.target" ];
+        script = ''
+          install -m 0700 -o tor -g tor -d ${torDirectory} ${torDirectory}/onion
+          install -m 0750 -o tor -g tor -d ${torRunDirectory}
+        '';
+        serviceConfig = {
+          Type = "oneshot";
+          RemainAfterExit = true;
+        };
+      };
+
     systemd.services.tor =
       { description = "Tor Daemon";
         path = [ pkgs.tor ];
 
         wantedBy = [ "multi-user.target" ];
-        after    = [ "network.target" ];
+        after    = [ "tor-init.service" "network.target" ];
         restartTriggers = [ torRcFile ];
 
         serviceConfig =
           { Type         = "simple";
             # Translated from the upstream contrib/dist/tor.service.in
             ExecStartPre = "${pkgs.tor}/bin/tor -f ${torRcFile} --verify-config";
-            ExecStart    = "${pkgs.tor}/bin/tor -f ${torRcFile} --RunAsDaemon 0";
+            ExecStart    = "${pkgs.tor}/bin/tor -f ${torRcFile}";
             ExecReload   = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
             KillSignal   = "SIGINT";
             TimeoutSec   = 30;
@@ -715,20 +734,18 @@ in
             LimitNOFILE  = 32768;
 
             # Hardening
-            # Note: DevicePolicy is set to 'closed', although the
-            # minimal permissions are really:
-            #   DeviceAllow /dev/null rw
-            #   DeviceAllow /dev/urandom r
-            # .. but we can't specify DeviceAllow multiple times. 'closed'
-            # is close enough.
-            RuntimeDirectory        = "tor";
-            StateDirectory          = [ "tor" "tor/onion" ];
-            PrivateTmp              = "yes";
-            DevicePolicy            = "closed";
-            InaccessibleDirectories = "/home";
-            ReadOnlyDirectories     = "/";
-            ReadWriteDirectories    = [torDirectory torRunDirectory];
+            # this seems to unshare /run despite what systemd.exec(5) says
+            PrivateTmp              = mkIf (!cfg.controlSocket.enable) "yes";
+            PrivateDevices          = "yes";
+            ProtectHome             = "yes";
+            ProtectSystem           = "strict";
+            InaccessiblePaths       = "/home";
+            ReadOnlyPaths           = "/";
+            ReadWritePaths          = [ torDirectory torRunDirectory ];
             NoNewPrivileges         = "yes";
+
+            # tor.service.in has this in, but this line it fails to spawn a namespace when using hidden services
+            #CapabilityBoundingSet   = "CAP_SETUID CAP_SETGID CAP_NET_BIND_SERVICE";
           };
       };
 
diff --git a/nixos/modules/services/security/vault.nix b/nixos/modules/services/security/vault.nix
index 146afec344ab..47c70cf0687b 100644
--- a/nixos/modules/services/security/vault.nix
+++ b/nixos/modules/services/security/vault.nix
@@ -97,13 +97,13 @@ in
       }
     ];
 
-    users.extraUsers.vault = {
+    users.users.vault = {
       name = "vault";
       group = "vault";
       uid = config.ids.uids.vault;
       description = "Vault daemon user";
     };
-    users.extraGroups.vault.gid = config.ids.gids.vault;
+    users.groups.vault.gid = config.ids.gids.vault;
 
     systemd.services.vault = {
       description = "Vault server daemon";
diff --git a/nixos/modules/services/system/dbus.nix b/nixos/modules/services/system/dbus.nix
index 643bec188142..e04580218442 100644
--- a/nixos/modules/services/system/dbus.nix
+++ b/nixos/modules/services/system/dbus.nix
@@ -71,14 +71,14 @@ in
         target = "dbus-1";
       };
 
-    users.extraUsers.messagebus = {
+    users.users.messagebus = {
       uid = config.ids.uids.messagebus;
       description = "D-Bus system message bus daemon user";
       home = homeDir;
       group = "messagebus";
     };
 
-    users.extraGroups.messagebus.gid = config.ids.gids.messagebus;
+    users.groups.messagebus.gid = config.ids.gids.messagebus;
 
     systemd.packages = [ pkgs.dbus.daemon ];
 
@@ -100,6 +100,7 @@ in
       # Don't restart dbus-daemon. Bad things tend to happen if we do.
       reloadIfChanged = true;
       restartTriggers = [ configDir ];
+      environment = { LD_LIBRARY_PATH = config.system.nssModules.path; };
     };
 
     systemd.user = {
diff --git a/nixos/modules/services/system/kerberos.nix b/nixos/modules/services/system/kerberos.nix
index 4f2e2fdf662b..d151385d2f9b 100644
--- a/nixos/modules/services/system/kerberos.nix
+++ b/nixos/modules/services/system/kerberos.nix
@@ -2,7 +2,7 @@
 
 let
 
-  inherit (lib) mkOption mkIf singleton;
+  inherit (lib) mkOption mkIf;
 
   inherit (pkgs) heimdalFull;
 
@@ -41,8 +41,8 @@ in
         flags = "REUSE NAMEINARGS";
         protocol = "tcp";
         user = "root";
-        server = "${pkgs.tcp_wrappers}/sbin/tcpd";
-        serverArgs = "${pkgs.heimdalFull}/sbin/kadmind";
+        server = "${pkgs.tcp_wrappers}/bin/tcpd";
+        serverArgs = "${pkgs.heimdalFull}/bin/kadmind";
       };
 
     systemd.services.kdc = {
@@ -51,13 +51,13 @@ in
       preStart = ''
         mkdir -m 0755 -p ${stateDir}
       '';
-      script = "${heimdalFull}/sbin/kdc";
+      script = "${heimdalFull}/bin/kdc";
     };
 
     systemd.services.kpasswdd = {
       description = "Kerberos Password Changing daemon";
       wantedBy = [ "multi-user.target" ];
-      script = "${heimdalFull}/sbin/kpasswdd";
+      script = "${heimdalFull}/bin/kpasswdd";
     };
   };
 
diff --git a/nixos/modules/services/system/nscd.nix b/nixos/modules/services/system/nscd.nix
index eb4b5281c7c6..fd1570d11980 100644
--- a/nixos/modules/services/system/nscd.nix
+++ b/nixos/modules/services/system/nscd.nix
@@ -7,8 +7,6 @@ let
   nssModulesPath = config.system.nssModules.path;
   cfg = config.services.nscd;
 
-  inherit (lib) singleton;
-
 in
 
 {
@@ -41,7 +39,7 @@ in
   config = mkIf cfg.enable {
     environment.etc."nscd.conf".text = cfg.config;
 
-    users.extraUsers.nscd =
+    users.users.nscd =
       { isSystemUser = true;
         description = "Name service cache daemon user";
       };
diff --git a/nixos/modules/services/system/saslauthd.nix b/nixos/modules/services/system/saslauthd.nix
index 281716cf1860..c8ddca9a0db6 100644
--- a/nixos/modules/services/system/saslauthd.nix
+++ b/nixos/modules/services/system/saslauthd.nix
@@ -4,7 +4,6 @@ with lib;
 
 let
 
-  nssModulesPath = config.system.nssModules.path;
   cfg = config.services.saslauthd;
 
 in
diff --git a/nixos/modules/services/system/uptimed.nix b/nixos/modules/services/system/uptimed.nix
index b20d60968032..3c9978ab2269 100644
--- a/nixos/modules/services/system/uptimed.nix
+++ b/nixos/modules/services/system/uptimed.nix
@@ -20,7 +20,7 @@ in
   };
 
   config = mkIf cfg.enable {
-    users.extraUsers.uptimed = {
+    users.users.uptimed = {
       description = "Uptimed daemon user";
       home        = stateDir;
       createHome  = true;
diff --git a/nixos/modules/services/torrent/deluge.nix b/nixos/modules/services/torrent/deluge.nix
index bff22cd13594..84f0437b9411 100644
--- a/nixos/modules/services/torrent/deluge.nix
+++ b/nixos/modules/services/torrent/deluge.nix
@@ -55,7 +55,7 @@ in {
 
     environment.systemPackages = [ pkgs.deluge ];
 
-    users.extraUsers.deluge = {
+    users.users.deluge = {
       group = "deluge";
       uid = config.ids.uids.deluge;
       home = "/var/lib/deluge/";
@@ -63,6 +63,6 @@ in {
       description = "Deluge Daemon user";
     };
 
-    users.extraGroups.deluge.gid = config.ids.gids.deluge;
+    users.groups.deluge.gid = config.ids.gids.deluge;
   };
 }
diff --git a/nixos/modules/services/torrent/peerflix.nix b/nixos/modules/services/torrent/peerflix.nix
index 2e3dd9902d72..bed6661f84d6 100644
--- a/nixos/modules/services/torrent/peerflix.nix
+++ b/nixos/modules/services/torrent/peerflix.nix
@@ -58,6 +58,6 @@ in {
       };
     };
 
-    users.extraUsers.peerflix.uid = config.ids.uids.peerflix;
+    users.users.peerflix.uid = config.ids.uids.peerflix;
   };
 }
diff --git a/nixos/modules/services/torrent/transmission.nix b/nixos/modules/services/torrent/transmission.nix
index 3564afd77f41..96413d2dd563 100644
--- a/nixos/modules/services/torrent/transmission.nix
+++ b/nixos/modules/services/torrent/transmission.nix
@@ -13,12 +13,6 @@ let
   settingsDir = "${homeDir}/.config/transmission-daemon";
   settingsFile = pkgs.writeText "settings.json" (builtins.toJSON fullSettings);
 
-  # Strings must be quoted, ints and bools must not (for settings.json).
-  toOption = x:
-    if isBool x then boolToString x
-    else if isInt x then toString x
-    else toString ''"${x}"'';
-
   # for users in group "transmission" to have access to torrents
   fullSettings = { umask = 2; download-dir = downloadDir; incomplete-dir = incompleteDir; } // cfg.settings;
 
@@ -113,8 +107,8 @@ in
     # It's useful to have transmission in path, e.g. for remote control
     environment.systemPackages = [ pkgs.transmission ];
 
-    users.extraGroups.transmission.gid = config.ids.gids.transmission;
-    users.extraUsers.transmission = {
+    users.groups.transmission.gid = config.ids.gids.transmission;
+    users.users.transmission = {
       group = "transmission";
       uid = config.ids.uids.transmission;
       description = "Transmission BitTorrent user";
diff --git a/nixos/modules/services/ttys/kmscon.nix b/nixos/modules/services/ttys/kmscon.nix
index 88e488425bce..59c45fcb44ee 100644
--- a/nixos/modules/services/ttys/kmscon.nix
+++ b/nixos/modules/services/ttys/kmscon.nix
@@ -1,6 +1,6 @@
 { config, pkgs, lib, ... }:
 let
-  inherit (lib) mkOption types mkIf optionalString;
+  inherit (lib) mkOption types mkIf;
 
   cfg = config.services.kmscon;
 
diff --git a/nixos/modules/services/web-apps/atlassian/confluence.nix b/nixos/modules/services/web-apps/atlassian/confluence.nix
index 84c41b6e53c2..f896d92fd6fc 100644
--- a/nixos/modules/services/web-apps/atlassian/confluence.nix
+++ b/nixos/modules/services/web-apps/atlassian/confluence.nix
@@ -137,12 +137,12 @@ in
   };
 
   config = mkIf cfg.enable {
-    users.extraUsers."${cfg.user}" = {
+    users.users."${cfg.user}" = {
       isSystemUser = true;
       group = cfg.group;
     };
 
-    users.extraGroups."${cfg.group}" = {};
+    users.groups."${cfg.group}" = {};
 
     systemd.services.confluence = {
       description = "Atlassian Confluence";
diff --git a/nixos/modules/services/web-apps/atlassian/crowd.nix b/nixos/modules/services/web-apps/atlassian/crowd.nix
index 0ac941b6ec99..b6cb9f3b7c41 100644
--- a/nixos/modules/services/web-apps/atlassian/crowd.nix
+++ b/nixos/modules/services/web-apps/atlassian/crowd.nix
@@ -103,12 +103,12 @@ in
   };
 
   config = mkIf cfg.enable {
-    users.extraUsers."${cfg.user}" = {
+    users.users."${cfg.user}" = {
       isSystemUser = true;
       group = cfg.group;
     };
 
-    users.extraGroups."${cfg.group}" = {};
+    users.groups."${cfg.group}" = {};
 
     systemd.services.atlassian-crowd = {
       description = "Atlassian Crowd";
@@ -126,12 +126,13 @@ in
       };
 
       preStart = ''
-        mkdir -p ${cfg.home}/{logs,work,database}
+        rm -rf ${cfg.home}/work
+        mkdir -p ${cfg.home}/{logs,database,work}
 
         mkdir -p /run/atlassian-crowd
         ln -sf ${cfg.home}/{database,work,server.xml} /run/atlassian-crowd
 
-        chown -R ${cfg.user} ${cfg.home}
+        chown -R ${cfg.user}:${cfg.group} ${cfg.home}
 
         sed -e 's,port="8095",port="${toString cfg.listenPort}" address="${cfg.listenAddress}",' \
         '' + (lib.optionalString cfg.proxy.enable ''
diff --git a/nixos/modules/services/web-apps/atlassian/jira.nix b/nixos/modules/services/web-apps/atlassian/jira.nix
index 13c5951524d9..f5ec0a5f31b8 100644
--- a/nixos/modules/services/web-apps/atlassian/jira.nix
+++ b/nixos/modules/services/web-apps/atlassian/jira.nix
@@ -141,12 +141,12 @@ in
   };
 
   config = mkIf cfg.enable {
-    users.extraUsers."${cfg.user}" = {
+    users.users."${cfg.user}" = {
       isSystemUser = true;
       group = cfg.group;
     };
 
-    users.extraGroups."${cfg.group}" = {};
+    users.groups."${cfg.group}" = {};
 
     systemd.services.atlassian-jira = {
       description = "Atlassian JIRA";
diff --git a/nixos/modules/services/web-apps/frab.nix b/nixos/modules/services/web-apps/frab.nix
index d5329ef03c89..fb95e024817c 100644
--- a/nixos/modules/services/web-apps/frab.nix
+++ b/nixos/modules/services/web-apps/frab.nix
@@ -6,7 +6,6 @@ let
   cfg = config.services.frab;
 
   package = pkgs.frab;
-  ruby = package.ruby;
 
   databaseConfig = builtins.toJSON { production = cfg.database; };
 
@@ -174,14 +173,14 @@ in
   config = mkIf cfg.enable {
     environment.systemPackages = [ frab-rake ];
 
-    users.extraUsers = [
+    users.users = [
       { name = cfg.user;
         group = cfg.group;
         home = "${cfg.statePath}";
       }
     ];
 
-    users.extraGroups = [ { name = cfg.group; } ];
+    users.groups = [ { name = cfg.group; } ];
 
     systemd.services.frab = {
       after = [ "network.target" "gitlab.service" ];
diff --git a/nixos/modules/services/web-apps/matomo.nix b/nixos/modules/services/web-apps/matomo.nix
index ef6ac9698e21..42affb06b51f 100644
--- a/nixos/modules/services/web-apps/matomo.nix
+++ b/nixos/modules/services/web-apps/matomo.nix
@@ -109,13 +109,13 @@ in {
         message = "Either services.matomo.nginx or services.matomo.nginx.webServerUser is mandatory";
     }];
 
-    users.extraUsers.${user} = {
+    users.users.${user} = {
       isSystemUser = true;
       createHome = true;
       home = dataDir;
       group  = user;
     };
-    users.extraGroups.${user} = {};
+    users.groups.${user} = {};
 
     systemd.services.matomo_setup_update = {
       # everything needs to set up and up to date before matomo php files are executed
@@ -241,6 +241,6 @@ in {
 
   meta = {
     doc = ./matomo-doc.xml;
-    maintainers = with stdenv.lib.maintainers; [ florianjacob ];
+    maintainers = with lib.maintainers; [ florianjacob ];
   };
 }
diff --git a/nixos/modules/services/web-apps/mattermost.nix b/nixos/modules/services/web-apps/mattermost.nix
index be74a2b1955b..8c7fc4056adc 100644
--- a/nixos/modules/services/web-apps/mattermost.nix
+++ b/nixos/modules/services/web-apps/mattermost.nix
@@ -25,7 +25,7 @@ in
 {
   options = {
     services.mattermost = {
-      enable = mkEnableOption "Mattermost chat platform";
+      enable = mkEnableOption "Mattermost chat server";
 
       statePath = mkOption {
         type = types.str;
@@ -146,14 +146,14 @@ in
 
   config = mkMerge [
     (mkIf cfg.enable {
-      users.extraUsers = optionalAttrs (cfg.user == "mattermost") (singleton {
+      users.users = optionalAttrs (cfg.user == "mattermost") (singleton {
         name = "mattermost";
         group = cfg.group;
         uid = config.ids.uids.mattermost;
         home = cfg.statePath;
       });
 
-      users.extraGroups = optionalAttrs (cfg.group == "mattermost") (singleton {
+      users.groups = optionalAttrs (cfg.group == "mattermost") (singleton {
         name = "mattermost";
         gid = config.ids.gids.mattermost;
       });
@@ -167,7 +167,7 @@ in
       '';
 
       systemd.services.mattermost = {
-        description = "Mattermost chat platform service";
+        description = "Mattermost chat service";
         wantedBy = [ "multi-user.target" ];
         after = [ "network.target" "postgresql.service" ];
 
@@ -201,13 +201,13 @@ in
           PermissionsStartOnly = true;
           User = cfg.user;
           Group = cfg.group;
-          ExecStart = "${pkgs.mattermost}/bin/mattermost-platform";
+          ExecStart = "${pkgs.mattermost}/bin/mattermost";
           WorkingDirectory = "${cfg.statePath}";
-          JoinsNamespaceOf = mkIf cfg.localDatabaseCreate "postgresql.service";
           Restart = "always";
           RestartSec = "10";
           LimitNOFILE = "49152";
         };
+        unitConfig.JoinsNamespaceOf = mkIf cfg.localDatabaseCreate "postgresql.service";
       };
     })
     (mkIf cfg.matterircd.enable {
diff --git a/nixos/modules/services/web-apps/nexus.nix b/nixos/modules/services/web-apps/nexus.nix
index d5bd0f12febb..050f8757fa5f 100644
--- a/nixos/modules/services/web-apps/nexus.nix
+++ b/nixos/modules/services/web-apps/nexus.nix
@@ -13,6 +13,12 @@ in
     services.nexus = {
       enable = mkEnableOption "Sonatype Nexus3 OSS service";
 
+      package = mkOption {
+        type = types.package;
+        default = pkgs.nexus;
+        description = "Package which runs Nexus3";
+      };
+
       user = mkOption {
         type = types.str;
         default = "nexus";
@@ -55,10 +61,10 @@ in
           -XX:LogFile=${cfg.home}/nexus3/log/jvm.log
           -XX:-OmitStackTraceInFastThrow
           -Djava.net.preferIPv4Stack=true
-          -Dkaraf.home=${pkgs.nexus}
-          -Dkaraf.base=${pkgs.nexus}
-          -Dkaraf.etc=${pkgs.nexus}/etc/karaf
-          -Djava.util.logging.config.file=${pkgs.nexus}/etc/karaf/java.util.logging.properties
+          -Dkaraf.home=${cfg.package}
+          -Dkaraf.base=${cfg.package}
+          -Dkaraf.etc=${cfg.package}/etc/karaf
+          -Djava.util.logging.config.file=${cfg.package}/etc/karaf/java.util.logging.properties
           -Dkaraf.data=${cfg.home}/nexus3
           -Djava.io.tmpdir=${cfg.home}/nexus3/tmp
           -Dkaraf.startLocalConsole=false
@@ -74,12 +80,12 @@ in
   };
 
   config = mkIf cfg.enable {
-    users.extraUsers."${cfg.user}" = {
+    users.users."${cfg.user}" = {
       isSystemUser = true;
       group = cfg.group;
     };
 
-    users.extraGroups."${cfg.group}" = {};
+    users.groups."${cfg.group}" = {};
 
     systemd.services.nexus = {
       description = "Sonatype Nexus3";
@@ -112,7 +118,7 @@ in
         fi
       '';
 
-      script = "${pkgs.nexus}/bin/nexus run";
+      script = "${cfg.package}/bin/nexus run";
 
       serviceConfig = {
         User = cfg.user;
@@ -124,5 +130,5 @@ in
     };
   };
 
-  meta.maintainers = with stdenv.lib.maintainers; [ ironpinguin ];
+  meta.maintainers = with lib.maintainers; [ ironpinguin ];
 }
diff --git a/nixos/modules/services/web-apps/restya-board.nix b/nixos/modules/services/web-apps/restya-board.nix
index cee725e8fe5f..bc6689bdb271 100644
--- a/nixos/modules/services/web-apps/restya-board.nix
+++ b/nixos/modules/services/web-apps/restya-board.nix
@@ -358,13 +358,13 @@ in
       '';
     };
 
-    users.extraUsers.restya-board = {
+    users.users.restya-board = {
       isSystemUser = true;
       createHome = false;
       home = runDir;
       group  = "restya-board";
     };
-    users.extraGroups.restya-board = {};
+    users.groups.restya-board = {};
 
     services.postgresql.enable = mkIf (isNull cfg.database.host) true;
 
diff --git a/nixos/modules/services/web-apps/tt-rss.nix b/nixos/modules/services/web-apps/tt-rss.nix
index 610c6463a5eb..2b171aa1b2b2 100644
--- a/nixos/modules/services/web-apps/tt-rss.nix
+++ b/nixos/modules/services/web-apps/tt-rss.nix
@@ -76,6 +76,8 @@ let
       define('SMTP_FROM_NAME', '${escape ["'" "\\"] cfg.email.fromName}');
       define('SMTP_FROM_ADDRESS', '${escape ["'" "\\"] cfg.email.fromAddress}');
       define('DIGEST_SUBJECT', '${escape ["'" "\\"] cfg.email.digestSubject}');
+
+      ${cfg.extraConfig}
   '';
 
  in {
@@ -431,6 +433,26 @@ let
         '';
       };
 
+      pluginPackages = mkOption {
+        type = types.listOf types.package;
+        default = [];
+        description = ''
+          List of plugins to install. The list elements are expected to
+          be derivations. All elements in this derivation are automatically
+          copied to the <literal>plugins.local</literal> directory.
+        '';
+      };
+
+      themePackages = mkOption {
+        type = types.listOf types.package;
+        default = [];
+        description = ''
+          List of themes to install. The list elements are expected to
+          be derivations. All elements in this derivation are automatically
+          copied to the <literal>themes.local</literal> directory.
+        '';
+      };
+
       logDestination = mkOption {
         type = types.enum ["" "sql" "syslog"];
         default = "sql";
@@ -441,6 +463,14 @@ let
           error.log).
         '';
       };
+
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Additional lines to append to <literal>config.php</literal>.
+        '';
+      };
     };
   };
 
@@ -517,6 +547,16 @@ let
           rm -rf "${cfg.root}/*"
           mkdir -m 755 -p "${cfg.root}"
           cp -r "${pkgs.tt-rss}/"* "${cfg.root}"
+          ${optionalString (cfg.pluginPackages != []) ''
+            for plugin in ${concatStringsSep " " cfg.pluginPackages}; do
+              cp -r "$plugin"/* "${cfg.root}/plugins.local/"
+            done
+          ''}
+          ${optionalString (cfg.themePackages != []) ''
+            for theme in ${concatStringsSep " " cfg.themePackages}; do
+              cp -r "$theme"/* "${cfg.root}/themes.local/"
+            done
+          ''}
           ln -sf "${tt-rss-config}" "${cfg.root}/config.php"
           chown -R "${cfg.user}" "${cfg.root}"
           chmod -R 755 "${cfg.root}"
@@ -584,8 +624,8 @@ let
     };
 
     users = optionalAttrs (cfg.user == "tt_rss") {
-      extraUsers.tt_rss.group = "tt_rss";
-      extraGroups.tt_rss = {};
+      users.tt_rss.group = "tt_rss";
+      groups.tt_rss = {};
     };
   };
 }
diff --git a/nixos/modules/services/web-apps/virtlyst.nix b/nixos/modules/services/web-apps/virtlyst.nix
new file mode 100644
index 000000000000..e5c0bff2168a
--- /dev/null
+++ b/nixos/modules/services/web-apps/virtlyst.nix
@@ -0,0 +1,72 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  cfg = config.services.virtlyst;
+  stateDir = "/var/lib/virtlyst";
+
+  ini = pkgs.writeText "virtlyst-config.ini" ''
+    [wsgi]
+    master = true
+    threads = auto
+    http-socket = ${cfg.httpSocket}
+    application = ${pkgs.virtlyst}/lib/libVirtlyst.so
+    chdir2 = ${stateDir}
+    static-map = /static=${pkgs.virtlyst}/root/static
+
+    [Cutelyst]
+    production = true
+    DatabasePath = virtlyst.sqlite
+    TemplatePath = ${pkgs.virtlyst}/root/src
+
+    [Rules]
+    cutelyst.* = true
+    virtlyst.* = true
+  '';
+
+in
+
+{
+
+  options.services.virtlyst = {
+    enable = mkEnableOption "Virtlyst libvirt web interface";
+
+    adminPassword = mkOption {
+      type = types.str;
+      description = ''
+        Initial admin password with which the database will be seeded.
+      '';
+    };
+
+    httpSocket = mkOption {
+      type = types.str;
+      default = "localhost:3000";
+      description = ''
+        IP and/or port to which to bind the http socket.
+      '';
+    };
+  };
+
+  config = mkIf cfg.enable {
+    users.users.virtlyst = {
+      home = stateDir;
+      createHome = true;
+      group = mkIf config.virtualisation.libvirtd.enable "libvirtd";
+    };
+
+    systemd.services.virtlyst = {
+      wantedBy = [ "multi-user.target" ];
+      environment = {
+        VIRTLYST_ADMIN_PASSWORD = cfg.adminPassword;
+      };
+      serviceConfig = {
+        ExecStart = "${pkgs.cutelyst}/bin/cutelyst-wsgi2 --ini ${ini}";
+        User = "virtlyst";
+        WorkingDirectory = stateDir;
+      };
+    };
+  };
+
+}
diff --git a/nixos/modules/services/web-servers/apache-httpd/default.nix b/nixos/modules/services/web-servers/apache-httpd/default.nix
index f9f2511f45dc..73607c6f9a3b 100644
--- a/nixos/modules/services/web-servers/apache-httpd/default.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/default.nix
@@ -98,11 +98,6 @@ let
   allSubservices = mainSubservices ++ concatMap subservicesFor mainCfg.virtualHosts;
 
 
-  # !!! should be in lib
-  writeTextInDir = name: text:
-    pkgs.runCommand name {inherit text;} "mkdir -p $out; echo -n \"$text\" > $out/$name";
-
-
   enableSSL = any (vhost: vhost.enableSSL) allHosts;
 
 
@@ -656,16 +651,16 @@ 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);
+    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
+    users.users = optionalAttrs (mainCfg.user == "wwwrun") (singleton
       { name = "wwwrun";
         group = mainCfg.group;
         description = "Apache httpd user";
         uid = config.ids.uids.wwwrun;
       });
 
-    users.extraGroups = optionalAttrs (mainCfg.group == "wwwrun") (singleton
+    users.groups = optionalAttrs (mainCfg.group == "wwwrun") (singleton
       { name = "wwwrun";
         gid = config.ids.gids.wwwrun;
       });
diff --git a/nixos/modules/services/web-servers/apache-httpd/owncloud.nix b/nixos/modules/services/web-servers/apache-httpd/owncloud.nix
index 82b8bf3e30db..6345a9a56935 100644
--- a/nixos/modules/services/web-servers/apache-httpd/owncloud.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/owncloud.nix
@@ -4,17 +4,6 @@ with lib;
 
 let
 
-  httpd = serverInfo.serverConfig.package;
-
-  version24 = !versionOlder httpd.version "2.4";
-
-  allGranted = if version24 then ''
-    Require all granted
-  '' else ''
-    Order allow,deny
-    Allow from all
-  '';
-
   owncloudConfig = pkgs.writeText "config.php"
     ''
       <?php
diff --git a/nixos/modules/services/web-servers/apache-httpd/trac.nix b/nixos/modules/services/web-servers/apache-httpd/trac.nix
index 35b9ab56087c..28b411a64b6f 100644
--- a/nixos/modules/services/web-servers/apache-httpd/trac.nix
+++ b/nixos/modules/services/web-servers/apache-httpd/trac.nix
@@ -12,8 +12,6 @@ let
     apacheHttpd = httpd;
   };
 
-  pythonLib = p: "${p}/";
-
   httpd = serverInfo.serverConfig.package;
 
   versionPre24 = versionOlder httpd.version "2.4";
diff --git a/nixos/modules/services/web-servers/caddy.nix b/nixos/modules/services/web-servers/caddy.nix
index fe65fba42a46..4237cfdd9198 100644
--- a/nixos/modules/services/web-servers/caddy.nix
+++ b/nixos/modules/services/web-servers/caddy.nix
@@ -93,13 +93,13 @@ in {
       };
     };
 
-    users.extraUsers.caddy = {
+    users.users.caddy = {
       group = "caddy";
       uid = config.ids.uids.caddy;
       home = cfg.dataDir;
       createHome = true;
     };
 
-    users.extraGroups.caddy.gid = config.ids.uids.caddy;
+    users.groups.caddy.gid = config.ids.uids.caddy;
   };
 }
diff --git a/nixos/modules/services/web-servers/hitch/default.nix b/nixos/modules/services/web-servers/hitch/default.nix
index 895d02827f71..a6c4cbea1225 100644
--- a/nixos/modules/services/web-servers/hitch/default.nix
+++ b/nixos/modules/services/web-servers/hitch/default.nix
@@ -102,7 +102,7 @@ with lib;
 
     environment.systemPackages = [ pkgs.hitch ];
 
-    users.extraUsers.hitch.group = "hitch";
-    users.extraGroups.hitch = {};
+    users.users.hitch.group = "hitch";
+    users.groups.hitch = {};
   };
 }
diff --git a/nixos/modules/services/web-servers/hydron.nix b/nixos/modules/services/web-servers/hydron.nix
new file mode 100644
index 000000000000..49a18f5e7b28
--- /dev/null
+++ b/nixos/modules/services/web-servers/hydron.nix
@@ -0,0 +1,105 @@
+{ config, lib, pkgs, ... }:
+
+let cfg = config.services.hydron;
+in with lib; {
+  options.services.hydron = {
+    enable = mkEnableOption "hydron";
+
+    dataDir = mkOption {
+      type = types.path;
+      default = "/var/lib/hydron";
+      example = "/home/okina/hydron";
+      description = "Location where hydron runs and stores data.";
+    };
+
+    interval = mkOption {
+      type = types.str;
+      default = "hourly";
+      example = "06:00";
+      description = ''
+        How often we run hydron import and possibly fetch tags. Runs by default every hour.
+
+        The format is described in
+        <citerefentry><refentrytitle>systemd.time</refentrytitle>
+        <manvolnum>7</manvolnum></citerefentry>.
+      '';
+    };
+
+    listenAddress = mkOption {
+      type = types.nullOr types.str;
+      default = null;
+      example = "127.0.0.1:8010";
+      description = "Listen on a specific IP address and port.";
+    };
+
+    importPaths = mkOption {
+      type = types.listOf types.path;
+      default = [];
+      example = [ "/home/okina/Pictures" ];
+      description = "Paths that hydron will recursively import.";
+    };
+
+    fetchTags = mkOption {
+      type = types.bool;
+      default = true;
+      description = "Fetch tags for imported images and webm from gelbooru.";
+    };
+  };
+
+  config = mkIf cfg.enable {
+    systemd.services.hydron = {
+      description = "hydron";
+      after = [ "network.target" ];
+      wantedBy = [ "multi-user.target" ];
+
+      preStart = ''
+        # Ensure folder exists and permissions are correct
+        mkdir -p ${escapeShellArg cfg.dataDir}/images
+        chmod 750 ${escapeShellArg cfg.dataDir}
+        chown -R hydron:hydron ${escapeShellArg cfg.dataDir}
+      '';
+
+      serviceConfig = {
+        PermissionsStartOnly = true;
+        User = "hydron";
+        Group = "hydron";
+        ExecStart = "${pkgs.hydron}/bin/hydron serve"
+        + optionalString (cfg.listenAddress != null) " -a ${cfg.listenAddress}";
+      };
+    };
+
+    systemd.services.hydron-fetch = {
+      description = "Import paths into hydron and possibly fetch tags";
+
+      serviceConfig = {
+        Type = "oneshot";
+        User = "hydron";
+        Group = "hydron";
+        ExecStart = "${pkgs.hydron}/bin/hydron import "
+        + optionalString cfg.fetchTags "-f "
+        + (escapeShellArg cfg.dataDir) + "/images " + (escapeShellArgs cfg.importPaths);
+      };
+    };
+
+    systemd.timers.hydron-fetch = {
+      description = "Automatically import paths into hydron and possibly fetch tags";
+      after = [ "network.target" ];
+      wantedBy = [ "timers.target" ];
+      timerConfig.OnCalendar = cfg.interval;
+    };
+
+    users = {
+      groups.hydron.gid = config.ids.gids.hydron;
+      
+      users.hydron = {
+        description = "hydron server service user";
+        home = cfg.dataDir;
+        createHome = true;
+        group = "hydron";
+        uid = config.ids.uids.hydron;
+      };
+    };
+  };
+
+  meta.maintainers = with maintainers; [ chiiruno ];
+}
diff --git a/nixos/modules/services/web-servers/lighttpd/cgit.nix b/nixos/modules/services/web-servers/lighttpd/cgit.nix
index 710fecc0c05c..e6a054c296dc 100644
--- a/nixos/modules/services/web-servers/lighttpd/cgit.nix
+++ b/nixos/modules/services/web-servers/lighttpd/cgit.nix
@@ -4,8 +4,15 @@ with lib;
 
 let
   cfg = config.services.lighttpd.cgit;
+  pathPrefix = if stringLength cfg.subdir == 0 then "" else "/" + cfg.subdir;
   configFile = pkgs.writeText "cgitrc"
     ''
+      # default paths to static assets
+      css=${pathPrefix}/cgit.css
+      logo=${pathPrefix}/cgit.png
+      favicon=${pathPrefix}/favicon.ico
+
+      # user configuration
       ${cfg.configText}
     '';
 in
@@ -18,8 +25,17 @@ in
       type = types.bool;
       description = ''
         If true, enable cgit (fast web interface for git repositories) as a
-        sub-service in lighttpd. cgit will be accessible at
-        http://yourserver/cgit
+        sub-service in lighttpd.
+      '';
+    };
+
+    subdir = mkOption {
+      default = "cgit";
+      example = "";
+      type = types.str;
+      description = ''
+        The subdirectory in which to serve cgit. The web application will be
+        accessible at http://yourserver/''${subdir}
       '';
     };
 
@@ -48,14 +64,14 @@ in
     services.lighttpd.enableModules = [ "mod_cgi" "mod_alias" "mod_setenv" ];
 
     services.lighttpd.extraConfig = ''
-      $HTTP["url"] =~ "^/cgit" {
+      $HTTP["url"] =~ "^/${cfg.subdir}" {
           cgi.assign = (
               "cgit.cgi" => "${pkgs.cgit}/cgit/cgit.cgi"
           )
           alias.url = (
-              "/cgit.css" => "${pkgs.cgit}/cgit/cgit.css",
-              "/cgit.png" => "${pkgs.cgit}/cgit/cgit.png",
-              "/cgit"     => "${pkgs.cgit}/cgit/cgit.cgi"
+              "${pathPrefix}/cgit.css" => "${pkgs.cgit}/cgit/cgit.css",
+              "${pathPrefix}/cgit.png" => "${pkgs.cgit}/cgit/cgit.png",
+              "${pathPrefix}"          => "${pkgs.cgit}/cgit/cgit.cgi"
           )
           setenv.add-environment = (
               "CGIT_CONFIG" => "${configFile}"
diff --git a/nixos/modules/services/web-servers/lighttpd/default.nix b/nixos/modules/services/web-servers/lighttpd/default.nix
index d23e810dcc62..7a3df26e47a6 100644
--- a/nixos/modules/services/web-servers/lighttpd/default.nix
+++ b/nixos/modules/services/web-servers/lighttpd/default.nix
@@ -245,12 +245,12 @@ in
       serviceConfig.KillSignal = "SIGINT";
     };
 
-    users.extraUsers.lighttpd = {
+    users.users.lighttpd = {
       group = "lighttpd";
       description = "lighttpd web server privilege separation user";
       uid = config.ids.uids.lighttpd;
     };
 
-    users.extraGroups.lighttpd.gid = config.ids.gids.lighttpd;
+    users.groups.lighttpd.gid = config.ids.gids.lighttpd;
   };
 }
diff --git a/nixos/modules/services/web-servers/lighttpd/inginious.nix b/nixos/modules/services/web-servers/lighttpd/inginious.nix
deleted file mode 100644
index 8c813d116a52..000000000000
--- a/nixos/modules/services/web-servers/lighttpd/inginious.nix
+++ /dev/null
@@ -1,261 +0,0 @@
-{ config, lib, pkgs, ... }:
-with lib;
-
-let
-  cfg = config.services.lighttpd.inginious;
-  inginious = pkgs.inginious;
-  execName = "inginious-${if cfg.useLTI then "lti" else "webapp"}";
-
-  inginiousConfigFile = if cfg.configFile != null then cfg.configFile else pkgs.writeText "inginious.yaml" ''
-    # Backend; can be:
-    # - "local" (run containers on the same machine)
-    # - "remote" (connect to distant docker daemon and auto start agents) (choose this if you use boot2docker)
-    # - "remote_manual" (connect to distant and manually installed agents)
-    backend: "${cfg.backendType}"
-
-    ## TODO (maybe): Add an option for the "remote" backend in this NixOS module.
-    # List of remote docker daemon to which the backend will try
-    # to connect (backend: remote only)
-    #docker_daemons:
-    #  - # Host of the docker daemon *from the webapp*
-    #    remote_host: "some.remote.server"
-    #    # Port of the distant docker daemon *from the webapp*
-    #    remote_docker_port: "2375"
-    #    # A mandatory port used by the backend and the agent that will be automatically started.
-    #    # Needs to be available on the remote host, and to be open in the firewall.
-    #    remote_agent_port: "63456"
-    #    # Does the remote docker requires tls? Defaults to false.
-    #    # Parameter can be set to true or path to the certificates
-    #    #use_tls: false
-    #    # Link to the docker daemon *from the host that runs the docker daemon*. Defaults to:
-    #    #local_location: "unix:///var/run/docker.sock"
-    #    # Path to the cgroups "mount" *from the host that runs the docker daemon*. Defaults to:
-    #    #cgroups_location: "/sys/fs/cgroup"
-    #    # Name that will be used to reference the agent
-    #    #"agent_name": "inginious-agent"
-
-    # List of remote agents to which the backend will try
-    # to connect (backend: remote_manual only)
-    # Example:
-    #agents:
-    #  - host: "192.168.59.103"
-    #    port: 5001
-    agents:
-    ${lib.concatMapStrings (agent:
-      "  - host: \"${agent.host}\"\n" +
-      "    port: ${agent.port}\n"
-    ) cfg.remoteAgents}
-
-    # Location of the task directory
-    tasks_directory: "${cfg.tasksDirectory}"
-
-    # Super admins: list of user names that can do everything in the backend
-    superadmins:
-    ${lib.concatMapStrings (x: "  - \"${x}\"\n") cfg.superadmins}
-
-    # Aliases for containers
-    # Only containers listed here can be used by tasks
-    containers:
-    ${lib.concatStrings (lib.mapAttrsToList (name: fullname:
-      "  ${name}: \"${fullname}\"\n"
-    ) cfg.containers)}
-
-    # Use single minified javascript file (production) or multiple files (dev) ?
-    use_minified_js: true
-
-    ## TODO (maybe): Add NixOS options for these parameters.
-
-    # MongoDB options
-    #mongo_opt:
-    #    host: localhost
-    #    database: INGInious
-
-    # Disable INGInious?
-    #maintenance: false
-
-    #smtp:
-    #    sendername: 'INGInious <no-reply@inginious.org>'
-    #    host: 'smtp.gmail.com'
-    #    port: 587
-    #    username: 'configme@gmail.com'
-    #    password: 'secret'
-    #    starttls: True
-
-    ## NixOS extra config
-
-    ${cfg.extraConfig}
-  '';
-in
-{
-  options.services.lighttpd.inginious = {
-    enable = mkEnableOption  "INGInious, an automated code testing and grading system.";
-
-    configFile = mkOption {
-      type = types.nullOr types.path;
-      default = null;
-      example = literalExample ''pkgs.writeText "configuration.yaml" "# custom config options ...";'';
-      description = ''The path to an INGInious configuration file.'';
-    };
-
-    extraConfig = mkOption {
-      type = types.lines;
-      default = "";
-      example = ''
-        # Load the dummy auth plugin.
-        plugins:
-          - plugin_module: inginious.frontend.webapp.plugins.auth.demo_auth
-            users:
-              # register the user "test" with the password "someverycomplexpassword"
-              test: someverycomplexpassword
-      '';
-      description = ''Extra option in YaML format, to be appended to the config file.'';
-    };
-
-    tasksDirectory = mkOption {
-      type = types.path;
-      example = "/var/lib/INGInious/tasks";
-      description = ''
-        Path to the tasks folder.
-        Defaults to the provided test tasks folder (readonly).
-      '';
-    };
-
-    useLTI = mkOption {
-      type = types.bool;
-      default = false;
-      description = ''Whether to start the LTI frontend in place of the webapp.'';
-    };
-
-    superadmins = mkOption {
-      type = types.uniq (types.listOf types.str);
-      default = [ "admin" ];
-      example = [ "john" "pepe" "emilia" ];
-      description = ''List of user logins allowed to administrate the whole server.'';
-    };
-
-    containers = mkOption {
-      type = types.attrsOf types.str;
-      default = {
-          default = "ingi/inginious-c-default";
-      };
-      example = {
-        default = "ingi/inginious-c-default";
-        sekexe  = "ingi/inginious-c-sekexe";
-        java    = "ingi/inginious-c-java";
-        oz      = "ingi/inginious-c-oz";
-        pythia1compat = "ingi/inginious-c-pythia1compat";
-      };
-      description = ''
-        An attrset describing the required containers
-        These containers will be available in INGInious using their short name (key)
-        and will be automatically downloaded before INGInious starts.
-      '';
-    };
-
-    hostPattern = mkOption {
-      type = types.str;
-      default = "^inginious.";
-      example = "^inginious.mydomain.xyz$";
-      description = ''
-        The domain that serves INGInious.
-        INGInious uses absolute paths which makes it difficult to relocate in its own subdir.
-        The default configuration will serve INGInious when the server is accessed with a hostname starting with "inginious.".
-        If left blank, INGInious will take the precedence over all the other lighttpd sites, which is probably not what you want.
-      '';
-    };
-
-    backendType = mkOption {
-      type = types.enum [ "local" "remote_manual" ]; # TODO: support backend "remote"
-      default = "local";
-      description = ''
-        Select how INGINious accesses to grading containers.
-        The default "local" option ensures that Docker is started and provisioned.
-        Fore more information, see http://inginious.readthedocs.io/en/latest/install_doc/config_reference.html
-        Not all backends are supported. Use services.inginious.configFile for full flexibility.
-      '';
-    };
-
-    remoteAgents = mkOption {
-      type = types.listOf (types.attrsOf types.str);
-      default = [];
-      example = [ { host = "192.0.2.25"; port = "1345"; } ];
-      description = ''A list of remote agents, used only when services.inginious.backendType is "remote_manual".'';
-    };
-  };
-
-  config = mkIf cfg.enable (
-    mkMerge [
-      # For a local install, we need docker.
-      (mkIf (cfg.backendType == "local") {
-        virtualisation.docker = {
-          enable = true;
-          # We need docker to listen on port 2375.
-          listenOptions = ["127.0.0.1:2375" "/var/run/docker.sock"];
-          storageDriver = mkDefault "overlay";
-        };
-
-        users.extraUsers."lighttpd".extraGroups = [ "docker" ];
-
-        # Ensure that docker has pulled the required images.
-        systemd.services.inginious-prefetch = {
-          script = let
-            images = lib.unique (
-              [ "centos" "ingi/inginious-agent" ]
-              ++ lib.mapAttrsToList (_: image: image) cfg.containers
-            );
-          in lib.concatMapStrings (image: ''
-            ${pkgs.docker}/bin/docker pull ${image}
-          '') images;
-
-          serviceConfig.Type = "oneshot";
-          wants = [ "docker.service" ];
-          after = [ "docker.service" ];
-          wantedBy = [ "lighttpd.service" ];
-          before = [ "lighttpd.service" ];
-        };
-      })
-
-      # Common
-      {
-        services.lighttpd.inginious.tasksDirectory = mkDefault "${inginious}/lib/python2.7/site-packages/inginious/tasks";
-        # To access inginous tools (like inginious-test-task)
-        environment.systemPackages = [ inginious ];
-
-        services.mongodb.enable = true;
-
-        services.lighttpd.enable = true;
-        services.lighttpd.enableModules = [ "mod_access" "mod_alias" "mod_fastcgi" "mod_redirect" "mod_rewrite" ];
-        services.lighttpd.extraConfig = ''
-          $HTTP["host"] =~ "${cfg.hostPattern}" {
-            fastcgi.server = ( "/${execName}" =>
-              ((
-                "socket" => "/run/lighttpd/inginious-fastcgi.socket",
-                "bin-path" => "${inginious}/bin/${execName} --config=${inginiousConfigFile}",
-                "max-procs" => 1,
-                "bin-environment" => ( "REAL_SCRIPT_NAME" => "" ),
-                "check-local" => "disable"
-              ))
-            )
-            url.rewrite-once = (
-              "^/.well-known/.*" => "$0",
-              "^/static/.*" => "$0",
-              "^/.*$" => "/${execName}$0",
-              "^/favicon.ico$" => "/static/common/favicon.ico",
-            )
-            alias.url += (
-              "/static/webapp/" => "${inginious}/lib/python2.7/site-packages/inginious/frontend/webapp/static/",
-              "/static/common/" => "${inginious}/lib/python2.7/site-packages/inginious/frontend/common/static/"
-            )
-          }
-        '';
-
-        systemd.services.lighttpd.preStart = ''
-          mkdir -p /run/lighttpd
-          chown lighttpd.lighttpd /run/lighttpd
-        '';
-
-        systemd.services.lighttpd.wants = [ "mongodb.service" "docker.service" ];
-        systemd.services.lighttpd.after = [ "mongodb.service" "docker.service" ];
-      }
-    ]);
-}
diff --git a/nixos/modules/services/web-servers/meguca.nix b/nixos/modules/services/web-servers/meguca.nix
new file mode 100644
index 000000000000..ed7325ff0790
--- /dev/null
+++ b/nixos/modules/services/web-servers/meguca.nix
@@ -0,0 +1,159 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+let
+  cfg = config.services.meguca;
+  postgres = config.services.postgresql;
+in
+{
+  options.services.meguca = {
+    enable = mkEnableOption "meguca";
+
+    baseDir = mkOption {
+      type = types.path;
+      default = "/run/meguca";
+      description = "Location where meguca stores it's database and links.";
+    };
+
+    password = mkOption {
+      type = types.str;
+      default = "meguca";
+      description = "Password for the meguca database.";
+    };
+
+    passwordFile = mkOption {
+      type = types.path;
+      default = "/run/keys/meguca-password-file";
+      description = "Password file for the meguca database.";
+    };
+
+    reverseProxy = mkOption {
+      type = types.nullOr types.str;
+      default = null;
+      description = "Reverse proxy IP.";
+    };
+
+    sslCertificate = mkOption {
+      type = types.nullOr types.str;
+      default = null;
+      description = "Path to the SSL certificate.";
+    };
+
+    listenAddress = mkOption {
+      type = types.nullOr types.str;
+      default = null;
+      description = "Listen on a specific IP address and port.";
+    };
+
+    cacheSize = mkOption {
+      type = types.nullOr types.int;
+      default = null;
+      description = "Cache size in MB.";
+    };
+
+    postgresArgs = mkOption {
+      type = types.str;
+      default = "user=meguca password=" + cfg.password + " dbname=meguca sslmode=disable";
+      description = "Postgresql connection arguments.";
+    };
+
+    postgresArgsFile = mkOption {
+      type = types.path;
+      default = "/run/keys/meguca-postgres-args";
+      description = "Postgresql connection arguments file.";
+    };
+
+    compressTraffic = mkOption {
+      type = types.bool;
+      default = false;
+      description = "Compress all traffic with gzip.";
+    };
+
+    assumeReverseProxy = mkOption {
+      type = types.bool;
+      default = false;
+      description = "Assume the server is behind a reverse proxy, when resolving client IPs.";
+    };
+
+    httpsOnly = mkOption {
+      type = types.bool;
+      default = false;
+      description = "Serve and listen only through HTTPS.";
+    };
+  };
+
+  config = mkIf cfg.enable {
+    security.sudo.enable = cfg.enable == true;
+    services.postgresql.enable = cfg.enable == true;
+
+    services.meguca.passwordFile = mkDefault (toString (pkgs.writeTextFile {
+      name = "meguca-password-file";
+      text = cfg.password;
+    }));
+
+    services.meguca.postgresArgsFile = mkDefault (toString (pkgs.writeTextFile {
+      name = "meguca-postgres-args";
+      text = cfg.postgresArgs;
+    }));
+
+    systemd.services.meguca = {
+      description = "meguca";
+      after = [ "network.target" "postgresql.service" ];
+      wantedBy = [ "multi-user.target" ];
+
+      preStart = ''
+        # Ensure folder exists and links are correct or create them
+        mkdir -p ${cfg.baseDir}
+        chmod 750 ${cfg.baseDir}
+        ln -sf ${pkgs.meguca}/share/meguca/www ${cfg.baseDir}
+
+        # Ensure the database is correct or create it
+        ${pkgs.sudo}/bin/sudo -u ${postgres.superUser} ${postgres.package}/bin/createuser \
+          -SDR meguca || true
+        ${pkgs.sudo}/bin/sudo -u ${postgres.superUser} ${postgres.package}/bin/createdb \
+          -T template0 -E UTF8 -O meguca meguca || true
+        ${pkgs.sudo}/bin/sudo -u meguca ${postgres.package}/bin/psql \
+          -c "ALTER ROLE meguca WITH PASSWORD '$(cat ${cfg.passwordFile})';" || true
+      '';
+
+    script = ''
+      cd ${cfg.baseDir}
+
+      ${pkgs.meguca}/bin/meguca -d "$(cat ${cfg.postgresArgsFile})"\
+        ${optionalString (cfg.reverseProxy != null) " -R ${cfg.reverseProxy}"}\
+        ${optionalString (cfg.sslCertificate != null) " -S ${cfg.sslCertificate}"}\
+        ${optionalString (cfg.listenAddress != null) " -a ${cfg.listenAddress}"}\
+        ${optionalString (cfg.cacheSize != null) " -c ${toString cfg.cacheSize}"}\
+        ${optionalString (cfg.compressTraffic) " -g"}\
+        ${optionalString (cfg.assumeReverseProxy) " -r"}\
+        ${optionalString (cfg.httpsOnly) " -s"} start
+    '';
+
+      serviceConfig = {
+        PermissionsStartOnly = true;
+        Type = "forking";
+        User = "meguca";
+        Group = "meguca";
+        RuntimeDirectory = "meguca";
+        ExecStop = "${pkgs.meguca}/bin/meguca stop";
+      };
+    };
+
+    users = {
+      users.meguca = {
+        description = "meguca server service user";
+        home = cfg.baseDir;
+        createHome = true;
+        group = "meguca";
+        uid = config.ids.uids.meguca;
+      };
+
+      groups.meguca = {
+        gid = config.ids.gids.meguca;
+        members = [ "meguca" ];
+      };
+    };
+  };
+
+  meta.maintainers = with maintainers; [ chiiruno ];
+}
diff --git a/nixos/modules/services/web-servers/mighttpd2.nix b/nixos/modules/services/web-servers/mighttpd2.nix
index a888f623616e..4e7082c67690 100644
--- a/nixos/modules/services/web-servers/mighttpd2.nix
+++ b/nixos/modules/services/web-servers/mighttpd2.nix
@@ -119,13 +119,13 @@ in {
       };
     };
 
-    users.extraUsers.mighttpd2 = {
+    users.users.mighttpd2 = {
       group = "mighttpd2";
       uid = config.ids.uids.mighttpd2;
       isSystemUser = true;
     };
 
-    users.extraGroups.mighttpd2.gid = config.ids.gids.mighttpd2;
+    users.groups.mighttpd2.gid = config.ids.gids.mighttpd2;
   };
 
   meta.maintainers = with lib.maintainers; [ fgaz ];
diff --git a/nixos/modules/services/web-servers/minio.nix b/nixos/modules/services/web-servers/minio.nix
index 843f0d986877..f78a966989b6 100644
--- a/nixos/modules/services/web-servers/minio.nix
+++ b/nixos/modules/services/web-servers/minio.nix
@@ -85,7 +85,7 @@ in
       '';
       serviceConfig = {
         PermissionsStartOnly = true;
-        ExecStart = "${cfg.package}/bin/minio server --address ${cfg.listenAddress} --config-dir=${cfg.configDir} ${cfg.dataDir}";
+        ExecStart = "${cfg.package}/bin/minio server --json --address ${cfg.listenAddress} --config-dir=${cfg.configDir} ${cfg.dataDir}";
         Type = "simple";
         User = "minio";
         Group = "minio";
@@ -101,11 +101,11 @@ in
       };
     };
 
-    users.extraUsers.minio = {
+    users.users.minio = {
       group = "minio";
       uid = config.ids.uids.minio;
     };
 
-    users.extraGroups.minio.gid = config.ids.uids.minio;
+    users.groups.minio.gid = config.ids.uids.minio;
   };
 }
diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix
index 0aa780bf6da1..355976c4b7cb 100644
--- a/nixos/modules/services/web-servers/nginx/default.nix
+++ b/nixos/modules/services/web-servers/nginx/default.nix
@@ -613,13 +613,13 @@ in
         listToAttrs acmePairs
     );
 
-    users.extraUsers = optionalAttrs (cfg.user == "nginx") (singleton
+    users.users = optionalAttrs (cfg.user == "nginx") (singleton
       { name = "nginx";
         group = cfg.group;
         uid = config.ids.uids.nginx;
       });
 
-    users.extraGroups = optionalAttrs (cfg.group == "nginx") (singleton
+    users.groups = optionalAttrs (cfg.group == "nginx") (singleton
       { name = "nginx";
         gid = config.ids.gids.nginx;
       });
diff --git a/nixos/modules/services/web-servers/nginx/vhost-options.nix b/nixos/modules/services/web-servers/nginx/vhost-options.nix
index f014d817e80e..e4494dff37da 100644
--- a/nixos/modules/services/web-servers/nginx/vhost-options.nix
+++ b/nixos/modules/services/web-servers/nginx/vhost-options.nix
@@ -62,6 +62,7 @@ with lib;
         This is useful if you have many subdomains and want to avoid hitting the
         <link xlink:href="https://letsencrypt.org/docs/rate-limits/">rate limit</link>.
         Alternately, you can generate a certificate through <option>enableACME</option>.
+        <emphasis>Note that this option does not create any certificates, nor it does add subdomains to existing ones – you will need to create them manually using  <xref linkend="opt-security.acme.certs"/>.</emphasis>
       '';
     };
 
diff --git a/nixos/modules/services/web-servers/tomcat.nix b/nixos/modules/services/web-servers/tomcat.nix
index aa94e0e976c9..d8ccb7ca65d6 100644
--- a/nixos/modules/services/web-servers/tomcat.nix
+++ b/nixos/modules/services/web-servers/tomcat.nix
@@ -110,7 +110,7 @@ in
       webapps = mkOption {
         type = types.listOf types.package;
         default = [ tomcat.webapps ];
-        defaultText = "[ tomcat.webapps ]";
+        defaultText = "[ pkgs.tomcat85.webapps ]";
         description = "List containing WAR files or directories with WAR files which are web applications to be deployed on Tomcat";
       };
 
@@ -166,12 +166,12 @@ in
 
   config = mkIf config.services.tomcat.enable {
 
-    users.extraGroups = singleton
+    users.groups = singleton
       { name = "tomcat";
         gid = config.ids.gids.tomcat;
       };
 
-    users.extraUsers = singleton
+    users.users = singleton
       { name = "tomcat";
         uid = config.ids.uids.tomcat;
         description = "Tomcat user";
diff --git a/nixos/modules/services/web-servers/traefik.nix b/nixos/modules/services/web-servers/traefik.nix
index b6c7fef21fb2..700202b1d28f 100644
--- a/nixos/modules/services/web-servers/traefik.nix
+++ b/nixos/modules/services/web-servers/traefik.nix
@@ -114,12 +114,12 @@ in {
       };
     };
 
-    users.extraUsers.traefik = {
+    users.users.traefik = {
       group = "traefik";
       home = cfg.dataDir;
       createHome = true;
     };
 
-    users.extraGroups.traefik = {};
+    users.groups.traefik = {};
   };
 }
diff --git a/nixos/modules/services/web-servers/uwsgi.nix b/nixos/modules/services/web-servers/uwsgi.nix
index 14596bb3add0..3f858d90fa46 100644
--- a/nixos/modules/services/web-servers/uwsgi.nix
+++ b/nixos/modules/services/web-servers/uwsgi.nix
@@ -27,13 +27,7 @@ let
         else if hasPython3 then uwsgi.python3
         else null;
 
-      pythonPackages = pkgs.pythonPackages.override {
-        inherit python;
-      };
-
-      penv = python.buildEnv.override {
-        extraLibs = (c.pythonPackages or (self: [])) pythonPackages;
-      };
+      pythonEnv = python.withPackages (c.pythonPackages or (self: []));
 
       uwsgiCfg = {
         uwsgi =
@@ -42,7 +36,7 @@ let
               inherit plugins;
             } // removeAttrs c [ "type" "pythonPackages" ]
               // optionalAttrs (python != null) {
-                pythonpath = "${penv}/${python.sitePackages}";
+                pythonpath = "${pythonEnv}/${python.sitePackages}";
                 env =
                   # Argh, uwsgi expects list of key-values there instead of a dictionary.
                   let env' = c.env or [];
@@ -51,7 +45,7 @@ let
                            then substring (stringLength "PATH=") (stringLength x) x
                            else null;
                       oldPaths = filter (x: x != null) (map getPath env');
-                  in env' ++ [ "PATH=${optionalString (oldPaths != []) "${last oldPaths}:"}${penv}/bin" ];
+                  in env' ++ [ "PATH=${optionalString (oldPaths != []) "${last oldPaths}:"}${pythonEnv}/bin" ];
               }
           else if c.type == "emperor"
             then {
@@ -152,13 +146,13 @@ in {
       };
     };
 
-    users.extraUsers = optionalAttrs (cfg.user == "uwsgi") (singleton
+    users.users = optionalAttrs (cfg.user == "uwsgi") (singleton
       { name = "uwsgi";
         group = cfg.group;
         uid = config.ids.uids.uwsgi;
       });
 
-    users.extraGroups = optionalAttrs (cfg.group == "uwsgi") (singleton
+    users.groups = optionalAttrs (cfg.group == "uwsgi") (singleton
       { name = "uwsgi";
         gid = config.ids.gids.uwsgi;
       });
diff --git a/nixos/modules/services/web-servers/varnish/default.nix b/nixos/modules/services/web-servers/varnish/default.nix
index bc74d62b116a..63f967185c2d 100644
--- a/nixos/modules/services/web-servers/varnish/default.nix
+++ b/nixos/modules/services/web-servers/varnish/default.nix
@@ -103,11 +103,11 @@ in
       })
     ];
 
-    users.extraUsers.varnish = {
+    users.users.varnish = {
       group = "varnish";
       uid = config.ids.uids.varnish;
     };
 
-    users.extraGroups.varnish.gid = config.ids.uids.varnish;
+    users.groups.varnish.gid = config.ids.uids.varnish;
   };
 }
diff --git a/nixos/modules/services/web-servers/zope2.nix b/nixos/modules/services/web-servers/zope2.nix
index 496e34db4a96..1dcc3ac9d8d4 100644
--- a/nixos/modules/services/web-servers/zope2.nix
+++ b/nixos/modules/services/web-servers/zope2.nix
@@ -103,7 +103,7 @@ in
 
   config = mkIf (cfg.instances != {}) {
 
-    users.extraUsers.zope2.uid = config.ids.uids.zope2;
+    users.users.zope2.uid = config.ids.uids.zope2;
 
     systemd.services =
       let
diff --git a/nixos/modules/services/x11/desktop-managers/gnome3.nix b/nixos/modules/services/x11/desktop-managers/gnome3.nix
index 27b62df7097c..9fb8f44b2421 100644
--- a/nixos/modules/services/x11/desktop-managers/gnome3.nix
+++ b/nixos/modules/services/x11/desktop-managers/gnome3.nix
@@ -10,7 +10,6 @@ let
     let
       pkgName = drv: (builtins.parseDrvName drv.name).name;
       ysNames = map pkgName ys;
-      res = (filter (x: !(builtins.elem (pkgName x) ysNames)) xs);
     in
       filter (x: !(builtins.elem (pkgName x) ysNames)) xs;
 
diff --git a/nixos/modules/services/x11/desktop-managers/plasma5.nix b/nixos/modules/services/x11/desktop-managers/plasma5.nix
index 91d091d7d7e2..17733aa7e4f6 100644
--- a/nixos/modules/services/x11/desktop-managers/plasma5.nix
+++ b/nixos/modules/services/x11/desktop-managers/plasma5.nix
@@ -7,7 +7,7 @@ let
   xcfg = config.services.xserver;
   cfg = xcfg.desktopManager.plasma5;
 
-  inherit (pkgs) kdeApplications plasma5 libsForQt5 qt5 xorg;
+  inherit (pkgs) kdeApplications plasma5 libsForQt5 qt5;
 
 in
 
@@ -221,6 +221,11 @@ in
       security.pam.services.sddm.enableKwallet = true;
       security.pam.services.slim.enableKwallet = true;
 
+      # Update the start menu for each user that has `isNormalUser` set.
+      system.activationScripts.plasmaSetup = stringAfter [ "users" "groups" ]
+        (concatStringsSep "\n"
+          (mapAttrsToList (name: value: "${pkgs.su}/bin/su ${name} -c kbuildsycoca5")
+            (filterAttrs (n: v: v.isNormalUser) config.users.users)));
     })
   ];
 
diff --git a/nixos/modules/services/x11/desktop-managers/xfce.nix b/nixos/modules/services/x11/desktop-managers/xfce.nix
index 7dcc600d2664..ae155470419d 100644
--- a/nixos/modules/services/x11/desktop-managers/xfce.nix
+++ b/nixos/modules/services/x11/desktop-managers/xfce.nix
@@ -43,12 +43,6 @@ in
         default = true;
         description = "Enable the XFWM (default) window manager.";
       };
-
-      screenLock = mkOption {
-        type = types.enum [ "xscreensaver" "xlockmore" "slock" ];
-        default = "xlockmore";
-        description = "Application used by XFCE to lock the screen.";
-      };
     };
   };
 
@@ -92,7 +86,7 @@ in
       thunar-volman # TODO: drop
     ] ++ (if config.hardware.pulseaudio.enable
           then [ xfce4-mixer-pulse xfce4-volumed-pulse ]
-	  else [ xfce4-mixer xfce4-volumed ])
+          else [ xfce4-mixer xfce4-volumed ])
       # TODO: NetworkManager doesn't belong here
       ++ optionals config.networking.networkmanager.enable [ networkmanagerapplet ]
       ++ optionals config.powerManagement.enable [ xfce4-power-manager ]
diff --git a/nixos/modules/services/x11/display-managers/gdm.nix b/nixos/modules/services/x11/display-managers/gdm.nix
index a6a38a21b617..8b08c01ea0db 100644
--- a/nixos/modules/services/x11/display-managers/gdm.nix
+++ b/nixos/modules/services/x11/display-managers/gdm.nix
@@ -89,7 +89,7 @@ in
 
     services.xserver.displayManager.slim.enable = false;
 
-    users.extraUsers.gdm =
+    users.users.gdm =
       { name = "gdm";
         uid = config.ids.uids.gdm;
         group = "gdm";
@@ -97,7 +97,7 @@ in
         description = "GDM user";
       };
 
-    users.extraGroups.gdm.gid = config.ids.gids.gdm;
+    users.groups.gdm.gid = config.ids.gids.gdm;
 
     # GDM needs different xserverArgs, presumable because using wayland by default.
     services.xserver.tty = null;
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 2a71d2338607..385f20b7e066 100644
--- a/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix
+++ b/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix
@@ -8,7 +8,7 @@ let
   ldmcfg = dmcfg.lightdm;
   cfg = ldmcfg.greeters.gtk;
 
-  inherit (pkgs) stdenv lightdm writeScript writeText;
+  inherit (pkgs) writeText;
 
   theme = cfg.theme.package;
   icons = cfg.iconTheme.package;
diff --git a/nixos/modules/services/x11/display-managers/lightdm-greeters/mini.nix b/nixos/modules/services/x11/display-managers/lightdm-greeters/mini.nix
new file mode 100644
index 000000000000..ba8151a60f20
--- /dev/null
+++ b/nixos/modules/services/x11/display-managers/lightdm-greeters/mini.nix
@@ -0,0 +1,100 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  dmcfg = config.services.xserver.displayManager;
+  ldmcfg = dmcfg.lightdm;
+  cfg = ldmcfg.greeters.mini;
+
+  xgreeters = pkgs.linkFarm "lightdm-mini-greeter-xgreeters" [{
+    path = "${pkgs.lightdm-mini-greeter}/share/xgreeters/lightdm-mini-greeter.desktop";
+    name = "lightdm-mini-greeter.desktop";
+  }];
+
+  miniGreeterConf = pkgs.writeText "lightdm-mini-greeter.conf"
+    ''
+    [greeter]
+    user = ${cfg.user}
+    show-password-label = true
+    password-label-text = Password:
+    show-input-cursor = true
+
+    [greeter-hotkeys]
+    mod-key = meta
+    shutdown-key = s
+    restart-key = r
+    hibernate-key = h
+    suspend-key = u
+
+    [greeter-theme]
+    font = Sans
+    font-size = 1em
+    text-color = "#080800"
+    error-color = "#F8F8F0"
+    background-image = "${ldmcfg.background}"
+    background-color = "#1B1D1E"
+    window-color = "#F92672"
+    border-color = "#080800"
+    border-width = 2px
+    layout-space = 15
+    password-color = "#F8F8F0"
+    password-background-color = "#1B1D1E"
+
+    ${cfg.extraConfig}
+    '';
+
+in
+{
+  options = {
+
+    services.xserver.displayManager.lightdm.greeters.mini = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          Whether to enable lightdm-mini-greeter as the lightdm greeter.
+
+          Note that this greeter starts only the default X session.
+          You can configure the default X session by
+          <option>services.xserver.desktopManager.default</option> and
+          <option>services.xserver.windowManager.default</option>.
+        '';
+      };
+
+      user = mkOption {
+        type = types.str;
+        default = "root";
+        description = ''
+          The user to login as.
+        '';
+      };
+
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Extra configuration that should be put in the lightdm-mini-greeter.conf
+          configuration file.
+        '';
+      };
+
+    };
+
+  };
+
+  config = mkIf (ldmcfg.enable && cfg.enable) {
+
+    services.xserver.displayManager.lightdm.greeters.gtk.enable = false;
+
+    services.xserver.displayManager.lightdm.greeter = mkDefault {
+      package = xgreeters;
+      name = "lightdm-mini-greeter";
+    };
+
+    environment.etc."lightdm/lightdm-mini-greeter.conf".source = miniGreeterConf;
+
+  };
+}
diff --git a/nixos/modules/services/x11/display-managers/lightdm.nix b/nixos/modules/services/x11/display-managers/lightdm.nix
index 9d30155a7234..54d4520a0c8b 100644
--- a/nixos/modules/services/x11/display-managers/lightdm.nix
+++ b/nixos/modules/services/x11/display-managers/lightdm.nix
@@ -13,7 +13,7 @@ let
   wmDefault = xcfg.windowManager.default;
   hasDefaultUserSession = dmDefault != "none" || wmDefault != "none";
 
-  inherit (pkgs) stdenv lightdm writeScript writeText;
+  inherit (pkgs) lightdm writeScript writeText;
 
   # lightdm runs with clearenv(), but we need a few things in the enviornment for X to startup
   xserverWrapper = writeScript "xserver-wrapper"
@@ -42,7 +42,7 @@ let
     ''
       [LightDM]
       ${optionalString cfg.greeter.enable ''
-        greeter-user = ${config.users.extraUsers.lightdm.name}
+        greeter-user = ${config.users.users.lightdm.name}
         greeters-directory = ${cfg.greeter.package}
       ''}
       sessions-directory = ${dmcfg.session.desktops}
@@ -72,6 +72,7 @@ in
   # preferred.
   imports = [
     ./lightdm-greeters/gtk.nix
+    ./lightdm-greeters/mini.nix
   ];
 
   options = {
@@ -251,14 +252,14 @@ in
         session  include   lightdm
     '';
 
-    users.extraUsers.lightdm = {
+    users.users.lightdm = {
       createHome = true;
       home = "/var/lib/lightdm-data";
       group = "lightdm";
       uid = config.ids.uids.lightdm;
     };
 
-    users.extraGroups.lightdm.gid = config.ids.gids.lightdm;
+    users.groups.lightdm.gid = config.ids.gids.lightdm;
     services.xserver.tty     = null; # We might start multiple X servers so let the tty increment themselves..
     services.xserver.display = null; # We specify our own display (and logfile) in xserver-wrapper up there
   };
diff --git a/nixos/modules/services/x11/display-managers/sddm.nix b/nixos/modules/services/x11/display-managers/sddm.nix
index 2d4cb8aa20a5..426b899586f5 100644
--- a/nixos/modules/services/x11/display-managers/sddm.nix
+++ b/nixos/modules/services/x11/display-managers/sddm.nix
@@ -19,17 +19,6 @@ let
 
   Xsetup = pkgs.writeScript "Xsetup" ''
     #!/bin/sh
-
-    # Prior to Qt 5.9.2, there is a QML cache invalidation bug which sometimes
-    # strikes new Plasma 5 releases. If the QML cache is not invalidated, SDDM
-    # will segfault without explanation. We really tore our hair out for awhile
-    # before finding the bug:
-    # https://bugreports.qt.io/browse/QTBUG-62302
-    # We work around the problem by deleting the QML cache before startup. It
-    # will be regenerated, causing a small but perceptible delay when SDDM
-    # starts.
-    rm -fr /var/lib/sddm/.cache/sddm-greeter/qmlcache
-
     ${cfg.setupScript}
   '';
 
@@ -65,6 +54,10 @@ let
     XauthPath=${pkgs.xorg.xauth}/bin/xauth
     DisplayCommand=${Xsetup}
     DisplayStopCommand=${Xstop}
+    EnableHidpi=${if cfg.enableHidpi then "true" else "false"}
+
+    [Wayland]
+    EnableHidpi=${if cfg.enableHidpi then "true" else "false"}
 
     ${optionalString cfg.autoLogin.enable ''
     [Autologin]
@@ -95,6 +88,17 @@ in
         '';
       };
 
+      enableHidpi = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Whether to enable automatic HiDPI mode.
+          </para>
+          <para>
+          Versions up to 0.17 are broken so this only works from 0.18 onwards.
+        '';
+      };
+
       extraConfig = mkOption {
         type = types.lines;
         default = "";
@@ -253,7 +257,7 @@ in
       '';
     };
 
-    users.extraUsers.sddm = {
+    users.users.sddm = {
       createHome = true;
       home = "/var/lib/sddm";
       group = "sddm";
@@ -262,7 +266,7 @@ in
 
     environment.etc."sddm.conf".source = cfgFile;
 
-    users.extraGroups.sddm.gid = config.ids.gids.sddm;
+    users.groups.sddm.gid = config.ids.gids.sddm;
 
     environment.systemPackages = [ sddm ];
     services.dbus.packages = [ sddm ];
@@ -270,5 +274,20 @@ in
     # To enable user switching, allow sddm to allocate TTYs/displays dynamically.
     services.xserver.tty = null;
     services.xserver.display = null;
+
+    systemd.tmpfiles.rules = [
+      # Prior to Qt 5.9.2, there is a QML cache invalidation bug which sometimes
+      # strikes new Plasma 5 releases. If the QML cache is not invalidated, SDDM
+      # will segfault without explanation. We really tore our hair out for awhile
+      # before finding the bug:
+      # https://bugreports.qt.io/browse/QTBUG-62302
+      # We work around the problem by deleting the QML cache before startup.
+      # This was supposedly fixed in Qt 5.9.2 however it has been reported with
+      # 5.10 and 5.11 as well. The initial workaround was to delete the directory
+      # in the Xsetup script but that doesn't do anything.
+      # Instead we use tmpfiles.d to ensure it gets wiped.
+      # This causes a small but perceptible delay when SDDM starts.
+      "e ${config.users.users.sddm.home}/.cache - - - 0"
+    ];
   };
 }
diff --git a/nixos/modules/services/x11/hardware/libinput.nix b/nixos/modules/services/x11/hardware/libinput.nix
index d0a87f183b6f..072004d5dd91 100644
--- a/nixos/modules/services/x11/hardware/libinput.nix
+++ b/nixos/modules/services/x11/hardware/libinput.nix
@@ -116,7 +116,7 @@ in {
       };
 
       scrollMethod = mkOption {
-        type = types.enum [ "twofinger" "edge" "none" ];
+        type = types.enum [ "twofinger" "edge" "button" "none" ];
         default = "twofinger";
         example = "edge";
         description =
diff --git a/nixos/modules/services/x11/window-managers/awesome.nix b/nixos/modules/services/x11/window-managers/awesome.nix
index 71eb02ec5954..089e9f769f0a 100644
--- a/nixos/modules/services/x11/window-managers/awesome.nix
+++ b/nixos/modules/services/x11/window-managers/awesome.nix
@@ -37,6 +37,11 @@ in
         apply = pkg: if pkg == null then pkgs.awesome else pkg;
       };
 
+      noArgb = mkOption {
+        default = false;
+        type = types.bool;
+        description = "Disable client transparency support, which can be greatly detrimental to performance in some setups";
+      };
     };
 
   };
@@ -50,7 +55,7 @@ in
       { name = "awesome";
         start =
           ''
-            ${awesome}/bin/awesome ${makeSearchPath cfg.luaModules} &
+            ${awesome}/bin/awesome ${lib.optionalString cfg.noArgb "--no-argb"} ${makeSearchPath cfg.luaModules} &
             waitPID=$!
           '';
       };
diff --git a/nixos/modules/services/x11/window-managers/openbox.nix b/nixos/modules/services/x11/window-managers/openbox.nix
index 07ef77151e95..165772d1aa09 100644
--- a/nixos/modules/services/x11/window-managers/openbox.nix
+++ b/nixos/modules/services/x11/window-managers/openbox.nix
@@ -2,7 +2,6 @@
 
 with lib;
 let
-  inherit (lib) mkOption mkIf;
   cfg = config.services.xserver.windowManager.openbox;
 in
 
diff --git a/nixos/modules/services/x11/window-managers/wmii.nix b/nixos/modules/services/x11/window-managers/wmii.nix
index 30c8df782245..eec6f2b2b81b 100644
--- a/nixos/modules/services/x11/window-managers/wmii.nix
+++ b/nixos/modules/services/x11/window-managers/wmii.nix
@@ -2,7 +2,6 @@
 
 with lib;
 let
-  inherit (lib) mkOption mkIf singleton;
   cfg = config.services.xserver.windowManager.wmii;
   wmii = pkgs.wmii_hg;
 in
diff --git a/nixos/modules/services/x11/xserver.nix b/nixos/modules/services/x11/xserver.nix
index 1404231f837e..3048cd02683f 100644
--- a/nixos/modules/services/x11/xserver.nix
+++ b/nixos/modules/services/x11/xserver.nix
@@ -244,6 +244,13 @@ in
           "ati_unfree" "amdgpu" "amdgpu-pro"
           "nv" "nvidia" "nvidiaLegacy340" "nvidiaLegacy304"
         ];
+        # TODO(@oxij): think how to easily add the rest, like those nvidia things
+        relatedPackages = concatLists
+          (mapAttrsToList (n: v:
+            optional (hasPrefix "xf86video" n) {
+              path  = [ "xorg" n ];
+              title = removePrefix "xf86video" n;
+            }) pkgs.xorg);
         description = ''
           The names of the video drivers the configuration
           supports. They will be tried in order until one that
diff --git a/nixos/modules/system/boot/initrd-network.nix b/nixos/modules/system/boot/initrd-network.nix
index 33862b0965cc..384ae909b701 100644
--- a/nixos/modules/system/boot/initrd-network.nix
+++ b/nixos/modules/system/boot/initrd-network.nix
@@ -12,6 +12,7 @@ let
       if [ "$1" = bound ]; then
         ip address add "$ip/$mask" dev "$interface"
         if [ -n "$router" ]; then
+          ip route add "$router" dev "$interface" # just in case if "$router" is not within "$ip/$mask" (e.g. Hetzner Cloud)
           ip route add default via "$router" dev "$interface"
         fi
         if [ -n "$dns" ]; then
diff --git a/nixos/modules/system/boot/initrd-ssh.nix b/nixos/modules/system/boot/initrd-ssh.nix
index 8b3dc2d90eb3..53e993603e27 100644
--- a/nixos/modules/system/boot/initrd-ssh.nix
+++ b/nixos/modules/system/boot/initrd-ssh.nix
@@ -79,7 +79,7 @@ in
 
     boot.initrd.network.ssh.authorizedKeys = mkOption {
       type = types.listOf types.str;
-      default = config.users.extraUsers.root.openssh.authorizedKeys.keys;
+      default = config.users.users.root.openssh.authorizedKeys.keys;
       description = ''
         Authorized keys for the root user on initrd.
       '';
diff --git a/nixos/modules/system/boot/loader/grub/grub.nix b/nixos/modules/system/boot/loader/grub/grub.nix
index e2cff1c1bd94..42da65857221 100644
--- a/nixos/modules/system/boot/loader/grub/grub.nix
+++ b/nixos/modules/system/boot/loader/grub/grub.nix
@@ -64,9 +64,10 @@ let
       )) + ":" + (makeSearchPathOutput "bin" "sbin" [
         pkgs.mdadm pkgs.utillinux
       ]);
-      font = if lib.last (lib.splitString "." cfg.font) == "pf2"
+      font = if cfg.font == null then ""
+        else (if lib.last (lib.splitString "." cfg.font) == "pf2"
              then cfg.font
-             else "${convertedFont}";
+             else "${convertedFont}");
     });
 
   bootDeviceCounters = fold (device: attr: attr // { "${device}" = (attr."${device}" or 0) + 1; }) {}
@@ -308,10 +309,22 @@ in
         type = types.nullOr types.path;
         example = literalExample "./my-background.png";
         description = ''
-          Background image used for GRUB.  It must be a 640x480,
+          Background image used for GRUB.
+          Set to <literal>null</literal> to run GRUB in text mode.
+
+          <note><para>
+          For grub 1:
+          It must be a 640x480,
           14-colour image in XPM format, optionally compressed with
-          <command>gzip</command> or <command>bzip2</command>.  Set to
-          <literal>null</literal> to run GRUB in text mode.
+          <command>gzip</command> or <command>bzip2</command>.
+          </para></note>
+
+          <note><para>
+          For grub 2:
+          File must be one of .png, .tga, .jpg, or .jpeg. JPEG images must
+          not be progressive.
+          The image will be scaled if necessary to fit the screen.
+          </para></note>
         '';
       };
 
@@ -372,8 +385,9 @@ in
       };
 
       default = mkOption {
-        default = 0;
-        type = types.int;
+        default = "0";
+        type = types.either types.int types.str;
+        apply = toString;
         description = ''
           Index of the default menu item to be booted.
         '';
diff --git a/nixos/modules/system/boot/loader/grub/install-grub.pl b/nixos/modules/system/boot/loader/grub/install-grub.pl
index 8bd203106f55..d1ff6e6bf525 100644
--- a/nixos/modules/system/boot/loader/grub/install-grub.pl
+++ b/nixos/modules/system/boot/loader/grub/install-grub.pl
@@ -54,7 +54,7 @@ my $splashImage = get("splashImage");
 my $configurationLimit = int(get("configurationLimit"));
 my $copyKernels = get("copyKernels") eq "true";
 my $timeout = int(get("timeout"));
-my $defaultEntry = int(get("default"));
+my $defaultEntry = get("default");
 my $fsIdentifier = get("fsIdentifier");
 my $grubEfi = get("grubEfi");
 my $grubTargetEfi = get("grubTargetEfi");
@@ -281,30 +281,36 @@ else {
         else
           insmod vbe
         fi
-        insmod font
-        if loadfont " . $grubBoot->path . "/converted-font.pf2; then
-          insmod gfxterm
-          if [ \"\${grub_platform}\" = \"efi\" ]; then
-            set gfxmode=$gfxmodeEfi
-            set gfxpayload=keep
-          else
-            set gfxmode=$gfxmodeBios
-            set gfxpayload=text
-          fi
-          terminal_output gfxterm
-        fi
     ";
 
     if ($font) {
         copy $font, "$bootPath/converted-font.pf2" or die "cannot copy $font to $bootPath\n";
+        $conf .= "
+            insmod font
+            if loadfont " . $grubBoot->path . "/converted-font.pf2; then
+              insmod gfxterm
+              if [ \"\${grub_platform}\" = \"efi\" ]; then
+                set gfxmode=$gfxmodeEfi
+                set gfxpayload=keep
+              else
+                set gfxmode=$gfxmodeBios
+                set gfxpayload=text
+              fi
+              terminal_output gfxterm
+            fi
+        ";
     }
     if ($splashImage) {
-        # FIXME: GRUB 1.97 doesn't resize the background image if it
-        # doesn't match the video resolution.
-        copy $splashImage, "$bootPath/background.png" or die "cannot copy $splashImage to $bootPath\n";
+        # Keeps the image's extension.
+        my ($filename, $dirs, $suffix) = fileparse($splashImage, qr"\..[^.]*$");
+        # The module for jpg is jpeg.
+        if ($suffix eq ".jpg") {
+            $suffix = ".jpeg";
+        }
+        copy $splashImage, "$bootPath/background$suffix" or die "cannot copy $splashImage to $bootPath\n";
         $conf .= "
-            insmod png
-            if background_image " . $grubBoot->path . "/background.png; then
+            insmod " . substr($suffix, 1) . "
+            if background_image " . $grubBoot->path . "/background$suffix; then
               set color_normal=white/black
               set color_highlight=black/white
             else
diff --git a/nixos/modules/system/boot/resolved.nix b/nixos/modules/system/boot/resolved.nix
index 4d9de020c84e..e1095fb988eb 100644
--- a/nixos/modules/system/boot/resolved.nix
+++ b/nixos/modules/system/boot/resolved.nix
@@ -147,6 +147,8 @@ in
       ${config.services.resolved.extraConfig}
     '';
 
+    # If networkmanager is enabled, ask it to interface with resolved.
+    networking.networkmanager.dns = "systemd-resolved";
   };
 
 }
diff --git a/nixos/modules/system/boot/stage-1-init.sh b/nixos/modules/system/boot/stage-1-init.sh
index 92e68b72664a..de8451bbe31b 100644
--- a/nixos/modules/system/boot/stage-1-init.sh
+++ b/nixos/modules/system/boot/stage-1-init.sh
@@ -251,6 +251,9 @@ checkFS() {
     # Skip fsck for bcachefs - not implemented yet.
     if [ "$fsType" = bcachefs ]; then return 0; fi
 
+    # Skip fsck for nilfs2 - not needed by design and no fsck tool for this filesystem.
+    if [ "$fsType" = nilfs2 ]; then return 0; fi
+
     # Skip fsck for inherently readonly filesystems.
     if [ "$fsType" = squashfs ]; then return 0; fi
 
diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix
index 55bb6d3449c5..71b806a0b4e1 100644
--- a/nixos/modules/system/boot/stage-1.nix
+++ b/nixos/modules/system/boot/stage-1.nix
@@ -11,7 +11,6 @@ let
 
   udev = config.systemd.package;
 
-  kernelPackages = config.boot.kernelPackages;
   modulesTree = config.system.modulesTree;
   firmware = config.hardware.firmware;
 
@@ -56,6 +55,12 @@ let
       left=("''${left[@]:3}")
       if [ -z ''${seen[$next]+x} ]; then
         seen[$next]=1
+
+        # Ignore the dynamic linker which for some reason appears as a DT_NEEDED of glibc but isn't in glibc's RPATH.
+        case "$next" in
+          ld*.so.?) continue;;
+        esac
+
         IFS=: read -ra paths <<< $rpath
         res=
         for path in "''${paths[@]}"; do
@@ -158,7 +163,7 @@ let
 
       # Strip binaries further than normal.
       chmod -R u+w $out
-      stripDirs "lib bin" "-s"
+      stripDirs "$STRIP" "lib bin" "-s"
 
       # Run patchelf to make the programs refer to the copied libraries.
       find $out/bin $out/lib -type f | while read i; do
diff --git a/nixos/modules/system/boot/stage-2.nix b/nixos/modules/system/boot/stage-2.nix
index 78afbd8dbc12..9fd89b6319db 100644
--- a/nixos/modules/system/boot/stage-2.nix
+++ b/nixos/modules/system/boot/stage-2.nix
@@ -4,9 +4,6 @@ with lib;
 
 let
 
-  kernel = config.boot.kernelPackages.kernel;
-  activateConfiguration = config.system.activationScripts.script;
-
   bootStage2 = pkgs.substituteAll {
     src = ./stage-2-init.sh;
     shellDebug = "${pkgs.bashInteractive}/bin/bash";
diff --git a/nixos/modules/system/boot/systemd-lib.nix b/nixos/modules/system/boot/systemd-lib.nix
index ae9ee8811f77..8b37bf8d35d8 100644
--- a/nixos/modules/system/boot/systemd-lib.nix
+++ b/nixos/modules/system/boot/systemd-lib.nix
@@ -78,10 +78,16 @@ in rec {
     optional (badFields != [ ])
       "Systemd ${group} has extra fields [${concatStringsSep " " badFields}].";
 
-  checkUnitConfig = group: checks: v:
-    let errors = concatMap (c: c group v) checks; in
-    if errors == [] then true
-      else builtins.trace (concatStringsSep "\n" errors) false;
+  checkUnitConfig = group: checks: attrs: let
+    # We're applied at the top-level type (attrsOf unitOption), so the actual
+    # unit options might contain attributes from mkOverride that we need to
+    # convert into single values before checking them.
+    defs = mapAttrs (const (v:
+      if v._type or "" == "override" then v.content else v
+    )) attrs;
+    errors = concatMap (c: c group defs) checks;
+  in if errors == [] then true
+     else builtins.trace (concatStringsSep "\n" errors) false;
 
   toOption = x:
     if x == true then "true"
diff --git a/nixos/modules/system/boot/systemd-nspawn.nix b/nixos/modules/system/boot/systemd-nspawn.nix
index 64b3b8b584e3..83fef8354360 100644
--- a/nixos/modules/system/boot/systemd-nspawn.nix
+++ b/nixos/modules/system/boot/systemd-nspawn.nix
@@ -6,9 +6,6 @@ with import ./systemd-lib.nix { inherit config lib pkgs; };
 
 let
   cfg = config.systemd.nspawn;
-  assertions = [
-    # boot = true -> processtwo != true
-  ];
 
   checkExec = checkUnitConfig "Exec" [
     (assertOnlyFields [
diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix
index d2fe33488a7a..500c2d406615 100644
--- a/nixos/modules/system/boot/systemd.nix
+++ b/nixos/modules/system/boot/systemd.nix
@@ -188,8 +188,6 @@ let
       "timers.target"
     ];
 
-  boolToString = value: if value then "yes" else "no";
-
   makeJobScript = name: text:
     let mkScriptName =  s: (replaceChars [ "\\" ] [ "-" ] (shellEscape s) );
         x = pkgs.writeTextFile { name = "unit-script"; executable = true; destination = "/bin/${mkScriptName name}"; inherit text; };
@@ -515,7 +513,7 @@ in
     };
 
     systemd.globalEnvironment = mkOption {
-      type = with types; attrsOf (nullOr (either str package));
+      type = with types; attrsOf (nullOr (either str (either path package)));
       default = {};
       example = { TZ = "CET"; };
       description = ''
@@ -798,13 +796,13 @@ in
         mkdir -m 0700 -p /var/log/journal
       '';
 
-    users.extraUsers.systemd-network.uid = config.ids.uids.systemd-network;
-    users.extraGroups.systemd-network.gid = config.ids.gids.systemd-network;
-    users.extraUsers.systemd-resolve.uid = config.ids.uids.systemd-resolve;
-    users.extraGroups.systemd-resolve.gid = config.ids.gids.systemd-resolve;
+    users.users.systemd-network.uid = config.ids.uids.systemd-network;
+    users.groups.systemd-network.gid = config.ids.gids.systemd-network;
+    users.users.systemd-resolve.uid = config.ids.uids.systemd-resolve;
+    users.groups.systemd-resolve.gid = config.ids.gids.systemd-resolve;
 
     # Target for ‘charon send-keys’ to hook into.
-    users.extraGroups.keys.gid = config.ids.gids.keys;
+    users.groups.keys.gid = config.ids.gids.keys;
 
     systemd.targets.keys =
       { description = "Security Keys";
@@ -840,9 +838,9 @@ in
         "TMPFS_XATTR" "SECCOMP"
       ];
 
-    users.extraGroups.systemd-journal.gid = config.ids.gids.systemd-journal;
-    users.extraUsers.systemd-journal-gateway.uid = config.ids.uids.systemd-journal-gateway;
-    users.extraGroups.systemd-journal-gateway.gid = config.ids.gids.systemd-journal-gateway;
+    users.groups.systemd-journal.gid = config.ids.gids.systemd-journal;
+    users.users.systemd-journal-gateway.uid = config.ids.uids.systemd-journal-gateway;
+    users.groups.systemd-journal-gateway.gid = config.ids.gids.systemd-journal-gateway;
 
     # Generate timer units for all services that have a ‘startAt’ value.
     systemd.timers =
diff --git a/nixos/modules/system/boot/timesyncd.nix b/nixos/modules/system/boot/timesyncd.nix
index f643723ab141..18aad58b36cc 100644
--- a/nixos/modules/system/boot/timesyncd.nix
+++ b/nixos/modules/system/boot/timesyncd.nix
@@ -34,11 +34,11 @@ with lib;
 
     environment.etc."systemd/timesyncd.conf".text = ''
       [Time]
-      NTP=${concatStringsSep " " config.services.ntp.servers}
+      NTP=${concatStringsSep " " config.services.timesyncd.servers}
     '';
 
-    users.extraUsers.systemd-timesync.uid = config.ids.uids.systemd-timesync;
-    users.extraGroups.systemd-timesync.gid = config.ids.gids.systemd-timesync;
+    users.users.systemd-timesync.uid = config.ids.uids.systemd-timesync;
+    users.groups.systemd-timesync.gid = config.ids.gids.systemd-timesync;
 
   };
 
diff --git a/nixos/modules/tasks/encrypted-devices.nix b/nixos/modules/tasks/encrypted-devices.nix
index da0c9408d891..11ed5d7e4d0c 100644
--- a/nixos/modules/tasks/encrypted-devices.nix
+++ b/nixos/modules/tasks/encrypted-devices.nix
@@ -7,7 +7,6 @@ let
   encDevs = filter (dev: dev.encrypted.enable) fileSystems;
   keyedEncDevs = filter (dev: dev.encrypted.keyFile != null) encDevs;
   keylessEncDevs = filter (dev: dev.encrypted.keyFile == null) encDevs;
-  isIn = needle: haystack: filter (p: p == needle) haystack != [];
   anyEncrypted =
     fold (j: v: v || j.encrypted.enable) false encDevs;
 
diff --git a/nixos/modules/tasks/filesystems/zfs.nix b/nixos/modules/tasks/filesystems/zfs.nix
index c3bf897d51fd..7120856387ef 100644
--- a/nixos/modules/tasks/filesystems/zfs.nix
+++ b/nixos/modules/tasks/filesystems/zfs.nix
@@ -9,7 +9,6 @@ with lib;
 
 let
 
-  cfgSpl = config.boot.spl;
   cfgZfs = config.boot.zfs;
   cfgSnapshots = config.services.zfs.autoSnapshot;
   cfgSnapFlags = cfgSnapshots.flags;
@@ -58,6 +57,45 @@ let
 
   snapshotNames = [ "frequent" "hourly" "daily" "weekly" "monthly" ];
 
+  # When importing ZFS pools, there's one difficulty: These scripts may run
+  # before the backing devices (physical HDDs, etc.) of the pool have been
+  # scanned and initialized.
+  #
+  # An attempted import with all devices missing will just fail, and can be
+  # retried, but an import where e.g. two out of three disks in a three-way
+  # mirror are missing, will succeed. This is a problem: When the missing disks
+  # are later discovered, they won't be automatically set online, rendering the
+  # pool redundancy-less (and far slower) until such time as the system reboots.
+  #
+  # The solution is the below. poolReady checks the status of an un-imported
+  # pool, to see if *every* device is available -- in which case the pool will be
+  # in state ONLINE, as opposed to DEGRADED, FAULTED or MISSING.
+  #
+  # The import scripts then loop over this, waiting until the pool is ready or a
+  # sufficient amount of time has passed that we can assume it won't be. In the
+  # latter case it makes one last attempt at importing, allowing the system to
+  # (eventually) boot even with a degraded pool.
+  importLib = {zpoolCmd, awkCmd, cfgZfs}: ''
+    poolReady() {
+      pool="$1"
+      state="$("${zpoolCmd}" import | "${awkCmd}" "/pool: $pool/ { found = 1 }; /state:/ { if (found == 1) { print \$2; exit } }; END { if (found == 0) { print \"MISSING\" } }")"
+      if [[ "$state" = "ONLINE" ]]; then
+        return 0
+      else
+        echo "Pool $pool in state $state, waiting"
+        return 1
+      fi
+    }
+    poolImported() {
+      pool="$1"
+      "${zpoolCmd}" list "$pool" >/dev/null 2>/dev/null
+    }
+    poolImport() {
+      pool="$1"
+      "${zpoolCmd}" import -d "${cfgZfs.devNodes}" -N $ZFS_FORCE "$pool"
+    }
+  '';
+
 in
 
 {
@@ -171,8 +209,12 @@ in
         default = config.boot.zfs.enableUnstable;
         description = ''
           Request encryption keys or passwords for all encrypted datasets on import.
-
           Dataset encryption is only supported in zfsUnstable at the moment.
+          For root pools the encryption key can be supplied via both an
+          interactive prompt (keylocation=prompt) and from a file
+          (keylocation=file://). Note that for data pools the encryption key can
+          be only loaded from a file and not via interactive prompt since the
+          import is processed in a background systemd service.
         '';
       };
 
@@ -335,19 +377,26 @@ in
                   ;;
               esac
             done
-            ''] ++ (map (pool: ''
+          ''] ++ [(importLib {
+            # See comments at importLib definition.
+            zpoolCmd = "zpool";
+            awkCmd = "awk";
+            inherit cfgZfs;
+          })] ++ (map (pool: ''
             echo -n "importing root ZFS pool \"${pool}\"..."
-            trial=0
-            until msg="$(zpool import -d ${cfgZfs.devNodes} -N $ZFS_FORCE '${pool}' 2>&1)"; do
-              sleep 0.25
-              echo -n .
-              trial=$(($trial + 1))
-              if [[ $trial -eq 60 ]]; then
-                break
+            # Loop across the import until it succeeds, because the devices needed may not be discovered yet.
+            if ! poolImported "${pool}"; then
+              for trial in `seq 1 60`; do
+                poolReady "${pool}" > /dev/null && msg="$(poolImport "${pool}" 2>&1)" && break
+                sleep 1
+                echo -n .
+              done
+              echo
+              if [[ -n "$msg" ]]; then
+                echo "$msg";
               fi
-            done
-            echo
-            if [[ -n "$msg" ]]; then echo "$msg"; fi
+              poolImported "${pool}" || poolImport "${pool}"  # Try one last time, e.g. to import a degraded pool.
+            fi
             ${lib.optionalString cfgZfs.requestEncryptionCredentials ''
               zfs load-key -a
             ''}
@@ -391,9 +440,26 @@ in
               Type = "oneshot";
               RemainAfterExit = true;
             };
-            script = ''
-              zpool_cmd="${packages.zfsUser}/sbin/zpool"
-              ("$zpool_cmd" list "${pool}" >/dev/null) || "$zpool_cmd" import -d ${cfgZfs.devNodes} -N ${optionalString cfgZfs.forceImportAll "-f"} "${pool}"
+            script = (importLib {
+              # See comments at importLib definition.
+              zpoolCmd="${packages.zfsUser}/sbin/zpool";
+              awkCmd="${pkgs.gawk}/bin/awk";
+              inherit cfgZfs;
+            }) + ''
+              poolImported "${pool}" && exit
+              echo -n "importing ZFS pool \"${pool}\"..."
+              # Loop across the import until it succeeds, because the devices needed may not be discovered yet.
+              for trial in `seq 1 60`; do
+                poolReady "${pool}" && poolImport "${pool}" && break
+                sleep 1
+              done
+              poolImported "${pool}" || poolImport "${pool}"  # Try one last time, e.g. to import a degraded pool.
+              if poolImported "${pool}"; then
+                ${optionalString cfgZfs.requestEncryptionCredentials "\"${packages.zfsUser}/sbin/zfs\" load-key -r \"${pool}\""}
+                echo "Successfully imported ${pool}"
+              else
+                exit 1
+              fi
             '';
           };
 
@@ -403,6 +469,9 @@ in
           nameValuePair "zfs-sync-${pool}" {
             description = "Sync ZFS pool \"${pool}\"";
             wantedBy = [ "shutdown.target" ];
+            unitConfig = {
+              DefaultDependencies = false;
+            };
             serviceConfig = {
               Type = "oneshot";
               RemainAfterExit = true;
@@ -411,12 +480,15 @@ in
               ${packages.zfsUser}/sbin/zfs set nixos:shutdown-time="$(date)" "${pool}"
             '';
           };
+        createZfsService = serv:
+          nameValuePair serv {
+            after = [ "systemd-modules-load.service" ];
+            wantedBy = [ "zfs.target" ];
+          };
 
-      in listToAttrs (map createImportService dataPools ++ map createSyncService allPools) // {
-        "zfs-mount" = { after = [ "systemd-modules-load.service" ]; };
-        "zfs-share" = { after = [ "systemd-modules-load.service" ]; };
-        "zfs-zed" = { after = [ "systemd-modules-load.service" ]; };
-      };
+      in listToAttrs (map createImportService dataPools ++
+                      map createSyncService allPools ++
+                      map createZfsService [ "zfs-mount" "zfs-share" "zfs-zed" ]);
 
       systemd.targets."zfs-import" =
         let
@@ -425,6 +497,7 @@ in
           {
             requires = services;
             after = services;
+            wantedBy = [ "zfs.target" ];
           };
 
       systemd.targets."zfs".wantedBy = [ "multi-user.target" ];
diff --git a/nixos/modules/tasks/network-interfaces-scripted.nix b/nixos/modules/tasks/network-interfaces-scripted.nix
index e754a1e8718d..f3f6a19318a2 100644
--- a/nixos/modules/tasks/network-interfaces-scripted.nix
+++ b/nixos/modules/tasks/network-interfaces-scripted.nix
@@ -7,7 +7,6 @@ let
 
   cfg = config.networking;
   interfaces = attrValues cfg.interfaces;
-  hasVirtuals = any (i: i.virtual) interfaces;
 
   slaves = concatMap (i: i.interfaces) (attrValues cfg.bonds)
     ++ concatMap (i: i.interfaces) (attrValues cfg.bridges)
@@ -209,7 +208,7 @@ let
                   ''
                      echo "${cidr}" >> $state
                      echo -n "adding route ${cidr}... "
-                     if out=$(ip route add "${cidr}" ${options} ${via} dev "${i.name}" 2>&1); then
+                     if out=$(ip route add "${cidr}" ${options} ${via} dev "${i.name}" proto static 2>&1); then
                        echo "done"
                      elif ! echo "$out" | grep "File exists" >/dev/null 2>&1; then
                        echo "'ip route add "${cidr}" ${options} ${via} dev "${i.name}"' failed: $out"
diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix
index 14f9b9567515..7053aa57f803 100644
--- a/nixos/modules/tasks/network-interfaces.nix
+++ b/nixos/modules/tasks/network-interfaces.nix
@@ -46,22 +46,6 @@ let
     '';
   });
 
-  # Collect all interfaces that are defined for a device
-  # as device:interface key:value pairs.
-  wlanDeviceInterfaces =
-    let
-      allDevices = unique (mapAttrsToList (_: v: v.device) cfg.wlanInterfaces);
-      interfacesOfDevice = d: filterAttrs (_: v: v.device == d) cfg.wlanInterfaces;
-    in
-      genAttrs allDevices (d: interfacesOfDevice d);
-
-  # Convert device:interface key:value pairs into a list, and if it exists,
-  # place the interface which is named after the device at the beginning.
-  wlanListDeviceFirst = device: interfaces:
-    if hasAttr device interfaces
-    then mapAttrsToList (n: v: v//{_iName=n;}) (filterAttrs (n: _: n==device) interfaces) ++ mapAttrsToList (n: v: v//{_iName=n;}) (filterAttrs (n: _: n!=device) interfaces)
-    else mapAttrsToList (n: v: v // {_iName = n;}) interfaces;
-
   # We must escape interfaces due to the systemd interpretation
   subsystemDevice = interface:
     "sys-subsystem-net-devices-${escapeSystemdPath interface}.device";
@@ -1069,7 +1053,7 @@ in
       };
     } // (listToAttrs (flip map interfaces (i:
       let
-        deviceDependency = if config.boot.isContainer
+        deviceDependency = if (config.boot.isContainer || i.name == "lo")
           then []
           else [ (subsystemDevice i.name) ];
       in
diff --git a/nixos/modules/tasks/scsi-link-power-management.nix b/nixos/modules/tasks/scsi-link-power-management.nix
index 484c0a0186d7..69599bda6d32 100644
--- a/nixos/modules/tasks/scsi-link-power-management.nix
+++ b/nixos/modules/tasks/scsi-link-power-management.nix
@@ -2,7 +2,20 @@
 
 with lib;
 
-let cfg = config.powerManagement.scsiLinkPolicy; in
+let
+
+  cfg = config.powerManagement.scsiLinkPolicy;
+
+  kernel = config.boot.kernelPackages.kernel;
+
+  allowedValues = [
+    "min_power"
+    "max_performance"
+    "medium_power"
+    "med_power_with_dipm"
+  ];
+
+in
 
 {
   ###### interface
@@ -11,10 +24,13 @@ let cfg = config.powerManagement.scsiLinkPolicy; in
 
     powerManagement.scsiLinkPolicy = mkOption {
       default = null;
-      type = types.nullOr (types.enum [ "min_power" "max_performance" "medium_power" ]);
+      type = types.nullOr (types.enum allowedValues);
       description = ''
         SCSI link power management policy. The kernel default is
         "max_performance".
+        </para><para>
+        "med_power_with_dipm" is supported by kernel versions
+        4.15 and newer.
       '';
     };
 
@@ -24,6 +40,12 @@ let cfg = config.powerManagement.scsiLinkPolicy; in
   ###### implementation
 
   config = mkIf (cfg != null) {
+
+    assertions = singleton {
+      assertion = (cfg == "med_power_with_dipm") -> versionAtLeast kernel.version "4.15";
+      message = "med_power_with_dipm is not supported for kernels older than 4.15";
+    };
+
     services.udev.extraRules = ''
       SUBSYSTEM=="scsi_host", ACTION=="add", KERNEL=="host*", ATTR{link_power_management_policy}="${cfg}"
     '';
diff --git a/nixos/modules/tasks/swraid.nix b/nixos/modules/tasks/swraid.nix
index d6cb1c96ef46..1b142fb8fd36 100644
--- a/nixos/modules/tasks/swraid.nix
+++ b/nixos/modules/tasks/swraid.nix
@@ -6,7 +6,7 @@
 
   services.udev.packages = [ pkgs.mdadm ];
 
-  boot.initrd.availableKernelModules = [ "md_mod" "raid0" "raid1" "raid456" ];
+  boot.initrd.availableKernelModules = [ "md_mod" "raid0" "raid1" "raid10" "raid456" ];
 
   boot.initrd.extraUdevRulesCommands = ''
     cp -v ${pkgs.mdadm}/lib/udev/rules.d/*.rules $out/
diff --git a/nixos/modules/testing/test-instrumentation.nix b/nixos/modules/testing/test-instrumentation.nix
index 3d46ba72493c..114e0ca39fa2 100644
--- a/nixos/modules/testing/test-instrumentation.nix
+++ b/nixos/modules/testing/test-instrumentation.nix
@@ -6,10 +6,6 @@
 with lib;
 with import ../../lib/qemu-flags.nix { inherit pkgs; };
 
-let
-  kernel = config.boot.kernelPackages.kernel;
-in
-
 {
 
   # This option is a dummy that if used in conjunction with
@@ -126,7 +122,7 @@ in
     networking.usePredictableInterfaceNames = false;
 
     # Make it easy to log in as root when running the test interactively.
-    users.extraUsers.root.initialHashedPassword = mkOverride 150 "";
+    users.users.root.initialHashedPassword = mkOverride 150 "";
 
     services.xserver.displayManager.job.logToJournal = true;
 
diff --git a/nixos/modules/virtualisation/azure-image.nix b/nixos/modules/virtualisation/azure-image.nix
index cb756842f369..dd2108ccc379 100644
--- a/nixos/modules/virtualisation/azure-image.nix
+++ b/nixos/modules/virtualisation/azure-image.nix
@@ -2,13 +2,13 @@
 
 with lib;
 let
-  diskSize = 30720;
+  diskSize = 2048;
 in
 {
   system.build.azureImage = import ../../lib/make-disk-image.nix {
     name = "azure-image";
     postVM = ''
-      ${pkgs.vmTools.qemu-220}/bin/qemu-img convert -f raw -o subformat=fixed -O vpc $diskImage $out/disk.vhd
+      ${pkgs.vmTools.qemu}/bin/qemu-img convert -f raw -o subformat=fixed,force_size -O vpc $diskImage $out/disk.vhd
     '';
     configFile = ./azure-config-user.nix;
     format = "raw";
diff --git a/nixos/modules/virtualisation/azure-qemu-220-no-etc-install.patch b/nixos/modules/virtualisation/azure-qemu-220-no-etc-install.patch
deleted file mode 100644
index 81d29feea3de..000000000000
--- a/nixos/modules/virtualisation/azure-qemu-220-no-etc-install.patch
+++ /dev/null
@@ -1,14 +0,0 @@
-diff --git a/Makefile b/Makefile
-index d6b9dc1..ce7c493 100644
---- a/Makefile
-+++ b/Makefile
-@@ -384,8 +384,7 @@ install-confdir:
- install-sysconfig: install-datadir install-confdir
- 	$(INSTALL_DATA) $(SRC_PATH)/sysconfigs/target/target-x86_64.conf "$(DESTDIR)$(qemu_confdir)"
- 
--install: all $(if $(BUILD_DOCS),install-doc) install-sysconfig \
--install-datadir install-localstatedir
-+install: all $(if $(BUILD_DOCS),install-doc) install-datadir
- ifneq ($(TOOLS),)
- 	$(call install-prog,$(TOOLS),$(DESTDIR)$(bindir))
- endif
diff --git a/nixos/modules/virtualisation/docker.nix b/nixos/modules/virtualisation/docker.nix
index a9a2095499a7..a1a32c1c59a1 100644
--- a/nixos/modules/virtualisation/docker.nix
+++ b/nixos/modules/virtualisation/docker.nix
@@ -141,7 +141,7 @@ in
 
   config = mkIf cfg.enable (mkMerge [{
       environment.systemPackages = [ cfg.package ];
-      users.extraGroups.docker.gid = config.ids.gids.docker;
+      users.groups.docker.gid = config.ids.gids.docker;
       systemd.packages = [ cfg.package ];
 
       systemd.services.docker = {
diff --git a/nixos/modules/virtualisation/gce-images.nix b/nixos/modules/virtualisation/gce-images.nix
index 8a9bda1b60c2..575bbaadbcdb 100644
--- a/nixos/modules/virtualisation/gce-images.nix
+++ b/nixos/modules/virtualisation/gce-images.nix
@@ -3,6 +3,7 @@ let self = {
   "15.09" = "gs://nixos-cloud-images/nixos-15.09.425.7870f20-x86_64-linux.raw.tar.gz";
   "16.03" = "gs://nixos-cloud-images/nixos-image-16.03.847.8688c17-x86_64-linux.raw.tar.gz";
   "17.03" = "gs://nixos-cloud-images/nixos-image-17.03.1082.4aab5c5798-x86_64-linux.raw.tar.gz";
+  "18.03" = "gs://nixos-cloud-images/nixos-image-18.03.132536.fdb5ba4cdf9-x86_64-linux.raw.tar.gz";
 
-  latest = self."17.03";
+  latest = self."18.03";
 }; in self
diff --git a/nixos/modules/virtualisation/google-compute-image.nix b/nixos/modules/virtualisation/google-compute-image.nix
index 374a84332357..de2c43b8a40a 100644
--- a/nixos/modules/virtualisation/google-compute-image.nix
+++ b/nixos/modules/virtualisation/google-compute-image.nix
@@ -257,7 +257,7 @@ in
               echo "Setup of ssh host keys from http://metadata.google.internal/computeMetadata/v1/instance/attributes/ failed."
               false
           fi
-          rm -f $SSH_HOST_KEYS_DIR
+          rm -rf $SSH_HOST_KEYS_DIR
         '';
       serviceConfig.Type = "oneshot";
       serviceConfig.RemainAfterExit = true;
diff --git a/nixos/modules/virtualisation/kvmgt.nix b/nixos/modules/virtualisation/kvmgt.nix
new file mode 100644
index 000000000000..fc0bedb68bd0
--- /dev/null
+++ b/nixos/modules/virtualisation/kvmgt.nix
@@ -0,0 +1,64 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.virtualisation.kvmgt;
+  kernelPackages = config.boot.kernelPackages;
+  vgpuOptions = {
+    uuid = mkOption {
+      type = types.string;
+      description = "UUID of VGPU device. You can generate one with <package>libossp_uuid</package>.";
+    };
+  };
+in {
+  options = {
+    virtualisation.kvmgt = {
+      enable = mkEnableOption ''
+        KVMGT (iGVT-g) VGPU support. Allows Qemu/KVM guests to share host's Intel integrated graphics card.
+        Currently only one graphical device can be shared
+      '';
+      # multi GPU support is under the question
+      device = mkOption {
+        type = types.string;
+        default = "0000:00:02.0";
+        description = "PCI ID of graphics card. You can figure it with <command>ls /sys/class/mdev_bus</command>.";
+      };
+      vgpus = mkOption {
+        default = {};
+        type = with types; attrsOf (submodule [ { options = vgpuOptions; } ]);
+        description = ''
+          Virtual GPUs to be used in Qemu. You can find devices via <command>ls /sys/bus/pci/devices/*/mdev_supported_types</command>
+          and find info about device via <command>cat /sys/bus/pci/devices/*/mdev_supported_types/i915-GVTg_V5_4/description</command>
+        '';
+        example = {
+          "i915-GVTg_V5_8" = {
+            uuid = "a297db4a-f4c2-11e6-90f6-d3b88d6c9525";
+          };
+        };
+      };
+    };
+  };
+
+  config = mkIf cfg.enable {
+    assertions = singleton {
+      assertion = versionAtLeast kernelPackages.kernel.version "4.16";
+      message = "KVMGT is not properly supported for kernels older than 4.16";
+    };
+    boot.kernelParams = [ "i915.enable_gvt=1" ];
+    systemd.services = mapAttrs' (name: value:
+      nameValuePair "kvmgt-${name}" {
+        description = "KVMGT VGPU ${name}";
+        serviceConfig = {
+          Type = "oneshot";
+          RemainAfterExit = true;
+          ExecStart = "${pkgs.runtimeShell} -c 'echo ${value.uuid} > /sys/bus/pci/devices/${cfg.device}/mdev_supported_types/${name}/create'";
+          ExecStop = "${pkgs.runtimeShell} -c 'echo 1 > /sys/bus/pci/devices/${cfg.device}/${value.uuid}/remove'";
+        };
+        wantedBy = [ "multi-user.target" ];
+      }
+    ) cfg.vgpus;
+  };
+
+  meta.maintainers = with maintainers; [ gnidorah ];
+}
diff --git a/nixos/modules/virtualisation/libvirtd.nix b/nixos/modules/virtualisation/libvirtd.nix
index 024db7f87c2e..87409db4320c 100644
--- a/nixos/modules/virtualisation/libvirtd.nix
+++ b/nixos/modules/virtualisation/libvirtd.nix
@@ -108,7 +108,7 @@ in {
 
     boot.kernelModules = [ "tun" ];
 
-    users.extraGroups.libvirtd.gid = config.ids.gids.libvirtd;
+    users.groups.libvirtd.gid = config.ids.gids.libvirtd;
 
     systemd.packages = [ pkgs.libvirt ];
 
diff --git a/nixos/modules/virtualisation/lxc-container.nix b/nixos/modules/virtualisation/lxc-container.nix
index 0208787e7795..dbb7b881955a 100644
--- a/nixos/modules/virtualisation/lxc-container.nix
+++ b/nixos/modules/virtualisation/lxc-container.nix
@@ -8,7 +8,7 @@ with lib;
   ];
 
   # Allow the user to login as root without password.
-  users.extraUsers.root.initialHashedPassword = mkOverride 150 "";
+  users.users.root.initialHashedPassword = mkOverride 150 "";
 
   # Some more help text.
   services.mingetty.helpLine =
diff --git a/nixos/modules/virtualisation/lxd.nix b/nixos/modules/virtualisation/lxd.nix
index 3e76cdacfc4b..505c11abd208 100644
--- a/nixos/modules/virtualisation/lxd.nix
+++ b/nixos/modules/virtualisation/lxd.nix
@@ -73,9 +73,9 @@ in
 
     };
 
-    users.extraGroups.lxd.gid = config.ids.gids.lxd;
+    users.groups.lxd.gid = config.ids.gids.lxd;
 
-    users.extraUsers.root = {
+    users.users.root = {
       subUidRanges = [ { startUid = 1000000; count = 65536; } ];
       subGidRanges = [ { startGid = 1000000; count = 65536; } ];
     };
diff --git a/nixos/modules/virtualisation/openvswitch.nix b/nixos/modules/virtualisation/openvswitch.nix
index 38b138e06326..bb8b9172f23f 100644
--- a/nixos/modules/virtualisation/openvswitch.nix
+++ b/nixos/modules/virtualisation/openvswitch.nix
@@ -51,9 +51,6 @@ in {
     # Where the communication sockets live
     runDir = "/var/run/openvswitch";
 
-    # Where the config database live (can't be in nix-store)
-    stateDir = "/var/db/openvswitch";
-
     # The path to the an initialized version of the database
     db = pkgs.stdenv.mkDerivation {
       name = "vswitch.db";
diff --git a/nixos/modules/virtualisation/rkt.nix b/nixos/modules/virtualisation/rkt.nix
index 98be4f680c3a..fd662b52df52 100644
--- a/nixos/modules/virtualisation/rkt.nix
+++ b/nixos/modules/virtualisation/rkt.nix
@@ -59,6 +59,6 @@ in
       };
     };
 
-    users.extraGroups.rkt = {};
+    users.groups.rkt = {};
   };
 }
diff --git a/nixos/modules/virtualisation/virtualbox-guest.nix b/nixos/modules/virtualisation/virtualbox-guest.nix
index 5da4b7e3bafd..78c6f740788e 100644
--- a/nixos/modules/virtualisation/virtualbox-guest.nix
+++ b/nixos/modules/virtualisation/virtualbox-guest.nix
@@ -44,7 +44,7 @@ in
     boot.supportedFilesystems = [ "vboxsf" ];
     boot.initrd.supportedFilesystems = [ "vboxsf" ];
 
-    users.extraGroups.vboxsf.gid = config.ids.gids.vboxsf;
+    users.groups.vboxsf.gid = config.ids.gids.vboxsf;
 
     systemd.services.virtualbox =
       { description = "VirtualBox Guest Services";
diff --git a/nixos/modules/virtualisation/virtualbox-host.nix b/nixos/modules/virtualisation/virtualbox-host.nix
index 885d752577d5..8adf3aa919d8 100644
--- a/nixos/modules/virtualisation/virtualbox-host.nix
+++ b/nixos/modules/virtualisation/virtualbox-host.nix
@@ -86,7 +86,7 @@ in
       "VirtualBox"
     ]));
 
-    users.extraGroups.vboxusers.gid = config.ids.gids.vboxusers;
+    users.groups.vboxusers.gid = config.ids.gids.vboxusers;
 
     services.udev.extraRules =
       ''
diff --git a/nixos/modules/virtualisation/virtualbox-image.nix b/nixos/modules/virtualisation/virtualbox-image.nix
index 64f145f77ca3..475852d1546c 100644
--- a/nixos/modules/virtualisation/virtualbox-image.nix
+++ b/nixos/modules/virtualisation/virtualbox-image.nix
@@ -17,12 +17,40 @@ in {
           The size of the VirtualBox base image in MiB.
         '';
       };
+      memorySize = mkOption {
+        type = types.int;
+        default = 1536;
+        description = ''
+          The amount of RAM the VirtualBox appliance can use in MiB.
+        '';
+      };
+      vmDerivationName = mkOption {
+        type = types.str;
+        default = "nixos-ova-${config.system.nixos.label}-${pkgs.stdenv.system}";
+        description = ''
+          The name of the derivation for the VirtualBox appliance.
+        '';
+      };
+      vmName = mkOption {
+        type = types.str;
+        default = "NixOS ${config.system.nixos.label} (${pkgs.stdenv.system})";
+        description = ''
+          The name of the VirtualBox appliance.
+        '';
+      };
+      vmFileName = mkOption {
+        type = types.str;
+        default = "nixos-${config.system.nixos.label}-${pkgs.stdenv.system}.ova";
+        description = ''
+          The file name of the VirtualBox appliance.
+        '';
+      };
     };
   };
 
   config = {
     system.build.virtualBoxOVA = import ../../lib/make-disk-image.nix {
-      name = "nixos-ova-${config.system.nixos.label}-${pkgs.stdenv.system}";
+      name = cfg.vmDerivationName;
 
       inherit pkgs lib config;
       partitionTableType = "legacy";
@@ -37,11 +65,11 @@ in {
           VBoxManage internalcommands createrawvmdk -filename disk.vmdk -rawdisk $diskImage
 
           echo "creating VirtualBox VM..."
-          vmName="NixOS ${config.system.nixos.label} (${pkgs.stdenv.system})"
+          vmName="${cfg.vmName}";
           VBoxManage createvm --name "$vmName" --register \
             --ostype ${if pkgs.stdenv.system == "x86_64-linux" then "Linux26_64" else "Linux26"}
           VBoxManage modifyvm "$vmName" \
-            --memory 1536 --acpi on --vram 32 \
+            --memory ${toString cfg.memorySize} --acpi on --vram 32 \
             ${optionalString (pkgs.stdenv.system == "i686-linux") "--pae on"} \
             --nictype1 virtio --nic1 nat \
             --audiocontroller ac97 --audio alsa \
@@ -53,7 +81,7 @@ in {
 
           echo "exporting VirtualBox VM..."
           mkdir -p $out
-          fn="$out/nixos-${config.system.nixos.label}-${pkgs.stdenv.system}.ova"
+          fn="$out/${cfg.vmFileName}"
           VBoxManage export "$vmName" --output "$fn"
 
           rm -v $diskImage
diff --git a/nixos/release-combined.nix b/nixos/release-combined.nix
index 989764874c48..66b253c230f1 100644
--- a/nixos/release-combined.nix
+++ b/nixos/release-combined.nix
@@ -88,12 +88,14 @@ in rec {
         (all nixos.tests.env)
         (all nixos.tests.ipv6)
         (all nixos.tests.i3wm)
-        (all nixos.tests.keymap.azerty)
-        (all nixos.tests.keymap.colemak)
-        (all nixos.tests.keymap.dvorak)
-        (all nixos.tests.keymap.dvp)
-        (all nixos.tests.keymap.neo)
-        (all nixos.tests.keymap.qwertz)
+        # 2018-06-06: keymap tests temporarily removed from tested job
+        # since non-deterministic failure are blocking the channel (#41538)
+        #(all nixos.tests.keymap.azerty)
+        #(all nixos.tests.keymap.colemak)
+        #(all nixos.tests.keymap.dvorak)
+        #(all nixos.tests.keymap.dvp)
+        #(all nixos.tests.keymap.neo)
+        #(all nixos.tests.keymap.qwertz)
         (all nixos.tests.plasma5)
         #(all nixos.tests.lightdm)
         (all nixos.tests.login)
diff --git a/nixos/release.nix b/nixos/release.nix
index 4c0bb7bfb756..f11f372335a0 100644
--- a/nixos/release.nix
+++ b/nixos/release.nix
@@ -248,6 +248,7 @@ in rec {
   tests.avahi = callTest tests/avahi.nix {};
   tests.beegfs = callTest tests/beegfs.nix {};
   tests.bittorrent = callTest tests/bittorrent.nix {};
+  tests.bind = callTest tests/bind.nix {};
   tests.blivet = callTest tests/blivet.nix {};
   tests.boot = callSubTests tests/boot.nix {};
   tests.boot-stage1 = callTest tests/boot-stage1.nix {};
@@ -288,6 +289,7 @@ in rec {
   tests.flatpak = callTest tests/flatpak.nix {};
   tests.firewall = callTest tests/firewall.nix {};
   tests.fwupd = callTest tests/fwupd.nix {};
+  tests.gdk-pixbuf = callTest tests/gdk-pixbuf.nix {};
   #tests.gitlab = callTest tests/gitlab.nix {};
   tests.gitolite = callTest tests/gitolite.nix {};
   tests.gjs = callTest tests/gjs.nix {};
@@ -297,12 +299,16 @@ in rec {
   tests.gnome3-gdm = callTest tests/gnome3-gdm.nix {};
   tests.grafana = callTest tests/grafana.nix {};
   tests.graphite = callTest tests/graphite.nix {};
+  tests.hadoop.hdfs = callTestOnMatchingSystems [ "x86_64-linux" ] tests/hadoop/hdfs.nix {};
+  tests.hadoop.yarn = callTestOnMatchingSystems [ "x86_64-linux" ] tests/hadoop/yarn.nix {};
   tests.hardened = callTest tests/hardened.nix { };
+  tests.haproxy = callTest tests/haproxy.nix {};
   tests.hibernate = callTest tests/hibernate.nix {};
   tests.hitch = callTest tests/hitch {};
   tests.home-assistant = callTest tests/home-assistant.nix { };
   tests.hound = callTest tests/hound.nix {};
   tests.hocker-fetchdocker = callTest tests/hocker-fetchdocker {};
+  tests.hydra = callTest tests/hydra {};
   tests.i3wm = callTest tests/i3wm.nix {};
   tests.iftop = callTest tests/iftop.nix {};
   tests.initrd-network-ssh = callTest tests/initrd-network-ssh {};
@@ -310,6 +316,7 @@ in rec {
   tests.influxdb = callTest tests/influxdb.nix {};
   tests.ipv6 = callTest tests/ipv6.nix {};
   tests.jenkins = callTest tests/jenkins.nix {};
+  tests.ostree = callTest tests/ostree.nix {};
   tests.osquery = callTest tests/osquery.nix {};
   tests.plasma5 = callTest tests/plasma5.nix {};
   tests.plotinus = callTest tests/plotinus.nix {};
@@ -330,9 +337,11 @@ in rec {
   #tests.logstash = callTest tests/logstash.nix {};
   tests.mathics = callTest tests/mathics.nix {};
   tests.matrix-synapse = callTest tests/matrix-synapse.nix {};
+  tests.memcached = callTest tests/memcached.nix {};
   tests.mesos = callTest tests/mesos.nix {};
   tests.misc = callTest tests/misc.nix {};
   tests.mongodb = callTest tests/mongodb.nix {};
+  tests.mpd = callTest tests/mpd.nix {};
   tests.mumble = callTest tests/mumble.nix {};
   tests.munin = callTest tests/munin.nix {};
   tests.mutableUsers = callTest tests/mutable-users.nix {};
@@ -358,6 +367,7 @@ in rec {
   tests.nsd = callTest tests/nsd.nix {};
   tests.openssh = callTest tests/openssh.nix {};
   tests.openldap = callTest tests/openldap.nix {};
+  tests.opensmtpd = callTest tests/opensmtpd.nix {};
   tests.owncloud = callTest tests/owncloud.nix {};
   tests.pam-oath-login = callTest tests/pam-oath-login.nix {};
   tests.peerflix = callTest tests/peerflix.nix {};
@@ -383,6 +393,7 @@ in rec {
   tests.sddm = callSubTests tests/sddm.nix {};
   tests.simple = callTest tests/simple.nix {};
   tests.slim = callTest tests/slim.nix {};
+  tests.slurm = callTest tests/slurm.nix {};
   tests.smokeping = callTest tests/smokeping.nix {};
   tests.snapper = callTest tests/snapper.nix {};
   tests.statsd = callTest tests/statsd.nix {};
@@ -392,6 +403,7 @@ in rec {
   tests.switchTest = callTest tests/switch-test.nix {};
   tests.taskserver = callTest tests/taskserver.nix {};
   tests.tomcat = callTest tests/tomcat.nix {};
+  tests.tor = callTest tests/tor.nix {};
   tests.transmission = callTest tests/transmission.nix {};
   tests.udisks2 = callTest tests/udisks2.nix {};
   tests.vault = callTest tests/vault.nix {};
@@ -402,8 +414,10 @@ in rec {
   tests.xfce = callTest tests/xfce.nix {};
   tests.xmonad = callTest tests/xmonad.nix {};
   tests.xrdp = callTest tests/xrdp.nix {};
+  tests.xss-lock = callTest tests/xss-lock.nix {};
   tests.yabar = callTest tests/yabar.nix {};
   tests.zookeeper = callTest tests/zookeeper.nix {};
+  tests.morty = callTest tests/morty.nix { };
 
   /* Build a bunch of typical closures so that Hydra can keep track of
      the evolution of closure sizes. */
diff --git a/nixos/tests/acme.nix b/nixos/tests/acme.nix
index 21b0fedcfefe..c5898db6b325 100644
--- a/nixos/tests/acme.nix
+++ b/nixos/tests/acme.nix
@@ -29,7 +29,7 @@ in import ./make-test.nix {
   name = "acme";
 
   nodes = {
-    letsencrypt = ./common/letsencrypt.nix;
+    letsencrypt = ./common/letsencrypt;
 
     webserver = { config, pkgs, ... }: {
       imports = [ commonConfig ];
diff --git a/nixos/tests/atd.nix b/nixos/tests/atd.nix
index 5260c8ddfb82..ef848c2a374f 100644
--- a/nixos/tests/atd.nix
+++ b/nixos/tests/atd.nix
@@ -9,7 +9,7 @@ import ./make-test.nix ({ pkgs, lib, ... }:
   machine =
     { config, pkgs, ... }:
     { services.atd.enable = true;
-      users.extraUsers.alice = { isNormalUser = true; };
+      users.users.alice = { isNormalUser = true; };
     };
 
   # "at" has a resolution of 1 minute
diff --git a/nixos/tests/bind.nix b/nixos/tests/bind.nix
new file mode 100644
index 000000000000..1f8c1dc7be40
--- /dev/null
+++ b/nixos/tests/bind.nix
@@ -0,0 +1,27 @@
+import ./make-test.nix {
+  name = "bind";
+
+  machine = { pkgs, lib, ... }: {
+    services.bind.enable = true;
+    services.bind.extraOptions = "empty-zones-enable no;";
+    services.bind.zones = lib.singleton {
+      name = ".";
+      file = pkgs.writeText "root.zone" ''
+        $TTL 3600
+        . IN SOA ns.example.org. admin.example.org. ( 1 3h 1h 1w 1d )
+        . IN NS ns.example.org.
+
+        ns.example.org. IN A    192.168.0.1
+        ns.example.org. IN AAAA abcd::1
+
+        1.0.168.192.in-addr.arpa IN PTR ns.example.org.
+      '';
+    };
+  };
+
+  testScript = ''
+    $machine->waitForUnit('bind.service');
+    $machine->waitForOpenPort(53);
+    $machine->succeed('host 192.168.0.1 127.0.0.1 | grep -qF ns.example.org');
+  '';
+}
diff --git a/nixos/tests/cjdns.nix b/nixos/tests/cjdns.nix
index 4d3b58abc6e5..db89c496944e 100644
--- a/nixos/tests/cjdns.nix
+++ b/nixos/tests/cjdns.nix
@@ -2,7 +2,6 @@ let
   carolKey = "2d2a338b46f8e4a8c462f0c385b481292a05f678e19a2b82755258cf0f0af7e2";
   carolPubKey = "n932l3pjvmhtxxcdrqq2qpw5zc58f01vvjx01h4dtd1bb0nnu2h0.k";
   carolPassword = "678287829ce4c67bc8b227e56d94422ee1b85fa11618157b2f591de6c6322b52";
-  carolIp4 = "192.168.0.9";
 
   basicConfig =
     { config, pkgs, ... }:
@@ -44,9 +43,7 @@ import ./make-test.nix ({ pkgs, ...} : {
       bob =
         { config, lib, nodes, ... }:
 
-        let carolIp4 = lib.mkForce nodes.carol.config.networking.interfaces.eth1; in
-
-          { imports = [ basicConfig ];
+        { imports = [ basicConfig ];
 
           networking.interfaces.eth1.ipv4.addresses = [
             { address = "192.168.0.2"; prefixLength = 24; }
@@ -67,10 +64,7 @@ import ./make-test.nix ({ pkgs, ...} : {
       # but knows neither Alice or Bob.
       carol =
         { config, lib, nodes, ... }:
-          let
-            carolIp4 = (lib.mkForce nodes.carol.config.networking.interfaces.eth1);
-          in
-          { imports = [ basicConfig ];
+        { imports = [ basicConfig ];
 
           environment.etc."cjdns.keys".text = ''
             CJDNS_PRIVATE_KEY=${carolKey}
diff --git a/nixos/tests/common/letsencrypt.nix b/nixos/tests/common/letsencrypt/default.nix
index 7c6b3b29e36d..4b841a03cc47 100644
--- a/nixos/tests/common/letsencrypt.nix
+++ b/nixos/tests/common/letsencrypt/default.nix
@@ -17,7 +17,7 @@
 # A configuration example of a full node setup using this would be this:
 #
 # {
-#   letsencrypt = import ./common/letsencrypt.nix;
+#   letsencrypt = import ./common/letsencrypt;
 #
 #   example = { nodes, ... }: {
 #     networking.nameservers = [
@@ -30,14 +30,14 @@
 # }
 #
 # By default, this module runs a local resolver, generated using resolver.nix
-# from the same directory to automatically discover all zones in the network.
+# from the parent directory to automatically discover all zones in the network.
 #
 # If you do not want this and want to use your own resolver, you can just
 # override networking.nameservers like this:
 #
 # {
 #   letsencrypt = { nodes, ... }: {
-#     imports = [ ./common/letsencrypt.nix ];
+#     imports = [ ./common/letsencrypt ];
 #     networking.nameservers = [
 #       nodes.myresolver.config.networking.primaryIPAddress
 #     ];
@@ -164,8 +164,8 @@ let
         -e 's,exec \./bin/,,' \
         test/startservers.py
 
-      cat "${snakeOilCa}/ca.key" > test/test-ca.key
-      cat "${snakeOilCa}/ca.pem" > test/test-ca.pem
+      cat ${lib.escapeShellArg snakeOilCerts.ca.key} > test/test-ca.key
+      cat ${lib.escapeShellArg snakeOilCerts.ca.cert} > test/test-ca.pem
     '';
 
     # Until vendored pkcs11 is go 1.9 compatible
@@ -173,6 +173,21 @@ let
       rm -r go/src/github.com/letsencrypt/boulder/vendor/github.com/miekg/pkcs11
     '';
 
+    # XXX: Temporarily brought back putting the source code in the output,
+    # since e95f17e2720e67e2eabd59d7754c814d3e27a0b2 was removing that from
+    # buildGoPackage.
+    preInstall = ''
+      mkdir -p $out
+      pushd "$NIX_BUILD_TOP/go"
+      while read f; do
+        echo "$f" | grep -q '^./\(src\|pkg/[^/]*\)/${goPackagePath}' \
+          || continue
+        mkdir -p "$(dirname "$out/share/go/$f")"
+        cp "$NIX_BUILD_TOP/go/$f" "$out/share/go/$f"
+      done < <(find . -type f)
+      popd
+    '';
+
     extraSrcs = map mkGoDep [
       { goPackagePath = "github.com/miekg/pkcs11";
         rev           = "6dbd569b952ec150d1425722dbbe80f2c6193f83";
@@ -191,51 +206,15 @@ let
     1:/var/lib/softhsm/slot1.db
   '';
 
-  snakeOilCa = pkgs.runCommand "snakeoil-ca" {
-    buildInputs = [ pkgs.openssl ];
-  } ''
-    mkdir "$out"
-    openssl req -newkey rsa:4096 -x509 -sha256 -days 36500 \
-      -subj '/CN=Snakeoil CA' -nodes \
-      -out "$out/ca.pem" -keyout "$out/ca.key"
-  '';
-
-  createAndSignCert = fqdn: let
-    snakeoilCertConf = pkgs.writeText "snakeoil.cnf" ''
-      [req]
-      default_bits = 4096
-      prompt = no
-      default_md = sha256
-      req_extensions = req_ext
-      distinguished_name = dn
-      [dn]
-      CN = ${fqdn}
-      [req_ext]
-      subjectAltName = DNS:${fqdn}
-    '';
-  in pkgs.runCommand "snakeoil-certs-${fqdn}" {
-    buildInputs = [ pkgs.openssl ];
-  } ''
-    mkdir "$out"
-    openssl genrsa -out "$out/snakeoil.key" 4096
-    openssl req -new -key "$out/snakeoil.key" \
-      -config ${lib.escapeShellArg snakeoilCertConf} \
-      -out snakeoil.csr
-    openssl x509 -req -in snakeoil.csr -sha256 -set_serial 666 \
-      -CA "${snakeOilCa}/ca.pem" -CAkey "${snakeOilCa}/ca.key" \
-      -extfile ${lib.escapeShellArg snakeoilCertConf} \
-      -out "$out/snakeoil.pem" -days 36500
-  '';
+  snakeOilCerts = import ./snakeoil-certs.nix;
 
-  wfeCerts = createAndSignCert wfeDomain;
   wfeDomain = "acme-v01.api.letsencrypt.org";
-  wfeCertFile = "${wfeCerts}/snakeoil.pem";
-  wfeKeyFile = "${wfeCerts}/snakeoil.key";
+  wfeCertFile = snakeOilCerts.${wfeDomain}.cert;
+  wfeKeyFile = snakeOilCerts.${wfeDomain}.key;
 
-  siteCerts = createAndSignCert siteDomain;
   siteDomain = "letsencrypt.org";
-  siteCertFile = "${siteCerts}/snakeoil.pem";
-  siteKeyFile = "${siteCerts}/snakeoil.key";
+  siteCertFile = snakeOilCerts.${siteDomain}.cert;
+  siteKeyFile = snakeOilCerts.${siteDomain}.key;
 
   # Retrieved via:
   # curl -s -I https://acme-v01.api.letsencrypt.org/terms \
@@ -348,7 +327,7 @@ let
   }) components;
 
 in {
-  imports = [ ./resolver.nix ];
+  imports = [ ../resolver.nix ];
 
   options.test-support.letsencrypt.caCert = lib.mkOption {
     type = lib.types.path;
@@ -364,7 +343,7 @@ in {
       resolver.enable = let
         isLocalResolver = config.networking.nameservers == [ "127.0.0.1" ];
       in lib.mkOverride 900 isLocalResolver;
-      letsencrypt.caCert = "${snakeOilCa}/ca.pem";
+      letsencrypt.caCert = snakeOilCerts.ca.cert;
     };
 
     # This has priority 140, because modules/testing/test-instrumentation.nix
diff --git a/nixos/tests/common/letsencrypt/mkcerts.nix b/nixos/tests/common/letsencrypt/mkcerts.nix
new file mode 100644
index 000000000000..3b4a589e4142
--- /dev/null
+++ b/nixos/tests/common/letsencrypt/mkcerts.nix
@@ -0,0 +1,69 @@
+{ pkgs ? import <nixpkgs> {}
+, lib ? pkgs.lib
+
+, domains ? [ "acme-v01.api.letsencrypt.org" "letsencrypt.org" ]
+}:
+
+pkgs.runCommand "letsencrypt-snakeoil-ca" {
+  nativeBuildInputs = [ pkgs.openssl ];
+} ''
+  addpem() {
+    local file="$1"; shift
+    local storeFileName="$(IFS=.; echo "$*")"
+
+    echo -n "  " >> "$out"
+
+    # Every following argument is an attribute, so let's recurse and check
+    # every attribute whether it must be quoted and write it into $out.
+    while [ -n "$1" ]; do
+      if expr match "$1" '^[a-zA-Z][a-zA-Z0-9]*$' > /dev/null; then
+        echo -n "$1" >> "$out"
+      else
+        echo -n '"' >> "$out"
+        echo -n "$1" | sed -e 's/["$]/\\&/g' >> "$out"
+        echo -n '"' >> "$out"
+      fi
+      shift
+      [ -z "$1" ] || echo -n . >> "$out"
+    done
+
+    echo " = builtins.toFile \"$storeFileName\" '''" >> "$out"
+    sed -e 's/^/    /' "$file" >> "$out"
+
+    echo "  ''';" >> "$out"
+  }
+
+  echo '# Generated via mkcert.sh in the same directory.' > "$out"
+  echo '{' >> "$out"
+
+  openssl req -newkey rsa:4096 -x509 -sha256 -days 36500 \
+    -subj '/CN=Snakeoil CA' -nodes -out ca.pem -keyout ca.key
+
+  addpem ca.key ca key
+  addpem ca.pem ca cert
+
+  ${lib.concatMapStrings (fqdn: let
+    opensslConfig = pkgs.writeText "snakeoil.cnf" ''
+      [req]
+      default_bits = 4096
+      prompt = no
+      default_md = sha256
+      req_extensions = req_ext
+      distinguished_name = dn
+      [dn]
+      CN = ${fqdn}
+      [req_ext]
+      subjectAltName = DNS:${fqdn}
+    '';
+  in ''
+    export OPENSSL_CONF=${lib.escapeShellArg opensslConfig}
+    openssl genrsa -out snakeoil.key 4096
+    openssl req -new -key snakeoil.key -out snakeoil.csr
+    openssl x509 -req -in snakeoil.csr -sha256 -set_serial 666 \
+      -CA ca.pem -CAkey ca.key -out snakeoil.pem -days 36500
+    addpem snakeoil.key ${lib.escapeShellArg fqdn} key
+    addpem snakeoil.pem ${lib.escapeShellArg fqdn} cert
+  '') domains}
+
+  echo '}' >> "$out"
+''
diff --git a/nixos/tests/common/letsencrypt/mkcerts.sh b/nixos/tests/common/letsencrypt/mkcerts.sh
new file mode 100755
index 000000000000..cc7f8ca650dd
--- /dev/null
+++ b/nixos/tests/common/letsencrypt/mkcerts.sh
@@ -0,0 +1,6 @@
+#!/usr/bin/env nix-shell
+#!nix-shell -p nix bash -i bash
+set -e
+cd "$(dirname "$0")"
+storepath="$(nix-build --no-out-link mkcerts.nix)"
+cat "$storepath" > snakeoil-certs.nix
diff --git a/nixos/tests/common/letsencrypt/snakeoil-certs.nix b/nixos/tests/common/letsencrypt/snakeoil-certs.nix
new file mode 100644
index 000000000000..c3d29ab8f163
--- /dev/null
+++ b/nixos/tests/common/letsencrypt/snakeoil-certs.nix
@@ -0,0 +1,253 @@
+# Generated via mkcert.sh in the same directory.
+{
+  ca.key = builtins.toFile "ca.key" ''
+    -----BEGIN PRIVATE KEY-----
+    MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDfdVxC/4HwhuzD
+    9or9CDDu3TBQE5lirJI5KYmfMZtfgdzEjgOzmR9AVSkn2rQeCqzM5m+YCzPO+2y7
+    0Fdk7vDORi1OdhYfUQIW6/TZ27xEjx4t82j9i705yUqTJZKjMbD830geXImJ6VGj
+    Nv/WisTHmwBspWKefYQPN68ZvYNCn0d5rYJg9uROZPJHSI0MYj9iERWIPN+xhZoS
+    xN74ILJ0rEOQfx2GHDhTr99vZYAFqbAIfh35fYulRWarUSekI+rDxa83FD8q9cMg
+    OP84KkLep2dRXXTbUWErGUOpHP55M9M7ws0RVNdl9PUSbDgChl7yYlHCde3261q/
+    zGp5dMV/t/jXXNUgRurvXc4gUKKjS4Sffvg0XVnPs3sMlZ4JNmycK9klgISVmbTK
+    VcjRRJv8Bva2NQVsJ9TIryV0QEk94DucgsC3LbhQfQdmnWVcEdzwrZHNpk9az5mn
+    w42RuvZW9L19T7xpIrdLSHaOis4VEquZjkWIhfIz0DVMeXtYEQmwqFG23Ww0utcp
+    mCW4FPvpyYs5GAPmGWfrlMxsLD/7eteot3AheC+56ZBoVBnI8FFvIX2qci+gfVDu
+    CjvDmbyS/0NvxLGqvSC1GUPmWP3TR5Fb1H8Rp+39zJHRmH+qYWlhcv6p7FlY2/6d
+    9Rkw8WKRTSCB7yeUdNNPiPopk6N4NwIDAQABAoICAQCzV0ei5dntpvwjEp3eElLj
+    glYiDnjOPt5kTjgLsg6XCmyau7ewzrXMNgz/1YE1ky+4i0EI8AS2nAdafQ2HDlXp
+    11zJWfDLVYKtztYGe1qQU6TPEEo1I4/M7waRLliP7XO0n6cL5wzjyIQi0CNolprz
+    8CzZBasutGHmrLQ1nmnYcGk2+NBo7f2yBUaFe27of3mLRVbYrrKBkU5kveiNkABp
+    r0/SipKxbbivQbm7d+TVpqiHSGDaOa54CEksOcfs7n6efOvw8qj326KtG9GJzDE6
+    7XP4U19UHe40XuR0t7Zso/FmRyO6QzNUutJt5LjXHezZ75razTcdMyr0QCU8MUHH
+    jXZxQCsbt+9AmdxUMBm1SMNVBdHYM8oiNHynlgsEj9eM6jxDEss/Uc3FeKoHl+XL
+    L6m28guIB8NivqjVzZcwhxvdiQCzYxjyqMC+/eX7aaK4NIlX2QRMoDL6mJ58Bz/8
+    V2Qxp2UNVwKJFWAmpgXC+sq6XV/TP3HkOvd0OK82Nid2QxEvfE/EmOhU63qAjgUR
+    QnteLEcJ3MkGGurs05pYBDE7ejKVz6uu2tHahFMOv+yanGP2gfivnT9a323/nTqH
+    oR5ffMEI1u/ufpWU7sWXZfL/mH1L47x87k+9wwXHCPeSigcy+hFI7t1+rYsdCmz9
+    V6QtmxZHMLanwzh5R0ipcQKCAQEA8kuZIz9JyYP6L+5qmIUxiWESihVlRCSKIqLB
+    fJ5sQ06aDBV2sqS4XnoWsHuJWUd39rulks8cg8WIQu8oJwVkFI9EpARt/+a1fRP0
+    Ncc9qiBdP6VctQGgKfe5KyOfMzIBUl3zj2cAmU6q+CW1OgdhnEl4QhgBe5XQGquZ
+    Alrd2P2jhJbMO3sNFgzTy7xPEr3KqUy+L4gtRnGOegKIh8EllmsyMRO4eIrZV2z3
+    XI+S2ZLyUn3WHYkaJqvUFrbfekgBBmbk5Ead6ImlsLsBla6MolKrVYV1kN6KT+Y+
+    plcxNpWY8bnWfw5058OWPLPa9LPfReu9rxAeGT2ZLmAhSkjGxQKCAQEA7BkBzT3m
+    SIzop9RKl5VzYbVysCYDjFU9KYMW5kBIw5ghSMnRmU7kXIZUkc6C1L/v9cTNFFLw
+    ZSF4vCHLdYLmDysW2d4DU8fS4qdlDlco5A00g8T1FS7nD9CzdkVN/oix6ujw7RuI
+    7pE1K3JELUYFBc8AZ7mIGGbddeCwnM+NdPIlhWzk5s4x4/r31cdk0gzor0kE4e+d
+    5m0s1T4O/Iak6rc0MGDeTejZQg04p1eAJFYQ6OY23tJhH/kO8CMYnQ4fidfCkf8v
+    85v4EC1MCorFR7J65uSj8MiaL7LTXPvLAkgFls1c3ijQ2tJ8qXvqmfo0by33T1OF
+    ZGyaOP9/1WQSywKCAQB47m6CfyYO5EZNAgxGD8SHsuGT9dXTSwF/BAjacB/NAEA2
+    48eYpko3LWyBrUcCPn+LsGCVg7XRtxepgMBjqXcoI9G4o1VbsgTHZtwus0D91qV0
+    DM7WsPcFu1S6SU8+OCkcuTPFUT2lRvRiYj+vtNttK+ZP5rdmvYFermLyH/Q2R3ID
+    zVgmH+aKKODVASneSsgJ8/nAs5EVZbwc/YKzbx2Zk+s7P4KE95g+4G4dzrMW0RcN
+    QS1LFJDu2DhFFgU4fRO15Ek9/lj2JS2DpfLGiJY8tlI5nyDsq4YRFvQSBdbUTZpG
+    m+CJDegffSlRJtuT4ur/dQf5hmvfYTVBRk2XS/eZAoIBAB143a22PWnvFRfmO02C
+    3X1j/iYZCLZa6aCl+ZTSj4LDGdyRPPXrUDxwlFwDMHfIYfcHEyanV9T4Aa9SdKh9
+    p6RbF6YovbeWqS+b/9RzcupM77JHQuTbDwL9ZXmtGxhcDgGqBHFEz6ogPEfpIrOY
+    GwZnmcBY+7E4HgsZ+lII4rqng6GNP2HEeZvg91Eba+2AqQdAkTh3Bfn+xOr1rT8+
+    u5WFOyGS5g1JtN0280yIcrmWeNPp8Q2Nq4wnNgMqDmeEnNFDOsmo1l6NqMC0NtrW
+    CdxyXj82aXSkRgMQSqw/zk7BmNkDV8VvyOqX/fHWQynnfuYmEco4Pd2UZQgadOW5
+    cVMCggEBANGz1fC+QQaangUzsVNOJwg2+CsUFYlAKYA3pRKZPIyMob2CBXk3Oln/
+    YqOq6j373kG2AX74EZT07JFn28F27JF3r+zpyS/TYrfZyO1lz/5ZejPtDTmqBiVd
+    qa2coaPKwCOz64s77A9KSPyvpvyuTfRVa8UoArHcrQsPXMHgEhnFRsbxgmdP582A
+    kfYfoJBSse6dQtS9ZnREJtyWJlBNIBvsuKwzicuIgtE3oCBcIUZpEa6rBSN7Om2d
+    ex8ejCcS7qpHeULYspXbm5ZcwE4glKlQbJDTKaJ9mjiMdvuNFUZnv1BdMQ3Tb8zf
+    Gvfq54FbDuB10XP8JdLrsy9Z6GEsmoE=
+    -----END PRIVATE KEY-----
+  '';
+  ca.cert = builtins.toFile "ca.cert" ''
+    -----BEGIN CERTIFICATE-----
+    MIIFATCCAumgAwIBAgIJANydi4uFZr0LMA0GCSqGSIb3DQEBCwUAMBYxFDASBgNV
+    BAMMC1NuYWtlb2lsIENBMCAXDTE4MDcxMjAwMjIxNloYDzIxMTgwNjE4MDAyMjE2
+    WjAWMRQwEgYDVQQDDAtTbmFrZW9pbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
+    ADCCAgoCggIBAN91XEL/gfCG7MP2iv0IMO7dMFATmWKskjkpiZ8xm1+B3MSOA7OZ
+    H0BVKSfatB4KrMzmb5gLM877bLvQV2Tu8M5GLU52Fh9RAhbr9NnbvESPHi3zaP2L
+    vTnJSpMlkqMxsPzfSB5ciYnpUaM2/9aKxMebAGylYp59hA83rxm9g0KfR3mtgmD2
+    5E5k8kdIjQxiP2IRFYg837GFmhLE3vggsnSsQ5B/HYYcOFOv329lgAWpsAh+Hfl9
+    i6VFZqtRJ6Qj6sPFrzcUPyr1wyA4/zgqQt6nZ1FddNtRYSsZQ6kc/nkz0zvCzRFU
+    12X09RJsOAKGXvJiUcJ17fbrWr/Manl0xX+3+Ndc1SBG6u9dziBQoqNLhJ9++DRd
+    Wc+zewyVngk2bJwr2SWAhJWZtMpVyNFEm/wG9rY1BWwn1MivJXRAST3gO5yCwLct
+    uFB9B2adZVwR3PCtkc2mT1rPmafDjZG69lb0vX1PvGkit0tIdo6KzhUSq5mORYiF
+    8jPQNUx5e1gRCbCoUbbdbDS61ymYJbgU++nJizkYA+YZZ+uUzGwsP/t616i3cCF4
+    L7npkGhUGcjwUW8hfapyL6B9UO4KO8OZvJL/Q2/Esaq9ILUZQ+ZY/dNHkVvUfxGn
+    7f3MkdGYf6phaWFy/qnsWVjb/p31GTDxYpFNIIHvJ5R000+I+imTo3g3AgMBAAGj
+    UDBOMB0GA1UdDgQWBBQ3vPWzjLmu5krbSpfhBAht9KL3czAfBgNVHSMEGDAWgBQ3
+    vPWzjLmu5krbSpfhBAht9KL3czAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUA
+    A4ICAQDF9HyC1ZFN3Ob+JA9Dj5+Rcobi7JIA5F8uW3Q92LfPoVaUGEkBrwJSiTFX
+    47zvP/ySBJIpZ9rzHMbJ+1L+eJgczF1uQ91inthCKo1THTPo5TgBrpJj0YAIunsj
+    9eH1tBnfWFYdVIDZoTSiwPtgIvglpyuK/eJXEe+FRzubhtdc9w1Hlzox1sd0TQuy
+    Pl9KFHg7BlFZfCPig1mkB8pfwjBDgVhv5DKJ9cJXh3R5zSoiyuS2b+qYSvw8YTHq
+    0WNKWUthb7BVAYE3OmcbOHgUAUjtJ6EIGIB9z/SoLe90CofXLXFR5dppuVLKCMBA
+    kgL4luBIu7t8mcnN2yzobvcGHy8RVY6F5abCCy6gackLzjOzvH1SYOxP8yN74aKB
+    ANgcqdWspb8JYoU8lEbA8dhBVrsgBf7XeJlrZvMdcUENlJ2PI0JWr9WvlRAM9rYY
+    EY1alJqBCp6530Ggd6/f0V64cEqptejUdmN9L0zboxKjQf4LjpUNraGvg8tw/xkY
+    4dT1U2HlVnhOyBVkx/tE6zIK/RU16oMqwpjCdfbK/TuWCNc/emJz5PMlp81zm83+
+    dExpWwuV4rt6OQbZ/GSatNLJXOw+pkLjaEhnHgrsgI+HqAUXg3ByKol+1e76wN51
+    k1ZKpB6mk4kejySGPYBHiJwED0IyXu9gUfalSczXFO4ySAvhCg==
+    -----END CERTIFICATE-----
+  '';
+  "acme-v01.api.letsencrypt.org".key = builtins.toFile "acme-v01.api.letsencrypt.org.key" ''
+    -----BEGIN RSA PRIVATE KEY-----
+    MIIJKQIBAAKCAgEAvG+sL4q0VkgSClBTn4NkPiUrtXx5oLyZ+CCM1jrQx/xotUt5
+    X2S4/7vMnAK/yRLsR7R2PhXO8CZPqJ7B6OfAgaDTgvipJkZYPZQSMP3KOinM3WJL
+    ssqKh7/HOxZIf0iyUXewrnX5eTAo/CLsUnhBjBD7E99nmQz/leLWSl82sSYDkO3n
+    Uk3/1qJZA8iddb4uH0IEQWcNKev3WoQQzwiVrXBiftlRQOJy5JJXm5m8229MCpMA
+    1AUWmpdu6sl3/gFFdsDhUFq/a7LFrVyaUCMRIHg9szAB7ZFkixr9umQs8jKwuo98
+    3JHB11h2SirwgfIzHHmyhaWhCt22ucTwEXGhq63LtrzZvLsfP8Ql5S+AuqGTH0v8
+    meuc784leAjulBZjkpuIFwDnVv9+YeUEbqJeo1hSHrILddora3nkH4E2dJWmLpqp
+    iPr++GRi+BNgYKW/BQLTJ7C6v+vUs+kdPgYJH5z7oP6f0YZkT0Wkubp/UEz7UV2d
+    fjz57d77DYx5rFWGYzJriWR/xltgL1zDpjwjwG1FDpRqwlyYbBFpjQhxI+X0aT98
+    m6fCzBDQHDb/+JgvsjTHh6OZatahFAwzFIEfrceDv1BG8sBWIaZGhLzYiWQxafl8
+    oXbWv1T6I1jpsTlCdCSkWzaJb4ZjxI9Ga1ynVu8F16+GR2a71wKWu7UbZQsCAwEA
+    AQKCAgBYvrs4FLoD3KNqahRIDqhaQEVKjtn1Yn2dBy9tAXwsg2qI34fE7nnWLwsY
+    +o56U0gmKQ57BOhV36Uqg8JNP0BBjI2wpA19simCrsa2fgAMznzmUpHWHV+KuT5K
+    TJ9OGt2oUpdKQtOASLc0r/neiTZNkf29iTyQLzf7zj4f/qGSYpXRXsnP0F5KJmGH
+    z6agujWckQnSB4eCk9gFsCb+akubyE8K8Kw8w6lajrVl2czBB7SnUj5UnCTeH62k
+    M8goP08Is6QppON8BFDm6bLfRPSe9yIPzu9JhGz2unp+mwkz872Zz1P9yUOieM4U
+    9g4ZFQkPQx1ZpfynUm3pJZ/uhzadBabnIvMe/1qwDAEDifh/WzEM76/2kBpQkHtS
+    qcjwjAElfWnP8aBr1Pj42/cVJy3dbDqb0OawFHx/8xSO2CkY4Gq2h3OYv1XpPv3g
+    S9qqKhvuaT+aD0YjKhP4FYc2vvQSJwdZL8vqOyma8JGmc+r7jakIPCyOx3oPVqnS
+    L2P7DuJ1FcGIZyYOU3UUSzKndDU9fVC8YoLWvHDlwm4RK9UPtdsBY8mEu6BlaAwL
+    zEQG+fbcFnEkHPiJeAohYUCHiqCihLt0pqGwZi+QrudPQE6C47YijGZWJu4VVLjB
+    B2L9iDQKsN4FnBJ9egJIwWBLX3XXQfjC43UGm1A5sBvD+ScsCQKCAQEA7GxU7/SW
+    4YJ+wBXrp7Z3vzlc5mTT5U4L2muWZLhIjT/jmpHpZ4c9a5DY/K9OYcu8XJ+7kx2B
+    N40cU3ZkT2ZbB5/BUCEmi3Wzy3R/KZshHDzvvSZHcXJqVBtv+HGJgR5ssFqAw8c6
+    gJtDls+JE9Sz+nhLk0ZZ4658vbTQfG1lmtzrbC3Kz2xK8RPTdOU5Or7fayeaEKEW
+    ECBJPE41ME2UTdB/E85vyYoee0MBijjAs19QKqvoNbyrsZ5bihcIDYsrvjCmkdW1
+    20IUrSF3ZYJ9bb+CxHeRyNqwvRxPYSkzdMjZHx+xEAvJgw51QqmIi2QQf/qB+ych
+    cSbE/0Jhx4QbDQKCAQEAzAoenEOgmZvUegFUu8C6gWeibMjl3Y9SikQ4CoQO/zWr
+    aoCr5BpbzbtOffwnPfgk9wCGvXf6smOdrLUP1K2QAhBr/vJh7ih2MonvpYr5HPP7
+    maVARR66IgtxXP2ER2I9+9p2OQdecGRP2fUn2KCDQIASHSSY/VjBb8LLJgryC/DS
+    r2b0+m1e2qXfNWt/BYTQZhD/8B/jl/2pl/jI2ne3rkeiwEm7lqZaDt3Q8gC+qoP5
+    /IdG1Gob7UTMCbICWy1aGuzRYUmbpg0Vq4DAV1RtgBySB5oNq5PMBHYpOxedM2nM
+    NxHvf0u6wsxVULwQ4IfWUqUTspjxDmIgogSzmOGadwKCAQEA558if4tynjBImUtg
+    egirvG4oc5doeQhDWJN63eYlPizPgUleD41RQSbBTp04/1qoiV38WJ7ZT2Ex1Rry
+    H0+58vgyXZx8tLh1kufpBQv0HkQc44SzDZP4U7olspMZEaSK+yNPb36p9AEo8IEW
+    XJVQVhywffK4cfUqRHj2oFBU8KlrA6rBPQFtUk4IJkfED6ecHtDHgW8vvFDFLw23
+    0kDPAIU5WmAu6JYmUsBMq+v57kF8urF8Z9kVpIfuSpVR0GL+UfA74DgtWEefFhbp
+    cEutMm4jYPN7ofmOmVc49Yl13f4/qNxVjdDedUUe4FZTbax09cyotzOY8c/3w9R3
+    Ew57qQKCAQAa5jqi30eM+L5KV2KUXhQ4ezEupk2np/15vQSmXkKb4rd2kwAWUmNH
+    /Cmc8mE6CjzVU3xv/iFO41MmMbikkT0rCH80XUAL5cmvX//4ExpEduX0m5SdiC+B
+    zYBkggeuYYVKbsKnQhFxP8hHM8rNBFxJZJj+vpRs0gaudT/TBB5k9JrSBQDHAyQ+
+    Lx/+Ku3UDG5tBlC3l3ypzQdOwb25D49nqooKT64rbkLxMs0ZGoAIet26LRtpZZPI
+    9AjyPkWRP6lhY1c3PD0I5zC0K4Uv/jFxclLOLcEfnZyH+gv1fmd7H7eMixDH93Pn
+    uoiE3EZdU4st2hV+tisRel5S/cuvnA6BAoIBAQDJISK8H0hwYp+J4/WUv/WLtrm4
+    Mhmn8ItdEPAyCljycU6oLHJy4fgmmfRHeoO1i3jb87ks2GghegFBbJNzugfoGxIM
+    dLWIV+uFXWs24fMJ/J6lqN1JtAj7HjvqkXp061X+MdIJ0DsACygzFfJOjv+Ij77Q
+    Q1OBTSPfb0EWFNOuIJr9i2TwdN9eW/2ZMo1bPuwe4ttPEIBssfIC02dn2KD1RTqM
+    1l+L97vVFk7CoSJZf5rLeysLVyUeGdDcoEcRA6fKhfB/55h+iqrZNvySX1HrR6on
+    PQcxDRPJD7f9rMsTzVl3DOxzvXAU3lIcZtPZps97IwXceAAh2e1kZNNv/cxj
+    -----END RSA PRIVATE KEY-----
+  '';
+  "acme-v01.api.letsencrypt.org".cert = builtins.toFile "acme-v01.api.letsencrypt.org.cert" ''
+    -----BEGIN CERTIFICATE-----
+    MIIEtDCCApwCAgKaMA0GCSqGSIb3DQEBCwUAMBYxFDASBgNVBAMMC1NuYWtlb2ls
+    IENBMCAXDTE4MDcxMjAwMjIxN1oYDzIxMTgwNjE4MDAyMjE3WjAnMSUwIwYDVQQD
+    DBxhY21lLXYwMS5hcGkubGV0c2VuY3J5cHQub3JnMIICIjANBgkqhkiG9w0BAQEF
+    AAOCAg8AMIICCgKCAgEAvG+sL4q0VkgSClBTn4NkPiUrtXx5oLyZ+CCM1jrQx/xo
+    tUt5X2S4/7vMnAK/yRLsR7R2PhXO8CZPqJ7B6OfAgaDTgvipJkZYPZQSMP3KOinM
+    3WJLssqKh7/HOxZIf0iyUXewrnX5eTAo/CLsUnhBjBD7E99nmQz/leLWSl82sSYD
+    kO3nUk3/1qJZA8iddb4uH0IEQWcNKev3WoQQzwiVrXBiftlRQOJy5JJXm5m8229M
+    CpMA1AUWmpdu6sl3/gFFdsDhUFq/a7LFrVyaUCMRIHg9szAB7ZFkixr9umQs8jKw
+    uo983JHB11h2SirwgfIzHHmyhaWhCt22ucTwEXGhq63LtrzZvLsfP8Ql5S+AuqGT
+    H0v8meuc784leAjulBZjkpuIFwDnVv9+YeUEbqJeo1hSHrILddora3nkH4E2dJWm
+    LpqpiPr++GRi+BNgYKW/BQLTJ7C6v+vUs+kdPgYJH5z7oP6f0YZkT0Wkubp/UEz7
+    UV2dfjz57d77DYx5rFWGYzJriWR/xltgL1zDpjwjwG1FDpRqwlyYbBFpjQhxI+X0
+    aT98m6fCzBDQHDb/+JgvsjTHh6OZatahFAwzFIEfrceDv1BG8sBWIaZGhLzYiWQx
+    afl8oXbWv1T6I1jpsTlCdCSkWzaJb4ZjxI9Ga1ynVu8F16+GR2a71wKWu7UbZQsC
+    AwEAATANBgkqhkiG9w0BAQsFAAOCAgEAzeGlFMz1Bo+bbpZDQ60HLdw7qDp3SPJi
+    x5LYG860yzbh9ghvyc59MIm5E6vB140LRJAs+Xo6VdVSTC4jUA2kI9k1BQsbZKds
+    XT0RqA7HkqcLS3t3JWFkkKbCshMGZTSZ//hpbaUG1qEAfUfmZw1lAxqSa0kqavbP
+    awf7k8qHbqcj7WORCdH7fjKAjntEQwIpl1GEkAdCSghOJz2/o9aWmiGZt27OM/sG
+    MLSrcmL3QBElCjOxg14P8rnsmZ+VEp6MO93otoJ4dJL7fN7vTIh5ThbS384at/4l
+    4KK/y7XctUzAtWzhnodjk/NSgrrGX2kseOGOWEM1sZc9xtinHH2tpOMqtLVOkgHD
+    Lul+TArqgqeoOdEM/9OL64kgOrO/JzxBq+egLUi4wgAul2wmtecKZK1dkwYZHeqW
+    74i55yeBp+TTomnPr0ZBns6xKFYldJVzC34OB+2YVDxe8y9XtWtuQOxFw0LQHhNb
+    zy5aBverWzZFwiIIjJoVHTQq848uKBJec0YILfMinS1Wjif4xqW/IMfi+GFS0oka
+    sKCGNE/8ur9u/Jm6cbto3f2dtV8/vkhiITQgwzM2jalyuVJ9jyPxG7EvbTvZORgw
+    pRvBRTd4/eE7I1L+UDe6x8EjR/MrqfF9FWVGOZo4vPTyNbrSWYBh6s9kYy56ds1l
+    IRxst1BXEfI=
+    -----END CERTIFICATE-----
+  '';
+  "letsencrypt.org".key = builtins.toFile "letsencrypt.org.key" ''
+    -----BEGIN RSA PRIVATE KEY-----
+    MIIJKAIBAAKCAgEAwPvhlwemgPi6919sSD7Pz6l6CRfU1G/fDc0AvsMN/nTmiGND
+    pqn9ef1CA+RtLtOuPc1LLyEovcfu75/V+6KSgO4k19E2CrFCFwjEOWDGF4DgclT3
+    751WGmFJgzPEfZfhbOrmQfQau86KxAtNZVp9FxcKbuLyQ/sNNxfNMB+7IHbVhwvz
+    VcndHpYZEP6kdnwvNLP22bouX5q3avxWStln01uZ0BfUm4XwxaUNIU7t0Dv56FK9
+    C9hW9AZae0do0BJBWRF7xSwLeDJqn9uZz+sX0X/tIaaSQSBuZySj0He5ZKzdUO0t
+    px2xTS2Brl3Y2BOJaOE98HubWvdKoslLt4X2rVrMxGa86SmFzcyDL1RSowcP/ruy
+    y555l7pepL5s4cmMgRBBXj5tXhqUTVOn5WO+JClLk+rtvtAT4rogJmMqEKmMw2t7
+    LNy1W9ri/378QG/i3AGaLIL/7GsPbuRO51Sdti4QMVe2zNFze72mzNmj1SXokWy7
+    +ZvjUMp55oEjRRsTPUZdNOEHJWy6Os2znuqL7ZpIHCxBG8FKnkCViXRJqAA8bzcE
+    hR+pLamLIOHlv4kdzJ6phHkSvK68qvbRReUmOjJgSupVBI9jhK+fHay/UWR4zfJQ
+    ed99H8ZOoiXlrLCVs+VPDynUUKrzF1nYyolNzi/NS4e4AbnfWgyC5JKRpjUCAwEA
+    AQKCAgB0fNYL+zM3MGxy+2d6KGf6GnuuV3NBlBGY3ACyJT0iNmAdPYXNaVi2tPeP
+    L+fz1xSa+3uBhEt6Wt/QRrO8g8JZDuawWvl69MpG6yS+2bpY35MbkExkl50sqULd
+    bncRtIb+3r+EWht099RtR8E9B6TwNhk3G8hO3pB4i+ZwQQcMLo7vSHhmdUYCu2mA
+    B6UwW/+GmYbMoARz8wj6DDzuS1LPksBCis/r3KqcMue9Dk6gXkOYR7ETIFBEVj1x
+    ooYS6qIFaHdEajS2JgCUY9LxXR/wdn6lzE0GANSDb+tt34bJzUp+Gdxvvo2SX4Ci
+    xsUokIpmA2gG7CW3gAPORSFuMu/VYZtvt+owNYlODXRPuGi/eLDknFRB/S4Nx0J0
+    WZZq5uTgJdQainyKYtDZALia5X4cc5I2hNetCorG9jNZIsSunbIAG+htx2FI3eqK
+    jwOUiHE8SCZ6YdXoDQjg2w+g8jeB23eqkPyzunpZphYiKay7VFeLwQEMC2a791ln
+    +MbHhhpRAc1uAoU2reB2fxKyaPlOfAWVMgUOGlgpVOuEVeMoc1CwjajaFztGG7fI
+    8EHNoyAftCdXnTaLZk2KZnnIDHHzFXR62TE1GJFD1fdI1pHAloCbgA4h+Dtwm1Uu
+    iAEEfvVU/E5wbtAzv6pY32+OKX5kyHAbM5/e918B8ZxmHG1J9QKCAQEA6FwxsRG3
+    526NnZak540yboht5kV12BNBChjmARv/XgZ7o1VsfwjaosErMvasUBcHDEYOC/oE
+    ZgPAyrMVsYm0xe/5FSIFLJVeYXTr0rmCNhVtBCHx3IS94BCXreNnz0qoEWnb5E09
+    Z1O42D0yGcLXklg6QaJfb7EdHh03F3dSVMHyDR3JlAQHRINeuP6LlQpbvRD3adH5
+    QWr2M3k+Stuq2OJdG7eUS1dreCxRShLuDjDhiZekdl/TB3LM0prOaWrKBrryN2g6
+    mjiasH6I5zRD3LQP5zg57Thb8afHqA4Fb85Frt6ltfFlPTIoxXZ5drVhmRWfXXnQ
+    POnj8T+w4zVjvwKCAQEA1J4ivyFkCL0JTSY3/PtwAQvBBj3GazzU6P+urWeH74Vh
+    WK17Ae40iOUHGyy80Db/fVY4VLQTpxvAeG91Gj5Nd/AucXJgOrisabcEz6N/xUs5
+    sjJNgXuNKTAgjYBu0bqLXxgZj43zT8JhA6KW7RuYU0PtHMRragz4RbK9NWDaVvJb
+    xSR5QoVLS00PerUa0SfupEYKCrlSTP6FOM5YNkCuSMt7X6/m9cR0WwVINKvUQBiT
+    ObrN+KeBmF9awpQQnQOq/GbCl3kf6VyPQqYFhdrWSg52w33c2tBVYrtHJpeXGcin
+    akw4KKcj4rdU2qxMuuRiD5paagshbLdGsYMTbSzjCwKCAQEAh89DGAyUIcfDLAWd
+    st0bSfGh0oJsw3NVg3JUFPfpRWqiny/Rr1pcd95RwoLc6h7bdrgHg8aJBZtR9ue/
+    WTp0l3CQdGKjBZD0TiAJqevViIjzZAP3Gn3XgPwRu4f75/Pp0eu+o2zl49vSYUk7
+    XEU+vIGm4y/leiHaM/y9c5DBZVrKgBIV/NZx7QCfv56/tMgOIK6m/YnFlw/OgP1v
+    hE9qR0PfSdD98x9QaDf290WjMFYvrL0eWjXd4S+fOcVTude55z8jTXE1N2i4OUpr
+    +D7bH0d7OBjr+pQDYXZAQyCW2ueEYRYvYu2Jz7/ehrOdgN25AsHZmMgXB1NpcFta
+    pyJQfwKCAQByoPMwworRH0GVg4Zp8RFYrwKZH9MK29gZ6kc9m/Sw0OND0PvhdZCD
+    QZ8MKpl9VDl4VHS4TgHOdWrWQ5kJ1g8kG6yeY0C4R/pEYHTKkWaAcucfSHl61qar
+    TxQt1dFpZz5evXqCZ9CG7tApCo5+NQNx2MxMVyVmHqn3wb66uYXdnHqXlet+Tqji
+    ZyByUpOrsfC6RjyBvZo+gnZGwxDR5xtPiczxML+/PvRQYk+kfgNHrzgoxqrnZT+8
+    a6ReBT/TtzeHLsu4qIfo44slLqcJnIstkBC9ouzgV7PBMCDTEKVZNFH2QDOCz2HM
+    iHTKFFyl4h1wNhKK24dguor1hyqBENMzAoIBAAQvQHwRWIVlfCMRI170Ls8AXB9Z
+    MMdZJ37bh6kmJpkV3+HB1ZkKwofHKR9h/3xLt5iYXzqT+/zA4EAsFFs1A93+tkzh
+    yPrN5iTSJicophZSlA4ObX1hMkgshvl7ZB1fRM5WyiszBOfm8W7eAxaK8nY2oAoP
+    tI7rioo6CFBNMCGbOl4gEX6YJ4OsVSm+efCRSDDw+3HW8H2YgqufBzAULk1Jcj5t
+    ZvraXpC5qZ92VtsH0cGA1ovNDAmoOV4AAvtZVpLQsXwaphad/Fbn/ItGrrluvvFC
+    HuldRzYtl/AQtoirK86LTY3aAmcwVFuiYvDQMzjzkJvVMmRCFZBcUIaz2oI=
+    -----END RSA PRIVATE KEY-----
+  '';
+  "letsencrypt.org".cert = builtins.toFile "letsencrypt.org.cert" ''
+    -----BEGIN CERTIFICATE-----
+    MIIEpzCCAo8CAgKaMA0GCSqGSIb3DQEBCwUAMBYxFDASBgNVBAMMC1NuYWtlb2ls
+    IENBMCAXDTE4MDcxMjAwMjIxOVoYDzIxMTgwNjE4MDAyMjE5WjAaMRgwFgYDVQQD
+    DA9sZXRzZW5jcnlwdC5vcmcwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
+    AQDA++GXB6aA+Lr3X2xIPs/PqXoJF9TUb98NzQC+ww3+dOaIY0Omqf15/UID5G0u
+    0649zUsvISi9x+7vn9X7opKA7iTX0TYKsUIXCMQ5YMYXgOByVPfvnVYaYUmDM8R9
+    l+Fs6uZB9Bq7zorEC01lWn0XFwpu4vJD+w03F80wH7sgdtWHC/NVyd0elhkQ/qR2
+    fC80s/bZui5fmrdq/FZK2WfTW5nQF9SbhfDFpQ0hTu3QO/noUr0L2Fb0Blp7R2jQ
+    EkFZEXvFLAt4Mmqf25nP6xfRf+0hppJBIG5nJKPQd7lkrN1Q7S2nHbFNLYGuXdjY
+    E4lo4T3we5ta90qiyUu3hfatWszEZrzpKYXNzIMvVFKjBw/+u7LLnnmXul6kvmzh
+    yYyBEEFePm1eGpRNU6flY74kKUuT6u2+0BPiuiAmYyoQqYzDa3ss3LVb2uL/fvxA
+    b+LcAZosgv/saw9u5E7nVJ22LhAxV7bM0XN7vabM2aPVJeiRbLv5m+NQynnmgSNF
+    GxM9Rl004QclbLo6zbOe6ovtmkgcLEEbwUqeQJWJdEmoADxvNwSFH6ktqYsg4eW/
+    iR3MnqmEeRK8rryq9tFF5SY6MmBK6lUEj2OEr58drL9RZHjN8lB5330fxk6iJeWs
+    sJWz5U8PKdRQqvMXWdjKiU3OL81Lh7gBud9aDILkkpGmNQIDAQABMA0GCSqGSIb3
+    DQEBCwUAA4ICAQAkx3jcryukAuYP7PQxMy3LElOl65ZFVqxDtTDlr7DvAkWJzVCb
+    g08L6Tu+K0rKh2RbG/PqS0+8/jBgc4IwSOPfDDAX+sinfj0kwXG34WMzB0G3fQzU
+    2BMplJDOaBcNqHG8pLP1BG+9HAtR/RHe9p2Jw8LG2qmZs6uemPT/nCTNoyIL4oxh
+    UncjETV4ayCHDKD1XA7/icgddYsnfLQHWuIMuCrmQCHo0uQAd7qVHfUWZ+gcsZx0
+    jTNCcaI8OTS2S65Bjaq2HaM7GMcUYNUD2vSyNQeQbha4ZeyZ9bPyFzznPMmrPXQe
+    MJdkbJ009RQIG9As79En4m+l+/6zrdx4DNdROqaL6YNiSebWMnuFHpMW/rCnhrT/
+    HYadijHOiJJGj9tWSdC4XJs7fvZW3crMPUYxpOvl01xW2ZlgaekILi1FAjSMQVoV
+    NhWstdGCKJdthJqLL5MtNdfgihKcmgkJqKFXTkPv7sgAQCopu6X+S+srCgn856Lv
+    21haRWZa8Ml+E0L/ticT8Fd8Luysc6K9TJ4mT8ENC5ywvgDlEkwBD3yvINXm5lg1
+    xOIxv/Ye5gFk1knuM7OzpUFBrXUHdVVxflCUqNAhFPbcXwjgEQ+A+S5B0vI6Ohue
+    ZnR/wuiou6Y+Yzh8XfqL/3H18mGDdjyMXI1B6l4Judk000UVyr46cnI7mw==
+    -----END CERTIFICATE-----
+  '';
+}
diff --git a/nixos/tests/common/resolver.nix b/nixos/tests/common/resolver.nix
index a1901c5c8167..6be8d1d18e62 100644
--- a/nixos/tests/common/resolver.nix
+++ b/nixos/tests/common/resolver.nix
@@ -18,7 +18,7 @@
       defining this option needs to be explicitly imported.
 
       The reason this option exists is for the
-      <filename>nixos/tests/common/letsencrypt.nix</filename> module, which
+      <filename>nixos/tests/common/letsencrypt</filename> module, which
       needs that option to disable the resolver once the user has set its own
       resolver.
     '';
diff --git a/nixos/tests/common/user-account.nix b/nixos/tests/common/user-account.nix
index 93aeb60e456a..dc50e14750b0 100644
--- a/nixos/tests/common/user-account.nix
+++ b/nixos/tests/common/user-account.nix
@@ -1,12 +1,12 @@
 { lib, ... }:
 
-{ users.extraUsers.alice =
+{ users.users.alice =
     { isNormalUser = true;
       description = "Alice Foobar";
       password = "foobar";
     };
 
-  users.extraUsers.bob =
+  users.users.bob =
     { isNormalUser = true;
       description = "Bob Foobar";
       password = "foobar";
diff --git a/nixos/tests/containers-imperative.nix b/nixos/tests/containers-imperative.nix
index a548b17b1ff1..42bff6a9a3f9 100644
--- a/nixos/tests/containers-imperative.nix
+++ b/nixos/tests/containers-imperative.nix
@@ -10,7 +10,7 @@ import ./make-test.nix ({ pkgs, ...} : {
     { config, pkgs, lib, ... }:
     { imports = [ ../modules/installer/cd-dvd/channel.nix ];
       virtualisation.writableStore = true;
-      virtualisation.memorySize = 768;
+      virtualisation.memorySize = 1024;
       # Make sure we always have all the required dependencies for creating a
       # container available within the VM, because we don't have network access.
       virtualisation.pathsInNixDB = let
@@ -22,7 +22,10 @@ import ./make-test.nix ({ pkgs, ...} : {
             };
           };
         };
-      in [ pkgs.stdenv emptyContainer.config.containers.foo.path pkgs.libxslt ];
+      in [
+        pkgs.stdenv pkgs.stdenvNoCC emptyContainer.config.containers.foo.path
+        pkgs.libxslt
+      ];
     };
 
   testScript =
diff --git a/nixos/tests/containers-reloadable.nix b/nixos/tests/containers-reloadable.nix
index 5fb42f2272b3..15862ac64c12 100644
--- a/nixos/tests/containers-reloadable.nix
+++ b/nixos/tests/containers-reloadable.nix
@@ -45,7 +45,6 @@ in {
   };
 
   testScript = {nodes, ...}: let
-    originalSystem = nodes.client.config.system.build.toplevel;
     c1System = nodes.client_c1.config.system.build.toplevel;
     c2System = nodes.client_c2.config.system.build.toplevel;
   in ''
diff --git a/nixos/tests/dnscrypt-proxy.nix b/nixos/tests/dnscrypt-proxy.nix
index 845623368250..1fcf3903b13e 100644
--- a/nixos/tests/dnscrypt-proxy.nix
+++ b/nixos/tests/dnscrypt-proxy.nix
@@ -26,7 +26,8 @@ import ./make-test.nix ({ pkgs, ... }: {
     $client->waitForUnit("dnsmasq");
 
     # The daemon is socket activated; sending a single ping should activate it.
+    $client->fail("systemctl is-active dnscrypt-proxy");
     $client->execute("${pkgs.iputils}/bin/ping -c1 example.com");
-    $client->succeed("systemctl is-active dnscrypt-proxy");
+    $client->waitUntilSucceeds("systemctl is-active dnscrypt-proxy");
   '';
 })
diff --git a/nixos/tests/docker-tools.nix b/nixos/tests/docker-tools.nix
index 4466081d01e9..e2bcfbbd1f96 100644
--- a/nixos/tests/docker-tools.nix
+++ b/nixos/tests/docker-tools.nix
@@ -45,5 +45,11 @@ import ./make-test.nix ({ pkgs, ... }: {
       $docker->succeed("docker load --input='${pkgs.dockerTools.examples.onTopOfPulledImage}'");
       $docker->succeed("docker run --rm ontopofpulledimage hello");
       $docker->succeed("docker rmi ontopofpulledimage");
+
+      # Regression test for issue #34779
+      $docker->succeed("docker load --input='${pkgs.dockerTools.examples.runAsRootExtraCommands}'");
+      $docker->succeed("docker run --rm runasrootextracommands cat extraCommands");
+      $docker->succeed("docker run --rm runasrootextracommands cat runAsRoot");
+      $docker->succeed("docker rmi '${pkgs.dockerTools.examples.runAsRootExtraCommands.imageName}'");
     '';
 })
diff --git a/nixos/tests/flatpak.nix b/nixos/tests/flatpak.nix
index d1c7cf843147..9a5bdf070217 100644
--- a/nixos/tests/flatpak.nix
+++ b/nixos/tests/flatpak.nix
@@ -10,6 +10,7 @@ import ./make-test.nix ({ pkgs, ... }:
   machine = { config, pkgs, ... }: {
     imports = [ ./common/x11.nix ];
     services.xserver.desktopManager.gnome3.enable = true; # TODO: figure out minimal environment where the tests work
+    environment.gnome3.excludePackages = pkgs.gnome3.optionalPackages;
     services.flatpak.enable = true;
     environment.systemPackages = with pkgs; [ gnupg gnome-desktop-testing ostree python2 ];
     virtualisation.memorySize = 2047;
diff --git a/nixos/tests/gdk-pixbuf.nix b/nixos/tests/gdk-pixbuf.nix
new file mode 100644
index 000000000000..b20f61b5ffe2
--- /dev/null
+++ b/nixos/tests/gdk-pixbuf.nix
@@ -0,0 +1,19 @@
+# run installed tests
+import ./make-test.nix ({ pkgs, ... }: {
+  name = "gdk-pixbuf";
+
+  meta = {
+    maintainers = pkgs.gdk_pixbuf.meta.maintainers;
+  };
+
+  machine = { pkgs, ... }: {
+    environment.systemPackages = with pkgs; [ gnome-desktop-testing ];
+    environment.variables.XDG_DATA_DIRS = [ "${pkgs.gdk_pixbuf.installedTests}/share" ];
+
+    virtualisation.memorySize = 4096; # Tests allocate a lot of memory trying to exploit a CVE
+  };
+
+  testScript = ''
+    $machine->succeed("gnome-desktop-testing-runner");
+  '';
+})
diff --git a/nixos/tests/gitolite.nix b/nixos/tests/gitolite.nix
index 4b4e081acc5f..d4028efad1d8 100644
--- a/nixos/tests/gitolite.nix
+++ b/nixos/tests/gitolite.nix
@@ -78,8 +78,8 @@ in
             # there's nobody around that can input password
             PreferredAuthentications publickey
         '';
-        users.extraUsers.alice = { isNormalUser = true; };
-        users.extraUsers.bob = { isNormalUser = true; };
+        users.users.alice = { isNormalUser = true; };
+        users.users.bob = { isNormalUser = true; };
       };
 
   };
diff --git a/nixos/tests/gnome3.nix b/nixos/tests/gnome3.nix
index 492fa61484a0..591ed8600685 100644
--- a/nixos/tests/gnome3.nix
+++ b/nixos/tests/gnome3.nix
@@ -11,8 +11,9 @@ import ./make-test.nix ({ pkgs, ...} : {
 
       services.xserver.enable = true;
 
-      services.xserver.displayManager.auto.enable = true;
-      services.xserver.displayManager.auto.user = "alice";
+      services.xserver.displayManager.lightdm.enable = true;
+      services.xserver.displayManager.lightdm.autoLogin.enable = true;
+      services.xserver.displayManager.lightdm.autoLogin.user = "alice";
       services.xserver.desktopManager.gnome3.enable = true;
 
       virtualisation.memorySize = 1024;
@@ -21,7 +22,9 @@ import ./make-test.nix ({ pkgs, ...} : {
   testScript =
     ''
       $machine->waitForX;
-      $machine->sleep(15);
+
+      # wait for alice to be logged in
+      $machine->waitForUnit("default.target","alice");
 
       # Check that logging in has given the user ownership of devices.
       $machine->succeed("getfacl /dev/snd/timer | grep -q alice");
diff --git a/nixos/tests/hadoop/hdfs.nix b/nixos/tests/hadoop/hdfs.nix
new file mode 100644
index 000000000000..4206c940c1af
--- /dev/null
+++ b/nixos/tests/hadoop/hdfs.nix
@@ -0,0 +1,54 @@
+import ../make-test.nix ({pkgs, ...}: {
+  nodes = {
+    namenode = {pkgs, config, ...}: {
+      services.hadoop = {
+        package = pkgs.hadoop_3_1;
+        hdfs.namenode.enabled = true;
+        coreSite = {
+          "fs.defaultFS" = "hdfs://namenode:8020";
+        };
+        hdfsSite = {
+          "dfs.replication" = 1;
+          "dfs.namenode.rpc-bind-host" = "0.0.0.0";
+          "dfs.namenode.http-bind-host" = "0.0.0.0";
+        };
+      };
+      networking.firewall.allowedTCPPorts = [
+        9870 # namenode.http-address
+        8020 # namenode.rpc-address
+      ];
+    };
+    datanode = {pkgs, config, ...}: {
+      services.hadoop = {
+        package = pkgs.hadoop_3_1;
+        hdfs.datanode.enabled = true;
+        coreSite = {
+          "fs.defaultFS" = "hdfs://namenode:8020";
+        };
+      };
+      networking.firewall.allowedTCPPorts = [
+        9864 # datanode.http.address
+        9866 # datanode.address
+        9867 # datanode.ipc.address
+      ];
+    };
+  };
+
+  testScript = ''
+    startAll
+
+    $namenode->waitForUnit("hdfs-namenode");
+    $namenode->waitForUnit("network.target");
+    $namenode->waitForOpenPort(8020);
+    $namenode->waitForOpenPort(9870);
+
+    $datanode->waitForUnit("hdfs-datanode");
+    $datanode->waitForUnit("network.target");
+    $datanode->waitForOpenPort(9864);
+    $datanode->waitForOpenPort(9866);
+    $datanode->waitForOpenPort(9867);
+
+    $namenode->succeed("curl http://namenode:9870");
+    $datanode->succeed("curl http://datanode:9864");
+  '';
+})
diff --git a/nixos/tests/hadoop/yarn.nix b/nixos/tests/hadoop/yarn.nix
new file mode 100644
index 000000000000..e97cc1acc902
--- /dev/null
+++ b/nixos/tests/hadoop/yarn.nix
@@ -0,0 +1,46 @@
+import ../make-test.nix ({pkgs, ...}: {
+  nodes = {
+    resourcemanager = {pkgs, config, ...}: {
+      services.hadoop.package = pkgs.hadoop_3_1;
+      services.hadoop.yarn.resourcemanager.enabled = true;
+      services.hadoop.yarnSite = {
+        "yarn.resourcemanager.scheduler.class" = "org.apache.hadoop.yarn.server.resourcemanager.scheduler.fifo.FifoScheduler";
+      };
+      networking.firewall.allowedTCPPorts = [
+        8088 # resourcemanager.webapp.address
+        8031 # resourcemanager.resource-tracker.address
+      ];
+    };
+    nodemanager = {pkgs, config, ...}: {
+      services.hadoop.package = pkgs.hadoop_3_1;
+      services.hadoop.yarn.nodemanager.enabled = true;
+      services.hadoop.yarnSite = {
+        "yarn.resourcemanager.hostname" = "resourcemanager";
+        "yarn.nodemanager.log-dirs" = "/tmp/userlogs";
+        "yarn.nodemanager.address" = "0.0.0.0:8041";
+      };
+      networking.firewall.allowedTCPPorts = [
+        8042 # nodemanager.webapp.address
+        8041 # nodemanager.address
+      ];
+    };
+
+  };
+
+  testScript = ''
+    startAll;
+
+    $resourcemanager->waitForUnit("yarn-resourcemanager");
+    $resourcemanager->waitForUnit("network.target");
+    $resourcemanager->waitForOpenPort(8031);
+    $resourcemanager->waitForOpenPort(8088);
+
+    $nodemanager->waitForUnit("yarn-nodemanager");
+    $nodemanager->waitForUnit("network.target");
+    $nodemanager->waitForOpenPort(8042);
+    $nodemanager->waitForOpenPort(8041);
+
+    $resourcemanager->succeed("curl http://localhost:8088");
+    $nodemanager->succeed("curl http://localhost:8042");
+  '';
+})
diff --git a/nixos/tests/haproxy.nix b/nixos/tests/haproxy.nix
new file mode 100644
index 000000000000..ce4094237db2
--- /dev/null
+++ b/nixos/tests/haproxy.nix
@@ -0,0 +1,41 @@
+import ./make-test.nix ({ pkgs, ...}: {
+  name = "haproxy";
+  nodes = {
+    machine = { config, ...}: {
+      imports = [ ../modules/profiles/minimal.nix ];
+      services.haproxy = {
+        enable = true;
+        config = ''
+          defaults
+            timeout connect 10s
+
+          backend http_server
+            mode http
+            server httpd [::1]:8000
+
+          frontend http
+            bind *:80
+            mode http
+            use_backend http_server
+        '';
+      };
+      services.httpd = {
+        enable = true;
+        documentRoot = pkgs.writeTextDir "index.txt" "We are all good!";
+        adminAddr = "notme@yourhost.local";
+        listen = [{
+          ip = "::1";
+          port = 8000;
+        }];
+      };
+    };
+  };
+  testScript = ''
+    startAll;
+    $machine->waitForUnit('multi-user.target');
+    $machine->waitForUnit('haproxy.service');
+    $machine->waitForUnit('httpd.service');
+    $machine->succeed('curl -k http://localhost:80/index.txt | grep "We are all good!"');
+
+  '';
+})
diff --git a/nixos/tests/hardened.nix b/nixos/tests/hardened.nix
index cb33b69e7199..0a0639d62796 100644
--- a/nixos/tests/hardened.nix
+++ b/nixos/tests/hardened.nix
@@ -25,16 +25,18 @@ import ./make-test.nix ({ pkgs, ...} : {
 
   testScript =
     ''
+      $machine->waitForUnit("multi-user.target");
+
       # Test hidepid
       subtest "hidepid", sub {
           $machine->succeed("grep -Fq hidepid=2 /proc/mounts");
-          $machine->succeed("[ `su - sybil -c 'pgrep -c -u root'` = 0 ]");
-          $machine->succeed("[ `su - alice -c 'pgrep -c -u root'` != 0 ]");
+          # cannot use pgrep -u here, it segfaults when access to process info is denied
+          $machine->succeed("[ `su - sybil -c 'ps --no-headers --user root | wc -l'` = 0 ]");
+          $machine->succeed("[ `su - alice -c 'ps --no-headers --user root | wc -l'` != 0 ]");
       };
 
       # Test kernel module hardening
       subtest "lock-modules", sub {
-          $machine->waitForUnit("multi-user.target");
           # note: this better a be module we normally wouldn't load ...
           $machine->fail("modprobe dccp");
       };
diff --git a/nixos/tests/home-assistant.nix b/nixos/tests/home-assistant.nix
index 3d920dccc166..797706a062ca 100644
--- a/nixos/tests/home-assistant.nix
+++ b/nixos/tests/home-assistant.nix
@@ -71,6 +71,7 @@ in {
     print "$log\n";
 
     # Check that no errors were logged
-    $hass->fail("cat ${configDir}/home-assistant.log | grep -qF ERROR");
+    # The timer can get out of sync due to Hydra's load, so this error is ignored
+    $hass->fail("cat ${configDir}/home-assistant.log | grep -vF 'Timer got out of sync' | grep -qF ERROR");
   '';
 })
diff --git a/nixos/tests/hydra.nix b/nixos/tests/hydra.nix
deleted file mode 100644
index 6abd7a5ad300..000000000000
--- a/nixos/tests/hydra.nix
+++ /dev/null
@@ -1,32 +0,0 @@
-import ./make-test.nix ({ pkgs, ...} : {
-  name = "hydra-init-localdb";
-  meta = with pkgs.stdenv.lib.maintainers; {
-    maintainers = [ pstn ];
-  };
-
-  machine =
-    { config, pkgs, ... }:
-
-    {
-      services.hydra = {
-        enable = true;
-
-        #Hydra needs those settings to start up, so we add something not harmfull.
-        hydraURL = "example.com";
-        notificationSender = "example@example.com";
-      };
-    };
-
-  testScript =
-    ''
-      # let the system boot up
-      $machine->waitForUnit("multi-user.target");
-      # test whether the database is running
-      $machine->succeed("systemctl status postgresql.service");
-      # test whether the actual hydra daemons are running
-      $machine->succeed("systemctl status hydra-queue-runner.service");
-      $machine->succeed("systemctl status hydra-init.service");
-      $machine->succeed("systemctl status hydra-evaluator.service");
-      $machine->succeed("systemctl status hydra-send-stats.service");
-     '';
-})
diff --git a/nixos/tests/hydra/create-trivial-project.sh b/nixos/tests/hydra/create-trivial-project.sh
new file mode 100755
index 000000000000..3cca5665acc5
--- /dev/null
+++ b/nixos/tests/hydra/create-trivial-project.sh
@@ -0,0 +1,56 @@
+#!/usr/bin/env bash
+#
+# This script creates a project, a jobset with an input of type local
+# path. This local path is a directory that contains a Nix expression
+# to define a job.
+# The EXPR-PATH environment variable must be set with the local path.
+
+set -e
+
+URL=http://localhost:3000
+USERNAME="admin"
+PASSWORD="admin"
+PROJECT_NAME="trivial"
+JOBSET_NAME="trivial"
+EXPR_PATH=${EXPR_PATH:-}
+
+if [ -z $EXPR_PATH ]; then
+   echo "Environment variable EXPR_PATH must be set"
+   exit 1
+fi
+
+mycurl() {
+  curl --referer $URL -H "Accept: application/json" -H "Content-Type: application/json" $@
+}
+
+cat >data.json <<EOF
+{ "username": "$USERNAME", "password": "$PASSWORD" }
+EOF
+mycurl -X POST -d '@data.json' $URL/login -c hydra-cookie.txt
+
+cat >data.json <<EOF
+{
+  "displayname":"Trivial",
+  "enabled":"1"
+}
+EOF
+mycurl --silent -X PUT $URL/project/$PROJECT_NAME -d @data.json -b hydra-cookie.txt
+
+cat >data.json <<EOF
+{
+  "description": "Trivial",
+  "checkinterval": "60",
+  "enabled": "1",
+  "visible": "1",
+  "keepnr": "1",
+  "nixexprinput": "trivial",
+  "nixexprpath": "trivial.nix",
+  "inputs": {
+    "trivial": {
+      "value": "$EXPR_PATH",
+      "type": "path"
+    }
+  }
+}
+EOF
+mycurl --silent -X PUT $URL/jobset/$PROJECT_NAME/$JOBSET_NAME -d @data.json -b hydra-cookie.txt
diff --git a/nixos/tests/hydra/default.nix b/nixos/tests/hydra/default.nix
new file mode 100644
index 000000000000..74919444c16d
--- /dev/null
+++ b/nixos/tests/hydra/default.nix
@@ -0,0 +1,78 @@
+import ../make-test.nix ({ pkgs, ...} :
+
+let
+   trivialJob = pkgs.writeTextDir "trivial.nix" ''
+     with import <nix/config.nix>;
+
+     { trivial = builtins.derivation {
+         name = "trivial";
+         system = "x86_64-linux";
+         PATH = coreutils;
+         builder = shell;
+         args = ["-c" "touch $out; exit 0"];
+       };
+     }
+   '';
+
+    createTrivialProject = pkgs.stdenv.mkDerivation {
+      name = "create-trivial-project";
+      unpackPhase = ":";
+      buildInputs = [ pkgs.makeWrapper ];
+      installPhase = "install -m755 -D ${./create-trivial-project.sh} $out/bin/create-trivial-project.sh";
+      postFixup = ''
+        wrapProgram "$out/bin/create-trivial-project.sh" --prefix PATH ":" ${pkgs.stdenv.lib.makeBinPath [ pkgs.curl ]} --set EXPR_PATH ${trivialJob}
+      '';
+    };
+
+in {
+  name = "hydra-init-localdb";
+  meta = with pkgs.stdenv.lib.maintainers; {
+    maintainers = [ pstn lewo ];
+  };
+
+  machine =
+    { config, pkgs, ... }:
+
+    {
+      virtualisation.memorySize = 1024;
+      time.timeZone = "UTC";
+
+      environment.systemPackages = [ createTrivialProject pkgs.jq ];
+      services.hydra = {
+        enable = true;
+
+        #Hydra needs those settings to start up, so we add something not harmfull.
+        hydraURL = "example.com";
+        notificationSender = "example@example.com";
+      };
+      nix = {
+        buildMachines = [{
+          hostName = "localhost";
+          systems = [ "x86_64-linux" ];
+        }];
+      };
+    };
+
+  testScript =
+    ''
+      # let the system boot up
+      $machine->waitForUnit("multi-user.target");
+      # test whether the database is running
+      $machine->succeed("systemctl status postgresql.service");
+      # test whether the actual hydra daemons are running
+      $machine->succeed("systemctl status hydra-queue-runner.service");
+      $machine->succeed("systemctl status hydra-init.service");
+      $machine->succeed("systemctl status hydra-evaluator.service");
+      $machine->succeed("systemctl status hydra-send-stats.service");
+
+      $machine->succeed("hydra-create-user admin --role admin --password admin");
+
+      # create a project with a trivial job
+      $machine->waitForOpenPort(3000);
+
+      # make sure the build as been successfully built
+      $machine->succeed("create-trivial-project.sh");
+
+      $machine->waitUntilSucceeds('curl -L -s http://localhost:3000/build/1 -H "Accept: application/json" |  jq .buildstatus | xargs test 0 -eq');
+     '';
+})
diff --git a/nixos/tests/iftop.nix b/nixos/tests/iftop.nix
index 21ff3cafed7c..a4f524ceb27b 100644
--- a/nixos/tests/iftop.nix
+++ b/nixos/tests/iftop.nix
@@ -9,22 +9,26 @@ with lib;
   nodes = {
     withIftop = {
       imports = [ ./common/user-account.nix ];
-
       programs.iftop.enable = true;
     };
     withoutIftop = {
       imports = [ ./common/user-account.nix ];
+      environment.systemPackages = [ pkgs.iftop ];
     };
   };
 
   testScript = ''
     subtest "machine with iftop enabled", sub {
-      $withIftop->start;
-      $withIftop->succeed("su -l alice -c 'iftop -t -s 1'");
+      $withIftop->waitForUnit("default.target");
+      # limit to eth1 (eth0 is the test driver's control interface)
+      # and don't try name lookups
+      $withIftop->succeed("su -l alice -c 'iftop -t -s 1 -n -i eth1'");
     };
     subtest "machine without iftop", sub {
-      $withoutIftop->start;
-      $withoutIftop->mustFail("su -l alice -c 'iftop -t -s 1'");
+      $withoutIftop->waitForUnit("default.target");
+      # check that iftop is there but user alice lacks capabilities
+      $withoutIftop->succeed("iftop -t -s 1 -n -i eth1");
+      $withoutIftop->fail("su -l alice -c 'iftop -t -s 1 -n -i eth1'");
     };
   '';
 })
diff --git a/nixos/tests/installer.nix b/nixos/tests/installer.nix
index 7da02d9c204a..96230940e873 100644
--- a/nixos/tests/installer.nix
+++ b/nixos/tests/installer.nix
@@ -43,7 +43,7 @@ let
           boot.loader.systemd-boot.enable = true;
         ''}
 
-        users.extraUsers.alice = {
+        users.users.alice = {
           isNormalUser = true;
           home = "/home/alice";
           description = "Alice Foobar";
@@ -51,14 +51,13 @@ let
 
         hardware.enableAllFirmware = lib.mkForce false;
 
+        services.udisks2.enable = lib.mkDefault false;
+
         ${replaceChars ["\n"] ["\n  "] extraConfig}
       }
     '';
 
 
-  channelContents = [ pkgs.rlwrap ];
-
-
   # The test script boots a NixOS VM, installs NixOS on an empty hard
   # disk, and then reboot from the hard disk.  It's parameterized with
   # a test script fragment `createPartitions', which must create
@@ -235,7 +234,7 @@ let
                 libxml2.bin
                 libxslt.bin
                 docbook5
-                docbook5_xsl
+                docbook_xsl_ns
                 unionfs-fuse
                 ntp
                 nixos-artwork.wallpapers.gnome-dark
@@ -250,6 +249,8 @@ let
               ++ optional (bootLoader == "grub" && grubVersion == 1) pkgs.grub
               ++ optionals (bootLoader == "grub" && grubVersion == 2) [ pkgs.grub2 pkgs.grub2_efi ];
 
+            services.udisks2.enable = mkDefault false;
+
             nix.binaryCaches = mkForce [ ];
             nix.extraOptions =
               ''
diff --git a/nixos/tests/jenkins.nix b/nixos/tests/jenkins.nix
index ed55b2ff5871..25629efbfa49 100644
--- a/nixos/tests/jenkins.nix
+++ b/nixos/tests/jenkins.nix
@@ -18,7 +18,7 @@ import ./make-test.nix ({ pkgs, ...} : {
         # should have no effect
         services.jenkinsSlave.enable = true;
 
-        users.extraUsers.jenkins.extraGroups = [ "users" ];
+        users.users.jenkins.extraGroups = [ "users" ];
 
         systemd.services.jenkins.serviceConfig.TimeoutStartSec = "6min";
       };
@@ -27,7 +27,7 @@ import ./make-test.nix ({ pkgs, ...} : {
       { config, pkgs, ... }:
       { services.jenkinsSlave.enable = true;
 
-        users.extraUsers.jenkins.extraGroups = [ "users" ];
+        users.users.jenkins.extraGroups = [ "users" ];
       };
 
   };
diff --git a/nixos/tests/kubernetes/base.nix b/nixos/tests/kubernetes/base.nix
index 27b99aacab7d..e4bc5b326d34 100644
--- a/nixos/tests/kubernetes/base.nix
+++ b/nixos/tests/kubernetes/base.nix
@@ -24,7 +24,7 @@ let
         { config, pkgs, lib, nodes, ... }:
           mkMerge [
             {
-              virtualisation.memorySize = mkDefault 768;
+              virtualisation.memorySize = mkDefault 1536;
               virtualisation.diskSize = mkDefault 4096;
               networking = {
                 inherit domain extraHosts;
diff --git a/nixos/tests/kubernetes/kubernetes-common.nix b/nixos/tests/kubernetes/kubernetes-common.nix
index ddf427e1b01a..125c176f1132 100644
--- a/nixos/tests/kubernetes/kubernetes-common.nix
+++ b/nixos/tests/kubernetes/kubernetes-common.nix
@@ -6,7 +6,6 @@ let
     featureGates = ["AllAlpha"];
     flannel.enable = true;
     addons.dashboard.enable = true;
-    verbose = true;
 
     caFile = "${certs.master}/ca.pem";
     apiserver = {
diff --git a/nixos/tests/lightdm.nix b/nixos/tests/lightdm.nix
index 97ec79406b88..d2b561fa67b4 100644
--- a/nixos/tests/lightdm.nix
+++ b/nixos/tests/lightdm.nix
@@ -16,7 +16,7 @@ import ./make-test.nix ({ pkgs, ...} : {
   enableOCR = true;
 
   testScript = { nodes, ... }: let
-    user = nodes.machine.config.users.extraUsers.alice;
+    user = nodes.machine.config.users.users.alice;
   in ''
     startAll;
     $machine->waitForText(qr/${user.description}/);
diff --git a/nixos/tests/memcached.nix b/nixos/tests/memcached.nix
new file mode 100644
index 000000000000..f9ef3647bd1a
--- /dev/null
+++ b/nixos/tests/memcached.nix
@@ -0,0 +1,28 @@
+import ./make-test.nix ({ pkgs, ...} : {
+  name = "memcached";
+
+  nodes = {
+    machine =
+      { config, pkgs, ... }:
+      {
+        imports = [ ../modules/profiles/minimal.nix ];
+        services.memcached.enable = true;
+      };
+  };
+
+  testScript = let
+    testScript = pkgs.writeScript "testScript.py" ''
+      #!${pkgs.python3.withPackages (p: [p.memcached])}/bin/python
+
+      import memcache
+      c = memcache.Client(['localhost:11211'])
+      c.set('key', 'value')
+      assert 'value' == c.get('key')
+    '';
+  in ''
+    startAll;
+    $machine->waitForUnit("memcached.service");
+    $machine->waitForOpenPort("11211");
+    $machine->succeed("${testScript}");
+  '';
+})
diff --git a/nixos/tests/morty.nix b/nixos/tests/morty.nix
new file mode 100644
index 000000000000..0a5324259ada
--- /dev/null
+++ b/nixos/tests/morty.nix
@@ -0,0 +1,32 @@
+import ./make-test.nix ({ pkgs, ... }:
+
+{
+  name = "morty";
+  meta = with pkgs.stdenv.lib.maintainers; {
+    maintainers = [ leenaars ];
+  };
+
+  nodes =
+    { mortyProxyWithKey =
+
+      { config, pkgs, ... }:
+      { services.morty = {
+        enable = true;
+	key = "78a9cd0cfee20c672f78427efb2a2a96036027f0";
+	port = 3001;
+	};
+      };
+
+    };
+
+  testScript =
+    { nodes , ... }:
+    ''
+      $mortyProxyWithKey->waitForUnit("default.target");
+
+      $mortyProxyWithKey->waitForOpenPort(3001);
+      $mortyProxyWithKey->succeed("curl -L 127.0.0.1:3001 | grep MortyProxy");
+
+    '';
+
+})
diff --git a/nixos/tests/mpd.nix b/nixos/tests/mpd.nix
new file mode 100644
index 000000000000..2950a8d809d6
--- /dev/null
+++ b/nixos/tests/mpd.nix
@@ -0,0 +1,119 @@
+import ./make-test.nix ({ pkgs, ... }:
+  let
+    track = pkgs.fetchurl {
+      # Sourced from http://freemusicarchive.org/music/Blue_Wave_Theory/Surf_Music_Month_Challenge/Skyhawk_Beach_fade_in
+      # License: http://creativecommons.org/licenses/by-sa/4.0/
+
+      name = "Blue_Wave_Theory-Skyhawk_Beach.mp3";
+      url = https://freemusicarchive.org/file/music/ccCommunity/Blue_Wave_Theory/Surf_Music_Month_Challenge/Blue_Wave_Theory_-_04_-_Skyhawk_Beach.mp3;
+      sha256 = "0xw417bxkx4gqqy139bb21yldi37xx8xjfxrwaqa0gyw19dl6mgp";
+    };
+
+    defaultCfg = rec {
+      user = "mpd";
+      group = "mpd";
+      dataDir = "/var/lib/mpd";
+      musicDirectory = "${dataDir}/music";
+    };
+
+    defaultMpdCfg = with defaultCfg; {
+      inherit dataDir musicDirectory user group;
+      enable = true;
+    };
+
+    musicService = { user, group, musicDirectory }: {
+      description = "Sets up the music file(s) for MPD to use.";
+      requires = [ "mpd.service" ];
+      after = [ "mpd.service" ];
+      wantedBy = [ "default.target" ];
+      script = ''
+        mkdir -p ${musicDirectory} && chown -R ${user}:${group} ${musicDirectory}
+        cp ${track} ${musicDirectory}
+        chown ${user}:${group} ${musicDirectory}/$(basename ${track})
+      '';
+    };
+
+    mkServer = { mpd, musicService, }:
+      { boot.kernelModules = [ "snd-dummy" ];
+        sound.enable = true;
+        services.mpd = mpd;
+        systemd.services.musicService = musicService;
+      };
+  in {
+    name = "mpd";
+    meta = with pkgs.stdenv.lib.maintainers; {
+      maintainers = [ emmanuelrosa ];
+    };
+
+  nodes =
+    { client = 
+      { config, pkgs, ... }: { };
+
+      serverALSA =
+        { config, pkgs, ... }: (mkServer {
+          mpd = defaultMpdCfg // {
+            network.listenAddress = "any";
+            extraConfig = ''
+              audio_output {
+                type "alsa"
+                name "ALSA"
+                mixer_type "null"
+              }
+            '';
+          };
+
+          musicService = with defaultMpdCfg; musicService { inherit user group musicDirectory; };
+        }) // { networking.firewall.allowedTCPPorts = [ 6600 ]; };
+
+      serverPulseAudio =
+        { config, pkgs, ... }: (mkServer {
+          mpd = defaultMpdCfg // {
+            extraConfig = ''
+              audio_output {
+                type "pulse"
+                name "The Pulse"
+              }
+            '';
+          };
+
+          musicService = with defaultCfg; musicService { inherit user group musicDirectory; };
+        }) // { hardware.pulseaudio.enable = true; };
+    };
+
+  testScript = ''
+    my $mpc = "${pkgs.mpc_cli}/bin/mpc --wait";
+
+    # Connects to the given server and attempts to play a tune.
+    sub play_some_music {
+        my $server = $_[0];
+
+        $server->waitForUnit("mpd.service");
+        $server->succeed("$mpc update");
+        my @tracks = $server->execute("$mpc ls");
+
+        for my $track (split(/\n/, $tracks[1])) {
+            $server->succeed("$mpc add $track");
+        };
+
+        my @added_tracks = $server->execute("$mpc listall");
+        (length $added_tracks[1]) > 0 or die "Failed to add audio tracks to the playlist.";
+
+        $server->succeed("$mpc play");
+
+        my @status = $server->execute("$mpc status");
+        my @output = split(/\n/, $status[1]);
+        $output[1] =~ /.*playing.*/ or die "Audio track is not playing, as expected.";
+
+        $server->succeed("$mpc stop");
+    };
+
+    play_some_music($serverALSA);
+    play_some_music($serverPulseAudio);
+
+    $client->succeed("$mpc -h serverALSA status");
+
+    # The PulseAudio-based server is configured not to accept external client connections
+    # to perform the following test:
+    $client->fail("$mpc -h serverPulseAudio status");
+  '';
+})
diff --git a/nixos/tests/mysql-replication.nix b/nixos/tests/mysql-replication.nix
index 75c6d793febc..ed09ac10b75d 100644
--- a/nixos/tests/mysql-replication.nix
+++ b/nixos/tests/mysql-replication.nix
@@ -57,18 +57,25 @@ in
     $master->start;
     $master->waitForUnit("mysql");
     $master->waitForOpenPort(3306);
+    # Wait for testdb to be fully populated (5 rows).
+    $master->waitUntilSucceeds("mysql -u root -D testdb -N -B -e 'select count(id) from tests' | grep -q 5");
+
     $slave1->start;
     $slave2->start;
     $slave1->waitForUnit("mysql");
     $slave1->waitForOpenPort(3306);
     $slave2->waitForUnit("mysql");
     $slave2->waitForOpenPort(3306);
-    $slave2->succeed("echo 'use testdb; select * from tests' | mysql -u root -N | grep 4");
+
+    # wait for replications to finish
+    $slave1->waitUntilSucceeds("mysql -u root -D testdb -N -B -e 'select count(id) from tests' | grep -q 5");
+    $slave2->waitUntilSucceeds("mysql -u root -D testdb -N -B -e 'select count(id) from tests' | grep -q 5");
+
     $slave2->succeed("systemctl stop mysql");
     $master->succeed("echo 'insert into testdb.tests values (123, 456);' | mysql -u root -N");
     $slave2->succeed("systemctl start mysql");
     $slave2->waitForUnit("mysql");
     $slave2->waitForOpenPort(3306);
-    $slave2->succeed("echo 'select * from testdb.tests where Id = 123;' | mysql -u root -N | grep 456");
+    $slave2->waitUntilSucceeds("echo 'select * from testdb.tests where Id = 123;' | mysql -u root -N | grep 456");
   '';
 })
diff --git a/nixos/tests/mysql.nix b/nixos/tests/mysql.nix
index baaebf9f10db..c18fee6c7495 100644
--- a/nixos/tests/mysql.nix
+++ b/nixos/tests/mysql.nix
@@ -19,7 +19,6 @@ import ./make-test.nix ({ pkgs, ...} : {
     startAll;
 
     $master->waitForUnit("mysql");
-    $master->sleep(10); # Hopefully this is long enough!!
     $master->succeed("echo 'use testdb; select * from tests' | mysql -u root -N | grep 4");
   '';
 })
diff --git a/nixos/tests/nexus.nix b/nixos/tests/nexus.nix
index d12d06c2c00f..be8862018777 100644
--- a/nixos/tests/nexus.nix
+++ b/nixos/tests/nexus.nix
@@ -13,7 +13,7 @@ import ./make-test.nix ({ pkgs, ...} : {
 
     server =
       { config, pkgs, ... }:
-      { virtualisation.memorySize = 2048;
+      { virtualisation.memorySize = 2047; # qemu-system-i386 has a 2047M limit
         virtualisation.diskSize = 2048;
 
         services.nexus.enable = true;
diff --git a/nixos/tests/opensmtpd.nix b/nixos/tests/opensmtpd.nix
new file mode 100644
index 000000000000..5079779f35b4
--- /dev/null
+++ b/nixos/tests/opensmtpd.nix
@@ -0,0 +1,115 @@
+import ./make-test.nix {
+  name = "opensmtpd";
+
+  nodes = {
+    smtp1 = { pkgs, ... }: {
+      imports = [ common/user-account.nix ];
+      networking = {
+        firewall.allowedTCPPorts = [ 25 ];
+        useDHCP = false;
+        interfaces.eth1.ipv4.addresses = pkgs.lib.mkOverride 0 [
+          { address = "192.168.1.1"; prefixLength = 24; }
+        ];
+      };
+      environment.systemPackages = [ pkgs.opensmtpd ];
+      services.opensmtpd = {
+        enable = true;
+        extraServerArgs = [ "-v" ];
+        serverConfiguration = ''
+          listen on 0.0.0.0
+          # DO NOT DO THIS IN PRODUCTION!
+          # Setting up authentication requires a certificate which is painful in
+          # a test environment, but THIS WOULD BE DANGEROUS OUTSIDE OF A
+          # WELL-CONTROLLED ENVIRONMENT!
+          accept from any for any relay
+        '';
+      };
+    };
+
+    smtp2 = { pkgs, ... }: {
+      imports = [ common/user-account.nix ];
+      networking = {
+        firewall.allowedTCPPorts = [ 25 143 ];
+        useDHCP = false;
+        interfaces.eth1.ipv4.addresses = pkgs.lib.mkOverride 0 [
+          { address = "192.168.1.2"; prefixLength = 24; }
+        ];
+      };
+      environment.systemPackages = [ pkgs.opensmtpd ];
+      services.opensmtpd = {
+        enable = true;
+        extraServerArgs = [ "-v" ];
+        serverConfiguration = ''
+          listen on 0.0.0.0
+          accept from any for local deliver to mda \
+            "${pkgs.dovecot}/libexec/dovecot/deliver -d %{user.username}"
+        '';
+      };
+      services.dovecot2 = {
+        enable = true;
+        enableImap = true;
+        mailLocation = "maildir:~/mail";
+        protocols = [ "imap" ];
+      };
+    };
+
+    client = { pkgs, ... }: {
+      networking = {
+        useDHCP = false;
+        interfaces.eth1.ipv4.addresses = pkgs.lib.mkOverride 0 [
+          { address = "192.168.1.3"; prefixLength = 24; }
+        ];
+      };
+      environment.systemPackages = let
+        sendTestMail = pkgs.writeScriptBin "send-a-test-mail" ''
+          #!${pkgs.python3.interpreter}
+          import smtplib, sys
+
+          with smtplib.SMTP('192.168.1.1') as smtp:
+            smtp.sendmail('alice@[192.168.1.1]', 'bob@[192.168.1.2]', """
+              From: alice@smtp1
+              To: bob@smtp2
+              Subject: Test
+
+              Hello World
+            """)
+        '';
+
+        checkMailLanded = pkgs.writeScriptBin "check-mail-landed" ''
+          #!${pkgs.python3.interpreter}
+          import imaplib
+
+          with imaplib.IMAP4('192.168.1.2', 143) as imap:
+            imap.login('bob', 'foobar')
+            imap.select()
+            status, refs = imap.search(None, 'ALL')
+            assert status == 'OK'
+            assert len(refs) == 1
+            status, msg = imap.fetch(refs[0], 'BODY[TEXT]')
+            assert status == 'OK'
+            content = msg[0][1]
+            print("===> content:", content)
+            split = content.split(b'\r\n')
+            print("===> split:", split)
+            lastline = split[-3]
+            print("===> lastline:", lastline)
+            assert lastline.strip() == b'Hello World'
+        '';
+      in [ sendTestMail checkMailLanded ];
+    };
+  };
+
+  testScript = ''
+    startAll;
+
+    $client->waitForUnit("network.target");
+    $smtp1->waitForUnit('opensmtpd');
+    $smtp2->waitForUnit('opensmtpd');
+    $smtp2->waitForUnit('dovecot2');
+
+    $client->succeed('send-a-test-mail');
+    $smtp1->waitUntilFails('smtpctl show queue | egrep .');
+    $smtp2->waitUntilFails('smtpctl show queue | egrep .');
+    $client->succeed('check-mail-landed >&2');
+  '';
+}
diff --git a/nixos/tests/openssh.nix b/nixos/tests/openssh.nix
index b2d254e9d9d9..230b45206847 100644
--- a/nixos/tests/openssh.nix
+++ b/nixos/tests/openssh.nix
@@ -17,7 +17,7 @@ in {
         services.openssh.enable = true;
         security.pam.services.sshd.limits =
           [ { domain = "*"; item = "memlock"; type = "-"; value = 1024; } ];
-        users.extraUsers.root.openssh.authorizedKeys.keys = [
+        users.users.root.openssh.authorizedKeys.keys = [
           snakeOilPublicKey
         ];
       };
@@ -29,7 +29,7 @@ in {
         services.openssh = { enable = true; startWhenNeeded = true; };
         security.pam.services.sshd.limits =
           [ { domain = "*"; item = "memlock"; type = "-"; value = 1024; } ];
-        users.extraUsers.root.openssh.authorizedKeys.keys = [
+        users.users.root.openssh.authorizedKeys.keys = [
           snakeOilPublicKey
         ];
       };
diff --git a/nixos/tests/ostree.nix b/nixos/tests/ostree.nix
new file mode 100644
index 000000000000..8b19004874e7
--- /dev/null
+++ b/nixos/tests/ostree.nix
@@ -0,0 +1,21 @@
+# run installed tests
+import ./make-test.nix ({ pkgs, lib, ... }: {
+  name = "ostree";
+
+  meta = {
+    maintainers = pkgs.ostree.meta.maintainers;
+  };
+
+  # TODO: Wrap/patch the tests directly in the package
+  machine = { pkgs, ... }: {
+    environment.systemPackages = with pkgs; [
+      gnome-desktop-testing ostree gnupg (python3.withPackages (p: with p; [ pyyaml ]))
+    ];
+
+    environment.variables.GI_TYPELIB_PATH = lib.makeSearchPath "lib/girepository-1.0" (with pkgs; [ gtk3 pango.out ostree gdk_pixbuf atk ]); # for GJS tests
+  };
+
+  testScript = ''
+    $machine->succeed("gnome-desktop-testing-runner -d ${pkgs.ostree.installedTests}/share");
+  '';
+})
diff --git a/nixos/tests/pam-oath-login.nix b/nixos/tests/pam-oath-login.nix
index 4364d6e354a6..9f40ecfe865f 100644
--- a/nixos/tests/pam-oath-login.nix
+++ b/nixos/tests/pam-oath-login.nix
@@ -12,8 +12,6 @@ let
   # and picking a the first 4:
   oathSnakeOilPassword1 = "143349";
   oathSnakeOilPassword2 = "801753";
-  oathSnakeOilPassword3 = "019933";
-  oathSnakeOilPassword4 = "403895";
 
   alicePassword = "foobar";
   # Generated via: mkpasswd -m sha-512 and passing in "foobar"
@@ -30,7 +28,7 @@ in
         enable = true;
       };
 
-      users.extraUsers.alice = {
+      users.users.alice = {
         isNormalUser = true;
         name = "alice";
         uid = 1000;
diff --git a/nixos/tests/plasma5.nix b/nixos/tests/plasma5.nix
index f3bd4c5915b0..e479d3f1cb8f 100644
--- a/nixos/tests/plasma5.nix
+++ b/nixos/tests/plasma5.nix
@@ -6,13 +6,28 @@ import ./make-test.nix ({ pkgs, ...} :
     maintainers = [ ttuegel ];
   };
 
-  machine = { lib, ... }: {
+  machine = { lib, ... }:
+  let
+    sddm_theme = pkgs.stdenv.mkDerivation {
+      name = "breeze-ocr-theme";
+      phases = "buildPhase";
+      buildCommand = ''
+        mkdir -p $out/share/sddm/themes/
+        cp -r ${pkgs.plasma-workspace}/share/sddm/themes/breeze $out/share/sddm/themes/breeze-ocr-theme
+        chmod -R +w $out/share/sddm/themes/breeze-ocr-theme
+        printf "[General]\ntype=color\ncolor=#1d99f3\nbackground=\n" > $out/share/sddm/themes/breeze-ocr-theme/theme.conf
+      '';
+    };
+  in
+  {
     imports = [ ./common/user-account.nix ];
     services.xserver.enable = true;
     services.xserver.displayManager.sddm.enable = true;
+    services.xserver.displayManager.sddm.theme = "breeze-ocr-theme";
     services.xserver.desktopManager.plasma5.enable = true;
     services.xserver.desktopManager.default = "plasma5";
     virtualisation.memorySize = 1024;
+    environment.systemPackages = [ sddm_theme ];
 
     # fontconfig-penultimate-0.3.3 -> 0.3.4 broke OCR apparently, but no idea why.
     nixpkgs.config.packageOverrides = superPkgs: {
@@ -26,11 +41,10 @@ import ./make-test.nix ({ pkgs, ...} :
   enableOCR = true;
 
   testScript = { nodes, ... }: let
-    user = nodes.machine.config.users.extraUsers.alice;
+    user = nodes.machine.config.users.users.alice;
     xdo = "${pkgs.xdotool}/bin/xdotool";
   in ''
     startAll;
-
     # Wait for display manager to start
     $machine->waitForText(qr/${user.description}/);
     $machine->screenshot("sddm");
diff --git a/nixos/tests/postgresql.nix b/nixos/tests/postgresql.nix
index 0ce37b55bb7b..2381939552e2 100644
--- a/nixos/tests/postgresql.nix
+++ b/nixos/tests/postgresql.nix
@@ -26,6 +26,9 @@ let
       {
         services.postgresql.package=postgresql-package;
         services.postgresql.enable = true;
+
+        services.postgresqlBackup.enable = true;
+        services.postgresqlBackup.databases = [ "postgres" ];
       };
 
     testScript = ''
@@ -46,6 +49,10 @@ let
       $machine->succeed(check_count("SELECT * FROM sth;", 5));
       $machine->fail(check_count("SELECT * FROM sth;", 4));
       $machine->succeed(check_count("SELECT xpath(\'/test/text()\', doc) FROM xmltest;", 1));
+
+      # Check backup service
+      $machine->succeed("systemctl start postgresqlBackup-postgres.service");
+      $machine->succeed("zcat /var/backup/postgresql/postgres.sql.gz | grep '<test>ok</test>'");
       $machine->shutdown;
     '';
 
diff --git a/nixos/tests/sddm.nix b/nixos/tests/sddm.nix
index 1ce2b8157842..ac91a89f6695 100644
--- a/nixos/tests/sddm.nix
+++ b/nixos/tests/sddm.nix
@@ -21,7 +21,7 @@ let
       enableOCR = true;
 
       testScript = { nodes, ... }: let
-        user = nodes.machine.config.users.extraUsers.alice;
+        user = nodes.machine.config.users.users.alice;
       in ''
         startAll;
         $machine->waitForText(qr/select your user/i);
diff --git a/nixos/tests/slim.nix b/nixos/tests/slim.nix
index 7b939d836381..5c76c58cf3f3 100644
--- a/nixos/tests/slim.nix
+++ b/nixos/tests/slim.nix
@@ -48,7 +48,7 @@ import ./make-test.nix ({ pkgs, ...} : {
   enableOCR = true;
 
   testScript = { nodes, ... }: let
-    user = nodes.machine.config.users.extraUsers.alice;
+    user = nodes.machine.config.users.users.alice;
   in ''
     startAll;
     $machine->waitForText(qr/Username:/);
diff --git a/nixos/tests/slurm.nix b/nixos/tests/slurm.nix
index 0dd00dfb04c2..ec67ea092874 100644
--- a/nixos/tests/slurm.nix
+++ b/nixos/tests/slurm.nix
@@ -1,7 +1,6 @@
 import ./make-test.nix ({ pkgs, ... }:
 let mungekey = "mungeverryweakkeybuteasytointegratoinatest";
     slurmconfig = {
-      client.enable = true;
       controlMachine = "control";
       nodeName = ''
         control
@@ -20,36 +19,49 @@ in {
         # TODO slrumd port and slurmctld port should be configurations and
         # automatically allowed by the  firewall.
         networking.firewall.enable = false;
-        services.munge.enable = true;
-        services.slurm = slurmconfig;
+        services.slurm = {
+          client.enable = true;
+        } // slurmconfig;
       };
     in {
+
     control =
       { config, pkgs, ...}:
       {
         networking.firewall.enable = false;
-        services.munge.enable = true;
         services.slurm = {
           server.enable = true;
         } // slurmconfig;
       };
+
+    submit =
+      { config, pkgs, ...}:
+      {
+        networking.firewall.enable = false;
+        services.slurm = {
+          enableStools = true;
+        } // slurmconfig;
+      };
+
     node1 = computeNode;
     node2 = computeNode;
     node3 = computeNode;
   };
 
+
   testScript =
   ''
   startAll;
 
   # Set up authentification across the cluster
-  foreach my $node (($control,$node1,$node2,$node3))
+  foreach my $node (($submit,$control,$node1,$node2,$node3))
   {
     $node->waitForUnit("default.target");
 
     $node->succeed("mkdir /etc/munge");
     $node->succeed("echo '${mungekey}' > /etc/munge/munge.key");
     $node->succeed("chmod 0400 /etc/munge/munge.key");
+    $node->succeed("chown munge:munge /etc/munge/munge.key");
     $node->succeed("systemctl restart munged");
   }
 
@@ -62,7 +74,7 @@ in {
   };
 
   subtest "can_start_slurmd", sub {
-    foreach my $node (($control,$node1,$node2,$node3))
+    foreach my $node (($node1,$node2,$node3))
     {
       $node->succeed("systemctl restart slurmd.service");
       $node->waitForUnit("slurmd");
@@ -74,7 +86,7 @@ in {
   subtest "run_distributed_command", sub {
     # Run `hostname` on 3 nodes of the partition (so on all the 3 nodes).
     # The output must contain the 3 different names
-    $control->succeed("srun -N 3 hostname | sort | uniq | wc -l | xargs test 3 -eq");
+    $submit->succeed("srun -N 3 hostname | sort | uniq | wc -l | xargs test 3 -eq");
   };
   '';
 })
diff --git a/nixos/tests/sudo.nix b/nixos/tests/sudo.nix
index 35addb0ee805..5d6c8691230a 100644
--- a/nixos/tests/sudo.nix
+++ b/nixos/tests/sudo.nix
@@ -14,7 +14,7 @@ in
       { config, lib, pkgs, ... }:
       with lib;
       {
-        users.extraGroups = { foobar = {}; barfoo = {}; baz = { gid = 1337; }; };
+        users.groups = { foobar = {}; barfoo = {}; baz = { gid = 1337; }; };
         users.users = {
           test0 = { isNormalUser = true; extraGroups = [ "wheel" ]; };
           test1 = { isNormalUser = true; password = password; };
diff --git a/nixos/tests/taskserver.nix b/nixos/tests/taskserver.nix
index 75be97a507d0..ab9b589f8593 100644
--- a/nixos/tests/taskserver.nix
+++ b/nixos/tests/taskserver.nix
@@ -18,7 +18,7 @@ import ./make-test.nix ({ pkgs, ... }: let
     crlTemplate = pkgs.writeText "snakeoil-crl.template" ''
       expiration_days = -1
     '';
-    userCertTemplace = pkgs.writeText "snakoil-user-cert.template" ''
+    userCertTemplate = pkgs.writeText "snakeoil-user-cert.template" ''
       organization = snakeoil
       cn = server
       expiration_days = -1
@@ -49,7 +49,7 @@ import ./make-test.nix ({ pkgs, ... }: let
     certtool -p --bits 4096 | sed -n \
       -e '/^----* *BEGIN/,/^----* *END/p' > "$out/alice.key"
 
-    certtool -c --template "$userCertTemplace" \
+    certtool -c --template "$userCertTemplate" \
                 --load-privkey "$out/alice.key" \
                 --load-ca-privkey ca.key \
                 --load-ca-certificate "$cacert" \
@@ -82,8 +82,9 @@ in {
       # This is to avoid assigning a different network address to the new
       # generation.
       networking = lib.mapAttrs (lib.const lib.mkForce) {
+        interfaces.eth1.ipv4 = nodes.server.config.networking.interfaces.eth1.ipv4;
         inherit (nodes.server.config.networking)
-          hostName interfaces primaryIPAddress extraHosts;
+          hostName primaryIPAddress extraHosts;
       };
     };
 
diff --git a/nixos/tests/tor.nix b/nixos/tests/tor.nix
new file mode 100644
index 000000000000..24d46a03897e
--- /dev/null
+++ b/nixos/tests/tor.nix
@@ -0,0 +1,28 @@
+import ./make-test.nix ({ lib, ... }: with lib;
+
+rec {
+  name = "tor";
+  meta.maintainers = with maintainers; [ joachifm ];
+
+  common =
+    { config, ... }:
+    { boot.kernelParams = [ "audit=0" "apparmor=0" "quiet" ];
+      networking.firewall.enable = false;
+      networking.useDHCP = false;
+    };
+
+  nodes.client =
+    { config, pkgs, ... }:
+    { imports = [ common ];
+      environment.systemPackages = with pkgs; [ netcat ];
+      services.tor.enable = true;
+      services.tor.client.enable = true;
+      services.tor.controlPort = 9051;
+    };
+
+  testScript = ''
+    $client->waitForUnit("tor.service");
+    $client->waitForOpenPort(9051);
+    $client->succeed("echo GETINFO version | nc 127.0.0.1 9051") =~ /514 Authentication required./ or die;
+  '';
+})
diff --git a/nixos/tests/virtualbox.nix b/nixos/tests/virtualbox.nix
index 249571fcedec..008dab8459c8 100644
--- a/nixos/tests/virtualbox.nix
+++ b/nixos/tests/virtualbox.nix
@@ -334,7 +334,7 @@ let
       virtualisation.memorySize = 2048;
       virtualisation.virtualbox.host.enable = true;
       services.xserver.displayManager.auto.user = "alice";
-      users.extraUsers.alice.extraGroups = let
+      users.users.alice.extraGroups = let
         inherit (config.virtualisation.virtualbox.host) enableHardening;
       in lib.mkIf enableHardening (lib.singleton "vboxusers");
     };
diff --git a/nixos/tests/xss-lock.nix b/nixos/tests/xss-lock.nix
new file mode 100644
index 000000000000..045667bdcdec
--- /dev/null
+++ b/nixos/tests/xss-lock.nix
@@ -0,0 +1,25 @@
+import ./make-test.nix ({ pkgs, lib, ... }:
+
+with lib;
+
+{
+  name = "xss-lock";
+  meta.maintainers = with pkgs.stdenv.lib.maintainers; [ ma27 ];
+
+  machine = {
+    imports = [ ./common/x11.nix ./common/user-account.nix ];
+    programs.xss-lock.enable = true;
+    programs.xss-lock.lockerCommand = "${pkgs.xlockmore}/bin/xlock";
+    services.xserver.displayManager.auto.user = "alice";
+  };
+
+  testScript = ''
+    $machine->start;
+    $machine->waitForX;
+    $machine->waitForUnit("xss-lock.service", "alice");
+
+    $machine->fail("pgrep xlock");
+    $machine->succeed("su -l alice -c 'xset dpms force standby'");
+    $machine->waitUntilSucceeds("pgrep xlock");
+  '';
+})